summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/checksum
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2016-02-10 00:47:33 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2016-02-10 00:47:33 +0000
commit4d3cb38a59298cbae72d2d91741fd01fff8abd57 (patch)
tree42f2c69221039083a24f1f690500c2354f096a7a /src/VBox/Runtime/common/checksum
parent76a1dd09b0bdd02007bd9e9c47d5e63bc115f302 (diff)
downloadVirtualBox-svn-4d3cb38a59298cbae72d2d91741fd01fff8abd57.tar.gz
IPRT: Added 'off' parameter to RTVfsIoStrmSgWrite and RTVfsIoStrmSgRead so it's easier to write passthru layers. Added RTVfsIoStrmReadAll, RTVfsIoStrmReadAllFree, RTVfsIoStrmFromBuffer, RTManifestPtIosIsInstanceOf, RTCrX509Certificate_ReadFromBuffer and RTCrDigestUpdateFromVfsFile. Updated the manifest passthru read code to handle ReadAt requests which skips parts and jumps back to re-read stuff on streams/files which are seekable.
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@59620 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/Runtime/common/checksum')
-rw-r--r--src/VBox/Runtime/common/checksum/manifest2.cpp2
-rw-r--r--src/VBox/Runtime/common/checksum/manifest3.cpp127
2 files changed, 122 insertions, 7 deletions
diff --git a/src/VBox/Runtime/common/checksum/manifest2.cpp b/src/VBox/Runtime/common/checksum/manifest2.cpp
index 58d1e335200..a7d996afdba 100644
--- a/src/VBox/Runtime/common/checksum/manifest2.cpp
+++ b/src/VBox/Runtime/common/checksum/manifest2.cpp
@@ -526,7 +526,7 @@ static DECLCALLBACK(int) rtManifestEntryCompare(PRTSTRSPACECORE pStr, void *pvUs
PRTMANIFESTENTRY pEntry2;
/*
- * Ignore this entry.
+ * Ignore this entry?
*/
char const * const *ppsz = pEquals->papszIgnoreEntries;
if (ppsz)
diff --git a/src/VBox/Runtime/common/checksum/manifest3.cpp b/src/VBox/Runtime/common/checksum/manifest3.cpp
index 091953d6d83..5b24029d1bb 100644
--- a/src/VBox/Runtime/common/checksum/manifest3.cpp
+++ b/src/VBox/Runtime/common/checksum/manifest3.cpp
@@ -31,6 +31,7 @@
#include "internal/iprt.h"
#include <iprt/manifest.h>
+#include <iprt/alloca.h>
#include <iprt/asm.h>
#include <iprt/assert.h>
#include <iprt/err.h>
@@ -90,6 +91,8 @@ typedef struct RTMANIFESTPTIOS
RTVFSIOSTREAM hVfsIos;
/** The hashes. */
PRTMANIFESTHASHES pHashes;
+ /** The current hash position. */
+ RTFOFF offCurPos;
/** Whether we're reading or writing. */
bool fReadOrWrite;
/** Whether we've already added the entry to the manifest. */
@@ -314,10 +317,89 @@ static void rtManifestPtIos_UpdateHashes(PRTMANIFESTPTIOS pThis, PCRTSGBUF pSgBu
static DECLCALLBACK(int) rtManifestPtIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
{
PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
- int rc = RTVfsIoStrmSgRead(pThis->hVfsIos, pSgBuf, fBlocking, pcbRead);
- if (RT_SUCCESS(rc))
- rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbRead ? *pcbRead : ~(size_t)0);
- Assert(off == -1); NOREF(off);
+ int rc;
+
+ /*
+ * To make sure we're continuing where we left off, we must have the exact
+ * stream position since a previous read using 'off' may change it.
+ */
+ RTFOFF offActual = off == -1 ? RTVfsIoStrmTell(pThis->hVfsIos) : off;
+ if (offActual == pThis->offCurPos)
+ {
+ rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
+ if (RT_SUCCESS(rc))
+ {
+ rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbRead ? *pcbRead : ~(size_t)0);
+ if (!pcbRead)
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ pThis->offCurPos += pSgBuf->paSegs[iSeg].cbSeg;
+ else
+ pThis->offCurPos += *pcbRead;
+ }
+ Assert(RTVfsIoStrmTell(pThis->hVfsIos) == pThis->offCurPos);
+ }
+ else
+ {
+ /*
+ * If we're skipping over stuff, we need to read the gap and hash it.
+ */
+ if (pThis->offCurPos < offActual)
+ {
+ size_t cbBuf = _8K;
+ void *pvBuf = alloca(cbBuf);
+ do
+ {
+ RTFOFF cbGap = off - pThis->offCurPos;
+ size_t cbThisRead = cbGap >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbGap;
+ size_t cbActual;
+ rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offCurPos, pvBuf, cbThisRead, fBlocking, &cbActual);
+ if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN)
+ return rc;
+
+ rtManifestHashesUpdate(pThis->pHashes, pvBuf, cbActual);
+ pThis->offCurPos += cbActual;
+
+ if (rc == VINF_EOF)
+ {
+ if (pcbRead)
+ *pcbRead = 0;
+ else
+ rc = VERR_EOF;
+ return rc;
+ }
+ } while (pThis->offCurPos < offActual);
+ Assert(RTVfsIoStrmTell(pThis->hVfsIos) == offActual);
+ }
+
+ /*
+ * At this point we've eliminated any gap and can execute the requested read.
+ */
+ rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
+ if (RT_SUCCESS(rc))
+ {
+ /* See if there is anything to update the hash with. */
+ size_t cbLeft = pcbRead ? *pcbRead : ~(size_t)0;
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ {
+ size_t cbThis = pSgBuf->paSegs[iSeg].cbSeg;
+ if (cbThis > cbLeft)
+ cbThis = cbLeft;
+
+ if ( offActual >= pThis->offCurPos
+ && pThis->offCurPos < offActual + (ssize_t)cbThis)
+ {
+ size_t offSeg = (size_t)(offActual - pThis->offCurPos);
+ rtManifestHashesUpdate(pThis->pHashes, (uint8_t *)pSgBuf->paSegs[iSeg].pvSeg + offSeg, cbThis - offSeg);
+ pThis->offCurPos += cbThis - offSeg;
+ }
+
+ cbLeft -= cbThis;
+ if (!cbLeft)
+ break;
+ offActual += cbThis;
+ }
+ }
+ }
return rc;
}
@@ -328,10 +410,19 @@ static DECLCALLBACK(int) rtManifestPtIos_Read(void *pvThis, RTFOFF off, PCRTSGBU
static DECLCALLBACK(int) rtManifestPtIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
{
PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
- int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, pSgBuf, fBlocking, pcbWritten);
+ AssertReturn(off == -1 || off == pThis->offCurPos, VERR_WRONG_ORDER);
+ Assert(RTVfsIoStrmTell(pThis->hVfsIos) == pThis->offCurPos);
+
+ int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
if (RT_SUCCESS(rc))
+ {
rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbWritten ? *pcbWritten : ~(size_t)0);
- Assert(off == -1); NOREF(off);
+ if (!pcbWritten)
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ pThis->offCurPos += pSgBuf->paSegs[iSeg].cbSeg;
+ else
+ pThis->offCurPos += *pcbWritten;
+ }
return rc;
}
@@ -424,8 +515,13 @@ RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTRE
AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
AssertPtr(pszEntry);
AssertPtr(phVfsIosPassthru);
+
+ RTFOFF const offCurPos = RTVfsIoStrmTell(hVfsIos);
+ AssertReturn(offCurPos >= 0, (int)offCurPos);
+
uint32_t cRefs = RTManifestRetain(hManifest);
AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
+
cRefs = RTVfsIoStrmRetain(hVfsIos);
AssertReturnStmt(cRefs != UINT32_MAX, RTManifestRelease(hManifest), VERR_INVALID_HANDLE);
@@ -440,6 +536,7 @@ RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTRE
{
pThis->hVfsIos = hVfsIos;
pThis->pHashes = rtManifestHashesCreate(fAttrs);
+ pThis->offCurPos = offCurPos;
pThis->hManifest = hManifest;
pThis->fReadOrWrite = fReadOrWrite;
pThis->fAddedEntry = false;
@@ -481,6 +578,24 @@ RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos)
/**
+ * Checks if the give I/O stream is a manifest passthru instance or not.
+ *
+ * @returns true if it's a manifest passthru I/O stream, false if not.
+ * @param hVfsPtIos Possible the manifest passthru I/O stream handle.
+ */
+RTDECL(bool) RTManifestPtIosIsInstanceOf(RTVFSIOSTREAM hVfsPtIos)
+{
+ if (hVfsPtIos != NIL_RTVFSIOSTREAM)
+ {
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
+ if (pThis)
+ return true;
+ }
+ return false;
+}
+
+
+/**
* Adds an entry for a file with the specified set of attributes.
*
* @returns IPRT status code.