tar.cpp revision 4a4a02cc2a09b5e3c55908c6995182c6b038e398
/* $Id$ */
/** @file
* IPRT - Tar archive I/O.
*/
/*
* Copyright (C) 2009-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.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/******************************************************************************
* Header Files *
******************************************************************************/
/******************************************************************************
* Structures and Typedefs *
******************************************************************************/
/** @name RTTARRECORD::h::linkflag
* @{ */
/** @} */
typedef union RTTARRECORD
{
char d[512];
struct h
{
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char linkflag;
char linkname[100];
char magic[8];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
} h;
} RTTARRECORD;
typedef RTTARRECORD *PRTTARRECORD;
#if 0 /* not currently used */
typedef struct RTTARFILELIST
{
char *pszFilename;
typedef RTTARFILELIST *PRTTARFILELIST;
#endif
typedef struct RTTARFILEINTERNAL* PRTTARFILEINTERNAL;
typedef struct RTTARINTERNAL
{
bool fFileOpenForWrite;
bool fStreamMode;
typedef RTTARINTERNAL* PRTTARINTERNAL;
typedef struct RTTARFILEINTERNAL
{
char *pszFilename;
typedef RTTARFILEINTERNAL* PRTTARFILEINTERNAL;
/******************************************************************************
* Defined Constants And Macros *
******************************************************************************/
/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
/* RTTAR */
do { \
} while (0)
/* RTTARFILE */
do { \
} while (0)
/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
/* RTTAR */
/* RTTARFILE */
/** Validates a handle and returns (void) if not valid. */
/* RTTAR */
#define RTTAR_VALID_RETURN_VOID(hHandle) \
do { \
} while (0)
/* RTTARFILE */
#define RTTARFILE_VALID_RETURN_VOID(hHandle) \
do { \
} while (0)
/******************************************************************************
* Internal Functions *
******************************************************************************/
{
for (size_t i = 0; i < sizeof(RTTARRECORD); ++i)
{
/* Calculate the sum of every byte from the header. The checksum field
* itself is counted as all blanks. */
else
check += ' ';
/* Additional check if all fields are zero, which indicate EOF. */
}
/* EOF? */
if (!zero)
return VERR_TAR_END_OF_FILE;
return VINF_SUCCESS;
}
{
/* Check for EOF. EOF is valid in this case, cause it indicates no more
* data in the tar archive. */
return VERR_TAR_END_OF_FILE;
/* Report any other errors */
else if (RT_FAILURE(rc))
return rc;
/* Check for data integrity & an EOF record */
/* EOF? */
if (RT_FAILURE(rc))
return rc;
/* Verify the checksum */
return VINF_SUCCESS;
return VERR_TAR_CHKSUM_MISMATCH;
}
DECLINLINE(int) rtTarCreateHeaderRecord(PRTTARRECORD pRecord, const char *pszSrcName, uint64_t cbSize, RTUID uid, RTGID gid, RTFMODE fmode, int64_t mtime)
{
/* Fill the header record */
// RT_ZERO(pRecord);
/* Create the checksum out of the new header */
if (RT_FAILURE(rc))
return rc;
/* Format the checksum */
return VINF_SUCCESS;
}
{
*pcbSize = 0;
/* Allocate a reasonably large buffer, fall back on a tiny one. Note:
* has to be 512 byte aligned and >= 512 byte. */
if (!pvTmp)
{
cbTmp = sizeof(RTTARRECORD);
}
return pvTmp;
}
{
/* Allocate a temporary buffer for copying the tar content in blocks. */
if (!pvTmp)
return VERR_NO_MEMORY;
int rc = VINF_SUCCESS;
uint64_t cbAllWritten = 0;
for (;;)
{
if (cbAllWritten >= cbSize)
break;
if (RT_FAILURE(rc))
break;
}
return rc;
}
DECLINLINE(PRTTARFILEINTERNAL) rtCreateTarFileInternal(PRTTARINTERNAL pInt, const char *pszFilename, uint32_t fOpen)
{
if (!pFileInt)
return NULL;
return pFileInt;
}
{
if (!pNewInt)
return NULL;
return pNewInt;
}
{
if (pInt)
{
if (pInt->pszFilename)
}
}
static int rtTarExtractFileToFile(RTTARFILE hFile, const char *pszTargetName, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
/* Open the target file */
int rc = RTFileOpen(&hNewFile, pszTargetName, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
if (RT_FAILURE(rc))
return rc;
void *pvTmp = 0;
do
{
/* Allocate a temporary buffer for reading the tar content in blocks. */
if (!pvTmp)
{
rc = VERR_NO_MEMORY;
break;
}
/* Get the size of the source file */
if (RT_FAILURE(rc))
break;
/* Copy the content from hFile over to pszTargetName. */
for (;;)
{
if (pfnProgressCallback)
/* Finished already? */
if (cbAllWritten == cbToCopy)
break;
/* Read one block. */
if (RT_FAILURE(rc))
break;
/* Write the block */
if (RT_FAILURE(rc))
break;
/* Count how many bytes are written already */
cbAllWritten += cbRead;
}
}
while(0);
/* Cleanup */
if (pvTmp)
/* Now set all file attributes */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* Set the mode */
}
}
/* Delete the freshly created file in the case of an error */
if (RT_FAILURE(rc))
return rc;
}
static int rtTarAppendFileFromFile(RTTAR hTar, const char *pszSrcName, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
/* Open the source file */
if (RT_FAILURE(rc))
return rc;
void *pvTmp = 0;
do
{
/* Get the size of the source file */
if (RT_FAILURE(rc))
break;
if (RT_FAILURE(rc))
break;
/* Get some info from the source file */
/* This isn't critical. Use the defaults if it fails. */
if (RT_SUCCESS(rc))
{
}
/* Set the mode from the other file */
if (RT_FAILURE(rc))
break;
/* Set the modification time from the other file */
if (RT_FAILURE(rc))
break;
/* Set the owner from the other file */
if (RT_FAILURE(rc))
break;
/* Allocate a temporary buffer for copying the tar content in blocks. */
if (!pvTmp)
{
rc = VERR_NO_MEMORY;
break;
}
/* Copy the content from pszSrcName over to hFile. This is done block
* wise in 512 byte steps. After this copying is finished hFile will be
* on a 512 byte boundary, regardless if the file copied is 512 byte
* size aligned. */
for (;;)
{
if (pfnProgressCallback)
if (cbAllWritten >= cbToCopy)
break;
/* Read one block. Either its the buffer size or the rest of the
* file. */
/* Read one block */
if (RT_FAILURE(rc))
break;
/* Write one block. */
if (RT_FAILURE(rc))
break;
/* Count how many bytes (of the original file) are written already */
cbAllWritten += cbRead;
}
}
while(0);
/* Cleanup */
if (pvTmp)
if (hFile)
return rc;
}
{
int rc = VINF_SUCCESS;
/* Seek over the data parts (512 bytes aligned) */
if (offSeek > 0)
return rc;
}
{
/* Assume we are on the file head. */
int rc = VINF_SUCCESS;
bool fFound = false;
for (;;)
{
/* Read & verify a header record */
/* Check for error or EOF. */
if (RT_FAILURE(rc))
break;
/* We support normal files only */
{
{
/* Get the file size */
if (RT_FAILURE(rc))
break;
/* Seek back, to positionate the file pointer at the start of the header. */
fFound = true;
break;
}
}
if (RT_FAILURE(rc))
break;
}
if (rc == VERR_TAR_END_OF_FILE)
rc = VINF_SUCCESS;
/* Something found? */
if ( RT_SUCCESS(rc)
&& !fFound)
return rc;
}
static int rtTarGetFilesOverallSize(RTFILE hFile, const char * const *papszFiles, size_t cFiles, uint64_t *pcbOverallSize)
{
int rc = VINF_SUCCESS;
for (;;)
{
/* Read & verify a header record */
/* Check for error or EOF. */
if (RT_FAILURE(rc))
break;
/* We support normal files only */
{
{
{
/* Get the file size */
/* Sum up the overall size */
*pcbOverallSize += cbSize;
++cFound;
break;
}
}
|| RT_FAILURE(rc))
break;
}
if (RT_FAILURE(rc))
break;
}
if (rc == VERR_TAR_END_OF_FILE)
rc = VINF_SUCCESS;
/* Make sure the file pointer is at the begin of the file again. */
if (RT_SUCCESS(rc))
return rc;
}
/******************************************************************************
* Public Functions *
******************************************************************************/
{
if (!pInt)
return VERR_NO_MEMORY;
int rc = VINF_SUCCESS;
do
{
/* Open the tar file. */
if (RT_FAILURE(rc))
break;
}
while(0);
if (RT_FAILURE(rc))
{
/* Todo: remove if created by us */
}else
return rc;
}
{
return VINF_SUCCESS;
int rc = VINF_SUCCESS;
/* gtar gives a warning, but the documentation says EOF is indicated by a
* zero block. Disabled for now. */
#if 0
{
/* Append the EOF record which is filled all by zeros */
}
#endif
/* Delete any remaining cached file headers. */
if (pInt->pFileCache)
{
pInt->pFileCache = 0;
}
return rc;
}
{
return VERR_INVALID_HANDLE;
if (pInt->fStreamMode)
return VERR_INVALID_STATE;
if (fOpen & RTFILE_O_WRITE)
{
return VERR_WRITE_PROTECT;
if (pInt->fFileOpenForWrite)
return VERR_TOO_MANY_OPEN_FILES;
}
if (!pFileInt)
return VERR_NO_MEMORY;
int rc = VINF_SUCCESS;
do
{
{
pInt->fFileOpenForWrite = true;
/* If we are in write mode, we also in append mode. Add an dummy
* header at the end of the current file. It will be filled by the
* close operation. */
if (RT_FAILURE(rc))
break;
if (RT_FAILURE(rc))
break;
}
{
/* We need to be on the start of the file */
if (RT_FAILURE(rc))
break;
/* Search for the file. */
if (RT_FAILURE(rc))
break;
}
else
{
}
}
while(0);
/* Cleanup on failure */
if (RT_FAILURE(rc))
{
if (pFileInt->pszFilename)
}
else
return rc;
}
{
/* Already closed? */
if (hFile == NIL_RTTARFILE)
return VINF_SUCCESS;
int rc = VINF_SUCCESS;
/* In write mode: */
{
/* In read mode, we want to make sure to stay at the aligned end of this
* file, so the next file could be read immediately. */
/* Check that the file pointer is somewhere within the last open file.
* If we are at the beginning (nothing read yet) nothing will be done.
* something. */
if (pFileInt->uStart + sizeof(RTTARRECORD) < uCurPos && uCurPos < RT_ALIGN(pFileInt->uStart + sizeof(RTTARRECORD) + pFileInt->cbSize, sizeof(RTTARRECORD)))
{
/* Seek to the next file header. */
uint64_t uNextPos = RT_ALIGN(pFileInt->uStart + sizeof(RTTARRECORD) + pFileInt->cbSize, sizeof(RTTARRECORD));
}
}
{
do
{
/* If the user has called RTTarFileSetSize in the meantime, we have
to make sure the file has the right size. */
{
if (RT_FAILURE(rc))
break;
}
/* If the written size isn't 512 byte aligned, we need to fix this. */
{
/* Note the RTFile method. We didn't increase the cbSize or cbCurrentPos here. */
rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + sizeof(RTTARRECORD) + pFileInt->cbSize, &record, cbSizeAligned - pFileInt->cbSize, NULL);
if (RT_FAILURE(rc))
break;
}
/* Create a header record for the file */
/* Todo: mode, gid, uid, mtime should be setable (or detected myself) */
rc = rtTarCreateHeaderRecord(&record, pFileInt->pszFilename, pFileInt->cbSize, 0, 0, 0600, RTTimeSpecGetSeconds(&time));
if (RT_FAILURE(rc))
break;
/* Write this at the start of the file data */
if (RT_FAILURE(rc))
break;
}
while(0);
}
/* Now cleanup and delete the handle */
return rc;
}
RTR3DECL(int) RTTarFileSeek(RTTARFILE hFile, uint64_t uOffset, unsigned uMethod, uint64_t *poffActual)
{
return VERR_INVALID_STATE;
switch (uMethod)
{
case RTFILE_SEEK_BEGIN:
{
return VERR_SEEK_ON_DEVICE;
break;
}
case RTFILE_SEEK_CURRENT:
{
return VERR_SEEK_ON_DEVICE;
break;
}
case RTFILE_SEEK_END:
{
return VERR_NEGATIVE_SEEK;
break;
}
default: AssertFailedReturn(VERR_INVALID_PARAMETER); break;
}
return VINF_SUCCESS;
}
{
return pFileInt->uCurrentPos;
}
{
/* Todo: optimize this, by checking the current pos */
}
RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t uOffset, void *pvBuf, size_t cbToRead, size_t *pcbRead)
{
/* Check that we not read behind the end of file. If so return immediately. */
{
if (pcbRead)
*pcbRead = 0;
return VINF_SUCCESS; /* ??? VERR_EOF */
}
int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToCopy, &cbTmpRead);
if (pcbRead)
return rc;
}
RTR3DECL(int) RTTarFileWrite(RTTARFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
{
/* Todo: optimize this, by checking the current pos */
}
RTR3DECL(int) RTTarFileWriteAt(RTTARFILE hFile, uint64_t uOffset, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
{
return VERR_WRITE_ERROR;
size_t cbTmpWritten = 0;
int rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToWrite, &cbTmpWritten);
if (pcbWritten)
return rc;
}
{
/* Validate input */
return VINF_SUCCESS;
}
{
return VERR_WRITE_ERROR;
/* Todo: if cbSize is smaller than pFileInt->cbSize we have to truncate the
current file. */
return VINF_SUCCESS;
}
{
/* Validate input */
/* Read the mode out of the header entry */
char mode[8];
int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mode), mode, 8, NULL);
if (RT_FAILURE(rc))
return rc;
/* Convert it to an integer */
}
{
return VERR_WRITE_ERROR;
/* Convert the mode to an string. */
char mode[8];
/* Write it directly into the header */
return RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mode), mode, 8, NULL);
}
{
/* Read the time out of the header entry */
char mtime[12];
int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mtime), mtime, 12, NULL);
if (RT_FAILURE(rc))
return rc;
/* Convert it to an integer */
/* And back to our time structure */
if (RT_SUCCESS(rc))
return rc;
}
{
return VERR_WRITE_ERROR;
/* Convert the time to an string. */
char mtime[12];
/* Write it directly into the header */
return RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mtime), mtime, 12, NULL);
}
{
/* Read the uid and gid out of the header entry */
char uid[8];
int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.uid), uid, 8, NULL);
if (RT_FAILURE(rc))
return rc;
char gid[8];
rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.gid), gid, 8, NULL);
if (RT_FAILURE(rc))
return rc;
/* Convert it to integer */
if (RT_FAILURE(rc))
return rc;
}
{
return VERR_WRITE_ERROR;
int rc = VINF_SUCCESS;
{
/* Convert the uid to an string. */
char tmpUid[8];
/* Write it directly into the header */
rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.uid), tmpUid, 8, NULL);
if (RT_FAILURE(rc))
return rc;
}
{
/* Convert the gid to an string. */
char tmpGid[8];
/* Write it directly into the header */
rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.gid), tmpGid, 8, NULL);
if (RT_FAILURE(rc))
return rc;
}
return rc;
}
/******************************************************************************
* Convenience Functions *
******************************************************************************/
{
/* Validate input */
/* Open the tar file */
if (RT_FAILURE(rc))
return rc;
/* Just try to open that file readonly. If this succeed the file exists. */
if (RT_SUCCESS(rc))
return rc;
}
{
/* Validate input */
/* Open the tar file */
if (RT_FAILURE(rc))
return rc;
/* This is done by internal methods, cause we didn't have a RTTARDIR
* interface, yet. This should be fixed somedays. */
char **papszFiles = 0;
do
{
/* Initialize the file name array with one slot */
papszFiles = (char**)RTMemAlloc(sizeof(char *));
if (!papszFiles)
{
return VERR_NO_MEMORY;
break;
}
/* Iterate through the tar file record by record. Skip data records as we
* didn't need them. */
for (;;)
{
/* Read & verify a header record */
/* Check for error or EOF. */
if (RT_FAILURE(rc))
break;
/* We support normal files only */
{
if (cFiles >= cFilesAlloc)
{
/* Double the array size, make sure the size doesn't wrap. */
if (!pvNew)
{
rc = VERR_NO_MEMORY;
break;
}
papszFiles = (char **)pvNew;
cFilesAlloc *= 2;
}
/* Duplicate the name */
if (!papszFiles[cFiles])
{
rc = VERR_NO_MEMORY;
break;
}
cFiles++;
}
if (RT_FAILURE(rc))
break;
}
}
while(0);
if (rc == VERR_TAR_END_OF_FILE)
rc = VINF_SUCCESS;
/* Return the file array on success, dispose of it on failure. */
if (RT_SUCCESS(rc))
{
}
else
{
while (cFiles-- > 0)
}
return rc;
}
RTR3DECL(int) RTTarExtractFileToBuf(const char *pszTarFile, void **ppvBuf, size_t *pcbSize, const char *pszFile, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
/* Validate input */
/* Todo: progress bar */
int rc = VINF_SUCCESS;
char *pvTmp = 0;
do
{
if (RT_FAILURE(rc))
break;
if (RT_FAILURE(rc))
break;
if (RT_FAILURE(rc))
break;
/* Allocate the memory for the file content. */
if (!pvTmp)
{
rc = VERR_NO_MEMORY;
break;
}
for (;;)
{
if (pfnProgressCallback)
break;
if (RT_FAILURE(rc))
break;
}
}
while(0);
/* Set output values on success */
if (RT_SUCCESS(rc))
{
}
/* Cleanup */
if ( RT_FAILURE(rc)
&& pvTmp)
if (hFile)
if (hTar)
return rc;
}
RTR3DECL(int) RTTarExtractFiles(const char *pszTarFile, const char *pszOutputDir, const char * const *papszFiles, size_t cFiles, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
/* Validate input */
/* Open the tar file */
if (RT_FAILURE(rc))
return rc;
do
{
/* Get the overall size of all files to extract out of the tar archive
headers. Only necessary if there is a progress callback. */
uint64_t cbOverallSize = 0;
if (pfnProgressCallback)
{
// rc = rtTarGetFilesOverallSize(hFile, papszFiles, cFiles, &cbOverallSize);
// if (RT_FAILURE(rc))
// break;
}
uint64_t cbOverallWritten = 0;
{
rc = RTTarFileOpen(hTar, &hFile, papszFiles[i], RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
if (RT_FAILURE(rc))
break;
if (!pszTargetFile)
{
break;
}
rc = rtTarExtractFileToFile(hFile, pszTargetFile, cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
if (RT_FAILURE(rc))
break;
}
}
while(0);
return rc;
}
RTR3DECL(int) RTTarExtractAll(const char *pszTarFile, const char *pszOutputDir, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
/* Validate input */
char **papszFiles;
/* First fetch the files names contained in the tar file */
if (RT_FAILURE(rc))
return rc;
/* Extract all files */
return RTTarExtractFiles(pszTarFile, pszOutputDir, papszFiles, cFiles, pfnProgressCallback, pvUser);
}
RTR3DECL(int) RTTarCreate(const char *pszTarFile, const char * const *papszFiles, size_t cFiles, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
/* Validate input */
int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_CREATE | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE, false);
if (RT_FAILURE(rc))
return rc;
/* Get the overall size of all files to pack into the tar archive. Only
necessary if there is a progress callback. */
uint64_t cbOverallSize = 0;
if (pfnProgressCallback)
{
if (RT_FAILURE(rc))
break;
cbOverallSize += cbSize;
}
uint64_t cbOverallWritten = 0;
{
rc = rtTarAppendFileFromFile(hTar, papszFiles[i], cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
if (RT_FAILURE(rc))
break;
}
/* Cleanup */
return rc;
}
/******************************************************************************
* Streaming Functions *
******************************************************************************/
{
/* Validate input. */
/* Open and close the file on the current position. This makes sure the
* cache is filled in case we never read something before. On success it
* will return the current filename. */
int rc = RTTarFileOpenCurrentFile(hTar, &hFile, ppszFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
if (RT_SUCCESS(rc))
return rc;
}
{
int rc = VINF_SUCCESS;
if (!pInt->fStreamMode)
return VERR_INVALID_STATE;
/* If there is nothing in the cache, it means we never read something. Just
* ask for the current filename to fill the cache. */
if (!pInt->pFileCache)
{
if (RT_FAILURE(rc))
return rc;
}
/* Check that the file pointer is somewhere within the last open file.
* If not we are somehow busted. */
if (!(pInt->pFileCache->uStart <= uCurPos && uCurPos < pInt->pFileCache->uStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize))
return VERR_INVALID_STATE;
/* Seek to the next file header. */
uint64_t uNextPos = RT_ALIGN(pInt->pFileCache->uStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize, sizeof(RTTARRECORD));
if (RT_FAILURE(rc))
return rc;
/* Again check the current filename to fill the cache with the new value. */
return RTTarCurrentFile(hTar, 0);
}
RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **ppszFilename, uint32_t fOpen)
{
/* Validate input. */
if (!pInt->fStreamMode)
return VERR_INVALID_STATE;
int rc = VINF_SUCCESS;
/* Is there some cached entry? */
if (pInt->pFileCache)
{
/* Are we still direct behind that header? */
{
/* Yes, so the streaming can start. Just return the cached file
* structure to the caller. */
if (ppszFilename)
return VINF_SUCCESS;
}else
{
/* Else delete the last open file cache. Might be recreated below. */
pInt->pFileCache = 0;
}
}
do
{
/* Try to read a header entry from the current position. If we aren't
* on a header record, the header checksum will show and an error will
* be returned. */
/* Read & verify a header record */
/* Check for error or EOF. */
if (RT_FAILURE(rc))
break;
/* We support normal files only */
{
if (!pFileInt)
{
rc = VERR_NO_MEMORY;
break;
}
/* Get the file size */
if (RT_FAILURE(rc))
break;
/* The start is -512 from here. */
/* Copy the new file structure to our cache. */
if (ppszFilename)
}
}while (0);
if (RT_FAILURE(rc))
{
if (pFileInt)
}
else
return rc;
}