VirtualBox

Changeset 32751 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Sep 24, 2010 9:34:18 AM (14 years ago)
Author:
vboxsync
Message:

Runtime: initial VFS support for tar

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/tar.cpp

    r32630 r32751  
    2626
    2727
    28 /*******************************************************************************
    29 *   Header Files                                                               *
    30 *******************************************************************************/
     28/******************************************************************************
     29 *   Header Files                                                             *
     30 ******************************************************************************/
    3131#include "internal/iprt.h"
     32#include "internal/magics.h"
    3233#include <iprt/tar.h>
    3334
     
    4041#include <iprt/string.h>
    4142
    42 /*******************************************************************************
    43 *   Structures and Typedefs                                                    *
    44 *******************************************************************************/
     43/******************************************************************************
     44 *   Structures and Typedefs                                                  *
     45 ******************************************************************************/
    4546
    4647/** @name RTTARRECORD::h::linkflag
     
    9192#endif
    9293
    93 /*******************************************************************************
    94 *   Internal Functions                                                         *
    95 *******************************************************************************/
     94typedef struct RTTARINTERNAL
     95{
     96    uint32_t        u32Magic;
     97    RTFILE          hTarFile;
     98    bool            fFileOpenForWrite;
     99    uint32_t        fOpenMode;
     100} RTTARINTERNAL;
     101typedef RTTARINTERNAL* PRTTARINTERNAL;
     102
     103typedef struct RTTARFILEINTERNAL
     104{
     105    uint32_t        u32Magic;
     106    PRTTARINTERNAL  pTar;
     107    char           *pszFilename;
     108    uint64_t        uStart;
     109    uint64_t        cbSize;
     110    uint64_t        uCurrentPos;
     111    uint32_t        fOpenMode;
     112} RTTARFILEINTERNAL;
     113typedef RTTARFILEINTERNAL* PRTTARFILEINTERNAL;
     114
     115/******************************************************************************
     116 *   Defined Constants And Macros                                             *
     117 ******************************************************************************/
     118
     119/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
     120/* RTTAR */
     121#define RTTAR_VALID_RETURN_RC(hHandle, rc) \
     122    do { \
     123        AssertPtrReturn((hHandle), (rc)); \
     124        AssertReturn((hHandle)->u32Magic == RTTAR_MAGIC, (rc)); \
     125    } while (0)
     126/* RTTARFILE */
     127#define RTTARFILE_VALID_RETURN_RC(hHandle, rc) \
     128    do { \
     129        AssertPtrReturn((hHandle), (rc)); \
     130        AssertReturn((hHandle)->u32Magic == RTTARFILE_MAGIC, (rc)); \
     131    } while (0)
     132
     133/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
     134/* RTTAR */
     135#define RTTAR_VALID_RETURN(hHandle) RTTAR_VALID_RETURN_RC((hHandle), VERR_INVALID_HANDLE)
     136/* RTTARFILE */
     137#define RTTARFILE_VALID_RETURN(hHandle) RTTARFILE_VALID_RETURN_RC((hHandle), VERR_INVALID_HANDLE)
     138
     139/** Validates a handle and returns (void) if not valid. */
     140/* RTTAR */
     141#define RTTAR_VALID_RETURN_VOID(hHandle) \
     142    do { \
     143        AssertPtrReturnVoid(hHandle); \
     144        AssertReturnVoid((hHandle)->u32Magic == RTTAR_MAGIC); \
     145    } while (0)
     146/* RTTARFILE */
     147#define RTTARFILE_VALID_RETURN_VOID(hHandle) \
     148    do { \
     149        AssertPtrReturnVoid(hHandle); \
     150        AssertReturnVoid((hHandle)->u32Magic == RTTARFILE_MAGIC); \
     151    } while (0)
     152
     153/******************************************************************************
     154 *   Internal Functions                                                       *
     155 ******************************************************************************/
    96156
    97157DECLINLINE(int) rtTarCalcChkSum(PRTTARRECORD pRecord, uint32_t *pChkSum)
     
    146206}
    147207
     208DECLINLINE(int) rtTarCreateHeaderRecord(PRTTARRECORD pRecord, const char *pszSrcName, uint64_t cbSize, RTUID uid, RTGID gid, RTFMODE fmode, int64_t mtime)
     209{
     210    /* Fill the header record */
     211//    RT_ZERO(pRecord);
     212    RTStrPrintf(pRecord->h.name,  sizeof(pRecord->h.name),  "%s",     pszSrcName);
     213    RTStrPrintf(pRecord->h.mode,  sizeof(pRecord->h.mode),  "%0.7o",  fmode);
     214    RTStrPrintf(pRecord->h.uid,   sizeof(pRecord->h.uid),   "%0.7o",  uid);
     215    RTStrPrintf(pRecord->h.gid,   sizeof(pRecord->h.gid),   "%0.7o",  gid);
     216    RTStrPrintf(pRecord->h.size,  sizeof(pRecord->h.size),  "%0.11o", cbSize);
     217    RTStrPrintf(pRecord->h.mtime, sizeof(pRecord->h.mtime), "%0.11o", mtime);
     218    RTStrPrintf(pRecord->h.magic, sizeof(pRecord->h.magic), "ustar  ");
     219    RTStrPrintf(pRecord->h.uname, sizeof(pRecord->h.uname), "someone");
     220    RTStrPrintf(pRecord->h.gname, sizeof(pRecord->h.gname), "someone");
     221    pRecord->h.linkflag = LF_NORMAL;
     222
     223    /* Create the checksum out of the new header */
     224    uint32_t chksum = 0;
     225    int rc = rtTarCalcChkSum(pRecord, &chksum);
     226    if (RT_FAILURE(rc))
     227        return rc;
     228    /* Format the checksum */
     229    RTStrPrintf(pRecord->h.chksum, sizeof(pRecord->h.chksum), "%0.7o", chksum);
     230
     231    return VINF_SUCCESS;
     232}
     233
    148234DECLINLINE(void*) rtTarMemTmpAlloc(size_t *pcbSize)
    149235{
     
    162248}
    163249
    164 static int rtTarExtractFileToBuf(RTFILE hFile, void **ppvBuf, uint64_t *pcbSize, PRTTARRECORD pRecord, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    165 {
    166     int rc = VINF_SUCCESS;
    167 
    168     uint64_t cbToCopy = RTStrToUInt64(pRecord->h.size);
    169 
    170     *ppvBuf = 0;
     250static int rtTarExtractFileToFile(RTTARFILE hFile, const char *pszTargetName, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     251{
     252    RTFILE hNewFile;
     253    /* Open the target file */
     254    int rc = RTFileOpen(&hNewFile, pszTargetName, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
     255    if (RT_FAILURE(rc))
     256        return rc;
     257
     258    void *pvTmp = 0;
    171259    do
    172260    {
    173         /* Allocate the memory for the file content. */
    174         *ppvBuf = RTMemAlloc(cbToCopy);
    175         char* pcsTmp = (char*)*ppvBuf;
    176         if (!pcsTmp)
     261        /* Allocate a temporary buffer for reading the tar content in blocks. */
     262        size_t cbTmp = 0;
     263        pvTmp = rtTarMemTmpAlloc(&cbTmp);
     264        if (!pvTmp)
    177265        {
    178266            rc = VERR_NO_MEMORY;
    179267            break;
    180268        }
    181 
     269        /* Get the size of the source file */
     270        uint64_t cbToCopy = 0;
     271        rc = RTTarFileGetSize(hFile, &cbToCopy);
     272        if (RT_FAILURE(rc))
     273            break;
     274        /* Copy the content from hFile over to pszTargetName. */
    182275        uint64_t cbAllWritten = 0; /* Already copied */
    183         uint64_t cbToRead = 0; /* What to read in the next step */
    184         size_t cbRead = 0; /* Actually read in the last step */
    185         /* Copy the content from hFile over to the memory. */
     276        uint64_t cbRead = 0; /* Actually read in the last step */
    186277        for (;;)
    187278        {
     
    191282            if (cbAllWritten == cbToCopy)
    192283                break;
    193             /* Try to read all at once */
    194             cbToRead = cbToCopy - cbAllWritten;
    195             rc = RTFileRead(hFile, pcsTmp, cbToRead, &cbRead);
     284            /* Read one block. */
     285            cbRead = RT_MIN(cbToCopy - cbAllWritten, cbTmp);
     286            rc = RTTarFileRead(hFile, pvTmp, cbRead, NULL);
     287            if (RT_FAILURE(rc))
     288                break;
     289            /* Write the block */
     290            rc = RTFileWrite(hNewFile, pvTmp, cbRead, NULL);
    196291            if (RT_FAILURE(rc))
    197292                break;
     
    199294            cbAllWritten += cbRead;
    200295            cbOverallWritten += cbRead;
    201             pcsTmp += cbRead;
    202         }
    203         int64_t offSeek = RT_ALIGN(cbAllWritten, sizeof(RTTARRECORD)) - cbAllWritten;
    204         /* We have to make sure the file pointer is 512 byte aligned. */
    205         if (   RT_SUCCESS(rc)
    206             && offSeek > 0)
    207         {
    208             rc = RTFileSeek(hFile, offSeek, RTFILE_SEEK_CURRENT, NULL);
    209             if (RT_FAILURE(rc))
    210                 break;
    211         }
    212     }
    213     while(0);
    214 
    215     if (   RT_FAILURE(rc)
    216         && *ppvBuf)
    217         RTMemFree(*ppvBuf);
    218     else
    219         *pcbSize = cbToCopy;
    220 
    221     return rc;
    222 }
    223 
    224 static int rtTarExtractFileToFile(RTFILE hFile, const char *pszTargetName, PRTTARRECORD pRecord, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    225 {
    226     RTFILE hNewFile;
    227     /* Open the target file */
    228     int rc = RTFileOpen(&hNewFile, pszTargetName, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
    229     if (RT_FAILURE(rc))
    230         return rc;
    231 
    232     void *pvTmp = 0;
    233     do
    234     {
    235         /* Allocate a temporary buffer for reading the tar content in blocks. */
    236         size_t cbTmp = 0;
    237         pvTmp = rtTarMemTmpAlloc(&cbTmp);
    238         if (!pvTmp)
    239         {
    240             rc = VERR_NO_MEMORY;
    241             break;
    242         }
    243 
    244         uint64_t cbToCopy = RTStrToUInt64(pRecord->h.size);
    245         uint64_t cbAllWritten = 0; /* Already copied */
    246         uint64_t cbRead = 0; /* Actually read in the last step */
    247         /* Copy the content from hFile over to pszTargetName. This is done block
    248          * wise in 512 byte aligned steps. After this copying is finished hFile
    249          * will be on a 512 byte boundary, regardless if the file copied is 512
    250          * byte size aligned. */
    251         for (;;)
    252         {
    253             if (pfnProgressCallback)
    254                 pfnProgressCallback((unsigned)(100.0 / cbOverallSize * cbOverallWritten), pvUser);
    255             /* Finished already? */
    256             if (cbAllWritten == cbToCopy)
    257                 break;
    258             /* Read one block. This will be 512 aligned in any case. */
    259             cbRead = RT_ALIGN(RT_MIN(cbToCopy - cbAllWritten, cbTmp), sizeof(RTTARRECORD));
    260             rc = RTFileRead(hFile, pvTmp, cbRead, NULL);
    261             if (RT_FAILURE(rc))
    262                 break;
    263             /* Check for the last block which has not to be 512 bytes in size. */
    264             if (cbAllWritten + cbRead > cbToCopy)
    265                 cbRead = cbToCopy - cbAllWritten;
    266             /* Write the block */
    267             rc = RTFileWrite(hNewFile, pvTmp, cbRead, NULL);
    268             if (RT_FAILURE(rc))
    269                 break;
    270             /* Count how many bytes are written already */
    271             cbAllWritten += cbRead;
    272             cbOverallWritten += cbRead;
    273296        }
    274297
     
    283306    if (RT_SUCCESS(rc))
    284307    {
    285         int32_t mode;
    286         rc = RTStrToInt32Full(pRecord->h.mode, 8, &mode);
     308        uint32_t mode;
     309        rc = RTTarFileGetMode(hFile, &mode);
    287310        if (RT_SUCCESS(rc))
    288311        {
     
    302325}
    303326
    304 static int rtTarAppendFileFromFile(RTFILE hFile, const char *pszSrcName, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     327static int rtTarAppendFileFromFile(RTTAR hTar, const char *pszSrcName, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    305328{
    306329    RTFILE hOldFile;
     
    310333        return rc;
    311334
     335    RTTARFILE hFile = NIL_RTTARFILE;
    312336    void *pvTmp = 0;
    313337    do
     
    318342        if (RT_FAILURE(rc))
    319343            break;
     344
     345        rc = RTTarFileOpen(hTar, &hFile, RTPathFilename(pszSrcName), RTFILE_O_OPEN | RTFILE_O_WRITE);
     346        if (RT_FAILURE(rc))
     347            break;
     348
    320349        /* Get some info from the source file */
    321350        RTFSOBJINFO info;
     
    333362            mtime = RTTimeSpecGetSeconds(&info.ModificationTime);
    334363        }
    335 
    336         /* Fill the header record */
    337         RTTARRECORD record;
    338         RT_ZERO(record);
    339         RTStrPrintf(record.h.name,  sizeof(record.h.name),  "%s",     RTPathFilename(pszSrcName));
    340         RTStrPrintf(record.h.mode,  sizeof(record.h.mode),  "%0.7o",  fmode);
    341         RTStrPrintf(record.h.uid,   sizeof(record.h.uid),   "%0.7o",  uid);
    342         RTStrPrintf(record.h.gid,   sizeof(record.h.gid),   "%0.7o",  gid);
    343         RTStrPrintf(record.h.size,  sizeof(record.h.size),  "%0.11o", cbToCopy);
    344         RTStrPrintf(record.h.mtime, sizeof(record.h.mtime), "%0.11o", mtime);
    345         RTStrPrintf(record.h.magic, sizeof(record.h.magic), "ustar  ");
    346         RTStrPrintf(record.h.uname, sizeof(record.h.uname), "someone");
    347         RTStrPrintf(record.h.gname, sizeof(record.h.gname), "someone");
    348         record.h.linkflag = LF_NORMAL;
    349 
    350         /* Create the checksum out of the new header */
    351         uint32_t chksum = 0;
    352         rc = rtTarCalcChkSum(&record, &chksum);
    353         if (RT_FAILURE(rc))
    354             break;
    355         /* Format the checksum */
    356         RTStrPrintf(record.h.chksum, sizeof(record.h.chksum), "%0.7o", chksum);
    357         /* Write the header first */
    358         rc = RTFileWrite(hFile, &record, sizeof(record), NULL);
     364        /* Set the mode from the other file */
     365        rc = RTTarFileSetMode(hFile, fmode);
     366        if (RT_FAILURE(rc))
     367            break;
     368        /* Set the modification time from the other file */
     369        RTTIMESPEC time;
     370        RTTimeSpecSetSeconds(&time, mtime);
     371        rc = RTTarFileSetTime(hFile, &time);
     372        if (RT_FAILURE(rc))
     373            break;
     374        /* Set the owner from the other file */
     375        rc = RTTarFileSetOwner(hFile, uid, gid);
    359376        if (RT_FAILURE(rc))
    360377            break;
     
    385402             * file. */
    386403            cbRead = RT_MIN(cbToCopy - cbAllWritten, cbTmp);
    387             /* Write one block. This will be 512 byte aligned in any case. */
    388             cbWrite = RT_ALIGN(cbRead, sizeof(RTTARRECORD));
    389             /* Last record? */
    390             if (cbRead != cbWrite)
    391                 /* Initialize the rest with zeros */
    392                 RT_BZERO(&((char*)pvTmp)[cbRead], cbWrite-cbRead);
    393404            /* Read one block */
    394405            rc = RTFileRead(hOldFile, pvTmp, cbRead, NULL);
    395406            if (RT_FAILURE(rc))
    396407                break;
    397             /* Write one block. Tar needs to be 512 byte aligned. */
    398             rc = RTFileWrite(hFile, pvTmp, cbWrite, NULL);
     408            /* Write one block. */
     409            rc = RTTarFileWriteAt(hFile, cbAllWritten, pvTmp, cbRead, NULL);
    399410            if (RT_FAILURE(rc))
    400411                break;
     
    410421        RTMemTmpFree(pvTmp);
    411422
     423    if (hFile)
     424        RTTarFileClose(hFile);
     425
    412426    RTFileClose(hOldFile);
     427
    413428    return rc;
    414429}
     
    421436    if (offSeek > 0)
    422437        rc = RTFileSeek(hFile, offSeek, RTFILE_SEEK_CURRENT, NULL);
     438    return rc;
     439}
     440
     441static int rtTarFindFile(RTFILE hFile, const char *pszFile, uint64_t *puOffset, uint64_t *pcbSize)
     442{
     443    /* Assume we are on the file head. */
     444    int rc;
     445    bool fFound = false;
     446    RTTARRECORD record;
     447    for (;;)
     448    {
     449        /* Read & verify a header record */
     450        rc = rtTarReadHeaderRecord(hFile, &record);
     451        /* Check for error or EOF. */
     452        if (RT_FAILURE(rc))
     453            break;
     454        /* We support normal files only */
     455        if (   record.h.linkflag == LF_OLDNORMAL
     456            || record.h.linkflag == LF_NORMAL)
     457        {
     458            if (!RTStrCmp(record.h.name, pszFile))
     459            {
     460                /* Get the file size */
     461                rc = RTStrToUInt64Full(record.h.size, 8, pcbSize);
     462                if (RT_FAILURE(rc))
     463                    break;
     464                /* Seek back, to positionate the file pointer at the start of the header. */
     465                rc = RTFileSeek(hFile, -sizeof(RTTARRECORD), RTFILE_SEEK_CURRENT, puOffset);
     466                fFound = true;
     467                break;
     468            }
     469        }
     470        rc = rtTarSkipData(hFile, &record);
     471        if (RT_FAILURE(rc))
     472            break;
     473    }
     474
     475    if (rc == VERR_TAR_END_OF_FILE)
     476        rc = VINF_SUCCESS;
     477
     478    /* Something found? */
     479    if (    RT_SUCCESS(rc)
     480        &&  !fFound)
     481        rc = VERR_FILE_NOT_FOUND;
     482
    423483    return rc;
    424484}
     
    470530}
    471531
    472 /*******************************************************************************
    473 *   Public Functions                                                         *
    474 *******************************************************************************/
    475 
    476 RTR3DECL(int) RTTarQueryFileExists(const char *pszTarFile, const char *pszFile)
     532/******************************************************************************
     533 *   Public Functions                                                         *
     534 ******************************************************************************/
     535
     536RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char* pszTarname, uint32_t fMode)
     537{
     538    PRTTARINTERNAL pInt = (PRTTARINTERNAL)RTMemAllocZ(sizeof(RTTARINTERNAL));
     539    if (!pInt)
     540        return VERR_NO_MEMORY;
     541
     542    pInt->u32Magic = RTTAR_MAGIC;
     543
     544    int rc;
     545    do
     546    {
     547        /* Open the tar file. */
     548        rc = RTFileOpen(&pInt->hTarFile, pszTarname, fMode);
     549        if (RT_FAILURE(rc))
     550            break;
     551    }
     552    while(0);
     553
     554    if (RT_FAILURE(rc))
     555    {
     556        /* Todo: remove if created by us */
     557        if (pInt->hTarFile)
     558            RTFileClose(pInt->hTarFile);
     559        RTMemFree(pInt);
     560    }else
     561        *phTar = (RTTAR)pInt;
     562
     563    return rc;
     564}
     565
     566RTR3DECL(int) RTTarClose(RTTAR hTar)
     567{
     568    if (hTar == NIL_RTTAR)
     569        return VINF_SUCCESS;
     570
     571    PRTTARINTERNAL pInt = hTar;
     572    RTTAR_VALID_RETURN(pInt);
     573
     574    int rc = VINF_SUCCESS;
     575
     576    /* gtar gives a warning, but the documentation says EOF is indicated by a
     577     * zero block. Disabled for now. */
     578#if 0
     579    {
     580        /* Append the EOF record which is filled all by zeros */
     581        RTTARRECORD record;
     582        RT_ZERO(record);
     583        rc = RTFileWrite(pInt->hTarFile, &record, sizeof(record), NULL);
     584    }
     585#endif
     586
     587    if (pInt->hTarFile)
     588        rc = RTFileClose(pInt->hTarFile);
     589
     590    pInt->u32Magic = RTTAR_MAGIC_DEAD;
     591
     592    RTMemFree(pInt);
     593
     594    return rc;
     595}
     596
     597RTR3DECL(int) RTTarFileOpen(RTTAR hTar, PRTTARFILE phFile, const char *pszFilename, uint32_t fOpen)
     598{
     599    AssertReturn((fOpen & RTFILE_O_READ) || (fOpen & RTFILE_O_WRITE), VERR_INVALID_PARAMETER);
     600
     601    PRTTARINTERNAL pInt = hTar;
     602    RTTAR_VALID_RETURN(pInt);
     603
     604    if (!pInt->hTarFile)
     605        return VERR_INVALID_HANDLE;
     606
     607    if (fOpen & RTFILE_O_WRITE)
     608    {
     609        if (pInt->fOpenMode & RTFILE_O_READ)
     610            return VERR_WRITE_PROTECT;
     611        if (pInt->fFileOpenForWrite)
     612            return VERR_TOO_MANY_OPEN_FILES;
     613    }
     614
     615    PRTTARFILEINTERNAL pFileInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL));
     616    if (!pFileInt)
     617        return VERR_NO_MEMORY;
     618
     619    pFileInt->u32Magic = RTTARFILE_MAGIC;
     620
     621    int rc;
     622    do
     623    {
     624        pFileInt->pTar = pInt;
     625        pFileInt->pszFilename = RTStrDup(pszFilename);
     626        pFileInt->uStart = 0;
     627        pFileInt->cbSize = 0;
     628        pFileInt->fOpenMode = fOpen;
     629        pFileInt->uCurrentPos = 0;
     630
     631        if (pFileInt->fOpenMode & RTFILE_O_WRITE)
     632        {
     633            pInt->fFileOpenForWrite = true;
     634            /* If we are in write mode, we also in append mode. Add an dummy
     635             * header at the end of the current file. It will be filled by the
     636             * close operation. */
     637            rc = RTFileSeek(pFileInt->pTar->hTarFile, 0, RTFILE_SEEK_END, &pFileInt->uStart);
     638            if (RT_FAILURE(rc))
     639                break;
     640            RTTARRECORD record;
     641            RT_ZERO(record);
     642            rc = RTFileWrite(pFileInt->pTar->hTarFile, &record, sizeof(RTTARRECORD), NULL);
     643            if (RT_FAILURE(rc))
     644                break;
     645        }
     646        else if (pFileInt->fOpenMode & RTFILE_O_READ)
     647        {
     648            /* We need to be on the start of the file */
     649            rc = RTFileSeek(pFileInt->pTar->hTarFile, 0, RTFILE_SEEK_BEGIN, NULL);
     650            if (RT_FAILURE(rc))
     651                break;
     652            /* Search for the file. */
     653            rc = rtTarFindFile(pFileInt->pTar->hTarFile, pszFilename, &pFileInt->uStart, &pFileInt->cbSize);
     654            if (RT_FAILURE(rc))
     655                break;
     656        }
     657        else
     658        {
     659        }
     660
     661    }
     662    while(0);
     663
     664    /* Cleanup on failure */
     665    if (RT_FAILURE(rc))
     666    {
     667        if (pFileInt->pszFilename)
     668            RTStrFree(pFileInt->pszFilename);
     669        RTMemFree(pFileInt);
     670    }
     671    else
     672        *phFile = (RTTARFILE)pFileInt;
     673
     674    return rc;
     675}
     676
     677RTR3DECL(int) RTTarFileClose(RTTARFILE hFile)
     678{
     679    /* Already closed? */
     680    if (hFile == NIL_RTTARFILE)
     681        return VINF_SUCCESS;
     682
     683    PRTTARFILEINTERNAL pFileInt = hFile;
     684    RTTARFILE_VALID_RETURN(pFileInt);
     685
     686    int rc = VINF_SUCCESS;
     687
     688    /* In write mode: */
     689    if (pFileInt->fOpenMode & RTFILE_O_WRITE)
     690    {
     691        pFileInt->pTar->fFileOpenForWrite = false;
     692        do
     693        {
     694            RTTARRECORD record;
     695            RT_ZERO(record);
     696            /* If the written size isn't 512 byte aligned, we need to fix this. */
     697            uint64_t cbSizeAligned = RT_ALIGN(pFileInt->cbSize, sizeof(RTTARRECORD));
     698            if (cbSizeAligned != pFileInt->cbSize)
     699            {
     700                rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + pFileInt->cbSize, &record, cbSizeAligned - pFileInt->cbSize, NULL);
     701                if (RT_FAILURE(rc))
     702                    break;
     703            }
     704            /* Create a header record for the file */
     705            /* Todo: mode, gid, uid, mtime should be setable (or detected myself) */
     706            RTTIMESPEC time;
     707            RTTimeNow(&time);
     708            rc = rtTarCreateHeaderRecord(&record, pFileInt->pszFilename, pFileInt->cbSize, 0, 0, 0600, RTTimeSpecGetSeconds(&time));
     709            if (RT_FAILURE(rc))
     710                break;
     711            /* Write this at the start of the file data */
     712            rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart, &record, sizeof(RTTARRECORD), NULL);
     713            if (RT_FAILURE(rc))
     714                break;
     715        }
     716        while(0);
     717    }
     718    /* Nothing special in readmode. */
     719
     720    /* Now cleanup and delete the handle */
     721    RTStrFree(pFileInt->pszFilename);
     722    pFileInt->u32Magic = RTTARFILE_MAGIC_DEAD;
     723    RTMemFree(pFileInt);
     724
     725    return rc;
     726}
     727
     728RTR3DECL(int) RTTarFileSeek(RTTARFILE hFile, uint64_t uOffset,  unsigned uMethod, uint64_t *poffActual)
     729{
     730    PRTTARFILEINTERNAL pFileInt = hFile;
     731    RTTARFILE_VALID_RETURN(pFileInt);
     732
     733    switch (uMethod)
     734    {
     735        case RTFILE_SEEK_BEGIN:
     736        {
     737            if (uOffset > pFileInt->cbSize)
     738                return VERR_SEEK_ON_DEVICE;
     739            pFileInt->uCurrentPos = uOffset;
     740            break;
     741        }
     742        case RTFILE_SEEK_CURRENT:
     743        {
     744            if (pFileInt->uCurrentPos + uOffset > pFileInt->cbSize)
     745                return VERR_SEEK_ON_DEVICE;
     746            pFileInt->uCurrentPos += uOffset;
     747            break;
     748        }
     749        case RTFILE_SEEK_END:
     750        {
     751            if ((int64_t)pFileInt->cbSize - (int64_t)uOffset < 0)
     752                return VERR_NEGATIVE_SEEK;
     753            pFileInt->uCurrentPos = pFileInt->cbSize - uOffset;
     754            break;
     755        }
     756        default: AssertFailedReturn(VERR_INVALID_PARAMETER); break;
     757    }
     758
     759    return VINF_SUCCESS;
     760}
     761
     762RTR3DECL(uint64_t) RTTarFileTell(RTTARFILE hFile)
     763{
     764    PRTTARFILEINTERNAL pFileInt = hFile;
     765    RTTARFILE_VALID_RETURN_RC(pFileInt, ~0ULL);
     766
     767    return pFileInt->uCurrentPos;
     768}
     769
     770RTR3DECL(int) RTTarFileRead(RTTARFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
     771{
     772    PRTTARFILEINTERNAL pFileInt = hFile;
     773    RTTARFILE_VALID_RETURN(pFileInt);
     774
     775    /* Todo: optimize this, by checking the current pos */
     776    return RTTarFileReadAt(hFile, pFileInt->uCurrentPos, pvBuf, cbToRead, pcbRead);
     777}
     778
     779RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t uOffset, void *pvBuf, size_t cbToRead, size_t *pcbRead)
     780{
     781    PRTTARFILEINTERNAL pFileInt = hFile;
     782    RTTARFILE_VALID_RETURN(pFileInt);
     783
     784    size_t cbTmpRead = 0;
     785    int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToRead, &cbTmpRead);
     786    pFileInt->uCurrentPos = uOffset + cbTmpRead;
     787    if (pcbRead)
     788        *pcbRead = cbTmpRead;
     789
     790    return rc;
     791}
     792
     793RTR3DECL(int) RTTarFileWrite(RTTARFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
     794{
     795    PRTTARFILEINTERNAL pFileInt = hFile;
     796    RTTARFILE_VALID_RETURN(pFileInt);
     797
     798    /* Todo: optimize this, by checking the current pos */
     799    return RTTarFileWriteAt(hFile, pFileInt->uCurrentPos, pvBuf, cbToWrite, pcbWritten);
     800}
     801
     802RTR3DECL(int) RTTarFileWriteAt(RTTARFILE hFile, uint64_t uOffset, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
     803{
     804    PRTTARFILEINTERNAL pFileInt = hFile;
     805    RTTARFILE_VALID_RETURN(pFileInt);
     806
     807    if (!pFileInt->fOpenMode & RTFILE_O_WRITE)
     808        return VERR_WRITE_ERROR;
     809
     810    size_t cbTmpWritten = 0;
     811    int rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToWrite, &cbTmpWritten);
     812    pFileInt->cbSize += cbTmpWritten;
     813    pFileInt->uCurrentPos = uOffset + cbTmpWritten;
     814    if (pcbWritten)
     815        *pcbWritten = cbTmpWritten;
     816
     817    return rc;
     818}
     819
     820RTR3DECL(int) RTTarFileGetSize(RTTARFILE hFile, uint64_t *pcbSize)
     821{
     822    PRTTARFILEINTERNAL pFileInt = hFile;
     823    RTTARFILE_VALID_RETURN(pFileInt);
     824
     825    *pcbSize = pFileInt->cbSize;
     826
     827    return VINF_SUCCESS;
     828}
     829
     830RTR3DECL(int) RTTarFileSetSize(RTTARFILE hFile, uint64_t cbSize)
     831{
     832    PRTTARFILEINTERNAL pFileInt = hFile;
     833    RTTARFILE_VALID_RETURN(pFileInt);
     834
     835    if (!pFileInt->fOpenMode & RTFILE_O_WRITE)
     836        return VERR_WRITE_ERROR;
     837
     838    /* Check if we already have that size. */
     839    /* Todo: shrink files!!!! */
     840    if ((int64_t)cbSize - (int64_t)pFileInt->cbSize <= 0)
     841        return VINF_SUCCESS;
     842    uint64_t cbToCopy = cbSize - pFileInt->cbSize;
     843
     844    /* Allocate a temporary buffer for copying the tar content in blocks. */
     845    size_t cbTmp = 0;
     846    void *pvTmp = rtTarMemTmpAlloc(&cbTmp);
     847    if (!pvTmp)
     848        return VERR_NO_MEMORY;
     849    RT_BZERO(pvTmp, cbTmp);
     850
     851    int rc;
     852    uint64_t cbAllWritten = 0;
     853    size_t cbToWrite = 0;
     854    size_t cbWritten = 0;
     855    for (;;)
     856    {
     857        if (cbAllWritten >= cbToCopy)
     858            break;
     859        cbToWrite = RT_MIN(cbToCopy - cbAllWritten, cbTmp);
     860        rc = RTTarFileWrite(hFile, pvTmp, cbToWrite, &cbWritten);
     861        if (RT_FAILURE(rc))
     862            break;
     863        cbAllWritten += cbWritten;
     864    }
     865
     866    RTMemTmpFree(pvTmp);
     867
     868    return rc;
     869}
     870
     871RTR3DECL(int) RTTarFileGetMode(RTTARFILE hFile, uint32_t *pfMode)
     872{
     873    /* Validate input */
     874    AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
     875
     876    PRTTARFILEINTERNAL pFileInt = hFile;
     877    RTTARFILE_VALID_RETURN(pFileInt);
     878
     879    /* Read the mode out of the header entry */
     880    char mode[8];
     881    int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mode), mode, 8, NULL);
     882    if (RT_FAILURE(rc))
     883        return rc;
     884    /* Convert it to an integer */
     885    return RTStrToUInt32Full(mode, 8, pfMode);
     886}
     887
     888RTR3DECL(int) RTTarFileSetMode(RTTARFILE hFile, uint32_t fMode)
     889{
     890    PRTTARFILEINTERNAL pFileInt = hFile;
     891    RTTARFILE_VALID_RETURN(pFileInt);
     892
     893    if (!pFileInt->fOpenMode & RTFILE_O_WRITE)
     894        return VERR_WRITE_ERROR;
     895
     896    /* Convert the mode to an string. */
     897    char mode[8];
     898    RTStrPrintf(mode, sizeof(mode), "%0.7o", fMode);
     899    /* Write it directly into the header */
     900    return RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mode), mode, 8, NULL);
     901}
     902
     903RTR3DECL(int) RTTarFileGetTime(RTTARFILE hFile, PRTTIMESPEC pTime)
     904{
     905    PRTTARFILEINTERNAL pFileInt = hFile;
     906    RTTARFILE_VALID_RETURN(pFileInt);
     907
     908    /* Read the time out of the header entry */
     909    char mtime[12];
     910    int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mtime), mtime, 12, NULL);
     911    if (RT_FAILURE(rc))
     912        return rc;
     913    /* Convert it to an integer */
     914    int64_t tmpSeconds;
     915    rc = RTStrToInt64Full(mtime, 12, &tmpSeconds);
     916    /* And back to our time structure */
     917    if (RT_SUCCESS(rc))
     918        RTTimeSpecSetSeconds(pTime, tmpSeconds);
     919
     920    return rc;
     921}
     922
     923RTR3DECL(int) RTTarFileSetTime(RTTARFILE hFile, PRTTIMESPEC pTime)
     924{
     925    PRTTARFILEINTERNAL pFileInt = hFile;
     926    RTTARFILE_VALID_RETURN(pFileInt);
     927
     928    if (!pFileInt->fOpenMode & RTFILE_O_WRITE)
     929        return VERR_WRITE_ERROR;
     930
     931    /* Convert the time to an string. */
     932    char mtime[12];
     933    RTStrPrintf(mtime, sizeof(mtime), "%0.11o", RTTimeSpecGetSeconds(pTime));
     934    /* Write it directly into the header */
     935    return RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.mtime), mtime, 12, NULL);
     936}
     937
     938RTR3DECL(int) RTTarFileGetOwner(RTTARFILE hFile, uint32_t *pUid, uint32_t *pGid)
     939{
     940    PRTTARFILEINTERNAL pFileInt = hFile;
     941    RTTARFILE_VALID_RETURN(pFileInt);
     942
     943    /* Read the uid and gid out of the header entry */
     944    char uid[8];
     945    int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.uid), uid, 8, NULL);
     946    if (RT_FAILURE(rc))
     947        return rc;
     948    char gid[8];
     949    rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.gid), gid, 8, NULL);
     950    if (RT_FAILURE(rc))
     951        return rc;
     952    /* Convert it to integer */
     953    rc = RTStrToUInt32Full(uid, 8, pUid);
     954    if (RT_FAILURE(rc))
     955        return rc;
     956
     957    return RTStrToUInt32Full(gid, 8, pGid);
     958}
     959
     960RTR3DECL(int) RTTarFileSetOwner(RTTARFILE hFile, uint32_t uid, uint32_t gid)
     961{
     962    PRTTARFILEINTERNAL pFileInt = hFile;
     963    RTTARFILE_VALID_RETURN(pFileInt);
     964
     965    if (!pFileInt->fOpenMode & RTFILE_O_WRITE)
     966        return VERR_WRITE_ERROR;
     967
     968    int rc = VINF_SUCCESS;
     969
     970    if (uid != (uint32_t)-1)
     971    {
     972        /* Convert the uid to an string. */
     973        char tmpUid[8];
     974        RTStrPrintf(tmpUid, sizeof(tmpUid), "%0.7o", uid);
     975        /* Write it directly into the header */
     976        rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.uid), tmpUid, 8, NULL);
     977        if (RT_FAILURE(rc))
     978            return rc;
     979    }
     980    if (gid != (uint32_t)-1)
     981    {
     982        /* Convert the gid to an string. */
     983        char tmpGid[8];
     984        RTStrPrintf(tmpGid, sizeof(tmpGid), "%0.7o", gid);
     985        /* Write it directly into the header */
     986        rc = RTFileWriteAt(pFileInt->pTar->hTarFile, pFileInt->uStart + RT_OFFSETOF(RTTARRECORD, h.gid), tmpGid, 8, NULL);
     987        if (RT_FAILURE(rc))
     988            return rc;
     989    }
     990
     991    return rc;
     992}
     993
     994/******************************************************************************
     995 *   Convenience Functions                                                    *
     996 ******************************************************************************/
     997
     998RTR3DECL(int) RTTarFileExists(const char *pszTarFile, const char *pszFile)
    477999{
    4781000    /* Validate input */
     
    4811003
    4821004    /* Open the tar file */
    483     RTFILE hFile;
    484     int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    485     if (RT_FAILURE(rc))
    486         return rc;
    487 
    488     bool fFound = false;
    489     RTTARRECORD record;
    490     for (;;)
    491     {
    492         /* Read & verify a header record */
    493         rc = rtTarReadHeaderRecord(hFile, &record);
    494         /* Check for error or EOF. */
    495         if (RT_FAILURE(rc))
    496             break;
    497         /* We support normal files only */
    498         if (   record.h.linkflag == LF_OLDNORMAL
    499             || record.h.linkflag == LF_NORMAL)
    500         {
    501             if (!RTStrCmp(record.h.name, pszFile))
    502             {
    503                 fFound = true;
    504                 break;
    505             }
    506         }
    507         rc = rtTarSkipData(hFile, &record);
    508         if (RT_FAILURE(rc))
    509             break;
    510     }
    511 
    512     RTFileClose(hFile);
    513 
    514     if (rc == VERR_TAR_END_OF_FILE)
    515         rc = VINF_SUCCESS;
    516 
    517     /* Something found? */
    518     if (    RT_SUCCESS(rc)
    519         &&  !fFound)
    520         rc = VERR_FILE_NOT_FOUND;
     1005    RTTAR hTar;
     1006    int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     1007    if (RT_FAILURE(rc))
     1008        return rc;
     1009
     1010    /* Just try to open that file readonly. If this succeed the file exists. */
     1011    RTTARFILE hFile;
     1012    rc = RTTarFileOpen(hTar, &hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     1013    if (RT_SUCCESS(rc))
     1014        RTTarFileClose(hFile);
     1015
     1016    RTTarClose(hTar);
    5211017
    5221018    return rc;
     
    5311027
    5321028    /* Open the tar file */
    533     RTFILE hFile;
    534     int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    535     if (RT_FAILURE(rc))
    536         return rc;
    537 
    538     /* Initialize the file name array with one slot */
    539     size_t cFilesAlloc = 1;
    540     char **papszFiles = (char**)RTMemAlloc(sizeof(char *));
    541     if (!papszFiles)
    542     {
    543         RTFileClose(hFile);
    544         return VERR_NO_MEMORY;
    545     }
    546 
    547     /* Iterate through the tar file record by record. Skip data records as we
    548      * didn't need them. */
    549     RTTARRECORD record;
     1029    RTTAR hTar;
     1030    int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     1031    if (RT_FAILURE(rc))
     1032        return rc;
     1033
     1034    /* This is done by internal methods, cause we didn't have a RTTARDIR
     1035     * interface, yet. This should be fixed somedays. */
     1036
     1037    PRTTARINTERNAL pInt = hTar;
     1038    char **papszFiles = 0;
    5501039    size_t cFiles = 0;
    551     for (;;)
    552     {
    553         /* Read & verify a header record */
    554         rc = rtTarReadHeaderRecord(hFile, &record);
    555         /* Check for error or EOF. */
    556         if (RT_FAILURE(rc))
    557             break;
    558         /* We support normal files only */
    559         if (   record.h.linkflag == LF_OLDNORMAL
    560             || record.h.linkflag == LF_NORMAL)
    561         {
    562             if (cFiles >= cFilesAlloc)
     1040    do
     1041    {
     1042        /* Initialize the file name array with one slot */
     1043        size_t cFilesAlloc = 1;
     1044        papszFiles = (char**)RTMemAlloc(sizeof(char *));
     1045        if (!papszFiles)
     1046        {
     1047            return VERR_NO_MEMORY;
     1048            break;
     1049        }
     1050
     1051        /* Iterate through the tar file record by record. Skip data records as we
     1052         * didn't need them. */
     1053        RTTARRECORD record;
     1054        for (;;)
     1055        {
     1056            /* Read & verify a header record */
     1057            rc = rtTarReadHeaderRecord(pInt->hTarFile, &record);
     1058            /* Check for error or EOF. */
     1059            if (RT_FAILURE(rc))
     1060                break;
     1061            /* We support normal files only */
     1062            if (   record.h.linkflag == LF_OLDNORMAL
     1063                || record.h.linkflag == LF_NORMAL)
    5631064            {
    564                 /* Double the array size, make sure the size doesn't wrap. */
    565                 void  *pvNew = NULL;
    566                 size_t cbNew = cFilesAlloc * sizeof(char *) * 2;
    567                 if (cbNew / sizeof(char *) / 2 == cFilesAlloc)
    568                     pvNew = RTMemRealloc(papszFiles, cbNew);
    569                 if (!pvNew)
     1065                if (cFiles >= cFilesAlloc)
     1066                {
     1067                    /* Double the array size, make sure the size doesn't wrap. */
     1068                    void  *pvNew = NULL;
     1069                    size_t cbNew = cFilesAlloc * sizeof(char *) * 2;
     1070                    if (cbNew / sizeof(char *) / 2 == cFilesAlloc)
     1071                        pvNew = RTMemRealloc(papszFiles, cbNew);
     1072                    if (!pvNew)
     1073                    {
     1074                        rc = VERR_NO_MEMORY;
     1075                        break;
     1076                    }
     1077                    papszFiles = (char **)pvNew;
     1078                    cFilesAlloc *= 2;
     1079                }
     1080
     1081                /* Duplicate the name */
     1082                papszFiles[cFiles] = RTStrDup(record.h.name);
     1083                if (!papszFiles[cFiles])
    5701084                {
    5711085                    rc = VERR_NO_MEMORY;
    5721086                    break;
    5731087                }
    574                 papszFiles = (char **)pvNew;
    575                 cFilesAlloc *= 2;
     1088                cFiles++;
    5761089            }
    577 
    578             /* Duplicate the name */
    579             papszFiles[cFiles] = RTStrDup(record.h.name);
    580             if (!papszFiles[cFiles])
    581             {
    582                 rc = VERR_NO_MEMORY;
    583                 break;
    584             }
    585             cFiles++;
    586         }
    587         rc = rtTarSkipData(hFile, &record);
    588         if (RT_FAILURE(rc))
    589             break;
    590     }
    591 
    592     RTFileClose(hFile);
     1090            rc = rtTarSkipData(pInt->hTarFile, &record);
     1091            if (RT_FAILURE(rc))
     1092                break;
     1093        }
     1094    }
     1095    while(0);
    5931096
    5941097    if (rc == VERR_TAR_END_OF_FILE)
     
    6071110        RTMemFree(papszFiles);
    6081111    }
    609     return rc;
    610 }
    611 
    612 RTR3DECL(int) RTTarExtractFileToBuf(const char *pszTarFile, void **ppvBuf, uint64_t *pcbSize, const char *pszFile, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     1112
     1113    RTTarClose(hTar);
     1114
     1115    return rc;
     1116}
     1117
     1118RTR3DECL(int) RTTarExtractFileToBuf(const char *pszTarFile, void **ppvBuf, size_t *pcbSize, const char *pszFile, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    6131119{
    6141120    /* Validate input */
    6151121    AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
     1122    AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
     1123    AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
    6161124    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
    617 
    618     /* Open the tar file */
    619     RTFILE hFile;
    620     int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    621     if (RT_FAILURE(rc))
    622         return rc;
    623 
    624     /* Get the overall size of all files to extract out of the tar archive
    625        headers. Only necessary if there is a progress callback. */
    626     uint64_t cbOverallSize = 0;
    627     if (pfnProgressCallback)
    628         rc = rtTarGetFilesOverallSize(hFile, &pszFile, 1, &cbOverallSize);
     1125    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
     1126    AssertPtrNullReturn(pvUser, VERR_INVALID_POINTER);
     1127
     1128    /* Todo: progress bar */
     1129
     1130    int rc;
     1131    RTTAR hTar = NIL_RTTAR;
     1132    RTTARFILE hFile = NIL_RTTARFILE;
     1133    char *pvTmp = 0;
     1134    uint64_t cbToCopy = 0;
     1135    do
     1136    {
     1137        rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     1138        if (RT_FAILURE(rc))
     1139            break;
     1140        rc = RTTarFileOpen(hTar, &hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ);
     1141        if (RT_FAILURE(rc))
     1142            break;
     1143        rc = RTTarFileGetSize(hFile, &cbToCopy);
     1144        if (RT_FAILURE(rc))
     1145            break;
     1146        /* Allocate the memory for the file content. */
     1147        pvTmp = (char*)RTMemAlloc(cbToCopy);
     1148        if (!pvTmp)
     1149        {
     1150            rc = VERR_NO_MEMORY;
     1151            break;
     1152        }
     1153        size_t cbRead = 0;
     1154        size_t cbAllRead = 0;
     1155        for (;;)
     1156        {
     1157            if (pfnProgressCallback)
     1158                pfnProgressCallback((unsigned)(100.0 / cbToCopy * cbAllRead), pvUser);
     1159            if (cbAllRead == cbToCopy)
     1160                break;
     1161            rc = RTTarFileReadAt(hFile, 0, &pvTmp[cbAllRead], cbToCopy - cbAllRead, &cbRead);
     1162            if (RT_FAILURE(rc))
     1163                break;
     1164            cbAllRead += cbRead;
     1165        }
     1166    }
     1167    while(0);
     1168
     1169    /* Set output values on success */
    6291170    if (RT_SUCCESS(rc))
    6301171    {
    631         /* Iterate through the tar file record by record. */
    632         RTTARRECORD record;
    633         bool fFound = false;
    634         uint64_t cbOverallWritten = 0;
    635         for (;;)
    636         {
    637             /* Read & verify a header record */
    638             rc = rtTarReadHeaderRecord(hFile, &record);
    639             /* Check for error or EOF. */
    640             if (RT_FAILURE(rc))
    641                 break;
    642             /* We support normal files only */
    643             if (   record.h.linkflag == LF_OLDNORMAL
    644                 || record.h.linkflag == LF_NORMAL)
    645             {
    646                 if (!RTStrCmp(record.h.name, pszFile))
    647                 {
    648                     fFound = true;
    649                     rc = rtTarExtractFileToBuf(hFile, ppvBuf, pcbSize, &record, cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
    650                     /* We are finished */
    651                     break;
    652                 }
    653                 else
    654                 {
    655                     rc = rtTarSkipData(hFile, &record);
    656                     if (RT_FAILURE(rc))
    657                         break;
    658                 }
    659             }
    660         }
    661 
    662         if (rc == VERR_TAR_END_OF_FILE)
    663             rc = VINF_SUCCESS;
    664 
    665         /* If we didn't found the file, indicate an error */
    666         if (!fFound && RT_SUCCESS(rc))
    667             rc = VERR_FILE_NOT_FOUND;
    668     }
    669 
    670     RTFileClose(hFile);
     1172        *pcbSize = cbToCopy;
     1173        *ppvBuf = pvTmp;
     1174    }
     1175
     1176    /* Cleanup */
     1177    if (   RT_FAILURE(rc)
     1178        && pvTmp)
     1179        RTMemFree(pvTmp);
     1180    if (hFile)
     1181        RTTarFileClose(hFile);
     1182    if (hTar)
     1183        RTTarClose(hTar);
     1184
    6711185    return rc;
    6721186}
     
    6781192    AssertPtrReturn(pszOutputDir, VERR_INVALID_POINTER);
    6791193    AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
     1194    AssertReturn(cFiles, VERR_INVALID_PARAMETER);
     1195    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
     1196    AssertPtrNullReturn(pvUser, VERR_INVALID_POINTER);
    6801197
    6811198    /* Open the tar file */
    682     RTFILE hFile;
    683     int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    684     if (RT_FAILURE(rc))
    685         return rc;
    686 
    687     /* Get the overall size of all files to extract out of the tar archive
    688        headers. Only necessary if there is a progress callback. */
    689     uint64_t cbOverallSize = 0;
    690     if (pfnProgressCallback)
    691         rc = rtTarGetFilesOverallSize(hFile, papszFiles, cFiles, &cbOverallSize);
    692     if (RT_SUCCESS(rc))
    693     {
    694         /* Iterate through the tar file record by record. */
    695         RTTARRECORD record;
    696         char **paExtracted = (char **)RTMemTmpAllocZ(sizeof(char *) * cFiles);
    697         if (paExtracted)
    698         {
    699             size_t cExtracted = 0;
    700             uint64_t cbOverallWritten = 0;
    701             for (;;)
    702             {
    703                 /* Read & verify a header record */
    704                 rc = rtTarReadHeaderRecord(hFile, &record);
    705                 /* Check for error or EOF. */
    706                 if (RT_FAILURE(rc))
    707                     break;
    708                 /* We support normal files only */
    709                 if (   record.h.linkflag == LF_OLDNORMAL
    710                     || record.h.linkflag == LF_NORMAL)
    711                 {
    712                     bool fFound = false;
    713                     for (size_t i = 0; i < cFiles; ++i)
    714                     {
    715                         if (!RTStrCmp(record.h.name, papszFiles[i]))
    716                         {
    717                             fFound = true;
    718                             if (cExtracted < cFiles)
    719                             {
    720                                 char *pszTargetFile;
    721                                 rc = RTStrAPrintf(&pszTargetFile, "%s/%s", pszOutputDir, papszFiles[i]);
    722                                 if (rc > 0)
    723                                 {
    724                                     rc = rtTarExtractFileToFile(hFile, pszTargetFile, &record, cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
    725                                     if (RT_SUCCESS(rc))
    726                                         paExtracted[cExtracted++] = pszTargetFile;
    727                                     else
    728                                         RTStrFree(pszTargetFile);
    729                                 }
    730                                 else
    731                                     rc = VERR_NO_MEMORY;
    732                             }
    733                             else
    734                                 rc = VERR_ALREADY_EXISTS;
    735                             break;
    736                         }
    737                     }
    738                     if (RT_FAILURE(rc))
    739                         break;
    740                     /* If the current record isn't a file in the file list we have to
    741                      * skip the data */
    742                     if (!fFound)
    743                     {
    744                         rc = rtTarSkipData(hFile, &record);
    745                         if (RT_FAILURE(rc))
    746                             break;
    747                     }
    748                 }
    749             }
    750 
    751             if (rc == VERR_TAR_END_OF_FILE)
    752                 rc = VINF_SUCCESS;
    753 
    754             /* If we didn't found all files, indicate an error */
    755             if (cExtracted != cFiles && RT_SUCCESS(rc))
    756                 rc = VERR_FILE_NOT_FOUND;
    757 
    758             /* Cleanup the names of the extracted files, deleting them on failure. */
    759             while (cExtracted-- > 0)
    760             {
    761                 if (RT_FAILURE(rc))
    762                     RTFileDelete(paExtracted[cExtracted]);
    763                 RTStrFree(paExtracted[cExtracted]);
    764             }
    765             RTMemTmpFree(paExtracted);
    766         }
    767         else
    768             rc = VERR_NO_TMP_MEMORY;
    769     }
    770 
    771     RTFileClose(hFile);
    772     return rc;
    773 }
    774 
    775 RTR3DECL(int) RTTarExtractByIndex(const char *pszTarFile, const char *pszOutputDir, size_t iIndex, char **ppszFileName, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     1199    RTTAR hTar;
     1200    int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     1201    if (RT_FAILURE(rc))
     1202        return rc;
     1203
     1204    do
     1205    {
     1206        /* Get the overall size of all files to extract out of the tar archive
     1207           headers. Only necessary if there is a progress callback. */
     1208        uint64_t cbOverallSize = 0;
     1209        if (pfnProgressCallback)
     1210        {
     1211//            rc = rtTarGetFilesOverallSize(hFile, papszFiles, cFiles, &cbOverallSize);
     1212//            if (RT_FAILURE(rc))
     1213//                break;
     1214        }
     1215
     1216        uint64_t cbOverallWritten = 0;
     1217        for(size_t i=0; i < cFiles; ++i)
     1218        {
     1219            RTTARFILE hFile;
     1220            rc = RTTarFileOpen(hTar, &hFile, papszFiles[i], RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     1221            if (RT_FAILURE(rc))
     1222                break;
     1223            char *pszTargetFile;
     1224            rc = RTStrAPrintf(&pszTargetFile, "%s/%s", pszOutputDir, papszFiles[i]);
     1225            if (RT_FAILURE(rc))
     1226                break;
     1227            rc = rtTarExtractFileToFile(hFile, pszTargetFile, cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
     1228            RTStrFree(pszTargetFile);
     1229            RTTarFileClose(hFile);
     1230            if (RT_FAILURE(rc))
     1231                break;
     1232        }
     1233    }
     1234    while(0);
     1235
     1236    RTTarClose(hTar);
     1237
     1238    return rc;
     1239}
     1240
     1241RTR3DECL(int) RTTarExtractAll(const char *pszTarFile, const char *pszOutputDir, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    7761242{
    7771243    /* Validate input */
    7781244    AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
    7791245    AssertPtrReturn(pszOutputDir, VERR_INVALID_POINTER);
    780 
    781     /* Open the tar file */
    782     RTFILE hFile;
    783     int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    784     if (RT_FAILURE(rc))
    785         return rc;
    786 
    787     /* Iterate through the tar file record by record. */
    788     RTTARRECORD record;
    789     size_t iFile = 0;
    790     bool fFound = false;
    791     for (;;)
    792     {
    793         /* Read & verify a header record */
    794         rc = rtTarReadHeaderRecord(hFile, &record);
    795         /* Check for error or EOF. */
    796         if (RT_FAILURE(rc))
    797             break;
    798         /* We support normal files only */
    799         if (   record.h.linkflag == LF_OLDNORMAL
    800             || record.h.linkflag == LF_NORMAL)
    801         {
    802             if (iIndex == iFile)
    803             {
    804                 fFound = true;
    805                 char *pszTargetName;
    806                 rc = RTStrAPrintf(&pszTargetName, "%s/%s", pszOutputDir, record.h.name);
    807                 if (rc > 0)
    808                 {
    809                     uint64_t cbOverallSize;
    810                     uint64_t cbOverallWritten = 0;
    811                     /* Get the file size */
    812                     rc = RTStrToUInt64Full(record.h.size, 8, &cbOverallSize);
    813                     if (RT_FAILURE(rc))
    814                         break;
    815                     rc = rtTarExtractFileToFile(hFile, pszTargetName, &record, cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
    816                     /* On success pass on the filename if requested. */
    817                     if (    RT_SUCCESS(rc)
    818                         &&  ppszFileName)
    819                         *ppszFileName = pszTargetName;
    820                     else
    821                         RTStrFree(pszTargetName);
    822                 }
    823                 else
    824                     rc = VERR_NO_MEMORY;
    825                 break;
    826             }
    827         }
    828         rc = rtTarSkipData(hFile, &record);
    829         if (RT_FAILURE(rc))
    830             break;
    831         ++iFile;
    832     }
    833 
    834     RTFileClose(hFile);
    835 
    836     if (rc == VERR_TAR_END_OF_FILE)
    837         rc = VINF_SUCCESS;
    838 
    839     /* If we didn't found the index, indicate an error */
    840     if (!fFound && RT_SUCCESS(rc))
    841         rc = VERR_FILE_NOT_FOUND;
    842 
    843     return rc;
    844 }
    845 
    846 RTR3DECL(int) RTTarExtractAll(const char *pszTarFile, const char *pszOutputDir, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    847 {
    848     /* Validate input */
    849     AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
    850     AssertPtrReturn(pszOutputDir, VERR_INVALID_POINTER);
     1246    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
     1247    AssertPtrNullReturn(pvUser, VERR_INVALID_POINTER);
    8511248
    8521249    char **papszFiles;
     
    8671264    AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
    8681265    AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
    869 
    870     /* Open the tar file */
    871     RTFILE hFile;
    872     int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
     1266    AssertReturn(cFiles, VERR_INVALID_PARAMETER);
     1267    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
     1268    AssertPtrNullReturn(pvUser, VERR_INVALID_POINTER);
     1269
     1270    RTTAR hTar;
     1271    int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_CREATE | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE);
    8731272    if (RT_FAILURE(rc))
    8741273        return rc;
     
    8861285            cbOverallSize += cbSize;
    8871286        }
    888 
    889     if (RT_SUCCESS(rc))
    890     {
    891         uint64_t cbOverallWritten = 0;
    892 
    893         for (size_t i = 0; i < cFiles; ++i)
    894         {
    895             rc = rtTarAppendFileFromFile(hFile, papszFiles[i], cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
    896             if (RT_FAILURE(rc))
    897                 break;
    898         }
    899 
    900         /* gtar gives a warning, but the documentation says EOF is indicated by a
    901          * zero block. Disabled for now. */
    902 #if 0
    903         if (RT_SUCCESS(rc))
    904         {
    905             /* Append the EOF record which is filled all by zeros */
    906             RTTARRECORD record;
    907             ASMMemFill32(&record, sizeof(record), 0);
    908             rc = RTFileWrite(hFile, &record, sizeof(record), NULL);
    909         }
    910 #endif
    911     }
    912 
    913     /* Time to close the new tar archive */
    914     RTFileClose(hFile);
    915 
    916     /* Delete the freshly created tar archive on failure */
    917     if (RT_FAILURE(rc))
    918         RTFileDelete(pszTarFile);
    919 
    920     return rc;
    921 }
    922 
     1287    uint64_t cbOverallWritten = 0;
     1288    for (size_t i = 0; i < cFiles; ++i)
     1289    {
     1290        rc = rtTarAppendFileFromFile(hTar, papszFiles[i], cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
     1291        if (RT_FAILURE(rc))
     1292            break;
     1293    }
     1294
     1295    /* Cleanup */
     1296    RTTarClose(hTar);
     1297
     1298    return rc;
     1299}
     1300
  • trunk/src/VBox/Runtime/include/internal/magics.h

    r30935 r32751  
    153153/** The value of RTS3::u32Magic after RTS3Destroy().  */
    154154#define RTS3_MAGIC_DEAD                 UINT32_C(0x19320210)
     155/** The value of RTTAR::u32Magic. (Donald Ervin Knuth) */
     156#define RTTAR_MAGIC                     UINT32_C(0x19380110)
     157/** The value of RTTAR::u32Magic after RTTarClose(). */
     158#define RTTAR_MAGIC_DEAD                ~RTTAR_MAGIC
     159/** The value of RTTARFILE::u32Magic. (Abraham Stoker) */
     160#define RTTARFILE_MAGIC                 UINT32_C(0x18471108)
     161/** The value of RTTARFILE::u32Magic after RTTarFileClose(). */
     162#define RTTARFILE_MAGIC_DEAD            UINT32_C(0x19120420)
    155163
    156164/** @} */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette