summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-server/ApplianceImplIO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server/ApplianceImplIO.cpp')
-rw-r--r--src/VBox/Main/src-server/ApplianceImplIO.cpp191
1 files changed, 175 insertions, 16 deletions
diff --git a/src/VBox/Main/src-server/ApplianceImplIO.cpp b/src/VBox/Main/src-server/ApplianceImplIO.cpp
index a31f93a8..1a9ac12a 100644
--- a/src/VBox/Main/src-server/ApplianceImplIO.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplIO.cpp
@@ -1,11 +1,10 @@
/* $Id: ApplianceImplIO.cpp $ */
/** @file
- *
* IO helper for IAppliance COM class implementations.
*/
/*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,19 +22,23 @@
#include "ProgressImpl.h"
#include "ApplianceImpl.h"
#include "ApplianceImplPrivate.h"
+#include "VirtualBoxImpl.h"
+#include <iprt/zip.h>
#include <iprt/tar.h>
#include <iprt/sha.h>
#include <iprt/path.h>
#include <iprt/asm.h>
#include <iprt/stream.h>
#include <iprt/circbuf.h>
+#include <iprt/vfs.h>
+#include <iprt/manifest.h>
+#include <VBox/vd-ifs.h>
#include <VBox/vd.h>
/******************************************************************************
* Structures and Typedefs *
******************************************************************************/
-
typedef struct FILESTORAGEINTERNAL
{
/** File handle. */
@@ -107,13 +110,14 @@ typedef struct SHASTORAGEINTERNAL
#if 0
# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
#else
-# define DEBUG_PRINT_FLOW() do {} while(0)
+# define DEBUG_PRINT_FLOW() do {} while (0)
#endif
/******************************************************************************
* Internal Functions *
******************************************************************************/
+
/******************************************************************************
* Internal: RTFile interface
******************************************************************************/
@@ -281,7 +285,7 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
int rc = VINF_SUCCESS;
- if ( fOpen & RTFILE_O_READ
+ if (fOpen & RTFILE_O_READ
&& !(fOpen & RTFILE_O_WRITE))
{
/* Read only is a little bit more complicated than writing, cause we
@@ -297,13 +301,20 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
*
*/
bool fFound = false;
+
for (;;)
{
char *pszFilename = 0;
rc = RTTarCurrentFile(tar, &pszFilename);
if (RT_SUCCESS(rc))
{
- fFound = !strcmp(pszFilename, RTPathFilename(pszLocation));
+ if (rc == VINF_TAR_DIR_PATH)
+ {
+ break;
+ }
+
+ fFound = !RTStrICmp(pszFilename, pszLocation);
+
RTStrFree(pszFilename);
if (fFound)
break;
@@ -311,7 +322,9 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
{
rc = RTTarSeekNextFile(tar);
if (RT_FAILURE(rc))
+ {
break;
+ }
}
}
else
@@ -477,7 +490,7 @@ DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
int rc = VINF_SUCCESS;
bool fLoop = true;
- while(fLoop)
+ while (fLoop)
{
/* What should we do next? */
uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
@@ -755,7 +768,7 @@ static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
rc = shaSignalManifestThread(pInt, STATUS_READ);
}
}
- while(0);
+ while (0);
if (RT_FAILURE(rc))
{
@@ -1014,7 +1027,7 @@ static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
if ((cbWrite - cbAllWritten) > cbAvail)
{
rc = shaSignalManifestThread(pInt, STATUS_WRITE);
- if(RT_FAILURE(rc))
+ if (RT_FAILURE(rc))
break;
/* If there is _no_ free space available, we have to wait until it is. */
if (cbAvail == 0)
@@ -1084,24 +1097,29 @@ static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
size_t cbAllRead = 0;
+ size_t cbAvail = 0;
for (;;)
{
/* Finished? */
if (cbAllRead == cbRead)
break;
- size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
+
+ cbAvail = RTCircBufUsed(pInt->pCircBuf);
+
if ( cbAvail == 0
&& pInt->fEOF
&& !RTCircBufIsWriting(pInt->pCircBuf))
{
+ rc = VINF_EOF;
break;
}
+
/* If there isn't enough data make sure the worker thread is fetching
* more. */
if ((cbRead - cbAllRead) > cbAvail)
{
rc = shaSignalManifestThread(pInt, STATUS_READ);
- if(RT_FAILURE(rc))
+ if (RT_FAILURE(rc))
break;
/* If there is _no_ data available, we have to wait until it is. */
if (cbAvail == 0)
@@ -1136,6 +1154,7 @@ static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
/* Signal the thread to read more data in the mean time. */
if ( RT_SUCCESS(rc)
+ && rc != VINF_EOF
&& RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
rc = shaSignalManifestThread(pInt, STATUS_READ);
@@ -1164,10 +1183,6 @@ static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
}
-/******************************************************************************
- * Public Functions *
- ******************************************************************************/
-
PVDINTERFACEIO ShaCreateInterface()
{
PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
@@ -1274,7 +1289,7 @@ int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTE
memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
cbAllRead += cbRead;
}
- }while(0);
+ } while (0);
pIfIo->pfnClose(pvUser, pvStorage);
@@ -1325,8 +1340,152 @@ int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFA
cbAllWritten += cbWritten;
}
+ rc = pIfIo->pfnClose(pvUser, pvStorage);
+
+ return rc;
+}
+
+int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
+{
+ /* Validate input. */
+ AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
+
+ PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
+ /*
+ * Open the source file.
+ */
+ void *pvStorage;
+ int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
+ RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
+ &pvStorage);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Turn the source file handle/whatever into a VFS stream. */
+ RTVFSIOSTREAM hVfsIosCompressedSrc;
+
+ rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosCompressedSrc);
+ if (RT_SUCCESS(rc))
+ {
+ /* Pass the source thru gunzip. */
+ RTVFSIOSTREAM hVfsIosSrc;
+ rc = RTZipGzipDecompressIoStream(hVfsIosCompressedSrc, 0, &hVfsIosSrc);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the output file, including necessary paths.
+ * Any existing file will be overwritten.
+ */
+ rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true /*fCreate*/);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosDst;
+ rc = RTVfsIoStrmOpenNormal(pcszFullFilenameOut,
+ RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
+ &hVfsIosDst);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Pump the bytes thru. If we fail, delete the output file.
+ */
+ RTMANIFEST hFileManifest = NIL_RTMANIFEST;
+ rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosMfst;
+
+ uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
+
+ rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
+ hVfsIosSrc,
+ "ovf import",
+ digestType,
+ true /*read*/, &hVfsIosMfst);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosMfst);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosDst);
+ }
+ }
+
+ RTVfsIoStrmRelease(hVfsIosSrc);
+ }
+ }
pIfIo->pfnClose(pvUser, pvStorage);
return rc;
}
+int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser)
+{
+ /* Validate input. */
+ AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
+
+ PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
+ void *pvStorage;
+
+ int rc = pIfIo->pfnOpen(pvUser, pcszSourceFilename,
+ RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
+ &pvStorage);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Turn the source file handle/whatever into a VFS stream. */
+ RTVFSIOSTREAM hVfsIosSrc;
+
+ rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosSrc);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the output file, including necessary paths.
+ * Any existing file will be overwritten.
+ */
+ rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszTargetFilename), true /*fCreate*/);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosDst;
+ rc = RTVfsIoStrmOpenNormal(pcszTargetFilename,
+ RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
+ &hVfsIosDst);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Pump the bytes thru. If we fail, delete the output file.
+ */
+ RTMANIFEST hFileManifest = NIL_RTMANIFEST;
+ rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosMfst;
+
+ uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
+
+ rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
+ hVfsIosSrc,
+ "ovf import",
+ digestType,
+ true /*read*/, &hVfsIosMfst);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosMfst);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosDst);
+ }
+ }
+
+ RTVfsIoStrmRelease(hVfsIosSrc);
+
+ }
+
+ pIfIo->pfnClose(pvUser, pvStorage);
+ return rc;
+}