ApplianceImplIO.cpp revision 8a99522dee886d4ed00c8cd18788e9e722febd71
/* $Id$ */
/** @file
*
* IO helper for IAppliance COM class implementations.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/******************************************************************************
* Header Files *
******************************************************************************/
#include "ProgressImpl.h"
#include "ApplianceImpl.h"
#include "ApplianceImplPrivate.h"
#include <iprt/semaphore.h>
/******************************************************************************
* Structures and Typedefs *
******************************************************************************/
typedef struct RTFILESTORAGEINTERNAL
{
/** File handle. */
/** Completion callback. */
typedef struct RTTARSTORAGEINTERNAL
{
/** Tar handle. */
/** Completion callback. */
typedef struct SHA1STORAGEINTERNAL
{
/** Completion callback. */
/** Storage handle for the next callback in chain. */
void *pvStorage;
/** Memory buffer used for caching and SHA1 calculation. */
char *pcBuf;
/** Size of the memory buffer. */
/** Memory buffer for writing zeros. */
void *pvZeroBuf;
/** Size of the zero memory buffer. */
/** Current position in the caching memory buffer. */
/** Current absolute position. */
/** Current real position in the file. */
/** Handle of the SHA1 worker thread. */
/** Status of the worker thread. */
/** Event for signaling a new status. */
/** Event for signaling a finished SHA1 calculation. */
/** SHA1 calculation context. */
/******************************************************************************
* Defined Constants And Macros *
******************************************************************************/
#define STATUS_WAIT UINT32_C(0)
/* Enable for getting some flow history. */
#if 0
#else
# define DEBUG_PRINT_FLOW() do {} while(0)
#endif
/******************************************************************************
* Internal Functions *
******************************************************************************/
/******************************************************************************
* Internal: RTFile interface
******************************************************************************/
{
/* Validate input. */
if (!pInt)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
else
return rc;
}
{
/* Validate input. */
/* Cleanup */
return rc;
}
{
return RTFileDelete(pcszFilename);
}
static int rtFileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
{
}
static int rtFileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
static int rtFileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename, PRTTIMESPEC pModificationTime)
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
{
/* Validate input. */
// DEBUG_PRINT_FLOW();
}
{
/* Validate input. */
}
{
/* Validate input. */
}
{
/* Validate input. */
}
{
/* Validate input. */
}
/******************************************************************************
* Internal: RTTar interface
******************************************************************************/
{
/* Validate input. */
if (!pInt)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
else
return rc;
}
{
/* Validate input. */
/* Cleanup */
return rc;
}
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
static int rtTarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
static int rtTarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
{
/* Validate input. */
// DEBUG_PRINT_FLOW();
}
{
/* Validate input. */
}
{
/* Validate input. */
}
{
/* Validate input. */
}
{
/* Validate input. */
return VERR_NOT_IMPLEMENTED;
}
/******************************************************************************
* Internal: Sha1 interface
******************************************************************************/
{
/* Validate input. */
int rc = VINF_SUCCESS;
bool fLoop = true;
while(fLoop)
{
/* What should we do next? */
switch (u32Status)
{
case STATUS_WAIT:
{
/* Wait for new work. */
if ( RT_FAILURE(rc)
&& rc != VERR_TIMEOUT)
fLoop = false;
break;
}
case STATUS_CALC:
{
/* Update the SHA1 context with the next data block. */
{
fLoop = false;
}
/* Reset the thread status and signal the main thread that we
are finished. */
break;
}
case STATUS_END:
{
/* End signaled */
fLoop = false;
break;
}
}
}
return rc;
}
{
}
{
// RTPrintf("start\n");
int rc = VINF_SUCCESS;
for(;;)
{
// RTPrintf(" wait\n");
break;
}
if (rc == VERR_TIMEOUT)
rc = VINF_SUCCESS;
return rc;
}
DECLINLINE(int) sha1FlushCurBuf(PVDINTERFACE pIO, PVDINTERFACEIO pCallbacks, PSHA1STORAGEINTERNAL pInt, bool fCreateDigest)
{
int rc = VINF_SUCCESS;
if (fCreateDigest)
{
/* Let the sha1 worker thread start immediately. */
if (RT_FAILURE(rc))
return rc;
}
/* Write the buffer content to disk. */
size_t cbAllWritten = 0;
for(;;)
{
/* Finished? */
break;
rc = pCallbacks->pfnWriteSync(pIO->pvUser, pInt->pvStorage, pInt->cbCurFile, &pInt->pcBuf[cbAllWritten], cbToWrite, &cbWritten);
if (RT_FAILURE(rc))
return rc;
}
if (fCreateDigest)
{
/* Wait until the sha1 worker thread has finished. */
}
if (RT_SUCCESS(rc))
return rc;
}
{
/* Validate input. */
if (!pInt)
return VERR_NO_MEMORY;
int rc = VINF_SUCCESS;
do
{
/* For caching reasons and to be able to calculate the sha1 sum of the
data we need a memory buffer. */
{
rc = VERR_NO_MEMORY;
break;
}
/* The zero buffer is used for appending empty parts at the end of the
* file (or our buffer) in setSize or when uOffset in writeSync is
* increased in steps bigger than a byte. */
{
rc = VERR_NO_MEMORY;
break;
}
if (pSha1Storage->fCreateDigest)
{
/* Create a sha1 context the sha1 worker thread will work with. */
{
break;
}
/* Create an event semaphore to indicate a state change for the sha1
worker thread. */
if (RT_FAILURE(rc))
break;
/* Create an event semaphore to indicate a finished calculation of the
sha1 worker thread. */
if (RT_FAILURE(rc))
break;
/* Create the sha1 worker thread. */
rc = RTThreadCreate(&pInt->pMfThread, sha1CalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA1-Worker");
if (RT_FAILURE(rc))
break;
}
/* Open the file. */
}
while(0);
if (RT_FAILURE(rc))
{
if (pSha1Storage->fCreateDigest)
{
{
}
if (pInt->calcFinishedEvent)
if (pInt->newStatusEvent)
}
}
else
return rc;
}
{
/* Validate input. */
int rc = VINF_SUCCESS;
/* Make sure all pending writes are flushed */
if (pSha1Storage->fCreateDigest)
{
/* Signal the worker thread to end himself */
/* Finally calculate & format the SHA1 sum */
unsigned char auchDig[RTSHA1_HASH_SIZE];
char *pszDigest;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
/* Worker thread stopped? */
}
/* Close the file */
/* Cleanup */
if (pSha1Storage->fCreateDigest)
{
if (pInt->calcFinishedEvent)
if (pInt->newStatusEvent)
}
return rc;
}
{
/* Validate input. */
}
{
/* Validate input. */
}
{
/* Validate input. */
}
static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
{
/* Validate input. */
}
{
/* Validate input. */
// DEBUG_PRINT_FLOW();
if (RT_FAILURE(rc))
return rc;
return VINF_SUCCESS;
}
{
/* Validate input. */
}
{
/* Validate input. */
// DEBUG_PRINT_FLOW();
/* Check that the write is linear */
AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
int rc = VINF_SUCCESS;
/* Check if we have to add some free space at the end, before we start the
* real write. */
{
size_t cbAllWritten = 0;
for(;;)
{
/* Finished? */
if (cbAllWritten == cbSize)
break;
if (RT_FAILURE(rc))
break;
}
if (RT_FAILURE(rc))
return rc;
}
// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
size_t cbAllWritten = 0;
for(;;)
{
/* Finished? */
if (cbAllWritten == cbWrite)
break;
/* Need to start a real write? */
{
if (RT_FAILURE(rc))
break;
}
}
if (pcbWritten)
return rc;
}
{
/* Validate input. */
}
{
/* Validate input. */
int rc = VINF_SUCCESS;
/* Check if there is still something in the buffer. If yes, flush it. */
{
if (RT_FAILURE(rc))
return rc;
}
}
/******************************************************************************
* Public Functions *
******************************************************************************/
{
if (!pCallbacks)
return NULL;
return pCallbacks;
}
{
if (!pCallbacks)
return NULL;
return pCallbacks;
}
{
if (!pCallbacks)
return NULL;
return pCallbacks;
}
int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
{
/* Validate input. */
void *pvStorage;
&pvStorage);
if (RT_FAILURE(rc))
return rc;
size_t cbAllWritten = 0;
for(;;)
{
if (cbAllWritten >= cbSize)
break;
rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
if (RT_FAILURE(rc))
break;
}
return rc;
}