VirtualBox

Changeset 50194 in vbox for trunk


Ignore:
Timestamp:
Jan 23, 2014 5:52:28 PM (11 years ago)
Author:
vboxsync
Message:

tar.cpp: Stripped it futher down and documented what RTTarOpenCurrentFile actually need to do, simplifying the weird stuff that it used to do. You can only open the current file once now.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/mangling.h

    r50154 r50194  
    14971497# define RTSystemShutdown                               RT_MANGLER(RTSystemShutdown)
    14981498# define RTTarClose                                     RT_MANGLER(RTTarClose)
    1499 # define RTTarCreate                                    RT_MANGLER(RTTarCreate)
    15001499# define RTTarCurrentFile                               RT_MANGLER(RTTarCurrentFile)
    15011500# define RTTarFileClose                                 RT_MANGLER(RTTarFileClose)
     
    15031502# define RTTarFileOpen                                  RT_MANGLER(RTTarFileOpen)
    15041503# define RTTarFileOpenCurrentFile                       RT_MANGLER(RTTarFileOpenCurrentFile)
    1505 # define RTTarFileRead                                  RT_MANGLER(RTTarFileRead)
    15061504# define RTTarFileReadAt                                RT_MANGLER(RTTarFileReadAt)
    1507 # define RTTarFileSeek                                  RT_MANGLER(RTTarFileSeek)
    1508 # define RTTarFileSetMode                               RT_MANGLER(RTTarFileSetMode)
    1509 # define RTTarFileSetOwner                              RT_MANGLER(RTTarFileSetOwner)
    15101505# define RTTarFileSetSize                               RT_MANGLER(RTTarFileSetSize)
    1511 # define RTTarFileSetTime                               RT_MANGLER(RTTarFileSetTime)
    1512 # define RTTarFileTell                                  RT_MANGLER(RTTarFileTell)
    1513 # define RTTarFileWrite                                 RT_MANGLER(RTTarFileWrite)
    15141506# define RTTarFileWriteAt                               RT_MANGLER(RTTarFileWriteAt)
    1515 # define RTTarList                                      RT_MANGLER(RTTarList)
    15161507# define RTTarOpen                                      RT_MANGLER(RTTarOpen)
    15171508# define RTTarSeekNextFile                              RT_MANGLER(RTTarSeekNextFile)
  • trunk/include/iprt/tar.h

    r50154 r50194  
    44
    55/*
    6  * Copyright (C) 2009-2010 Oracle Corporation
     6 * Copyright (C) 2009-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3535/** @defgroup grp_rt_tar    RTTar - Tar archive I/O
    3636 * @ingroup grp_rt
     37 *
     38 * @deprecated  Only used for legacy code and writing.  Migrate new code to the
     39 *              VFS interface, add the write part when needed.
     40 *
    3741 * @{
    3842 */
     
    7781RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char *pszTarname, uint32_t fMode, bool fStream);
    7882
    79 #if 0
    80 /**
    81  * Opens a Tar archive by handle.
    82  *
    83  * Use the mask to specify the access type. In create mode the target file
    84  * have not to exists.
    85  *
    86  * @returns IPRT status code.
    87  *
    88  * @param   phTar          Where to store the RTTAR handle.
    89  * @param   hFile          The file handle of the tar file.  This is expected
    90  *                         to be a regular file at the moment.
    91  * @param   fStream        Open the file in stream mode. Within this mode no
    92  *                         seeking is allowed.  Use this together with
    93  *                         RTTarFileCurrent, RTTarFileOpenCurrent,
    94  *                         RTTarFileSeekNextFile and the read method to
    95  *                         sequential read a tar file.  Currently ignored with
    96  *                         RTFILE_O_WRITE.
    97  */
    98 RTR3DECL(int) RTTarOpenByHandle(PRTTAR phTar, RTFILE hFile, uint32_t fMode, bool fStream);
    99 #endif
    100 
    10183/**
    10284 * Close the Tar archive.
     
    10789 */
    10890RTR3DECL(int) RTTarClose(RTTAR hTar);
     91
     92/**
     93 * Jumps to the next file from the current RTTar position.
     94 *
     95 * @returns IPRT status code.
     96 *
     97 * @param   hTar           Handle to the RTTAR interface.
     98 */
     99RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar);
     100
     101/**
     102 * Return the filename where RTTar currently stays at.
     103 *
     104 * @returns IPRT status code.
     105 *
     106 * @param   hTar           Handle to the RTTAR interface.
     107 * @param   ppszFilename   On success the filename.
     108 */
     109RTR3DECL(int) RTTarCurrentFile(RTTAR hTar, char **ppszFilename);
     110
     111/**
     112 * Opens the file where RTTar currently stays at.
     113 *
     114 * The current file can only be opened once.  The next call will open the next
     115 * file, implicitly calling RTTarSeekNextFile().
     116 *
     117 * @returns IPRT status code.
     118 *
     119 * @param   hTar           Handle to the RTTAR interface.
     120 * @param   phFile         Where to store the handle to the opened file.
     121 * @param   ppszFilename   On success the filename.
     122 * @param   fOpen          Open flags, i.e a combination of the RTFILE_O_* defines.
     123 *                         The ACCESS, ACTION flags are mandatory! Currently
     124 *                         only RTFILE_O_OPEN | RTFILE_O_READ is supported.
     125 */
     126RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **ppszFilename, uint32_t fOpen);
    109127
    110128/**
     
    139157
    140158/**
    141  * Changes the read & write position in a file.
    142  *
    143  * @returns IPRT status code.
    144  *
    145  * @param   hFile          Handle to the file.
    146  * @param   offSeek        Offset to seek.
    147  * @param   uMethod        Seek method, i.e. one of the RTFILE_SEEK_* defines.
    148  * @param   poffActual     Where to store the new file position.
    149  *                         NULL is allowed.
    150  */
    151 RTR3DECL(int) RTTarFileSeek(RTTARFILE hFile, uint64_t offSeek, unsigned uMethod, uint64_t *poffActual);
    152 
    153 /**
    154  * Gets the current file position.
    155  *
    156  * @returns File offset.
    157  * @returns UINT64_MAX on failure.
    158  *
    159  * @param   hFile          Handle to the file.
    160  */
    161 RTR3DECL(uint64_t) RTTarFileTell(RTTARFILE hFile);
    162 
    163 /**
    164  * Read bytes from a file.
    165  *
    166  * @returns IPRT status code.
    167  *
    168  * @param   hFile          Handle to the file.
    169  * @param   pvBuf          Where to put the bytes we read.
    170  * @param   cbToRead       How much to read.
    171  * @param   *pcbRead       How much we actually read .
    172  *                         If NULL an error will be returned for a partial read.
    173  */
    174 RTR3DECL(int) RTTarFileRead(RTTARFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead);
    175 
    176 /**
    177159 * Read bytes from a file at a given offset.
    178160 * This function may modify the file position.
     
    184166 * @param   pvBuf          Where to put the bytes we read.
    185167 * @param   cbToRead       How much to read.
    186  * @param   *pcbRead       How much we actually read .
    187  *                         If NULL an error will be returned for a partial read.
     168 * @param   pcbRead        Where to return how much we actually read.  If NULL
     169 *                         an error will be returned for a partial read.
    188170 */
    189171RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t off, void *pvBuf, size_t cbToRead, size_t *pcbRead);
    190 
    191 /**
    192  * Write bytes to a file.
    193  *
    194  * @returns IPRT status code.
    195  *
    196  * @param   hFile          Handle to the file.
    197  * @param   pvBuf          What to write.
    198  * @param   cbToWrite      How much to write.
    199  * @param   *pcbWritten    How much we actually wrote.
    200  *                         If NULL an error will be returned for a partial write.
    201  */
    202 RTR3DECL(int) RTTarFileWrite(RTTARFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten);
    203172
    204173/**
     
    212181 * @param   pvBuf          What to write.
    213182 * @param   cbToWrite      How much to write.
    214  * @param   *pcbWritten    How much we actually wrote.
    215  *                         If NULL an error will be returned for a partial write.
     183 * @param   pcbWritten     Where to return how much we actually wrote.  If NULL
     184 *                         an error will be returned for a partial write.
    216185 */
    217186RTR3DECL(int) RTTarFileWriteAt(RTTARFILE hFile, uint64_t off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten);
     
    237206RTR3DECL(int) RTTarFileSetSize(RTTARFILE hFile, uint64_t cbSize);
    238207
    239 /**
    240  * Changes the mode flags of an open file.
    241  *
    242  * @returns IPRT status code.
    243  *
    244  * @param   hFile          Handle to the file.
    245  * @param   fMode          The new file mode, see @ref grp_rt_fs for details.
    246  */
    247 RTR3DECL(int) RTTarFileSetMode(RTTARFILE hFile, uint32_t fMode);
    248 
    249 /**
    250  * Sets the modification timestamp of the file.
    251  *
    252  * @returns IPRT status code.
    253  *
    254  * @param   pFile           Handle to the file.
    255  * @param   pTime           The time to store.
    256  */
    257 RTR3DECL(int) RTTarFileSetTime(RTTARFILE hFile, PRTTIMESPEC pTime);
    258 
    259 /**
    260  * Changes the owner and/or group of an open file.
    261  *
    262  * @returns IPRT status code.
    263  *
    264  * @param   hFile           Handle to the file.
    265  * @param   uid             The new file owner user id. Use -1 (or ~0) to leave this unchanged.
    266  * @param   gid             The new group id. Use -1 (or ~0) to leave this unchanged.
    267  */
    268 RTR3DECL(int) RTTarFileSetOwner(RTTARFILE hFile, uint32_t uid, uint32_t gid);
    269 
    270 /******************************************************************************
    271  *   Convenience Functions                                                    *
    272  ******************************************************************************/
    273 
    274 /**
    275  * Create a file list from a Tar archive.
    276  *
    277  * @note    Currently only regular files are supported.
    278  *
    279  * @returns IPRT status code.
    280  *
    281  * @param   pszTarFile      Tar file to list files from.
    282  * @param   ppapszFiles     On success an array with array with the filenames is
    283  *                          returned. The names must be freed with RTStrFree and
    284  *                          the array with RTMemFree.
    285  * @param   pcFiles         On success the number of entries in ppapszFiles.
    286  */
    287 RTR3DECL(int) RTTarList(const char *pszTarFile, char ***ppapszFiles, size_t *pcFiles);
    288 
    289 /**
    290  * Create a Tar archive out of the given files.
    291  *
    292  * @note Currently only regular files are supported.
    293  *
    294  * @returns IPRT status code.
    295  *
    296  * @param   pszTarFile           Where to create the Tar archive.
    297  * @param   papszFiles           Which files should be included.
    298  * @param   cFiles               The number of files in papszFiles.
    299  * @param   pfnProgressCallback  Progress callback function. Optional.
    300  * @param   pvUser               User defined data for the progress
    301  *                               callback. Optional.
    302  */
    303 RTR3DECL(int) RTTarCreate(const char *pszTarFile, const char * const *papszFiles, size_t cFiles, PFNRTPROGRESS pfnProgressCallback, void *pvUser);
    304 
    305 /******************************************************************************
    306  *   Streaming Functions                                                      *
    307  ******************************************************************************/
    308 
    309 /**
    310  * Return the filename where RTTar currently stays at.
    311  *
    312  * @returns IPRT status code.
    313  *
    314  * @param   hTar           Handle to the RTTAR interface.
    315  * @param   ppszFilename   On success the filename.
    316  */
    317 RTR3DECL(int) RTTarCurrentFile(RTTAR hTar, char **ppszFilename);
    318 
    319 /**
    320  * Jumps to the next file from the current RTTar position.
    321  *
    322  * @returns IPRT status code.
    323  *
    324  * @param   hTar           Handle to the RTTAR interface.
    325  */
    326 RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar);
    327 
    328 /**
    329  * Opens the file where RTTar currently stays at.
    330  *
    331  * @returns IPRT status code.
    332  *
    333  * @param   hTar           Handle to the RTTAR interface.
    334  * @param   phFile         Where to store the handle to the opened file.
    335  * @param   ppszFilename   On success the filename.
    336  * @param   fOpen          Open flags, i.e a combination of the RTFILE_O_* defines.
    337  *                         The ACCESS, ACTION flags are mandatory! Currently
    338  *                         only RTFILE_O_OPEN | RTFILE_O_READ is supported.
    339  */
    340 RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **ppszFilename, uint32_t fOpen);
    341 
    342 
    343208/** @} */
    344209
    345210RT_C_DECLS_END
    346211
    347 #endif /* ___iprt_tar_h */
    348 
     212#endif
     213
  • trunk/src/VBox/Runtime/common/zip/tar.cpp

    r50180 r50194  
    2525 */
    2626
    27 #define RT_USE_TAR_VFS_FOR_ALL_READS // the old code sticks around for a short while for debugging the new.
    28 
    29 /******************************************************************************
    30  *   Header Files                                                             *
    31  ******************************************************************************/
     27
     28/*******************************************************************************
     29*   Header Files                                                               *
     30*******************************************************************************/
    3231#include "internal/iprt.h"
    3332#include <iprt/tar.h>
     
    4039#include <iprt/path.h>
    4140#include <iprt/string.h>
    42 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    43 # include <iprt/vfs.h>
    44 # include <iprt/zip.h>
    45 #endif /* RT_USE_TAR_VFS_FOR_ALL_READS */
     41#include <iprt/vfs.h>
     42#include <iprt/zip.h>
    4643
    4744
     
    5047
    5148
    52 /******************************************************************************
    53  *   Structures and Typedefs                                                  *
    54  ******************************************************************************/
    55 
     49/*******************************************************************************
     50*   Structures and Typedefs                                                    *
     51*******************************************************************************/
    5652/** @name RTTARRECORD::h::linkflag
    5753 * @{  */
     
    116112    /** Whether operating in stream mode. */
    117113    bool                fStreamMode;
    118 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    119     /** The file cache of one file.  */
    120     PRTTARFILEINTERNAL  pFileCache;
    121 #else /* RT_USE_TAR_VFS_FOR_ALL_READS */
    122114    /** The tar file VFS handle. */
    123115    RTVFSFILE           hVfsFile;
     
    130122    /** The name of the current object (fStreamMode = true). */
    131123    char               *pszVfsCurName;
    132 #endif /* RT_USE_TAR_VFS_FOR_ALL_READS */
    133124} RTTARINTERNAL;
    134125/** Pointer to a the internal data of a tar handle.  */
     
    156147    /** The current offset within this file. */
    157148    uint64_t        offCurrent;
    158 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    159     /** The link flag. */
    160     char            linkflag;
    161 #endif
    162 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    163149    /** The VFS I/O stream (only for reading atm). */
    164150    RTVFSIOSTREAM   hVfsIos;
    165 #endif
    166151} RTTARFILEINTERNAL;
    167152/** Pointer to the internal data of a tar file.  */
     
    170155
    171156
    172 /******************************************************************************
    173  *   Defined Constants And Macros                                             *
    174  ******************************************************************************/
     157/*******************************************************************************
     158*   Defined Constants And Macros                                               *
     159*******************************************************************************/
    175160
    176161/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
     
    209194
    210195
    211 /******************************************************************************
    212  *   Internal Functions                                                       *
    213  ******************************************************************************/
    214 
    215 DECLINLINE(void) rtTarSizeToRec(PRTTARRECORD pRecord, uint64_t cbSize)
     196RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char *pszTarname, uint32_t fMode, bool fStream)
     197{
     198    AssertReturn(!fStream || !(fMode & RTFILE_O_WRITE), VERR_INVALID_PARAMETER);
     199
     200    /*
     201     * Create a tar instance.
     202     */
     203    PRTTARINTERNAL pThis = (PRTTARINTERNAL)RTMemAllocZ(sizeof(RTTARINTERNAL));
     204    if (!pThis)
     205        return VERR_NO_MEMORY;
     206
     207    pThis->u32Magic    = RTTAR_MAGIC;
     208    pThis->fOpenMode   = fMode;
     209    pThis->fStreamMode = fStream && (fMode & RTFILE_O_READ);
     210
     211    /*
     212     * Open the tar file.
     213     */
     214    pThis->hVfsFile         = NIL_RTVFSFILE;
     215    pThis->hVfsFss          = NIL_RTVFSFSSTREAM;
     216    pThis->fFssAtStart      = false;
     217    pThis->hVfsCur          = NIL_RTVFSIOSTREAM;
     218    pThis->pszVfsCurName    = NULL;
     219
     220    int rc;
     221    if (!(fMode & RTFILE_O_WRITE))
     222    {
     223        rc = RTVfsFileOpenNormal(pszTarname, fMode, &pThis->hVfsFile);
     224        if (RT_SUCCESS(rc))
     225        {
     226            RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(pThis->hVfsFile);
     227            rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, &pThis->hVfsFss);
     228            if (RT_SUCCESS(rc))
     229                pThis->fFssAtStart = true;
     230            else
     231            {
     232                RTVfsFileRelease(pThis->hVfsFile);
     233                pThis->hVfsFile = NIL_RTVFSFILE;
     234            }
     235            RTVfsIoStrmRelease(hVfsIos);
     236        }
     237    }
     238    else
     239        rc = RTFileOpen(&pThis->hTarFile, pszTarname, fMode);
     240    if (RT_SUCCESS(rc))
     241    {
     242        *phTar = pThis;
     243        return VINF_SUCCESS;
     244    }
     245
     246    RTMemFree(pThis);
     247    return rc;
     248}
     249
     250RTR3DECL(int) RTTarClose(RTTAR hTar)
     251{
     252    if (hTar == NIL_RTTAR)
     253        return VINF_SUCCESS;
     254
     255    PRTTARINTERNAL pInt = hTar;
     256    RTTAR_VALID_RETURN(pInt);
     257
     258    int rc = VINF_SUCCESS;
     259
     260    /* gtar gives a warning, but the documentation says EOF is indicated by a
     261     * zero block. Disabled for now. */
     262#if 0
     263    {
     264        /* Append the EOF record which is filled all by zeros */
     265        RTTARRECORD record;
     266        RT_ZERO(record);
     267        rc = RTFileWrite(pInt->hTarFile, &record, sizeof(record), NULL);
     268    }
     269#endif
     270
     271    if (pInt->hVfsFss != NIL_RTVFSFSSTREAM)
     272    {
     273        uint32_t cRefs = RTVfsFsStrmRelease(pInt->hVfsFss); Assert(cRefs != UINT32_MAX);
     274        pInt->hVfsFss  = NIL_RTVFSFSSTREAM;
     275    }
     276
     277    if (pInt->hVfsFile != NIL_RTVFSFILE)
     278    {
     279        uint32_t cRefs = RTVfsFileRelease(pInt->hVfsFile); Assert(cRefs != UINT32_MAX);
     280        pInt->hVfsFile = NIL_RTVFSFILE;
     281    }
     282
     283    if (pInt->hVfsCur != NIL_RTVFSIOSTREAM)
     284    {
     285        RTVfsIoStrmRelease(pInt->hVfsCur);
     286        pInt->hVfsCur = NIL_RTVFSIOSTREAM;
     287    }
     288
     289    if (pInt->pszVfsCurName)
     290    {
     291        RTStrFree(pInt->pszVfsCurName);
     292        pInt->pszVfsCurName = NULL;
     293    }
     294
     295    if (pInt->hTarFile != NIL_RTFILE)
     296    {
     297        rc = RTFileClose(pInt->hTarFile);
     298        pInt->hTarFile = NIL_RTFILE;
     299    }
     300
     301    pInt->u32Magic = RTTAR_MAGIC_DEAD;
     302
     303    RTMemFree(pInt);
     304
     305    return rc;
     306}
     307
     308
     309RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar)
     310{
     311    PRTTARINTERNAL pInt = hTar;
     312    RTTAR_VALID_RETURN(pInt);
     313
     314    if (!pInt->fStreamMode)
     315        return VERR_INVALID_STATE;
     316
     317    /*
     318     * Release the current object.
     319     */
     320    if (pInt->hVfsCur != NIL_RTVFSIOSTREAM)
     321    {
     322        RTVfsIoStrmRelease(pInt->hVfsCur);
     323        pInt->hVfsCur = NIL_RTVFSIOSTREAM;
     324    }
     325
     326    if (pInt->pszVfsCurName)
     327    {
     328        RTStrFree(pInt->pszVfsCurName);
     329        pInt->pszVfsCurName = NULL;
     330    }
     331
     332    /*
     333     * Find the next file.
     334     */
     335    for (;;)
     336    {
     337        char           *pszName;
     338        RTVFSOBJTYPE    enmType;
     339        RTVFSOBJ        hVfsObj;
     340        int rc = RTVfsFsStrmNext(hTar->hVfsFss, &pszName, &enmType, &hVfsObj);
     341        if (rc == VERR_EOF)
     342            return VERR_TAR_END_OF_FILE;
     343
     344        if (   enmType == RTVFSOBJTYPE_FILE
     345            || enmType == RTVFSOBJTYPE_IO_STREAM
     346            || enmType == RTVFSOBJTYPE_DIR)
     347        {
     348            pInt->pszVfsCurName = pszName;
     349            if (enmType == RTVFSOBJTYPE_DIR)
     350                rc = VINF_TAR_DIR_PATH;
     351            else
     352            {
     353                pInt->hVfsCur = RTVfsObjToIoStream(hVfsObj);
     354                Assert(pInt->hVfsCur != NIL_RTVFSIOSTREAM);
     355                rc = VINF_SUCCESS;
     356            }
     357            RTVfsObjRelease(hVfsObj);
     358            return rc;
     359        }
     360        RTStrFree(pszName);
     361        RTVfsObjRelease(hVfsObj);
     362    }
     363}
     364
     365
     366RTR3DECL(int) RTTarCurrentFile(RTTAR hTar, char **ppszFilename)
     367{
     368    /* Validate input. */
     369    AssertPtrNullReturn(ppszFilename, VERR_INVALID_POINTER);
     370
     371    PRTTARINTERNAL pInt = hTar;
     372    RTTAR_VALID_RETURN(pInt);
     373
     374    if (!pInt->fStreamMode)
     375        return VERR_INVALID_STATE;
     376
     377    if (!pInt->pszVfsCurName)
     378    {
     379        int rc = RTTarSeekNextFile(pInt);
     380        if (RT_FAILURE(rc))
     381            return rc;
     382    }
     383    Assert(pInt->pszVfsCurName);
     384
     385    if (ppszFilename)
     386    {
     387        *ppszFilename = RTStrDup(pInt->pszVfsCurName);
     388        if (!*ppszFilename)
     389            return VERR_NO_STR_MEMORY;
     390    }
     391
     392    return pInt->hVfsCur != NIL_RTVFSIOSTREAM ? VINF_SUCCESS : VINF_TAR_DIR_PATH;
     393}
     394
     395
     396/**
     397 * Creates a tar file handle for a read-only VFS stream object.
     398 *
     399 * @returns IPRT status code.
     400 * @param   pszName             The file name. Automatically freed on failure.
     401 * @param   hVfsIos             The VFS I/O stream we create the handle around.
     402 *                              The reference is NOT consumed.
     403 * @param   fOpen               The open flags.
     404 * @param   ppFile              Where to return the handle.
     405 */
     406static int rtTarFileCreateHandleForReadOnly(char *pszName, RTVFSIOSTREAM hVfsIos, uint32_t fOpen, PRTTARFILEINTERNAL *ppFile)
     407{
     408    int rc;
     409    PRTTARFILEINTERNAL pNewFile = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(*pNewFile));
     410    if (pNewFile)
     411    {
     412        RTFSOBJINFO ObjInfo;
     413        rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
     414        if (RT_SUCCESS(rc))
     415        {
     416            pNewFile->u32Magic      = RTTARFILE_MAGIC;
     417            pNewFile->pTar          = NULL;
     418            pNewFile->pszFilename   = pszName;
     419            pNewFile->offStart      = UINT64_MAX;
     420            pNewFile->cbSize        = ObjInfo.cbObject;
     421            pNewFile->cbSetSize     = 0;
     422            pNewFile->offCurrent    = 0;
     423            pNewFile->fOpenMode     = fOpen;
     424            pNewFile->hVfsIos       = hVfsIos;
     425
     426            uint32_t cRefs = RTVfsIoStrmRetain(hVfsIos); Assert(cRefs != UINT32_MAX); NOREF(cRefs);
     427
     428            *ppFile = pNewFile;
     429            return VINF_SUCCESS;
     430        }
     431
     432        RTMemFree(pNewFile);
     433    }
     434    else
     435        rc = VERR_NO_MEMORY;
     436    RTStrFree(pszName);
     437    return rc;
     438}
     439
     440
     441
     442RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **ppszFilename, uint32_t fOpen)
     443{
     444    /* Validate input. */
     445    AssertPtrReturn(phFile, VERR_INVALID_POINTER);
     446    AssertPtrNullReturn(ppszFilename, VERR_INVALID_POINTER);
     447    AssertReturn((fOpen & RTFILE_O_READ), VERR_INVALID_PARAMETER); /* Only valid in read mode. */
     448
     449    PRTTARINTERNAL pInt = hTar;
     450    RTTAR_VALID_RETURN(pInt);
     451
     452    if (!pInt->fStreamMode)
     453        return VERR_INVALID_STATE;
     454
     455    /*
     456     * Make sure there is a current file (first call w/o RTTarSeekNextFile call).
     457     */
     458    if (pInt->hVfsCur == NIL_RTVFSIOSTREAM)
     459    {
     460        if (pInt->pszVfsCurName)
     461            return -VINF_TAR_DIR_PATH;
     462
     463        int rc = RTTarSeekNextFile(pInt);
     464        if (RT_FAILURE(rc))
     465            return rc;
     466
     467        if (pInt->hVfsCur == NIL_RTVFSIOSTREAM)
     468            return -VINF_TAR_DIR_PATH;
     469    }
     470    Assert(pInt->pszVfsCurName);
     471
     472    /*
     473     * Return a copy of the filename if requested.
     474     */
     475    if (ppszFilename)
     476    {
     477        *ppszFilename = RTStrDup(pInt->pszVfsCurName);
     478        if (!*ppszFilename)
     479            return VERR_NO_STR_MEMORY;
     480    }
     481
     482    /*
     483     * Create a handle for it.
     484     */
     485    int rc = rtTarFileCreateHandleForReadOnly(RTStrDup(pInt->pszVfsCurName), pInt->hVfsCur, RTFILE_O_READ, phFile);
     486    if (RT_SUCCESS(rc))
     487    {
     488        /* Force a RTTarSeekNextFile call the next time around. */
     489        RTVfsIoStrmRelease(pInt->hVfsCur);
     490        pInt->hVfsCur = NIL_RTVFSIOSTREAM;
     491        RTStrFree(pInt->pszVfsCurName);
     492        pInt->pszVfsCurName = NULL;
     493    }
     494    else if (ppszFilename)
     495    {
     496        RTStrFree(*ppszFilename);
     497        *ppszFilename = NULL;
     498    }
     499
     500    return rc;
     501}
     502
     503
     504/* Only used for write handles. */
     505static PRTTARFILEINTERNAL rtTarFileCreateForWrite(PRTTARINTERNAL pInt, const char *pszFilename, uint32_t fOpen)
     506{
     507    PRTTARFILEINTERNAL pFileInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL));
     508    if (!pFileInt)
     509        return NULL;
     510
     511    pFileInt->u32Magic = RTTARFILE_MAGIC;
     512    pFileInt->pTar = pInt;
     513    pFileInt->fOpenMode = fOpen;
     514    pFileInt->pszFilename = RTStrDup(pszFilename);
     515    if (!pFileInt->pszFilename)
     516    {
     517        pFileInt->hVfsIos = NIL_RTVFSIOSTREAM;
     518        RTMemFree(pFileInt);
     519        return NULL;
     520    }
     521
     522    return pFileInt;
     523}
     524
     525
     526RTR3DECL(int) RTTarFileOpen(RTTAR hTar, PRTTARFILE phFile, const char *pszFilename, uint32_t fOpen)
     527{
     528    AssertReturn((fOpen & RTFILE_O_READ) || (fOpen & RTFILE_O_WRITE), VERR_INVALID_PARAMETER);
     529
     530    PRTTARINTERNAL pInt = hTar;
     531    RTTAR_VALID_RETURN(pInt);
     532
     533    if (!pInt->hTarFile)
     534        return VERR_INVALID_HANDLE;
     535
     536    if (pInt->fStreamMode)
     537        return VERR_INVALID_STATE;
     538
     539    if (fOpen & RTFILE_O_WRITE)
     540    {
     541        if (!(pInt->fOpenMode & RTFILE_O_WRITE))
     542            return VERR_WRITE_PROTECT;
     543        if (pInt->fFileOpenForWrite)
     544            return VERR_TOO_MANY_OPEN_FILES;
     545    }
     546
     547    int rc = VINF_SUCCESS;
     548    if (!(fOpen & RTFILE_O_WRITE))
     549    {
     550        /*
     551         * Rewind the stream if necessary.
     552         */
     553        if (!pInt->fFssAtStart)
     554        {
     555            if (pInt->hVfsFss != NIL_RTVFSFSSTREAM)
     556            {
     557                uint32_t cRefs = RTVfsFsStrmRelease(pInt->hVfsFss); Assert(cRefs != UINT32_MAX);
     558                pInt->hVfsFss  = NIL_RTVFSFSSTREAM;
     559            }
     560
     561            if (pInt->hVfsFile == NIL_RTVFSFILE)
     562            {
     563                rc = RTVfsFileFromRTFile(pInt->hTarFile, RTFILE_O_READ, true /*fLeaveOpen*/, &pInt->hVfsFile);
     564                if (RT_FAILURE(rc))
     565                    return rc;
     566            }
     567            Assert(pInt->hVfsCur == NIL_RTVFSIOSTREAM && pInt->pszVfsCurName == NULL);
     568
     569            RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(pInt->hVfsFile);
     570            rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, &pInt->hVfsFss);
     571            RTVfsIoStrmRelease(hVfsIos);
     572            if (RT_FAILURE(rc))
     573                return rc;
     574        }
     575
     576        /*
     577         * Search the file system stream.
     578         */
     579        pInt->fFssAtStart = false;
     580        for (;;)
     581        {
     582            char           *pszName;
     583            RTVFSOBJTYPE    enmType;
     584            RTVFSOBJ        hVfsObj;
     585            rc = RTVfsFsStrmNext(pInt->hVfsFss, &pszName, &enmType, &hVfsObj);
     586            if (rc == VERR_EOF)
     587                return VERR_FILE_NOT_FOUND;
     588            if (RT_FAILURE(rc))
     589                return rc;
     590
     591            if (!RTStrCmp(pszName, pszFilename))
     592            {
     593                if (enmType == RTVFSOBJTYPE_FILE || enmType == RTVFSOBJTYPE_IO_STREAM)
     594                    rc = rtTarFileCreateHandleForReadOnly(pszName, RTVfsObjToIoStream(hVfsObj), fOpen, phFile);
     595                else
     596                {
     597                    rc = VERR_UNEXPECTED_FS_OBJ_TYPE;
     598                    RTStrFree(pszName);
     599                }
     600                RTVfsObjRelease(hVfsObj);
     601                break;
     602            }
     603            RTStrFree(pszName);
     604            RTVfsObjRelease(hVfsObj);
     605        } /* Search loop. */
     606    }
     607    else
     608    {
     609        PRTTARFILEINTERNAL pFileInt = rtTarFileCreateForWrite(pInt, pszFilename, fOpen);
     610        if (!pFileInt)
     611            return VERR_NO_MEMORY;
     612
     613        pInt->fFileOpenForWrite = true;
     614
     615        /* If we are in write mode, we also in append mode. Add an dummy
     616         * header at the end of the current file. It will be filled by the
     617         * close operation. */
     618        rc = RTFileSeek(pFileInt->pTar->hTarFile, 0, RTFILE_SEEK_END, &pFileInt->offStart);
     619        if (RT_SUCCESS(rc))
     620        {
     621            RTTARRECORD record;
     622            RT_ZERO(record);
     623            rc = RTFileWrite(pFileInt->pTar->hTarFile, &record, sizeof(RTTARRECORD), NULL);
     624        }
     625
     626        if (RT_SUCCESS(rc))
     627            *phFile = (RTTARFILE)pFileInt;
     628        else
     629        {
     630            /* Cleanup on failure */
     631            if (pFileInt->pszFilename)
     632                RTStrFree(pFileInt->pszFilename);
     633            RTMemFree(pFileInt);
     634        }
     635    }
     636
     637    return rc;
     638}
     639
     640
     641/**
     642 * Calculates the TAR header checksums and detects if it's all zeros.
     643 *
     644 * @returns true if all zeros, false if not.
     645 * @param   pHdr                The header to checksum.
     646 * @param   pi32Unsigned        Where to store the checksum calculated using
     647 *                              unsigned chars.   This is the one POSIX
     648 *                              specifies.
     649 * @param   pi32Signed          Where to store the checksum calculated using
     650 *                              signed chars.
     651 *
     652 * @remarks The reason why we calculate the checksum as both signed and unsigned
     653 *          has to do with various the char C type being signed on some hosts
     654 *          and unsigned on others.
     655 *
     656 * @remarks Borrowed from tarvfs.cpp.
     657 */
     658static bool rtZipTarCalcChkSum(PCRTZIPTARHDR pHdr, int32_t *pi32Unsigned, int32_t *pi32Signed)
     659{
     660    int32_t i32Unsigned = 0;
     661    int32_t i32Signed   = 0;
     662
     663    /*
     664     * Sum up the entire header.
     665     */
     666    const char *pch    = (const char *)pHdr;
     667    const char *pchEnd = pch + sizeof(*pHdr);
     668    do
     669    {
     670        i32Unsigned += *(unsigned char *)pch;
     671        i32Signed   += *(signed   char *)pch;
     672    } while (++pch != pchEnd);
     673
     674    /*
     675     * Check if it's all zeros and replace the chksum field with spaces.
     676     */
     677    bool const fZeroHdr = i32Unsigned == 0;
     678
     679    pch    = pHdr->Common.chksum;
     680    pchEnd = pch + sizeof(pHdr->Common.chksum);
     681    do
     682    {
     683        i32Unsigned -= *(unsigned char *)pch;
     684        i32Signed   -= *(signed   char *)pch;
     685    } while (++pch != pchEnd);
     686
     687    i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Common.chksum);
     688    i32Signed   += (signed   char)' ' * sizeof(pHdr->Common.chksum);
     689
     690    *pi32Unsigned = i32Unsigned;
     691    if (pi32Signed)
     692        *pi32Signed = i32Signed;
     693    return fZeroHdr;
     694}
     695
     696
     697static void rtTarSizeToRec(PRTTARRECORD pRecord, uint64_t cbSize)
    216698{
    217699    /*
     
    246728}
    247729
    248 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    249 DECLINLINE(uint64_t) rtTarRecToSize(PRTTARRECORD pRecord)
    250 {
    251     int64_t cbSize = 0;
    252     if (pRecord->h.size[0] & 0x80)
    253     {
    254         size_t cchField = sizeof(pRecord->h.size);
    255         unsigned char const *puchField = (unsigned char const *)pRecord->h.size;
    256 
    257         /*
    258          * The first byte has the bit 7 set to indicate base-256, while bit 6
    259          * is the signed bit. Bits 5:0 are the most significant value bits.
    260          */
    261         cbSize = !(0x40 & *puchField) ? 0 : -1;
    262         cbSize = (cbSize << 6) | (*puchField & 0x3f);
    263         cchField--;
    264         puchField++;
    265 
    266         /*
    267          * The remaining bytes are used in full.
    268          */
    269         while (cchField-- > 0)
    270         {
    271             if (RT_UNLIKELY(   cbSize > INT64_MAX / 256
    272                             || cbSize < INT64_MIN / 256))
    273             {
    274                 cbSize = cbSize < 0 ? INT64_MIN : INT64_MAX;
    275                 break;
    276             }
    277             cbSize = (cbSize << 8) | *puchField++;
    278         }
    279     }
    280     else
    281         RTStrToInt64Full(pRecord->h.size, 8, &cbSize);
    282 
    283     if (cbSize < 0)
    284         cbSize = 0;
    285 
    286     return (uint64_t)cbSize;
    287 }
    288 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    289 
    290 /**
    291  * Calculates the TAR header checksums and detects if it's all zeros.
    292  *
    293  * @returns true if all zeros, false if not.
    294  * @param   pHdr                The header to checksum.
    295  * @param   pi32Unsigned        Where to store the checksum calculated using
    296  *                              unsigned chars.   This is the one POSIX
    297  *                              specifies.
    298  * @param   pi32Signed          Where to store the checksum calculated using
    299  *                              signed chars.
    300  *
    301  * @remarks The reason why we calculate the checksum as both signed and unsigned
    302  *          has to do with various the char C type being signed on some hosts
    303  *          and unsigned on others.
    304  *
    305  * @remarks Borrowed from tarvfs.cpp.
    306  */
    307 static bool rtZipTarCalcChkSum(PCRTZIPTARHDR pHdr, int32_t *pi32Unsigned, int32_t *pi32Signed)
    308 {
    309     int32_t i32Unsigned = 0;
    310     int32_t i32Signed   = 0;
    311 
    312     /*
    313      * Sum up the entire header.
    314      */
    315     const char *pch    = (const char *)pHdr;
    316     const char *pchEnd = pch + sizeof(*pHdr);
    317     do
    318     {
    319         i32Unsigned += *(unsigned char *)pch;
    320         i32Signed   += *(signed   char *)pch;
    321     } while (++pch != pchEnd);
    322 
    323     /*
    324      * Check if it's all zeros and replace the chksum field with spaces.
    325      */
    326     bool const fZeroHdr = i32Unsigned == 0;
    327 
    328     pch    = pHdr->Common.chksum;
    329     pchEnd = pch + sizeof(pHdr->Common.chksum);
    330     do
    331     {
    332         i32Unsigned -= *(unsigned char *)pch;
    333         i32Signed   -= *(signed   char *)pch;
    334     } while (++pch != pchEnd);
    335 
    336     i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Common.chksum);
    337     i32Signed   += (signed   char)' ' * sizeof(pHdr->Common.chksum);
    338 
    339     *pi32Unsigned = i32Unsigned;
    340     if (pi32Signed)
    341         *pi32Signed = i32Signed;
    342     return fZeroHdr;
    343 }
    344 
    345 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    346 DECLINLINE(int) rtTarReadHeaderRecord(RTFILE hFile, PRTTARRECORD pRecord)
    347 {
    348     int rc = RTFileRead(hFile, pRecord, sizeof(RTTARRECORD), NULL);
    349     /* Check for EOF. EOF is valid in this case, cause it indicates no more
    350      * data in the tar archive. */
    351     if (rc == VERR_EOF)
    352         return VERR_TAR_END_OF_FILE;
    353     /* Report any other errors */
    354     else if (RT_FAILURE(rc))
    355         return rc;
    356 
    357     /* Check for data integrity & an EOF record */
    358     int32_t iUnsignedChksum, iSignedChksum;
    359     if (rtZipTarCalcChkSum((PCRTZIPTARHDR)pRecord, &iUnsignedChksum, &iSignedChksum))
    360         return VERR_TAR_END_OF_FILE;
    361 
    362     /* Verify the checksum */
    363     uint32_t sum;
    364     rc = RTStrToUInt32Full(pRecord->h.chksum, 8, &sum);
    365     if (   RT_SUCCESS(rc)
    366         && (   sum == (uint32_t)iSignedChksum
    367             || sum == (uint32_t)iUnsignedChksum) )
    368     {
    369         /* Make sure the strings are zero terminated. */
    370         pRecord->h.name[sizeof(pRecord->h.name) - 1]         = 0;
    371         pRecord->h.linkname[sizeof(pRecord->h.linkname) - 1] = 0;
    372         pRecord->h.magic[sizeof(pRecord->h.magic) - 1]       = 0;
    373         pRecord->h.uname[sizeof(pRecord->h.uname) - 1]       = 0;
    374         pRecord->h.gname[sizeof(pRecord->h.gname) - 1]       = 0;
    375     }
    376     else
    377         rc = VERR_TAR_CHKSUM_MISMATCH;
    378 
    379     return rc;
    380 }
    381 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    382 
    383 DECLINLINE(int) rtTarCreateHeaderRecord(PRTTARRECORD pRecord, const char *pszSrcName, uint64_t cbSize,
    384                                         RTUID uid, RTGID gid, RTFMODE fmode, int64_t mtime)
     730
     731static int rtTarCreateHeaderRecord(PRTTARRECORD pRecord, const char *pszSrcName, uint64_t cbSize,
     732                                   RTUID uid, RTGID gid, RTFMODE fmode, int64_t mtime)
    385733{
    386734    /** @todo check for field overflows. */
     
    412760}
    413761
     762
    414763DECLINLINE(void *) rtTarMemTmpAlloc(size_t *pcbSize)
    415764{
     
    428777}
    429778
    430 DECLINLINE(int) rtTarAppendZeros(RTTARFILE hFile, uint64_t cbSize)
     779
     780static int rtTarAppendZeros(PRTTARFILEINTERNAL pFileInt, uint64_t cbSize)
    431781{
    432782    /* Allocate a temporary buffer for copying the tar content in blocks. */
     
    445795            break;
    446796        size_t cbToWrite = RT_MIN(cbSize - cbAllWritten, cbTmp);
    447         rc = RTTarFileWrite(hFile, pvTmp, cbToWrite, &cbWritten);
     797        rc = RTTarFileWriteAt(pFileInt, pFileInt->offCurrent, pvTmp, cbToWrite, &cbWritten);
    448798        if (RT_FAILURE(rc))
    449799            break;
     
    456806}
    457807
    458 /* Only used for write handles when RT_USE_TAR_VFS_FOR_ALL_READS is defined. */
    459 DECLINLINE(PRTTARFILEINTERNAL) rtCreateTarFileInternal(PRTTARINTERNAL pInt, const char *pszFilename, uint32_t fOpen)
    460 {
    461     PRTTARFILEINTERNAL pFileInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL));
    462     if (!pFileInt)
    463         return NULL;
    464 
    465     pFileInt->u32Magic = RTTARFILE_MAGIC;
    466     pFileInt->pTar = pInt;
    467     pFileInt->fOpenMode = fOpen;
    468     pFileInt->pszFilename = RTStrDup(pszFilename);
    469     if (!pFileInt->pszFilename)
    470     {
    471 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    472         pFileInt->hVfsIos = NIL_RTVFSIOSTREAM;
    473 #endif
    474         RTMemFree(pFileInt);
    475         return NULL;
    476     }
    477 
    478     return pFileInt;
    479 }
    480 
    481 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    482 
    483 /**
    484  * Creates a tar file handle for a read-only VFS stream object.
    485  *
    486  * @returns IPRT status code.
    487  * @param   pszName             The file name. Automatically freed on failure.
    488  * @param   hVfsIos             The VFS I/O stream we create the handle around.
    489  *                              The reference is NOT consumed.
    490  * @param   fOpen               The open flags.
    491  * @param   ppFile              Where to return the handle.
    492  */
    493 static int rtTarFileCreateHandleForReadOnly(char *pszName, RTVFSIOSTREAM hVfsIos, uint32_t fOpen, PRTTARFILEINTERNAL *ppFile)
    494 {
    495     int rc;
    496     PRTTARFILEINTERNAL pNewFile = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(*pNewFile));
    497     if (pNewFile)
    498     {
    499         RTFSOBJINFO ObjInfo;
    500         rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
    501         if (RT_SUCCESS(rc))
    502         {
    503             pNewFile->u32Magic      = RTTARFILE_MAGIC;
    504             pNewFile->pTar          = NULL;
    505             pNewFile->pszFilename   = pszName;
    506             pNewFile->offStart      = UINT64_MAX;
    507             pNewFile->cbSize        = ObjInfo.cbObject;
    508             pNewFile->cbSetSize     = 0;
    509             pNewFile->offCurrent    = 0;
    510             pNewFile->fOpenMode     = fOpen;
    511             pNewFile->hVfsIos       = hVfsIos;
    512 
    513             uint32_t cRefs = RTVfsIoStrmRetain(hVfsIos); Assert(cRefs != UINT32_MAX); NOREF(cRefs);
    514 
    515             *ppFile = pNewFile;
    516             return VINF_SUCCESS;
    517         }
    518 
    519         RTMemFree(pNewFile);
    520     }
    521     else
    522         rc = VERR_NO_MEMORY;
    523     RTStrFree(pszName);
    524     return rc;
    525 }
    526 
    527 #else  /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    528 
    529 DECLINLINE(PRTTARFILEINTERNAL) rtCopyTarFileInternal(PRTTARFILEINTERNAL pInt)
    530 {
    531     PRTTARFILEINTERNAL pNewInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL));
    532     if (!pNewInt)
    533         return NULL;
    534 
    535     memcpy(pNewInt, pInt, sizeof(RTTARFILEINTERNAL));
    536     pNewInt->pszFilename = RTStrDup(pInt->pszFilename);
    537     if (!pNewInt->pszFilename)
    538     {
    539         RTMemFree(pNewInt);
    540         return NULL;
    541     }
    542 
    543     return pNewInt;
    544 }
    545 
    546 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    547 
    548 DECLINLINE(void) rtDeleteTarFileInternal(PRTTARFILEINTERNAL pInt)
    549 {
    550     if (pInt)
    551     {
    552         if (pInt->pszFilename)
    553             RTStrFree(pInt->pszFilename);
    554 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    555         if (pInt->hVfsIos != NIL_RTVFSIOSTREAM)
    556         {
    557             RTVfsIoStrmRelease(pInt->hVfsIos);
    558             pInt->hVfsIos = NIL_RTVFSIOSTREAM;
    559         }
    560 #endif
    561 
    562         pInt->u32Magic = RTTARFILE_MAGIC_DEAD;
    563         RTMemFree(pInt);
    564     }
    565 }
    566 
    567 static int rtTarAppendFileFromFile(RTTAR hTar, const char *pszSrcName, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    568 {
    569     /* Open the source file */
    570     RTFILE hOldFile;
    571     int rc = RTFileOpen(&hOldFile, pszSrcName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
    572     if (RT_FAILURE(rc))
    573         return rc;
    574 
    575     RTTARFILE hFile = NIL_RTTARFILE;
    576     void *pvTmp = NULL;
    577     do
    578     {
    579         /* Get the size of the source file */
    580         uint64_t cbToCopy;
    581         rc = RTFileGetSize(hOldFile, &cbToCopy);
    582         if (RT_FAILURE(rc))
    583             break;
    584 
    585         rc = RTTarFileOpen(hTar, &hFile, RTPathFilename(pszSrcName), RTFILE_O_OPEN | RTFILE_O_WRITE);
    586         if (RT_FAILURE(rc))
    587             break;
    588 
    589         /* Get some info from the source file */
    590         RTFSOBJINFO info;
    591         RTUID uid = 0;
    592         RTGID gid = 0;
    593         RTFMODE fmode = 0600; /* Make some save default */
    594         int64_t mtime = 0;
    595 
    596         /* This isn't critical. Use the defaults if it fails. */
    597         rc = RTFileQueryInfo(hOldFile, &info, RTFSOBJATTRADD_UNIX);
    598         if (RT_SUCCESS(rc))
    599         {
    600             fmode = info.Attr.fMode & RTFS_UNIX_MASK;
    601             uid = info.Attr.u.Unix.uid;
    602             gid = info.Attr.u.Unix.gid;
    603             mtime = RTTimeSpecGetSeconds(&info.ModificationTime);
    604         }
    605 
    606         /* Set the mode from the other file */
    607         rc = RTTarFileSetMode(hFile, fmode);
    608         if (RT_FAILURE(rc))
    609             break;
    610 
    611         /* Set the modification time from the other file */
    612         RTTIMESPEC time;
    613         RTTimeSpecSetSeconds(&time, mtime);
    614         rc = RTTarFileSetTime(hFile, &time);
    615         if (RT_FAILURE(rc))
    616             break;
    617 
    618         /* Set the owner from the other file */
    619         rc = RTTarFileSetOwner(hFile, uid, gid);
    620         if (RT_FAILURE(rc))
    621             break;
    622 
    623         /* Allocate a temporary buffer for copying the tar content in blocks. */
    624         size_t cbTmp = 0;
    625         pvTmp = rtTarMemTmpAlloc(&cbTmp);
    626         if (!pvTmp)
    627         {
    628             rc = VERR_NO_MEMORY;
    629             break;
    630         }
    631 
    632         /* Copy the content from pszSrcName over to hFile. This is done block
    633          * wise in 512 byte steps. After this copying is finished hFile will be
    634          * on a 512 byte boundary, regardless if the file copied is 512 byte
    635          * size aligned. */
    636         uint64_t cbAllWritten = 0; /* Already copied */
    637         uint64_t cbRead       = 0; /* Actually read in the last step */
    638         for (;;)
    639         {
    640             if (pfnProgressCallback)
    641                 pfnProgressCallback((unsigned)(100.0 / cbOverallSize * cbOverallWritten), pvUser);
    642             if (cbAllWritten >= cbToCopy)
    643                 break;
    644 
    645             /* Read one block. Either its the buffer size or the rest of the
    646              * file. */
    647             cbRead = RT_MIN(cbToCopy - cbAllWritten, cbTmp);
    648             rc = RTFileRead(hOldFile, pvTmp, cbRead, NULL);
    649             if (RT_FAILURE(rc))
    650                 break;
    651 
    652             /* Write one block. */
    653             rc = RTTarFileWriteAt(hFile, cbAllWritten, pvTmp, cbRead, NULL);
    654             if (RT_FAILURE(rc))
    655                 break;
    656 
    657             /* Count how many bytes (of the original file) are written already */
    658             cbAllWritten += cbRead;
    659             cbOverallWritten += cbRead;
    660         }
    661     } while (0);
    662 
    663     /* Cleanup */
    664     if (pvTmp)
    665         RTMemTmpFree(pvTmp);
    666 
    667     if (hFile)
    668         RTTarFileClose(hFile);
    669 
    670     RTFileClose(hOldFile);
    671 
    672     return rc;
    673 }
    674 
    675 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    676 
    677 static int rtTarSkipData(RTFILE hFile, PRTTARRECORD pRecord)
    678 {
    679     int rc = VINF_SUCCESS;
    680     /* Seek over the data parts (512 bytes aligned) */
    681     int64_t offSeek = RT_ALIGN(rtTarRecToSize(pRecord), sizeof(RTTARRECORD));
    682     if (offSeek > 0)
    683         rc = RTFileSeek(hFile, offSeek, RTFILE_SEEK_CURRENT, NULL);
    684     return rc;
    685 }
    686 
    687 static int rtTarFindFile(RTFILE hFile, const char *pszFile, uint64_t *poff, uint64_t *pcbSize)
    688 {
    689     /* Assume we are on the file head. */
    690     int         rc      = VINF_SUCCESS;
    691     bool        fFound  = false;
    692     RTTARRECORD record;
    693     for (;;)
    694     {
    695         /* Read & verify a header record */
    696         rc = rtTarReadHeaderRecord(hFile, &record);
    697         /* Check for error or EOF. */
    698         if (RT_FAILURE(rc))
    699             break;
    700 
    701         /* We support normal files only */
    702         if (   record.h.linkflag == LF_OLDNORMAL
    703             || record.h.linkflag == LF_NORMAL)
    704         {
    705             if (!RTStrCmp(record.h.name, pszFile))
    706             {
    707                 /* Get the file size */
    708                 *pcbSize = rtTarRecToSize(&record);
    709                 /* Seek back, to position the file pointer at the start of the header. */
    710                 rc = RTFileSeek(hFile, -(int64_t)sizeof(RTTARRECORD), RTFILE_SEEK_CURRENT, poff);
    711                 fFound = true;
    712                 break;
    713             }
    714         }
    715         rc = rtTarSkipData(hFile, &record);
    716         if (RT_FAILURE(rc))
    717             break;
    718     }
    719 
    720     if (rc == VERR_TAR_END_OF_FILE)
    721         rc = VINF_SUCCESS;
    722 
    723     /* Something found? */
    724     if (    RT_SUCCESS(rc)
    725         &&  !fFound)
    726         rc = VERR_FILE_NOT_FOUND;
    727 
    728     return rc;
    729 }
    730 
    731 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    732 
    733 
    734 /******************************************************************************
    735  *   Public Functions                                                         *
    736  ******************************************************************************/
    737 
    738 RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char *pszTarname, uint32_t fMode, bool fStream)
    739 {
    740     AssertReturn(!fStream || !(fMode & RTFILE_O_WRITE), VERR_INVALID_PARAMETER);
    741 
    742     /*
    743      * Create a tar instance.
    744      */
    745     PRTTARINTERNAL pThis = (PRTTARINTERNAL)RTMemAllocZ(sizeof(RTTARINTERNAL));
    746     if (!pThis)
    747         return VERR_NO_MEMORY;
    748 
    749     pThis->u32Magic    = RTTAR_MAGIC;
    750     pThis->fOpenMode   = fMode;
    751     pThis->fStreamMode = fStream && (fMode & RTFILE_O_READ);
    752 
    753     /*
    754      * Open the tar file.
    755      */
    756     int rc;
    757 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    758     pThis->hVfsFile         = NIL_RTVFSFILE;
    759     pThis->hVfsFss          = NIL_RTVFSFSSTREAM;
    760     pThis->fFssAtStart      = false;
    761     pThis->hVfsCur          = NIL_RTVFSIOSTREAM;
    762     pThis->pszVfsCurName    = NULL;
    763 
    764     if (!(fMode & RTFILE_O_WRITE))
    765     {
    766         rc = RTVfsFileOpenNormal(pszTarname, fMode, &pThis->hVfsFile);
    767         if (RT_SUCCESS(rc))
    768         {
    769             RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(pThis->hVfsFile);
    770             rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, &pThis->hVfsFss);
    771             if (RT_SUCCESS(rc))
    772                 pThis->fFssAtStart = true;
    773             else
    774             {
    775                 RTVfsFileRelease(pThis->hVfsFile);
    776                 pThis->hVfsFile = NIL_RTVFSFILE;
    777             }
    778             RTVfsIoStrmRelease(hVfsIos);
    779         }
    780     }
    781     else
    782 #endif
    783         rc = RTFileOpen(&pThis->hTarFile, pszTarname, fMode);
    784     if (RT_SUCCESS(rc))
    785     {
    786         *phTar = pThis;
    787         return VINF_SUCCESS;
    788     }
    789 
    790     RTMemFree(pThis);
    791     return rc;
    792 }
    793 
    794 RTR3DECL(int) RTTarClose(RTTAR hTar)
    795 {
    796     if (hTar == NIL_RTTAR)
    797         return VINF_SUCCESS;
    798 
    799     PRTTARINTERNAL pInt = hTar;
    800     RTTAR_VALID_RETURN(pInt);
    801 
    802     int rc = VINF_SUCCESS;
    803 
    804     /* gtar gives a warning, but the documentation says EOF is indicated by a
    805      * zero block. Disabled for now. */
    806 #if 0
    807     {
    808         /* Append the EOF record which is filled all by zeros */
    809         RTTARRECORD record;
    810         RT_ZERO(record);
    811         rc = RTFileWrite(pInt->hTarFile, &record, sizeof(record), NULL);
    812     }
    813 #endif
    814 
    815 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    816     if (pInt->hVfsFss != NIL_RTVFSFSSTREAM)
    817     {
    818         uint32_t cRefs = RTVfsFsStrmRelease(pInt->hVfsFss); Assert(cRefs != UINT32_MAX);
    819         pInt->hVfsFss  = NIL_RTVFSFSSTREAM;
    820     }
    821 
    822     if (pInt->hVfsFile != NIL_RTVFSFILE)
    823     {
    824         uint32_t cRefs = RTVfsFileRelease(pInt->hVfsFile); Assert(cRefs != UINT32_MAX);
    825         pInt->hVfsFile = NIL_RTVFSFILE;
    826     }
    827 
    828     if (pInt->hVfsCur != NIL_RTVFSIOSTREAM)
    829     {
    830         RTVfsIoStrmRelease(pInt->hVfsCur);
    831         pInt->hVfsCur = NIL_RTVFSIOSTREAM;
    832     }
    833 
    834     if (pInt->pszVfsCurName)
    835     {
    836         RTStrFree(pInt->pszVfsCurName);
    837         pInt->pszVfsCurName = NULL;
    838     }
    839 #endif /* RT_USE_TAR_VFS_FOR_ALL_READS */
    840 
    841     if (pInt->hTarFile != NIL_RTFILE)
    842     {
    843         rc = RTFileClose(pInt->hTarFile);
    844         pInt->hTarFile = NIL_RTFILE;
    845     }
    846 
    847 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    848     /* Delete any remaining cached file headers. */
    849     if (pInt->pFileCache)
    850     {
    851         rtDeleteTarFileInternal(pInt->pFileCache);
    852         pInt->pFileCache = NULL;
    853     }
    854 #endif
    855 
    856     pInt->u32Magic = RTTAR_MAGIC_DEAD;
    857 
    858     RTMemFree(pInt);
    859 
    860     return rc;
    861 }
    862 
    863 RTR3DECL(int) RTTarFileOpen(RTTAR hTar, PRTTARFILE phFile, const char *pszFilename, uint32_t fOpen)
    864 {
    865     AssertReturn((fOpen & RTFILE_O_READ) || (fOpen & RTFILE_O_WRITE), VERR_INVALID_PARAMETER);
    866 
    867     PRTTARINTERNAL pInt = hTar;
    868     RTTAR_VALID_RETURN(pInt);
    869 
    870     if (!pInt->hTarFile)
    871         return VERR_INVALID_HANDLE;
    872 
    873     if (pInt->fStreamMode)
    874         return VERR_INVALID_STATE;
    875 
    876     if (fOpen & RTFILE_O_WRITE)
    877     {
    878         if (!(pInt->fOpenMode & RTFILE_O_WRITE))
    879             return VERR_WRITE_PROTECT;
    880         if (pInt->fFileOpenForWrite)
    881             return VERR_TOO_MANY_OPEN_FILES;
    882     }
    883 
    884     int rc = VINF_SUCCESS;
    885 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    886     if (!(fOpen & RTFILE_O_WRITE))
    887     {
    888         /*
    889          * Rewind the stream if necessary.
    890          */
    891         if (!pInt->fFssAtStart)
    892         {
    893             if (pInt->hVfsFss != NIL_RTVFSFSSTREAM)
    894             {
    895                 uint32_t cRefs = RTVfsFsStrmRelease(pInt->hVfsFss); Assert(cRefs != UINT32_MAX);
    896                 pInt->hVfsFss  = NIL_RTVFSFSSTREAM;
    897             }
    898 
    899             if (pInt->hVfsFile == NIL_RTVFSFILE)
    900             {
    901                 rc = RTVfsFileFromRTFile(pInt->hTarFile, RTFILE_O_READ, true /*fLeaveOpen*/, &pInt->hVfsFile);
    902                 if (RT_FAILURE(rc))
    903                     return rc;
    904             }
    905             Assert(pInt->hVfsCur == NIL_RTVFSIOSTREAM && pInt->pszVfsCurName == NULL);
    906 
    907             RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(pInt->hVfsFile);
    908             rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, &pInt->hVfsFss);
    909             RTVfsIoStrmRelease(hVfsIos);
    910             if (RT_FAILURE(rc))
    911                 return rc;
    912         }
    913 
    914         /*
    915          * Search the file system stream.
    916          */
    917         pInt->fFssAtStart = false;
    918         for (;;)
    919         {
    920             char           *pszName;
    921             RTVFSOBJTYPE    enmType;
    922             RTVFSOBJ        hVfsObj;
    923             rc = RTVfsFsStrmNext(pInt->hVfsFss, &pszName, &enmType, &hVfsObj);
    924             if (rc == VERR_EOF)
    925                 return VERR_FILE_NOT_FOUND;
    926             if (RT_FAILURE(rc))
    927                 return rc;
    928 
    929             if (!RTStrCmp(pszName, pszFilename))
    930             {
    931                 if (enmType == RTVFSOBJTYPE_FILE || enmType == RTVFSOBJTYPE_IO_STREAM)
    932                     rc = rtTarFileCreateHandleForReadOnly(pszName, RTVfsObjToIoStream(hVfsObj), fOpen, phFile);
    933                 else
    934                 {
    935                     rc = VERR_UNEXPECTED_FS_OBJ_TYPE;
    936                     RTStrFree(pszName);
    937                 }
    938                 RTVfsObjRelease(hVfsObj);
    939                 break;
    940             }
    941             RTStrFree(pszName);
    942             RTVfsObjRelease(hVfsObj);
    943         } /* Search loop. */
    944     }
    945     else
    946 #endif /* RT_USE_TAR_VFS_FOR_ALL_READS */
    947     {
    948         PRTTARFILEINTERNAL pFileInt = rtCreateTarFileInternal(pInt, pszFilename, fOpen);
    949         if (!pFileInt)
    950             return VERR_NO_MEMORY;
    951 
    952         do /* break loop */
    953         {
    954 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    955             if (pFileInt->fOpenMode & RTFILE_O_WRITE)
    956 #endif
    957             {
    958                 pInt->fFileOpenForWrite = true;
    959 
    960                 /* If we are in write mode, we also in append mode. Add an dummy
    961                  * header at the end of the current file. It will be filled by the
    962                  * close operation. */
    963                 rc = RTFileSeek(pFileInt->pTar->hTarFile, 0, RTFILE_SEEK_END, &pFileInt->offStart);
    964                 if (RT_FAILURE(rc))
    965                     break;
    966                 RTTARRECORD record;
    967                 RT_ZERO(record);
    968                 rc = RTFileWrite(pFileInt->pTar->hTarFile, &record, sizeof(RTTARRECORD), NULL);
    969                 if (RT_FAILURE(rc))
    970                     break;
    971             }
    972 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    973             else
    974             {
    975                 Assert(pFileInt->fOpenMode & RTFILE_O_READ); /* see first assertion */
    976 
    977                 /* We need to be on the start of the file */
    978                 rc = RTFileSeek(pFileInt->pTar->hTarFile, 0, RTFILE_SEEK_BEGIN, NULL);
    979                 if (RT_FAILURE(rc))
    980                     break;
    981 
    982                 /* Search for the file. */
    983                 rc = rtTarFindFile(pFileInt->pTar->hTarFile, pszFilename, &pFileInt->offStart, &pFileInt->cbSize);
    984                 if (RT_FAILURE(rc))
    985                     break;
    986             }
    987 #endif
    988         } while (0);
    989 
    990         /* Cleanup on failure */
    991         if (RT_FAILURE(rc))
    992         {
    993             if (pFileInt->pszFilename)
    994                 RTStrFree(pFileInt->pszFilename);
    995             RTMemFree(pFileInt);
    996         }
    997         else
    998             *phFile = (RTTARFILE)pFileInt;
    999     }
    1000 
    1001     return rc;
    1002 }
    1003808
    1004809RTR3DECL(int) RTTarFileClose(RTTARFILE hFile)
     
    1013818    int rc = VINF_SUCCESS;
    1014819
    1015     /* In read mode: */
    1016     if (pFileInt->fOpenMode & RTFILE_O_READ)
    1017     {
    1018 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    1019         /* In read mode, we want to make sure to stay at the aligned end of this
    1020          * file, so the next file could be read immediately. */
    1021         uint64_t offCur = RTFileTell(pFileInt->pTar->hTarFile);
    1022 
    1023         /* Check that the file pointer is somewhere within the last open file.
    1024          * If we are at the beginning (nothing read yet) nothing will be done.
    1025          * A user could open/close a file more than once, without reading
    1026          * something. */
    1027         if (   pFileInt->offStart + sizeof(RTTARRECORD) < offCur
    1028             && offCur < RT_ALIGN(pFileInt->offStart + sizeof(RTTARRECORD) + pFileInt->cbSize, sizeof(RTTARRECORD)))
    1029         {
    1030             /* Seek to the next file header. */
    1031             uint64_t offNext = RT_ALIGN(pFileInt->offStart + sizeof(RTTARRECORD) + pFileInt->cbSize, sizeof(RTTARRECORD));
    1032             rc = RTFileSeek(pFileInt->pTar->hTarFile, offNext - offCur, RTFILE_SEEK_CURRENT, NULL);
    1033         }
    1034 #endif
    1035     }
    1036     else if (pFileInt->fOpenMode & RTFILE_O_WRITE)
     820    /* In write mode: */
     821    if ((pFileInt->fOpenMode & (RTFILE_O_WRITE | RTFILE_O_READ)) == RTFILE_O_WRITE)
    1037822    {
    1038823        pFileInt->pTar->fFileOpenForWrite = false;
     
    1043828            if (pFileInt->cbSetSize > pFileInt->cbSize)
    1044829            {
    1045                 rc = rtTarAppendZeros(hFile, pFileInt->cbSetSize - pFileInt->cbSize);
     830                rc = rtTarAppendZeros(pFileInt, pFileInt->cbSetSize - pFileInt->cbSize);
    1046831                if (RT_FAILURE(rc))
    1047832                    break;
     
    1081866    }
    1082867
    1083     /* Now cleanup and delete the handle */
    1084     rtDeleteTarFileInternal(pFileInt);
     868    /*
     869     * Now cleanup and delete the handle.
     870     */
     871    if (pFileInt->pszFilename)
     872        RTStrFree(pFileInt->pszFilename);
     873    if (pFileInt->hVfsIos != NIL_RTVFSIOSTREAM)
     874    {
     875        RTVfsIoStrmRelease(pFileInt->hVfsIos);
     876        pFileInt->hVfsIos = NIL_RTVFSIOSTREAM;
     877    }
     878    pFileInt->u32Magic = RTTARFILE_MAGIC_DEAD;
     879    RTMemFree(pFileInt);
    1085880
    1086881    return rc;
    1087882}
    1088883
    1089 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    1090 RTR3DECL(int) RTTarFileSeek(RTTARFILE hFile, uint64_t offSeek, unsigned uMethod, uint64_t *poffActual)
     884
     885RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    1091886{
    1092887    PRTTARFILEINTERNAL pFileInt = hFile;
    1093888    RTTARFILE_VALID_RETURN(pFileInt);
    1094 
    1095     if (pFileInt->pTar->fStreamMode)
    1096         return VERR_INVALID_STATE;
    1097 
    1098     switch (uMethod)
    1099     {
    1100         case RTFILE_SEEK_BEGIN:
    1101         {
    1102             if (offSeek > pFileInt->cbSize)
    1103                 return VERR_SEEK_ON_DEVICE;
    1104             pFileInt->offCurrent = offSeek;
    1105             break;
    1106         }
    1107         case RTFILE_SEEK_CURRENT:
    1108         {
    1109             if (pFileInt->offCurrent + offSeek > pFileInt->cbSize)
    1110                 return VERR_SEEK_ON_DEVICE;
    1111             pFileInt->offCurrent += offSeek;
    1112             break;
    1113         }
    1114         case RTFILE_SEEK_END:
    1115         {
    1116             if ((int64_t)pFileInt->cbSize - (int64_t)offSeek < 0)
    1117                 return VERR_NEGATIVE_SEEK;
    1118             pFileInt->offCurrent = pFileInt->cbSize - offSeek;
    1119             break;
    1120         }
    1121         default: AssertFailedReturn(VERR_INVALID_PARAMETER);
    1122     }
    1123 
    1124     if (poffActual)
    1125         *poffActual = pFileInt->offCurrent;
    1126 
    1127     return VINF_SUCCESS;
    1128 }
    1129 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1130 
    1131 
    1132 #ifndef RT_USE_TAR_VFS_FOR_ALL_READS
    1133 RTR3DECL(uint64_t) RTTarFileTell(RTTARFILE hFile)
    1134 {
    1135     PRTTARFILEINTERNAL pFileInt = hFile;
    1136     RTTARFILE_VALID_RETURN_RC(pFileInt, UINT64_MAX);
    1137 
    1138     return pFileInt->offCurrent;
    1139 }
    1140 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1141 
    1142 RTR3DECL(int) RTTarFileRead(RTTARFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    1143 {
    1144     PRTTARFILEINTERNAL pFileInt = hFile;
    1145     RTTARFILE_VALID_RETURN(pFileInt);
    1146 
    1147     return RTTarFileReadAt(hFile, pFileInt->offCurrent, pvBuf, cbToRead, pcbRead);
    1148 }
    1149 
    1150 RTR3DECL(int) RTTarFileReadAt(RTTARFILE hFile, uint64_t off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    1151 {
    1152     PRTTARFILEINTERNAL pFileInt = hFile;
    1153     RTTARFILE_VALID_RETURN(pFileInt);
    1154 
    1155 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    1156889
    1157890    size_t cbTmpRead = 0;
     
    1167900    else if (pcbRead)
    1168901        *pcbRead = 0;
    1169 #else
    1170 
    1171     /* Check that we not read behind the end of file. If so return immediately. */
    1172     if (off > pFileInt->cbSize)
    1173     {
    1174         if (pcbRead)
    1175             *pcbRead = 0;
    1176         return VINF_SUCCESS; /* ??? VERR_EOF */
    1177     }
    1178 
    1179     size_t cbToCopy = RT_MIN(pFileInt->cbSize - off, cbToRead);
    1180     size_t cbTmpRead = 0;
    1181     int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->offStart + 512 + off, pvBuf, cbToCopy, &cbTmpRead);
    1182     pFileInt->offCurrent = off + cbTmpRead;
    1183     if (pcbRead)
    1184         *pcbRead = cbTmpRead;
    1185 
    1186 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1187 
    1188902    return rc;
    1189903}
    1190904
    1191 RTR3DECL(int) RTTarFileWrite(RTTARFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
    1192 {
    1193     PRTTARFILEINTERNAL pFileInt = hFile;
    1194     RTTARFILE_VALID_RETURN(pFileInt);
    1195 
    1196     /** @todo Optimize this, by checking the current pos */
    1197     return RTTarFileWriteAt(hFile, pFileInt->offCurrent, pvBuf, cbToWrite, pcbWritten);
    1198 }
    1199905
    1200906RTR3DECL(int) RTTarFileWriteAt(RTTARFILE hFile, uint64_t off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
     
    1216922}
    1217923
     924
    1218925RTR3DECL(int) RTTarFileGetSize(RTTARFILE hFile, uint64_t *pcbSize)
    1219926{
     
    1228935    return VINF_SUCCESS;
    1229936}
     937
    1230938
    1231939RTR3DECL(int) RTTarFileSetSize(RTTARFILE hFile, uint64_t cbSize)
     
    1244952}
    1245953
    1246 RTR3DECL(int) RTTarFileSetMode(RTTARFILE hFile, uint32_t fMode)
    1247 {
    1248     PRTTARFILEINTERNAL pFileInt = hFile;
    1249     RTTARFILE_VALID_RETURN(pFileInt);
    1250 
    1251     if ((pFileInt->fOpenMode & RTFILE_O_WRITE) != RTFILE_O_WRITE)
    1252         return VERR_WRITE_ERROR;
    1253 
    1254     /* Convert the mode to an string. */
    1255     char szMode[RT_SIZEOFMEMB(RTTARRECORD, h.mode)];
    1256     RTStrPrintf(szMode, sizeof(szMode), "%0.7o", fMode);
    1257 
    1258     /* Write it directly into the header */
    1259     return RTFileWriteAt(pFileInt->pTar->hTarFile,
    1260                          pFileInt->offStart + RT_OFFSETOF(RTTARRECORD, h.mode),
    1261                          szMode,
    1262                          RT_SIZEOFMEMB(RTTARRECORD, h.mode),
    1263                          NULL);
    1264 }
    1265 
    1266 RTR3DECL(int) RTTarFileSetTime(RTTARFILE hFile, PRTTIMESPEC pTime)
    1267 {
    1268     PRTTARFILEINTERNAL pFileInt = hFile;
    1269     RTTARFILE_VALID_RETURN(pFileInt);
    1270 
    1271     if ((pFileInt->fOpenMode & RTFILE_O_WRITE) != RTFILE_O_WRITE)
    1272         return VERR_WRITE_ERROR;
    1273 
    1274     /* Convert the time to an string. */
    1275     char szModTime[RT_SIZEOFMEMB(RTTARRECORD, h.mtime)];
    1276     RTStrPrintf(szModTime, sizeof(szModTime), "%0.11llo", RTTimeSpecGetSeconds(pTime));
    1277 
    1278     /* Write it directly into the header */
    1279     return RTFileWriteAt(pFileInt->pTar->hTarFile,
    1280                          pFileInt->offStart + RT_OFFSETOF(RTTARRECORD, h.mtime),
    1281                          szModTime,
    1282                          RT_SIZEOFMEMB(RTTARRECORD, h.mtime),
    1283                          NULL);
    1284 }
    1285 
    1286 RTR3DECL(int) RTTarFileSetOwner(RTTARFILE hFile, uint32_t uid, uint32_t gid)
    1287 {
    1288     PRTTARFILEINTERNAL pFileInt = hFile;
    1289     RTTARFILE_VALID_RETURN(pFileInt);
    1290 
    1291     if ((pFileInt->fOpenMode & RTFILE_O_WRITE) != RTFILE_O_WRITE)
    1292         return VERR_WRITE_ERROR;
    1293     AssertReturn(uid == (uint32_t)-1 || uid <= 07777777, VERR_OUT_OF_RANGE);
    1294     AssertReturn(gid == (uint32_t)-1 || gid <= 07777777, VERR_OUT_OF_RANGE);
    1295 
    1296     int rc = VINF_SUCCESS;
    1297 
    1298     if (uid != (uint32_t)-1)
    1299     {
    1300         /* Convert the uid to an string. */
    1301         char szUid[RT_SIZEOFMEMB(RTTARRECORD, h.uid)];
    1302         RTStrPrintf(szUid, sizeof(szUid), "%0.7o", uid);
    1303 
    1304         /* Write it directly into the header */
    1305         rc = RTFileWriteAt(pFileInt->pTar->hTarFile,
    1306                            pFileInt->offStart + RT_OFFSETOF(RTTARRECORD, h.uid),
    1307                            szUid,
    1308                            RT_SIZEOFMEMB(RTTARRECORD, h.uid),
    1309                            NULL);
    1310         if (RT_FAILURE(rc))
    1311             return rc;
    1312     }
    1313 
    1314     if (gid != (uint32_t)-1)
    1315     {
    1316         /* Convert the gid to an string. */
    1317         char szGid[RT_SIZEOFMEMB(RTTARRECORD, h.gid)];
    1318         RTStrPrintf(szGid, sizeof(szGid), "%0.7o", gid);
    1319 
    1320         /* Write it directly into the header */
    1321         rc = RTFileWriteAt(pFileInt->pTar->hTarFile,
    1322                            pFileInt->offStart + RT_OFFSETOF(RTTARRECORD, h.gid),
    1323                            szGid,
    1324                            RT_SIZEOFMEMB(RTTARRECORD, h.gid),
    1325                            NULL);
    1326         if (RT_FAILURE(rc))
    1327             return rc;
    1328     }
    1329 
    1330     return rc;
    1331 }
    1332 
    1333 /******************************************************************************
    1334  *   Convenience Functions                                                    *
    1335  ******************************************************************************/
    1336 
    1337 RTR3DECL(int) RTTarList(const char *pszTarFile, char ***ppapszFiles, size_t *pcFiles)
    1338 {
    1339     /* Validate input */
    1340     AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
    1341     AssertPtrReturn(ppapszFiles, VERR_INVALID_POINTER);
    1342     AssertPtrReturn(pcFiles, VERR_INVALID_POINTER);
    1343 
    1344     /* Open the tar file */
    1345     RTTAR hTar;
    1346     int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, false /*fStream*/);
    1347     if (RT_FAILURE(rc))
    1348         return rc;
    1349 
    1350 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    1351     /*
    1352      * Enumerate the VFS file system stream.
    1353      */
    1354     size_t cFiles          = 0;
    1355     size_t cFilesAllocated = 0;
    1356     char **papszFiles      = NULL;
    1357     for (;;)
    1358     {
    1359         char           *pszName;
    1360         RTVFSOBJTYPE    enmType;
    1361         RTVFSOBJ        hVfsObj;
    1362         rc = RTVfsFsStrmNext(hTar->hVfsFss, &pszName, &enmType, &hVfsObj);
    1363         if (rc == VERR_EOF)
    1364         {
    1365             RTTarClose(hTar);
    1366             *pcFiles = cFiles;
    1367             *ppapszFiles = papszFiles;
    1368             return VINF_SUCCESS;
    1369         }
    1370         if (RT_FAILURE(rc))
    1371             break;
    1372 
    1373         if (cFiles >= cFilesAllocated)
    1374         {
    1375             size_t cNew = !cFilesAllocated ? 64 : cFilesAllocated < _1M ? cFilesAllocated * 2 : cFilesAllocated + _1M;
    1376             void *pvNew = RTMemRealloc(papszFiles, cNew * sizeof(char *));
    1377             if (!pvNew)
    1378             {
    1379                 rc = VERR_NO_MEMORY;
    1380                 RTStrFree(pszName);
    1381                 RTVfsObjRelease(hVfsObj);
    1382                 break;
    1383             }
    1384             cFilesAllocated = cNew;
    1385             papszFiles = (char **)pvNew;
    1386         }
    1387 
    1388         papszFiles[cFiles++] = pszName;
    1389 
    1390         RTVfsObjRelease(hVfsObj);
    1391     } /* Search loop. */
    1392 
    1393     /*
    1394      * Failed, clean up and return.
    1395      */
    1396     if (papszFiles)
    1397     {
    1398         while (cFiles-- > 0)
    1399             RTStrFree(papszFiles[cFiles]);
    1400         RTMemFree(papszFiles);
    1401     }
    1402 
    1403 #else /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1404 
    1405     /* This is done by internal methods, cause we didn't have a RTTARDIR
    1406      * interface, yet. This should be fixed someday. */
    1407 
    1408     PRTTARINTERNAL pInt = hTar;
    1409     char **papszFiles = NULL;
    1410     size_t cFiles = 0;
    1411     do /* break loop */
    1412     {
    1413         /* Initialize the file name array with one slot */
    1414         size_t cFilesAlloc = 1;
    1415         papszFiles = (char **)RTMemAlloc(sizeof(char *));
    1416         if (!papszFiles)
    1417         {
    1418             rc = VERR_NO_MEMORY;
    1419             break;
    1420         }
    1421 
    1422         /* Iterate through the tar file record by record. Skip data records as we
    1423          * didn't need them. */
    1424         RTTARRECORD record;
    1425         for (;;)
    1426         {
    1427             /* Read & verify a header record */
    1428             rc = rtTarReadHeaderRecord(pInt->hTarFile, &record);
    1429             /* Check for error or EOF. */
    1430             if (RT_FAILURE(rc))
    1431                 break;
    1432             /* We support normal files only */
    1433             if (   record.h.linkflag == LF_OLDNORMAL
    1434                 || record.h.linkflag == LF_NORMAL)
    1435             {
    1436                 if (cFiles >= cFilesAlloc)
    1437                 {
    1438                     /* Double the array size, make sure the size doesn't wrap. */
    1439                     void  *pvNew = NULL;
    1440                     size_t cbNew = cFilesAlloc * sizeof(char *) * 2;
    1441                     if (cbNew / sizeof(char *) / 2 == cFilesAlloc)
    1442                         pvNew = RTMemRealloc(papszFiles, cbNew);
    1443                     if (!pvNew)
    1444                     {
    1445                         rc = VERR_NO_MEMORY;
    1446                         break;
    1447                     }
    1448                     papszFiles = (char **)pvNew;
    1449                     cFilesAlloc *= 2;
    1450                 }
    1451 
    1452                 /* Duplicate the name */
    1453                 papszFiles[cFiles] = RTStrDup(record.h.name);
    1454                 if (!papszFiles[cFiles])
    1455                 {
    1456                     rc = VERR_NO_MEMORY;
    1457                     break;
    1458                 }
    1459                 cFiles++;
    1460             }
    1461             rc = rtTarSkipData(pInt->hTarFile, &record);
    1462             if (RT_FAILURE(rc))
    1463                 break;
    1464         }
    1465     } while (0);
    1466 
    1467     if (rc == VERR_TAR_END_OF_FILE)
    1468         rc = VINF_SUCCESS;
    1469 
    1470     /* Return the file array on success, dispose of it on failure. */
    1471     if (RT_SUCCESS(rc))
    1472     {
    1473         *pcFiles = cFiles;
    1474         *ppapszFiles = papszFiles;
    1475     }
    1476     else
    1477     {
    1478         while (cFiles-- > 0)
    1479             RTStrFree(papszFiles[cFiles]);
    1480         RTMemFree(papszFiles);
    1481     }
    1482 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1483 
    1484     RTTarClose(hTar);
    1485 
    1486     return rc;
    1487 }
    1488 
    1489 RTR3DECL(int) RTTarCreate(const char *pszTarFile, const char * const *papszFiles, size_t cFiles, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    1490 {
    1491     /* Validate input */
    1492     AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
    1493     AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
    1494     AssertReturn(cFiles, VERR_INVALID_PARAMETER);
    1495     AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
    1496     AssertPtrNullReturn(pvUser, VERR_INVALID_POINTER);
    1497 
    1498     RTTAR hTar;
    1499     int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_CREATE | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE, false /*fStream*/);
    1500     if (RT_FAILURE(rc))
    1501         return rc;
    1502 
    1503     /* Get the overall size of all files to pack into the tar archive. Only
    1504        necessary if there is a progress callback. */
    1505     uint64_t cbOverallSize = 0;
    1506     if (pfnProgressCallback)
    1507         for (size_t i = 0; i < cFiles; ++i)
    1508         {
    1509             uint64_t cbSize;
    1510             rc = RTFileQuerySize(papszFiles[i], &cbSize);
    1511             if (RT_FAILURE(rc))
    1512                 break;
    1513             cbOverallSize += cbSize;
    1514         }
    1515     uint64_t cbOverallWritten = 0;
    1516     for (size_t i = 0; i < cFiles; ++i)
    1517     {
    1518         rc = rtTarAppendFileFromFile(hTar, papszFiles[i], cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
    1519         if (RT_FAILURE(rc))
    1520             break;
    1521     }
    1522 
    1523     /* Cleanup */
    1524     RTTarClose(hTar);
    1525 
    1526     return rc;
    1527 }
    1528 
    1529 /******************************************************************************
    1530  *   Streaming Functions                                                      *
    1531  ******************************************************************************/
    1532 
    1533 RTR3DECL(int) RTTarCurrentFile(RTTAR hTar, char **ppszFilename)
    1534 {
    1535     /* Validate input. */
    1536     AssertPtrNullReturn(ppszFilename, VERR_INVALID_POINTER);
    1537 
    1538     PRTTARINTERNAL pInt = hTar;
    1539     RTTAR_VALID_RETURN(pInt);
    1540 
    1541 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    1542     if (!pInt->fStreamMode)
    1543         return VERR_INVALID_STATE;
    1544 
    1545     if (!pInt->pszVfsCurName)
    1546     {
    1547         int rc = RTTarSeekNextFile(pInt);
    1548         if (RT_FAILURE(rc))
    1549             return rc;
    1550     }
    1551     Assert(pInt->pszVfsCurName);
    1552 
    1553     if (ppszFilename)
    1554     {
    1555         *ppszFilename = RTStrDup(pInt->pszVfsCurName);
    1556         if (!*ppszFilename)
    1557             return VERR_NO_STR_MEMORY;
    1558     }
    1559 
    1560     return pInt->hVfsCur != NIL_RTVFSIOSTREAM ? VINF_SUCCESS : VINF_TAR_DIR_PATH;
    1561 
    1562 #else  /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1563     /* Open and close the file on the current position. This makes sure the
    1564      * cache is filled in case we never read something before. On success it
    1565      * will return the current filename. */
    1566     RTTARFILE hFile;
    1567     int rc = RTTarFileOpenCurrentFile(hTar, &hFile, ppszFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
    1568     if (RT_SUCCESS(rc))
    1569         RTTarFileClose(hFile);
    1570 
    1571     return rc;
    1572 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1573 }
    1574 
    1575 RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar)
    1576 {
    1577     PRTTARINTERNAL pInt = hTar;
    1578     RTTAR_VALID_RETURN(pInt);
    1579 
    1580     if (!pInt->fStreamMode)
    1581         return VERR_INVALID_STATE;
    1582 
    1583 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    1584     /*
    1585      * Release the current object.
    1586      */
    1587     if (pInt->hVfsCur != NIL_RTVFSIOSTREAM)
    1588     {
    1589         RTVfsIoStrmRelease(pInt->hVfsCur);
    1590         pInt->hVfsCur = NIL_RTVFSIOSTREAM;
    1591     }
    1592 
    1593     if (pInt->pszVfsCurName)
    1594     {
    1595         RTStrFree(pInt->pszVfsCurName);
    1596         pInt->pszVfsCurName = NULL;
    1597     }
    1598 
    1599     /*
    1600      * Find the next file.
    1601      */
    1602     for (;;)
    1603     {
    1604         char           *pszName;
    1605         RTVFSOBJTYPE    enmType;
    1606         RTVFSOBJ        hVfsObj;
    1607         int rc = RTVfsFsStrmNext(hTar->hVfsFss, &pszName, &enmType, &hVfsObj);
    1608         if (rc == VERR_EOF)
    1609             return VERR_TAR_END_OF_FILE;
    1610 
    1611         if (   enmType == RTVFSOBJTYPE_FILE
    1612             || enmType == RTVFSOBJTYPE_IO_STREAM
    1613             || enmType == RTVFSOBJTYPE_DIR)
    1614         {
    1615             pInt->pszVfsCurName = pszName;
    1616             if (enmType == RTVFSOBJTYPE_DIR)
    1617                 rc = VINF_TAR_DIR_PATH;
    1618             else
    1619             {
    1620                 pInt->hVfsCur = RTVfsObjToIoStream(hVfsObj);
    1621                 Assert(pInt->hVfsCur != NIL_RTVFSIOSTREAM);
    1622                 rc = VINF_SUCCESS;
    1623             }
    1624             RTVfsObjRelease(hVfsObj);
    1625             return rc;
    1626         }
    1627         RTStrFree(pszName);
    1628         RTVfsObjRelease(hVfsObj);
    1629     }
    1630 
    1631 #else  /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1632     int rc = VINF_SUCCESS;
    1633 
    1634     /* If there is nothing in the cache, it means we never read something. Just
    1635      * ask for the current filename to fill the cache. */
    1636     if (!pInt->pFileCache)
    1637     {
    1638         rc = RTTarCurrentFile(hTar, NULL);
    1639         if (RT_FAILURE(rc))
    1640             return rc;
    1641     }
    1642 
    1643     /* Check that the file pointer is somewhere within the last open file.
    1644      * If not we are somehow busted. */
    1645     uint64_t offCur = RTFileTell(pInt->hTarFile);
    1646     if (!(   pInt->pFileCache->offStart <= offCur
    1647           && offCur <= pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize))
    1648         return VERR_INVALID_STATE;
    1649 
    1650     /* Seek to the next file header. */
    1651     uint64_t offNext = RT_ALIGN(pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize, sizeof(RTTARRECORD));
    1652     if (pInt->pFileCache->cbSize != 0)
    1653     {
    1654         rc = RTFileSeek(pInt->hTarFile, offNext - offCur, RTFILE_SEEK_CURRENT, NULL);
    1655         if (RT_FAILURE(rc))
    1656             return rc;
    1657     }
    1658     else
    1659     {
    1660         /* Else delete the last open file cache. Might be recreated below. */
    1661         rtDeleteTarFileInternal(pInt->pFileCache);
    1662         pInt->pFileCache = NULL;
    1663     }
    1664 
    1665     /* Again check the current filename to fill the cache with the new value. */
    1666     return RTTarCurrentFile(hTar, NULL);
    1667 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1668 }
    1669 
    1670 RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **ppszFilename, uint32_t fOpen)
    1671 {
    1672     /* Validate input. */
    1673     AssertPtrReturn(phFile, VERR_INVALID_POINTER);
    1674     AssertPtrNullReturn(ppszFilename, VERR_INVALID_POINTER);
    1675     AssertReturn((fOpen & RTFILE_O_READ), VERR_INVALID_PARAMETER); /* Only valid in read mode. */
    1676 
    1677     PRTTARINTERNAL pInt = hTar;
    1678     RTTAR_VALID_RETURN(pInt);
    1679 
    1680     if (!pInt->fStreamMode)
    1681         return VERR_INVALID_STATE;
    1682 
    1683 #ifdef RT_USE_TAR_VFS_FOR_ALL_READS
    1684     /*
    1685      * Make sure there is a current file (first call w/o RTTarSeekNextFile call).
    1686      */
    1687     if (pInt->hVfsCur == NIL_RTVFSIOSTREAM)
    1688     {
    1689         if (pInt->pszVfsCurName)
    1690             return -VINF_TAR_DIR_PATH;
    1691 
    1692         int rc = RTTarSeekNextFile(pInt);
    1693         if (RT_FAILURE(rc))
    1694             return rc;
    1695 
    1696         if (pInt->hVfsCur == NIL_RTVFSIOSTREAM)
    1697             return -VINF_TAR_DIR_PATH;
    1698     }
    1699     Assert(pInt->pszVfsCurName);
    1700 
    1701     /*
    1702      * Return a copy of the filename if requested.
    1703      */
    1704     if (ppszFilename)
    1705     {
    1706         *ppszFilename = RTStrDup(pInt->pszVfsCurName);
    1707         if (!*ppszFilename)
    1708             return VERR_NO_STR_MEMORY;
    1709     }
    1710 
    1711     /*
    1712      * Create a handle for it.
    1713      */
    1714     int rc = rtTarFileCreateHandleForReadOnly(RTStrDup(pInt->pszVfsCurName), pInt->hVfsCur, RTFILE_O_READ, phFile);
    1715     if (RT_FAILURE(rc) && ppszFilename)
    1716     {
    1717         RTStrFree(*ppszFilename);
    1718         *ppszFilename = NULL;
    1719     }
    1720 
    1721 #else  /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1722 
    1723     int rc = VINF_SUCCESS;
    1724 
    1725     /* Is there some cached entry? */
    1726     if (pInt->pFileCache)
    1727     {
    1728         if (pInt->pFileCache->offStart + sizeof(RTTARRECORD) < RTFileTell(pInt->hTarFile))
    1729         {
    1730             /* Else delete the last open file cache. Might be recreated below. */
    1731             rtDeleteTarFileInternal(pInt->pFileCache);
    1732             pInt->pFileCache = NULL;
    1733         }
    1734         else/* Are we still directly behind that header? */
    1735         {
    1736             /* Yes, so the streaming can start. Just return the cached file
    1737              * structure to the caller. */
    1738             *phFile = rtCopyTarFileInternal(pInt->pFileCache);
    1739             if (ppszFilename)
    1740                 *ppszFilename = RTStrDup(pInt->pFileCache->pszFilename);
    1741             if (pInt->pFileCache->linkflag == LF_DIR)
    1742                 return VINF_TAR_DIR_PATH;
    1743             return VINF_SUCCESS;
    1744         }
    1745 
    1746     }
    1747 
    1748     PRTTARFILEINTERNAL pFileInt = NULL;
    1749     do /* break loop */
    1750     {
    1751         /* Try to read a header entry from the current position. If we aren't
    1752          * on a header record, the header checksum will show and an error will
    1753          * be returned. */
    1754         RTTARRECORD record;
    1755         /* Read & verify a header record */
    1756         rc = rtTarReadHeaderRecord(pInt->hTarFile, &record);
    1757         /* Check for error or EOF. */
    1758         if (RT_FAILURE(rc))
    1759             break;
    1760 
    1761         /* We support normal files only */
    1762         if (   record.h.linkflag == LF_OLDNORMAL
    1763             || record.h.linkflag == LF_NORMAL
    1764             || record.h.linkflag == LF_DIR)
    1765         {
    1766             pFileInt = rtCreateTarFileInternal(pInt, record.h.name, fOpen);
    1767             if (!pFileInt)
    1768             {
    1769                 rc = VERR_NO_MEMORY;
    1770                 break;
    1771             }
    1772 
    1773             /* Get the file size */
    1774             pFileInt->cbSize = rtTarRecToSize(&record);
    1775             /* The start is -512 from here. */
    1776             pFileInt->offStart = RTFileTell(pInt->hTarFile) - sizeof(RTTARRECORD);
    1777             /* remember the type of a file */
    1778             pFileInt->linkflag = record.h.linkflag;
    1779 
    1780             /* Copy the new file structure to our cache. */
    1781             pInt->pFileCache = rtCopyTarFileInternal(pFileInt);
    1782             if (ppszFilename)
    1783                 *ppszFilename = RTStrDup(pFileInt->pszFilename);
    1784 
    1785             if (pFileInt->linkflag == LF_DIR)
    1786                 rc = VINF_TAR_DIR_PATH;
    1787         }
    1788     } while (0);
    1789 
    1790     if (RT_FAILURE(rc))
    1791     {
    1792         if (pFileInt)
    1793             rtDeleteTarFileInternal(pFileInt);
    1794     }
    1795     else
    1796         *phFile = pFileInt;
    1797 
    1798 #endif /* !RT_USE_TAR_VFS_FOR_ALL_READS */
    1799     return rc;
    1800 }
    1801 
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