VirtualBox

Changeset 84192 in vbox


Ignore:
Timestamp:
May 7, 2020 8:56:01 PM (5 years ago)
Author:
vboxsync
Message:

IPRT: Adding RTZIPTAR_C_UPDATE, RTZipTarFsStreamForFile and RTZipTarFsStreamTruncate. Also added some new VFS functions and changed the fReadOnly argument of RTVfsNewFsStream into RTFILE_O_ACCESS_MASK, so it is possible to specify read+write. Untested. bugref:9699

Location:
trunk
Files:
9 edited
1 copied

Legend:

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

    r84163 r84192  
    28082808# define RTVfsObjToFsStream                             RT_MANGLER(RTVfsObjToFsStream)
    28092809# define RTVfsObjToIoStream                             RT_MANGLER(RTVfsObjToIoStream)
     2810# define RTVfsObjToPrivate                              RT_MANGLER(RTVfsObjToPrivate)
    28102811# define RTVfsObjToSymlink                              RT_MANGLER(RTVfsObjToSymlink)
    28112812# define RTVfsObjToVfs                                  RT_MANGLER(RTVfsObjToVfs)
     
    28282829# define RTVfsSymlinkSetOwner                           RT_MANGLER(RTVfsSymlinkSetOwner)
    28292830# define RTVfsSymlinkSetTimes                           RT_MANGLER(RTVfsSymlinkSetTimes)
     2831# define RTVfsSymlinkToPrivate                          RT_MANGLER(RTVfsSymlinkToPrivate)
    28302832# define RTVfsUtilDummyPollOne                          RT_MANGLER(RTVfsUtilDummyPollOne)
    28312833# define RTVfsUtilPumpIoStreams                         RT_MANGLER(RTVfsUtilPumpIoStreams)
  • trunk/include/iprt/vfslowlevel.h

    r82968 r84192  
    311311                            PRTVFSOBJ phVfsObj, void **ppvInstance);
    312312
     313
     314/**
     315 * Gets the private data of a base object.
     316 *
     317 * @returns Pointer to the private data.  NULL if the handle is invalid in some
     318 *          way.
     319 * @param   hVfsObj             The I/O base object handle.
     320 * @param   pObjOps             The base object operations.  This servers as a
     321 *                              sort of password.
     322 */
     323RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps);
    313324
    314325/**
     
    493504 *                              object.  The reference is consumed.  NIL and
    494505 *                              special lock handles are fine.
    495  * @param   fReadOnly           Set if read-only, clear if write-only.
     506 * @param   fAccess             RTFILE_O_READ and/or RTFILE_O_WRITE.
    496507 * @param   phVfsFss            Where to return the new handle.
    497508 * @param   ppvInstance         Where to return the pointer to the instance data
    498509 *                              (size is @a cbInstance).
    499510 */
    500 RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,
     511RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess,
    501512                             PRTVFSFSSTREAM phVfsFss, void **ppvInstance);
    502513
     
    828839                            PRTVFSSYMLINK phVfsSym, void **ppvInstance);
    829840
     841
     842/**
     843 * Gets the private data of a symbolic link.
     844 *
     845 * @returns Pointer to the private data.  NULL if the handle is invalid in some
     846 *          way.
     847 * @param   hVfsIos             The I/O stream handle.
     848 * @param   pSymlinkOps         The symlink operations.  This servers as a sort
     849 *                              of password.
     850 */
     851RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps);
    830852
    831853/**
  • trunk/include/iprt/zip.h

    r82968 r84192  
    324324 *       twice. */
    325325#define RTZIPTAR_C_SPARSE           RT_BIT_32(0)
     326/** Set if opening for updating. */
     327#define RTZIPTAR_C_UPDATE           RT_BIT_32(1)
    326328/** Valid bits. */
    327 #define RTZIPTAR_C_VALID_MASK       UINT32_C(0x00000001)
     329#define RTZIPTAR_C_VALID_MASK       UINT32_C(0x00000003)
    328330/** @} */
    329331
     
    392394RTDECL(int) RTZipTarFsStreamSetMTime(RTVFSFSSTREAM hVfsFss, PCRTTIMESPEC pModificationTime);
    393395
     396/**
     397 * Truncates a TAR creator stream in update mode.
     398 *
     399 * Use RTVfsFsStrmNext to examine the TAR stream and locate the cut-off point.
     400 *
     401 * After performing this call, the stream will be in write mode and
     402 * RTVfsFsStrmNext will stop working (VERR_WRONG_ORDER).   The RTVfsFsStrmAdd()
     403 * and RTVfsFsStrmPushFile() can be used to add new object to the TAR file,
     404 * starting at the trunction point.  RTVfsFsStrmEnd() is used to finish the TAR
     405 * file (this performs the actual file trunction).
     406 *
     407 * @returns IPRT status code.
     408 * @param   hVfsFss             The handle to a TAR creator in update mode.
     409 * @param   hVfsObj             Object returned by RTVfsFsStrmNext that the
     410 *                              trunction is relative to.  This doesn't have to
     411 *                              be the current stream object, it can be an
     412 *                              earlier one too.
     413 * @param   fAfter              If set, @a hVfsObj will remain in the update TAR
     414 *                              file.  If clear, @a hVfsObj will not be
     415 *                              included.
     416 */
     417RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter);
    394418
    395419/**
  • trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp

    r82968 r84192  
    813813    *ppvInstance = pThis->pvThis;
    814814    return VINF_SUCCESS;
     815}
     816
     817
     818RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps)
     819{
     820    RTVFSOBJINTERNAL *pThis = hVfsObj;
     821    AssertPtrReturn(pThis, NULL);
     822    AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NULL);
     823    if (pThis->pOps != pObjOps)
     824        return NULL;
     825    return pThis->pvThis;
    815826}
    816827
     
    22822293
    22832294
    2284 RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,
     2295RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess,
    22852296                             PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
    22862297{
     
    22932304    Assert(!pFsStreamOps->fReserved);
    22942305    RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
    2295     if (fReadOnly)
     2306    Assert((fAccess & (RTFILE_O_READ | RTFILE_O_WRITE)) == fAccess);
     2307    Assert(fAccess);
     2308    if (fAccess & RTFILE_O_READ)
    22962309        AssertPtr(pFsStreamOps->pfnNext);
    2297     else
     2310    if (fAccess & RTFILE_O_WRITE)
    22982311    {
    22992312        AssertPtr(pFsStreamOps->pfnAdd);
     
    23242337
    23252338    pThis->uMagic = RTVFSFSSTREAM_MAGIC;
    2326     pThis->fFlags = fReadOnly
    2327                   ? RTFILE_O_READ  | RTFILE_O_OPEN   | RTFILE_O_DENY_NONE
    2328                   : RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
    23292339    pThis->pOps   = pFsStreamOps;
     2340    pThis->fFlags = fAccess;
     2341    if (fAccess == RTFILE_O_READ)
     2342        pThis->fFlags |= RTFILE_O_OPEN   | RTFILE_O_DENY_NONE;
     2343    else if (fAccess == RTFILE_O_WRITE)
     2344        pThis->fFlags |= RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
     2345    else
     2346        pThis->fFlags |= RTFILE_O_OPEN   | RTFILE_O_DENY_ALL;
    23302347
    23312348    *phVfsFss     = pThis;
     
    32773294
    32783295
     3296RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps)
     3297{
     3298    RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
     3299    AssertPtrReturn(pThis, NULL);
     3300    AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, NULL);
     3301    if (pThis->pOps != pSymlinkOps)
     3302        return NULL;
     3303    return pThis->Base.pvThis;
     3304}
     3305
     3306
    32793307RTDECL(uint32_t)    RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
    32803308{
  • trunk/src/VBox/Runtime/common/vfs/vfsfss2dir.cpp

    r82968 r84192  
    311311    PRTVFSFSSWRITE2DIR      pThis;
    312312    RTVFSFSSTREAM           hVfsFss;
    313     int rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, false /*fReadOnly*/,
     313    int rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE,
    314314                              &hVfsFss, (void **)&pThis);
    315315    if (RT_SUCCESS(rc))
     
    370370                RTVFSFSSTREAM           hVfsFss;
    371371                rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, RT_UOFFSETOF_DYN(RTVFSFSSWRITE2DIR, szBaseDir[cbBaseDir]),
    372                                       NIL_RTVFS, NIL_RTVFSLOCK, false /*fReadOnly*/, &hVfsFss, (void **)&pThis);
     372                                      NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE, &hVfsFss, (void **)&pThis);
    373373                if (RT_SUCCESS(rc))
    374374                {
  • trunk/src/VBox/Runtime/common/zip/pkzipvfs.cpp

    r82968 r84192  
    12641264    PRTZIPPKZIPFSSTREAM pThis;
    12651265    RTVFSFSSTREAM     hVfsFss;
    1266     int rc = RTVfsNewFsStream(&rtZipPkzipFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,
     1266    int rc = RTVfsNewFsStream(&rtZipPkzipFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ,
    12671267                              &hVfsFss, (void **)&pThis);
    12681268    if (RT_SUCCESS(rc))
  • trunk/src/VBox/Runtime/common/zip/tarvfs.cpp

    r82968 r84192  
    4343
    4444#include "tar.h"
    45 
    46 
    47 /*********************************************************************************************************************************
    48 *   Structures and Typedefs                                                                                                      *
    49 *********************************************************************************************************************************/
    50 /**
    51  * TAR reader state machine states.
    52  */
    53 typedef enum RTZIPTARREADERSTATE
    54 {
    55     /** Invalid state. */
    56     RTZIPTARREADERSTATE_INVALID = 0,
    57     /** Expecting the next file/dir/whatever entry. */
    58     RTZIPTARREADERSTATE_FIRST,
    59     /** Expecting more zero headers or the end of the stream. */
    60     RTZIPTARREADERSTATE_ZERO,
    61     /** Expecting a GNU long name. */
    62     RTZIPTARREADERSTATE_GNU_LONGNAME,
    63     /** Expecting a GNU long link. */
    64     RTZIPTARREADERSTATE_GNU_LONGLINK,
    65     /** Expecting a normal header or another GNU specific one. */
    66     RTZIPTARREADERSTATE_GNU_NEXT,
    67     /** End of valid states (not included). */
    68     RTZIPTARREADERSTATE_END
    69 } RTZIPTARREADERSTATE;
    70 
    71 /**
    72  * Tar reader instance data.
    73  */
    74 typedef struct RTZIPTARREADER
    75 {
    76     /** Zero header counter. */
    77     uint32_t                cZeroHdrs;
    78     /** The state machine state. */
    79     RTZIPTARREADERSTATE     enmState;
    80     /** The type of the previous TAR header.
    81      * @remarks Same a enmType for the first header in the TAR stream. */
    82     RTZIPTARTYPE            enmPrevType;
    83     /** The type of the current TAR header. */
    84     RTZIPTARTYPE            enmType;
    85     /** The current header. */
    86     RTZIPTARHDR             Hdr;
    87     /** The expected long name/link length (GNU). */
    88     uint32_t                cbGnuLongExpect;
    89     /** The current long name/link length (GNU). */
    90     uint32_t                offGnuLongCur;
    91     /** The name of the current object.
    92      * This is for handling GNU and PAX long names. */
    93     char                    szName[RTPATH_MAX];
    94     /** The current link target if symlink or hardlink. */
    95     char                    szTarget[RTPATH_MAX];
    96 } RTZIPTARREADER;
    97 /** Pointer to the TAR reader instance data. */
    98 typedef RTZIPTARREADER *PRTZIPTARREADER;
    99 
    100 /**
    101  * Tar directory, character device, block device, fifo socket or symbolic link.
    102  */
    103 typedef struct RTZIPTARBASEOBJ
    104 {
    105     /** The stream offset of the (first) header.  */
    106     RTFOFF                  offHdr;
    107     /** Pointer to the reader instance data (resides in the filesystem
    108      * stream).
    109      * @todo Fix this so it won't go stale... Back ref from this obj to fss? */
    110     PRTZIPTARREADER         pTarReader;
    111     /** The object info with unix attributes. */
    112     RTFSOBJINFO             ObjInfo;
    113 } RTZIPTARBASEOBJ;
    114 /** Pointer to a TAR filesystem stream base object. */
    115 typedef RTZIPTARBASEOBJ *PRTZIPTARBASEOBJ;
    116 
    117 
    118 /**
    119  * Tar file represented as a VFS I/O stream.
    120  */
    121 typedef struct RTZIPTARIOSTREAM
    122 {
    123     /** The basic TAR object data. */
    124     RTZIPTARBASEOBJ         BaseObj;
    125     /** The number of bytes in the file. */
    126     RTFOFF                  cbFile;
    127     /** The current file position. */
    128     RTFOFF                  offFile;
    129     /** The start position in the hVfsIos (for seekable hVfsIos). */
    130     RTFOFF                  offStart;
    131     /** The number of padding bytes following the file. */
    132     uint32_t                cbPadding;
    133     /** Set if we've reached the end of the file. */
    134     bool                    fEndOfStream;
    135     /** The input I/O stream. */
    136     RTVFSIOSTREAM           hVfsIos;
    137 } RTZIPTARIOSTREAM;
    138 /** Pointer to a the private data of a TAR file I/O stream. */
    139 typedef RTZIPTARIOSTREAM *PRTZIPTARIOSTREAM;
    140 
    141 
    142 /**
    143  * Tar filesystem stream private data.
    144  */
    145 typedef struct RTZIPTARFSSTREAM
    146 {
    147     /** The input I/O stream. */
    148     RTVFSIOSTREAM           hVfsIos;
    149 
    150     /** The current object (referenced). */
    151     RTVFSOBJ                hVfsCurObj;
    152     /** Pointer to the private data if hVfsCurObj is representing a file. */
    153     PRTZIPTARIOSTREAM       pCurIosData;
    154 
    155     /** The start offset. */
    156     RTFOFF                  offStart;
    157     /** The offset of the next header. */
    158     RTFOFF                  offNextHdr;
    159 
    160     /** Set if we've reached the end of the stream. */
    161     bool                    fEndOfStream;
    162     /** Set if we've encountered a fatal error. */
    163     int                     rcFatal;
    164 
    165     /** The TAR reader instance data. */
    166     RTZIPTARREADER          TarReader;
    167 } RTZIPTARFSSTREAM;
    168 /** Pointer to a the private data of a TAR filesystem stream. */
    169 typedef RTZIPTARFSSTREAM *PRTZIPTARFSSTREAM;
    170 
     45#include "tarvfsreader.h"
    17146
    17247
     
    12361111 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
    12371112 */
    1238 static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
     1113DECLHIDDEN(DECLCALLBACK(int)) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
    12391114{
    12401115    PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
     
    12851160    if (offHdr > pThis->offNextHdr)
    12861161        return pThis->rcFatal = VERR_INTERNAL_ERROR_3;
     1162    Assert(pThis->offNextHdr == offHdr);
     1163    pThis->offCurHdr = offHdr;
    12871164
    12881165    /*
     
    13561233                return pThis->rcFatal = rc;
    13571234
    1358             pIosData->BaseObj.offHdr    = offHdr;
    1359             pIosData->BaseObj.pTarReader= &pThis->TarReader;
    1360             pIosData->BaseObj.ObjInfo   = Info;
    1361             pIosData->cbFile            = Info.cbObject;
    1362             pIosData->offFile           = 0;
    1363             pIosData->offStart          = RTVfsIoStrmTell(pThis->hVfsIos);
    1364             pIosData->cbPadding         = (uint32_t)(Info.cbAllocated - Info.cbObject);
    1365             pIosData->fEndOfStream      = false;
    1366             pIosData->hVfsIos           = pThis->hVfsIos;
     1235            pIosData->BaseObj.offHdr     = offHdr;
     1236            pIosData->BaseObj.offNextHdr = pThis->offNextHdr;
     1237            pIosData->BaseObj.pTarReader = &pThis->TarReader;
     1238            pIosData->BaseObj.ObjInfo    = Info;
     1239            pIosData->cbFile             = Info.cbObject;
     1240            pIosData->offFile            = 0;
     1241            pIosData->offStart           = RTVfsIoStrmTell(pThis->hVfsIos);
     1242            pIosData->cbPadding          = (uint32_t)(Info.cbAllocated - Info.cbObject);
     1243            pIosData->fEndOfStream       = false;
     1244            pIosData->hVfsIos            = pThis->hVfsIos;
    13671245            RTVfsIoStrmRetain(pThis->hVfsIos);
    13681246
     
    13941272                return pThis->rcFatal = rc;
    13951273
    1396             pBaseObjData->offHdr    = offHdr;
    1397             pBaseObjData->pTarReader= &pThis->TarReader;
    1398             pBaseObjData->ObjInfo   = Info;
     1274            pBaseObjData->offHdr     = offHdr;
     1275            pBaseObjData->offNextHdr = pThis->offNextHdr;
     1276            pBaseObjData->pTarReader = &pThis->TarReader;
     1277            pBaseObjData->ObjInfo    = Info;
    13991278
    14001279            enmType = RTVFSOBJTYPE_SYMLINK;
     
    14241303                return pThis->rcFatal = rc;
    14251304
    1426             pBaseObjData->offHdr    = offHdr;
    1427             pBaseObjData->pTarReader= &pThis->TarReader;
    1428             pBaseObjData->ObjInfo   = Info;
     1305            pBaseObjData->offHdr     = offHdr;
     1306            pBaseObjData->offNextHdr = pThis->offNextHdr;
     1307            pBaseObjData->pTarReader = &pThis->TarReader;
     1308            pBaseObjData->ObjInfo    = Info;
    14291309
    14301310            enmType = RTVFSOBJTYPE_BASE;
     
    14851365
    14861366
     1367/**
     1368 * Internal function use both by RTZipTarFsStreamFromIoStream() and by
     1369 * RTZipTarFsStreamForFile() in updating mode.
     1370 */
     1371DECLHIDDEN(void) rtZipTarReaderInit(PRTZIPTARFSSTREAM pThis, RTVFSIOSTREAM hVfsIos, uint64_t offStart)
     1372{
     1373    pThis->hVfsIos              = hVfsIos;
     1374    pThis->hVfsCurObj           = NIL_RTVFSOBJ;
     1375    pThis->pCurIosData          = NULL;
     1376    pThis->offStart             = offStart;
     1377    pThis->offNextHdr           = offStart;
     1378    pThis->fEndOfStream         = false;
     1379    pThis->rcFatal              = VINF_SUCCESS;
     1380    pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID;
     1381    pThis->TarReader.enmType    = RTZIPTARTYPE_INVALID;
     1382    pThis->TarReader.enmState   = RTZIPTARREADERSTATE_FIRST;
     1383
     1384    /* Don't check if it's a TAR stream here, do that in the
     1385       rtZipTarFss_Next. */
     1386}
     1387
     1388
    14871389RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
    14881390{
     
    15061408    PRTZIPTARFSSTREAM pThis;
    15071409    RTVFSFSSTREAM     hVfsFss;
    1508     int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,
     1410    int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ,
    15091411                              &hVfsFss, (void **)&pThis);
    15101412    if (RT_SUCCESS(rc))
    15111413    {
    1512         pThis->hVfsIos              = hVfsIosIn;
    1513         pThis->hVfsCurObj           = NIL_RTVFSOBJ;
    1514         pThis->pCurIosData          = NULL;
    1515         pThis->offStart             = offStart;
    1516         pThis->offNextHdr           = offStart;
    1517         pThis->fEndOfStream         = false;
    1518         pThis->rcFatal              = VINF_SUCCESS;
    1519         pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID;
    1520         pThis->TarReader.enmType    = RTZIPTARTYPE_INVALID;
    1521         pThis->TarReader.enmState   = RTZIPTARREADERSTATE_FIRST;
    1522 
    1523         /* Don't check if it's a TAR stream here, do that in the
    1524            rtZipTarFss_Next. */
    1525 
     1414        rtZipTarReaderInit(pThis, hVfsIosIn, fFlags);
    15261415        *phVfsFss = hVfsFss;
    15271416        return VINF_SUCCESS;
     
    15321421}
    15331422
     1423
     1424/**
     1425 * Used by RTZipTarFsStreamTruncate to resolve @a hVfsObj.
     1426 */
     1427DECLHIDDEN(PRTZIPTARBASEOBJ) rtZipTarFsStreamBaseObjToPrivate(PRTZIPTARFSSTREAM pThis, RTVFSOBJ hVfsObj)
     1428{
     1429    PRTZIPTARBASEOBJ pThisObj;
     1430    RTVFSOBJTYPE enmType = RTVfsObjGetType(hVfsObj);
     1431    switch (enmType)
     1432    {
     1433        case RTVFSOBJTYPE_IO_STREAM:
     1434        {
     1435            RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
     1436            AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, NULL);
     1437            PRTZIPTARIOSTREAM pThisStrm = (PRTZIPTARIOSTREAM)RTVfsIoStreamToPrivate(hVfsIos, &g_rtZipTarFssIosOps);
     1438            RTVfsIoStrmRelease(hVfsIos);
     1439            pThisObj = &pThisStrm->BaseObj;
     1440            break;
     1441        }
     1442
     1443        case RTVFSOBJTYPE_SYMLINK:
     1444        {
     1445            RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
     1446            AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, NULL);
     1447            pThisObj = (PRTZIPTARBASEOBJ)RTVfsSymlinkToPrivate(hVfsSymlink, &g_rtZipTarFssSymOps);
     1448            RTVfsSymlinkRelease(hVfsSymlink);
     1449            break;
     1450        }
     1451
     1452        case RTVFSOBJTYPE_BASE:
     1453            pThisObj = (PRTZIPTARBASEOBJ)RTVfsObjToPrivate(hVfsObj, &g_rtZipTarFssBaseObjOps);
     1454            break;
     1455
     1456        default:
     1457            /** @todo implement.   */
     1458            AssertFailedReturn(NULL);
     1459    }
     1460
     1461    AssertReturn(pThisObj->pTarReader == &pThis->TarReader, NULL);
     1462    return pThisObj;
     1463}
     1464
  • trunk/src/VBox/Runtime/common/zip/tarvfsreader.h

    r84160 r84192  
    11/* $Id$ */
    22/** @file
    3  * IPRT - TAR Virtual Filesystem, Reader.
     3 * IPRT - TAR Virtual Filesystem.
    44 */
    55
     
    2525 */
    2626
    27 
    28 /*********************************************************************************************************************************
    29 *   Header Files                                                                                                                 *
    30 *********************************************************************************************************************************/
    31 #include "internal/iprt.h"
    32 #include <iprt/zip.h>
    33 
    34 #include <iprt/asm.h>
    35 #include <iprt/assert.h>
    36 #include <iprt/ctype.h>
    37 #include <iprt/err.h>
    38 #include <iprt/poll.h>
    39 #include <iprt/file.h>
    40 #include <iprt/string.h>
    41 #include <iprt/vfs.h>
    42 #include <iprt/vfslowlevel.h>
     27#ifndef IPRT_INCLUDED_SRC_common_zip_tarvfsreader_h
     28#define IPRT_INCLUDED_SRC_common_zip_tarvfsreader_h
     29#ifndef RT_WITHOUT_PRAGMA_ONCE
     30# pragma once
     31#endif
    4332
    4433#include "tar.h"
    4534
    4635
    47 /*********************************************************************************************************************************
    48 *   Structures and Typedefs                                                                                                      *
    49 *********************************************************************************************************************************/
    5036/**
    5137 * TAR reader state machine states.
     
    10389typedef struct RTZIPTARBASEOBJ
    10490{
    105     /** The stream offset of the (first) header.  */
     91    /** The stream offset of the (first) header in the input stream/file.  */
    10692    RTFOFF                  offHdr;
     93    /** The stream offset of the first header of the next object (for truncating the
     94     * tar file after this object (updating)). */
     95    RTFOFF                  offNextHdr;
    10796    /** Pointer to the reader instance data (resides in the filesystem
    10897     * stream).
     
    131120    /** The number of padding bytes following the file. */
    132121    uint32_t                cbPadding;
    133     /** Set if we've reached the end of the file. */
     122    /** Set if we've reached the end of this file. */
    134123    bool                    fEndOfStream;
    135124    /** The input I/O stream. */
     
    157146    /** The offset of the next header. */
    158147    RTFOFF                  offNextHdr;
     148    /** The offset of the first header for the current object.
     149     * When reaching the end, this will be the same as offNextHdr which will be
     150     * pointing to the first zero header */
     151    RTFOFF                  offCurHdr;
    159152
    160153    /** Set if we've reached the end of the stream. */
     
    169162typedef RTZIPTARFSSTREAM *PRTZIPTARFSSTREAM;
    170163
     164DECLHIDDEN(void)                rtZipTarReaderInit(PRTZIPTARFSSTREAM pThis, RTVFSIOSTREAM hVfsIos, uint64_t offStart);
     165DECLHIDDEN(DECLCALLBACK(int))   rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj);
     166DECLHIDDEN(PRTZIPTARBASEOBJ)    rtZipTarFsStreamBaseObjToPrivate(PRTZIPTARFSSTREAM pThis, RTVFSOBJ hVfsObj);
    171167
     168#endif /* !IPRT_INCLUDED_SRC_common_zip_tarvfsreader_h */
    172169
    173 /**
    174  * Converts a numeric header field to the C native type.
    175  *
    176  * @returns IPRT status code.
    177  *
    178  * @param   pszField            The TAR header field.
    179  * @param   cchField            The length of the field.
    180  * @param   fOctalOnly          Must be octal.
    181  * @param   pi64                Where to store the value.
    182  */
    183 static int rtZipTarHdrFieldToNum(const char *pszField, size_t cchField, bool fOctalOnly, int64_t *pi64)
    184 {
    185     unsigned char const *puchField   = (unsigned char const *)pszField;
    186     size_t const         cchFieldOrg = cchField;
    187     if (   fOctalOnly
    188         || !(*puchField & 0x80))
    189     {
    190         /*
    191          * Skip leading spaces. Include zeros to save a few slower loops below.
    192          */
    193         unsigned char ch;
    194         while (cchField > 0 && ((ch = *puchField) == ' '|| ch == '0'))
    195             cchField--, puchField++;
    196 
    197         /*
    198          * Convert octal digits.
    199          */
    200         int64_t i64 = 0;
    201         while (cchField > 0)
    202         {
    203             unsigned char uDigit = *puchField - '0';
    204             if (uDigit >= 8)
    205                 break;
    206             i64 <<= 3;
    207             i64 |= uDigit;
    208 
    209             puchField++;
    210             cchField--;
    211         }
    212         *pi64 = i64;
    213 
    214         /*
    215          * Was it terminated correctly?
    216          */
    217         while (cchField > 0)
    218         {
    219             ch = *puchField++;
    220             if (ch != 0 && ch != ' ')
    221                 return cchField < cchFieldOrg
    222                      ? VERR_TAR_BAD_NUM_FIELD_TERM
    223                      : VERR_TAR_BAD_NUM_FIELD;
    224             cchField--;
    225         }
    226     }
    227     else
    228     {
    229         /*
    230          * The first byte has the bit 7 set to indicate base-256, while bit 6
    231          * is the signed bit. Bits 5:0 are the most significant value bits.
    232          */
    233         uint64_t u64;
    234         if (!(0x40 & *puchField))
    235         {
    236             /* Positive or zero value. */
    237             u64 = *puchField & 0x3f;
    238             cchField--;
    239             puchField++;
    240 
    241             while (cchField-- > 0)
    242             {
    243                 if (RT_LIKELY(u64 <= (uint64_t)INT64_MAX / 256))
    244                     u64 = (u64 << 8) | *puchField++;
    245                 else
    246                     return VERR_TAR_NUM_VALUE_TOO_LARGE;
    247             }
    248         }
    249         else
    250         {
    251             /* Negative value (could be used in timestamp). We do manual sign extending here. */
    252             u64 = (UINT64_MAX << 6) | (*puchField & 0x3f);
    253             cchField--;
    254             puchField++;
    255 
    256             while (cchField-- > 0)
    257             {
    258                 if (RT_LIKELY(u64 >= (uint64_t)(INT64_MIN / 256)))
    259                     u64 = (u64 << 8) | *puchField++;
    260                 else
    261                     return VERR_TAR_NUM_VALUE_TOO_LARGE;
    262             }
    263         }
    264         *pi64 = (int64_t)u64;
    265     }
    266 
    267     return VINF_SUCCESS;
    268 }
    269 
    270 
    271 /**
    272  * Validates the TAR header.
    273  *
    274  * @returns VINF_SUCCESS if valid, VERR_TAR_ZERO_HEADER if all zeros, and
    275  *          the appropriate VERR_TAR_XXX otherwise.
    276  * @param   pTar                The TAR header.
    277  * @param   penmType            Where to return the type of header on success.
    278  */
    279 static int rtZipTarHdrValidate(PCRTZIPTARHDR pTar, PRTZIPTARTYPE penmType)
    280 {
    281     /*
    282      * Calc the checksum first since this enables us to detect zero headers.
    283      */
    284     int32_t i32ChkSum;
    285     int32_t i32ChkSumSignedAlt;
    286     if (rtZipTarCalcChkSum(pTar, &i32ChkSum, &i32ChkSumSignedAlt))
    287         return VERR_TAR_ZERO_HEADER;
    288 
    289     /*
    290      * Read the checksum field and match the checksums.
    291      */
    292     int64_t i64HdrChkSum;
    293     int rc = rtZipTarHdrFieldToNum(pTar->Common.chksum, sizeof(pTar->Common.chksum), true /*fOctalOnly*/, &i64HdrChkSum);
    294     if (RT_FAILURE(rc))
    295         return VERR_TAR_BAD_CHKSUM_FIELD;
    296     if (   i32ChkSum          != i64HdrChkSum
    297         && i32ChkSumSignedAlt != i64HdrChkSum) /** @todo test this */
    298         return VERR_TAR_CHKSUM_MISMATCH;
    299 
    300     /*
    301      * Detect the TAR type.
    302      */
    303     RTZIPTARTYPE enmType;
    304     if (   pTar->Common.magic[0] == 'u'
    305         && pTar->Common.magic[1] == 's'
    306         && pTar->Common.magic[2] == 't'
    307         && pTar->Common.magic[3] == 'a'
    308         && pTar->Common.magic[4] == 'r')
    309     {
    310 /** @todo detect star headers */
    311         if (   pTar->Common.magic[5]   == '\0'
    312             && pTar->Common.version[0] == '0'
    313             && pTar->Common.version[1] == '0')
    314             enmType = RTZIPTARTYPE_POSIX;
    315         else if (   pTar->Common.magic[5]   == ' '
    316                  && pTar->Common.version[0] == ' '
    317                  && pTar->Common.version[1] == '\0')
    318             enmType = RTZIPTARTYPE_GNU;
    319         else if (   pTar->Common.magic[5]   == '\0' /* VMWare ambiguity - they probably mean posix but */
    320                  && pTar->Common.version[0] == ' '  /*                    got the version wrong. */
    321                  && pTar->Common.version[1] == '\0')
    322             enmType = RTZIPTARTYPE_POSIX;
    323         else
    324             return VERR_TAR_NOT_USTAR_V00;
    325     }
    326     else
    327         enmType = RTZIPTARTYPE_ANCIENT;
    328     *penmType = enmType;
    329 
    330     /*
    331      * Perform some basic checks.
    332      */
    333     switch (enmType)
    334     {
    335         case RTZIPTARTYPE_POSIX:
    336             if (   !RT_C_IS_ALNUM(pTar->Common.typeflag)
    337                 && pTar->Common.typeflag != '\0')
    338                 return VERR_TAR_UNKNOWN_TYPE_FLAG;
    339             break;
    340 
    341         case RTZIPTARTYPE_GNU:
    342             switch (pTar->Common.typeflag)
    343             {
    344                 case RTZIPTAR_TF_OLDNORMAL:
    345                 case RTZIPTAR_TF_NORMAL:
    346                 case RTZIPTAR_TF_CONTIG:
    347                 case RTZIPTAR_TF_DIR:
    348                 case RTZIPTAR_TF_CHR:
    349                 case RTZIPTAR_TF_BLK:
    350                 case RTZIPTAR_TF_LINK:
    351                 case RTZIPTAR_TF_SYMLINK:
    352                 case RTZIPTAR_TF_FIFO:
    353                     break;
    354 
    355                 case RTZIPTAR_TF_GNU_LONGLINK:
    356                 case RTZIPTAR_TF_GNU_LONGNAME:
    357                     break;
    358 
    359                 case RTZIPTAR_TF_GNU_DUMPDIR:
    360                 case RTZIPTAR_TF_GNU_MULTIVOL:
    361                 case RTZIPTAR_TF_GNU_SPARSE:
    362                 case RTZIPTAR_TF_GNU_VOLDHR:
    363                     /** @todo Implement full GNU TAR support. .*/
    364                     return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;
    365 
    366                 default:
    367                     return VERR_TAR_UNKNOWN_TYPE_FLAG;
    368             }
    369             break;
    370 
    371         case RTZIPTARTYPE_ANCIENT:
    372             switch (pTar->Common.typeflag)
    373             {
    374                 case RTZIPTAR_TF_OLDNORMAL:
    375                 case RTZIPTAR_TF_NORMAL:
    376                 case RTZIPTAR_TF_CONTIG:
    377                 case RTZIPTAR_TF_DIR:
    378                 case RTZIPTAR_TF_LINK:
    379                 case RTZIPTAR_TF_SYMLINK:
    380                 case RTZIPTAR_TF_FIFO:
    381                     break;
    382                 default:
    383                     return VERR_TAR_UNKNOWN_TYPE_FLAG;
    384             }
    385             break;
    386         default: /* shut up gcc */
    387             AssertFailedReturn(VERR_INTERNAL_ERROR_3);
    388     }
    389 
    390     return VINF_SUCCESS;
    391 }
    392 
    393 
    394 /**
    395  * Parses and validates the first TAR header of a archive/file/dir/whatever.
    396  *
    397  * @returns IPRT status code.
    398  * @param   pThis               The TAR reader stat.
    399  * @param   pTar                The TAR header that has been read.
    400  * @param   fFirst              Set if this is the first header, otherwise
    401  *                              clear.
    402  */
    403 static int rtZipTarReaderParseNextHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr, bool fFirst)
    404 {
    405     int rc;
    406 
    407     /*
    408      * Basic header validation and detection first.
    409      */
    410     RTZIPTARTYPE enmType;
    411     rc = rtZipTarHdrValidate(pHdr, &enmType);
    412     if (RT_FAILURE_NP(rc))
    413     {
    414         if (rc == VERR_TAR_ZERO_HEADER)
    415         {
    416             pThis->cZeroHdrs = 1;
    417             pThis->enmState = RTZIPTARREADERSTATE_ZERO;
    418             return VINF_SUCCESS;
    419         }
    420         return rc;
    421     }
    422     if (fFirst)
    423     {
    424         pThis->enmType = enmType;
    425         if (pThis->enmPrevType == RTZIPTARTYPE_INVALID)
    426             pThis->enmPrevType = enmType;
    427     }
    428 
    429     /*
    430      * Handle the header by type.
    431      */
    432     switch (pHdr->Common.typeflag)
    433     {
    434         case RTZIPTAR_TF_OLDNORMAL:
    435         case RTZIPTAR_TF_NORMAL:
    436         case RTZIPTAR_TF_CONTIG:
    437         case RTZIPTAR_TF_LINK:
    438         case RTZIPTAR_TF_SYMLINK:
    439         case RTZIPTAR_TF_CHR:
    440         case RTZIPTAR_TF_BLK:
    441         case RTZIPTAR_TF_FIFO:
    442         case RTZIPTAR_TF_DIR:
    443             /*
    444              * Extract the name first.
    445              */
    446             if (!pHdr->Common.name[0])
    447                 return VERR_TAR_EMPTY_NAME;
    448             if (pThis->enmType == RTZIPTARTYPE_POSIX)
    449             {
    450                 Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0');
    451                 pThis->szName[0] = '\0';
    452                 if (pHdr->Posix.prefix[0])
    453                 {
    454                     rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Posix.prefix, sizeof(pHdr->Posix.prefix));
    455                     AssertRC(rc); /* shall not fail */
    456                     rc = RTStrCat(pThis->szName, sizeof(pThis->szName), "/");
    457                     AssertRC(rc); /* ditto */
    458                 }
    459                 rc = RTStrCatEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));
    460                 AssertRCReturn(rc, rc);
    461             }
    462             else if (pThis->enmType == RTZIPTARTYPE_GNU)
    463             {
    464                 if (!pThis->szName[0])
    465                 {
    466                     rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));
    467                     AssertRCReturn(rc, rc);
    468                 }
    469             }
    470             else
    471             {
    472                 /* Old TAR */
    473                 Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0');
    474                 rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));
    475                 AssertRCReturn(rc, rc);
    476             }
    477 
    478             /*
    479              * Extract the link target.
    480              */
    481             if (   pHdr->Common.typeflag == RTZIPTAR_TF_LINK
    482                 || pHdr->Common.typeflag == RTZIPTAR_TF_SYMLINK)
    483             {
    484                 if (   pThis->enmType == RTZIPTARTYPE_POSIX
    485                     || pThis->enmType == RTZIPTARTYPE_ANCIENT
    486                     || (pThis->enmType == RTZIPTARTYPE_GNU && pThis->szTarget[0] == '\0')
    487                    )
    488                 {
    489                     Assert(pThis->szTarget[0] == '\0');
    490                     rc = RTStrCopyEx(pThis->szTarget, sizeof(pThis->szTarget),
    491                                      pHdr->Common.linkname, sizeof(pHdr->Common.linkname));
    492                     AssertRCReturn(rc, rc);
    493                 }
    494             }
    495             else
    496                 pThis->szTarget[0] = '\0';
    497 
    498             pThis->Hdr = *pHdr;
    499             break;
    500 
    501         case RTZIPTAR_TF_X_HDR:
    502         case RTZIPTAR_TF_X_GLOBAL:
    503             /** @todo implement PAX */
    504             return VERR_TAR_UNSUPPORTED_PAX_TYPE;
    505 
    506         case RTZIPTAR_TF_SOLARIS_XHDR:
    507             /** @todo implement solaris / pax attribute lists. */
    508             return VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE;
    509 
    510 
    511         /*
    512          * A GNU long name or long link is a dummy record followed by one or
    513          * more 512 byte string blocks holding the long name/link.  The name
    514          * lenght is encoded in the size field, null terminator included.  If
    515          * it is a symlink or hard link the long name may be followed by a
    516          * long link sequence.
    517          */
    518         case RTZIPTAR_TF_GNU_LONGNAME:
    519         case RTZIPTAR_TF_GNU_LONGLINK:
    520         {
    521             if (strcmp(pHdr->Gnu.name, "././@LongLink"))
    522                 return VERR_TAR_MALFORMED_GNU_LONGXXXX;
    523 
    524             int64_t cb64;
    525             rc = rtZipTarHdrFieldToNum(pHdr->Gnu.size, sizeof(pHdr->Gnu.size), false /*fOctalOnly*/, &cb64);
    526             if (RT_FAILURE(rc) || cb64 < 0 || cb64 > _1M)
    527                 return VERR_TAR_MALFORMED_GNU_LONGXXXX;
    528             uint32_t cb = (uint32_t)cb64;
    529             if (cb >= sizeof(pThis->szName))
    530                 return VERR_TAR_NAME_TOO_LONG;
    531 
    532             pThis->cbGnuLongExpect  = cb;
    533             pThis->offGnuLongCur    = 0;
    534             pThis->enmState         = pHdr->Common.typeflag == RTZIPTAR_TF_GNU_LONGNAME
    535                                     ? RTZIPTARREADERSTATE_GNU_LONGNAME
    536                                     : RTZIPTARREADERSTATE_GNU_LONGLINK;
    537             break;
    538         }
    539 
    540         case RTZIPTAR_TF_GNU_DUMPDIR:
    541         case RTZIPTAR_TF_GNU_MULTIVOL:
    542         case RTZIPTAR_TF_GNU_SPARSE:
    543         case RTZIPTAR_TF_GNU_VOLDHR:
    544             /** @todo Implement or skip GNU headers */
    545             return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;
    546 
    547         default:
    548             return VERR_TAR_UNKNOWN_TYPE_FLAG;
    549     }
    550 
    551     return VINF_SUCCESS;
    552 }
    553 
    554 
    555 /**
    556  * Parses and validates a TAR header.
    557  *
    558  * @returns IPRT status code.
    559  * @param   pThis               The TAR reader stat.
    560  * @param   pTar                The TAR header that has been read.
    561  */
    562 static int rtZipTarReaderParseHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr)
    563 {
    564     switch (pThis->enmState)
    565     {
    566         /*
    567          * The first record for a file/directory/whatever.
    568          */
    569         case RTZIPTARREADERSTATE_FIRST:
    570             pThis->Hdr.Common.typeflag  = 0x7f;
    571             pThis->enmPrevType          = pThis->enmType;
    572             pThis->enmType              = RTZIPTARTYPE_INVALID;
    573             pThis->offGnuLongCur        = 0;
    574             pThis->cbGnuLongExpect      = 0;
    575             pThis->szName[0]            = '\0';
    576             pThis->szTarget[0]          = '\0';
    577             return rtZipTarReaderParseNextHeader(pThis, pHdr, true /*fFirst*/);
    578 
    579         /*
    580          * There should only be so many zero headers at the end of the file as
    581          * it is a function of the block size used when writing.  Don't go on
    582          * reading them forever in case someone points us to /dev/zero.
    583          */
    584         case RTZIPTARREADERSTATE_ZERO:
    585             if (!ASMMemIsZero(pHdr, sizeof(*pHdr)))
    586                 return VERR_TAR_ZERO_HEADER;
    587             pThis->cZeroHdrs++;
    588             if (pThis->cZeroHdrs <= _64K / 512 + 2)
    589                 return VINF_SUCCESS;
    590             return VERR_TAR_ZERO_HEADER;
    591 
    592         case RTZIPTARREADERSTATE_GNU_LONGNAME:
    593         case RTZIPTARREADERSTATE_GNU_LONGLINK:
    594         {
    595             size_t cbIncoming = RTStrNLen((const char *)pHdr->ab, sizeof(*pHdr));
    596             if (cbIncoming < sizeof(*pHdr))
    597                 cbIncoming += 1;
    598 
    599             if (cbIncoming + pThis->offGnuLongCur > pThis->cbGnuLongExpect)
    600                 return VERR_TAR_MALFORMED_GNU_LONGXXXX;
    601             if (   cbIncoming < sizeof(*pHdr)
    602                 && cbIncoming + pThis->offGnuLongCur != pThis->cbGnuLongExpect)
    603                 return VERR_TAR_MALFORMED_GNU_LONGXXXX;
    604 
    605             char *pszDst = pThis->enmState == RTZIPTARREADERSTATE_GNU_LONGNAME ? pThis->szName : pThis->szTarget;
    606             pszDst += pThis->offGnuLongCur;
    607             memcpy(pszDst, pHdr->ab, cbIncoming);
    608 
    609             pThis->offGnuLongCur += (uint32_t)cbIncoming;
    610             if (pThis->offGnuLongCur == pThis->cbGnuLongExpect)
    611                 pThis->enmState = RTZIPTARREADERSTATE_GNU_NEXT;
    612             return VINF_SUCCESS;
    613         }
    614 
    615         case RTZIPTARREADERSTATE_GNU_NEXT:
    616             pThis->enmState = RTZIPTARREADERSTATE_FIRST;
    617             return rtZipTarReaderParseNextHeader(pThis, pHdr, false /*fFirst*/);
    618 
    619         default:
    620             return VERR_INTERNAL_ERROR_5;
    621     }
    622 }
    623 
    624 
    625 /**
    626  * Translate a TAR header to an IPRT object info structure with additional UNIX
    627  * attributes.
    628  *
    629  * This completes the validation done by rtZipTarHdrValidate.
    630  *
    631  * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
    632  * @param   pThis               The TAR reader instance.
    633  * @param   pObjInfo            The object info structure (output).
    634  */
    635 static int rtZipTarReaderGetFsObjInfo(PRTZIPTARREADER pThis, PRTFSOBJINFO pObjInfo)
    636 {
    637     /*
    638      * Zap the whole structure, this takes care of unused space in the union.
    639      */
    640     RT_ZERO(*pObjInfo);
    641 
    642     /*
    643      * Convert the TAR field in RTFSOBJINFO order.
    644      */
    645     int         rc;
    646     int64_t     i64Tmp;
    647 #define GET_TAR_NUMERIC_FIELD_RET(a_Var, a_Field) \
    648         do { \
    649             rc = rtZipTarHdrFieldToNum(a_Field, sizeof(a_Field), false /*fOctalOnly*/, &i64Tmp); \
    650             if (RT_FAILURE(rc)) \
    651                 return rc; \
    652             (a_Var) = i64Tmp; \
    653             if ((a_Var) != i64Tmp) \
    654                 return VERR_TAR_NUM_VALUE_TOO_LARGE; \
    655         } while (0)
    656 
    657     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->cbObject,        pThis->Hdr.Common.size);
    658     pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 512);
    659     int64_t c64SecModTime;
    660     GET_TAR_NUMERIC_FIELD_RET(c64SecModTime,             pThis->Hdr.Common.mtime);
    661     RTTimeSpecSetSeconds(&pObjInfo->ChangeTime,          c64SecModTime);
    662     RTTimeSpecSetSeconds(&pObjInfo->ModificationTime,    c64SecModTime);
    663     RTTimeSpecSetSeconds(&pObjInfo->AccessTime,          c64SecModTime);
    664     RTTimeSpecSetSeconds(&pObjInfo->BirthTime,           c64SecModTime);
    665     if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
    666         return VERR_TAR_NUM_VALUE_TOO_LARGE;
    667     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode,      pThis->Hdr.Common.mode);
    668     pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
    669     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pThis->Hdr.Common.uid);
    670     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pThis->Hdr.Common.gid);
    671     pObjInfo->Attr.u.Unix.cHardlinks    = 1;
    672     pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
    673     pObjInfo->Attr.u.Unix.INodeId       = 0;
    674     pObjInfo->Attr.u.Unix.fFlags        = 0;
    675     pObjInfo->Attr.u.Unix.GenerationId  = 0;
    676     pObjInfo->Attr.u.Unix.Device        = 0;
    677     switch (pThis->enmType)
    678     {
    679         case RTZIPTARTYPE_POSIX:
    680         case RTZIPTARTYPE_GNU:
    681             if (   pThis->Hdr.Common.typeflag == RTZIPTAR_TF_CHR
    682                 || pThis->Hdr.Common.typeflag == RTZIPTAR_TF_BLK)
    683             {
    684                 uint32_t uMajor, uMinor;
    685                 GET_TAR_NUMERIC_FIELD_RET(uMajor,        pThis->Hdr.Common.devmajor);
    686                 GET_TAR_NUMERIC_FIELD_RET(uMinor,        pThis->Hdr.Common.devminor);
    687                 pObjInfo->Attr.u.Unix.Device    = RTDEV_MAKE(uMajor, uMinor);
    688                 if (   uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
    689                     || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
    690                     return VERR_TAR_DEV_VALUE_TOO_LARGE;
    691             }
    692             break;
    693 
    694         default:
    695             if (   pThis->Hdr.Common.typeflag == RTZIPTAR_TF_CHR
    696                 || pThis->Hdr.Common.typeflag == RTZIPTAR_TF_BLK)
    697                 return VERR_TAR_UNKNOWN_TYPE_FLAG;
    698     }
    699 
    700 #undef GET_TAR_NUMERIC_FIELD_RET
    701 
    702     /*
    703      * Massage the result a little bit.
    704      * Also validate some more now that we've got the numbers to work with.
    705      */
    706     if (   (pObjInfo->Attr.fMode & ~RTFS_UNIX_MASK)
    707         && pThis->enmType == RTZIPTARTYPE_POSIX)
    708         return VERR_TAR_BAD_MODE_FIELD;
    709     pObjInfo->Attr.fMode &= RTFS_UNIX_MASK;
    710 
    711     RTFMODE fModeType = 0;
    712     switch (pThis->Hdr.Common.typeflag)
    713     {
    714         case RTZIPTAR_TF_OLDNORMAL:
    715         case RTZIPTAR_TF_NORMAL:
    716         case RTZIPTAR_TF_CONTIG:
    717         {
    718             const char *pszEnd = strchr(pThis->szName, '\0');
    719             if (pszEnd == &pThis->szName[0] || pszEnd[-1] != '/')
    720                 fModeType |= RTFS_TYPE_FILE;
    721             else
    722                 fModeType |= RTFS_TYPE_DIRECTORY;
    723             break;
    724         }
    725 
    726         case RTZIPTAR_TF_LINK:
    727             if (pObjInfo->cbObject != 0)
    728 #if 0 /* too strict */
    729                 return VERR_TAR_SIZE_NOT_ZERO;
    730 #else
    731                 pObjInfo->cbObject = pObjInfo->cbAllocated = 0;
    732 #endif
    733             fModeType |= RTFS_TYPE_FILE; /* no better idea for now */
    734             break;
    735 
    736         case RTZIPTAR_TF_SYMLINK:
    737             fModeType |= RTFS_TYPE_SYMLINK;
    738             break;
    739 
    740         case RTZIPTAR_TF_CHR:
    741             fModeType |= RTFS_TYPE_DEV_CHAR;
    742             break;
    743 
    744         case RTZIPTAR_TF_BLK:
    745             fModeType |= RTFS_TYPE_DEV_BLOCK;
    746             break;
    747 
    748         case RTZIPTAR_TF_DIR:
    749             fModeType |= RTFS_TYPE_DIRECTORY;
    750             break;
    751 
    752         case RTZIPTAR_TF_FIFO:
    753             fModeType |= RTFS_TYPE_FIFO;
    754             break;
    755 
    756         case RTZIPTAR_TF_GNU_LONGLINK:
    757         case RTZIPTAR_TF_GNU_LONGNAME:
    758             /* ASSUMES RTFS_TYPE_XXX uses the same values as GNU stored in the mode field. */
    759             fModeType = pObjInfo->Attr.fMode & RTFS_TYPE_MASK;
    760             switch (fModeType)
    761             {
    762                 case RTFS_TYPE_FILE:
    763                 case RTFS_TYPE_DIRECTORY:
    764                 case RTFS_TYPE_SYMLINK:
    765                 case RTFS_TYPE_DEV_BLOCK:
    766                 case RTFS_TYPE_DEV_CHAR:
    767                 case RTFS_TYPE_FIFO:
    768                     break;
    769 
    770                 default:
    771                 case 0:
    772                     return VERR_TAR_UNKNOWN_TYPE_FLAG; /** @todo new status code */
    773             }
    774             break;
    775 
    776         default:
    777             return VERR_TAR_UNKNOWN_TYPE_FLAG; /* Should've been caught in validate. */
    778     }
    779     if (   (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)
    780         && (pObjInfo->Attr.fMode & RTFS_TYPE_MASK) != fModeType)
    781         return VERR_TAR_MODE_WITH_TYPE;
    782     pObjInfo->Attr.fMode &= ~RTFS_TYPE_MASK;
    783     pObjInfo->Attr.fMode |= fModeType;
    784 
    785     switch (pThis->Hdr.Common.typeflag)
    786     {
    787         case RTZIPTAR_TF_CHR:
    788         case RTZIPTAR_TF_BLK:
    789         case RTZIPTAR_TF_DIR:
    790         case RTZIPTAR_TF_FIFO:
    791             pObjInfo->cbObject    = 0;
    792             pObjInfo->cbAllocated = 0;
    793             break;
    794     }
    795 
    796     return VINF_SUCCESS;
    797 }
    798 
    799 
    800 /**
    801  * Checks if the reader is expecting more headers.
    802  *
    803  * @returns true / false.
    804  * @param   pThis               The TAR reader instance.
    805  */
    806 static bool rtZipTarReaderExpectingMoreHeaders(PRTZIPTARREADER pThis)
    807 {
    808     return pThis->enmState != RTZIPTARREADERSTATE_FIRST;
    809 }
    810 
    811 
    812 /**
    813  * Checks if we're at the end of the TAR file.
    814  *
    815  * @returns true / false.
    816  * @param   pThis               The TAR reader instance.
    817  */
    818 static bool rtZipTarReaderIsAtEnd(PRTZIPTARREADER pThis)
    819 {
    820     /*
    821      * In theory there shall always be two zero headers at the end of the
    822      * archive, but life isn't that simple.   We've been creating archives
    823      * without any zero headers at the end ourselves for a long long time
    824      * (old tar.cpp).
    825      *
    826      * So, we're fine if the state is 'FIRST' or 'ZERO' here, but we'll barf
    827      * if we're in the middle of a multi-header stream (long GNU names, sparse
    828      * files, PAX, etc).
    829      */
    830     return pThis->enmState == RTZIPTARREADERSTATE_FIRST
    831         || pThis->enmState == RTZIPTARREADERSTATE_ZERO;
    832 }
    833 
    834 
    835 /**
    836  * Checks if the current TAR object is a hard link or not.
    837  *
    838  * @returns true if it is, false if not.
    839  * @param   pThis               The TAR reader instance.
    840  */
    841 static bool rtZipTarReaderIsHardlink(PRTZIPTARREADER pThis)
    842 {
    843     return pThis->Hdr.Common.typeflag == RTZIPTAR_TF_LINK;
    844 }
    845 
    846 
    847 /**
    848  * Checks if the TAR header includes a POSIX or GNU user name field.
    849  *
    850  * @returns true / false.
    851  * @param   pThis               The TAR reader instance.
    852  */
    853 DECLINLINE(bool) rtZipTarReaderHasUserName(PRTZIPTARREADER pThis)
    854 {
    855     return pThis->Hdr.Common.uname[0] != '\0'
    856         && (   pThis->enmType == RTZIPTARTYPE_POSIX
    857             || pThis->enmType == RTZIPTARTYPE_GNU);
    858 }
    859 
    860 
    861 /**
    862  * Checks if the TAR header includes a POSIX or GNU group name field.
    863  *
    864  * @returns true / false.
    865  * @param   pThis               The TAR reader instance.
    866  */
    867 DECLINLINE(bool) rtZipTarReaderHasGroupName(PRTZIPTARREADER pThis)
    868 {
    869     return pThis->Hdr.Common.gname[0] != '\0'
    870         && (   pThis->enmType == RTZIPTARTYPE_POSIX
    871             || pThis->enmType == RTZIPTARTYPE_GNU);
    872 }
    873 
    874 
    875 /*
    876  *
    877  * T h e   V F S   F i l e s y s t e m   S t r e a m   B i t s.
    878  * T h e   V F S   F i l e s y s t e m   S t r e a m   B i t s.
    879  * T h e   V F S   F i l e s y s t e m   S t r e a m   B i t s.
    880  *
    881  */
    882 
    883 /**
    884  * @interface_method_impl{RTVFSOBJOPS,pfnClose}
    885  */
    886 static DECLCALLBACK(int) rtZipTarFssBaseObj_Close(void *pvThis)
    887 {
    888     PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
    889 
    890     /* Currently there is nothing we really have to do here. */
    891     pThis->offHdr = -1;
    892 
    893     return VINF_SUCCESS;
    894 }
    895 
    896 
    897 /**
    898  * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
    899  */
    900 static DECLCALLBACK(int) rtZipTarFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
    901 {
    902     PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
    903 
    904     /*
    905      * Copy the desired data.
    906      */
    907     switch (enmAddAttr)
    908     {
    909         case RTFSOBJATTRADD_NOTHING:
    910         case RTFSOBJATTRADD_UNIX:
    911             *pObjInfo = pThis->ObjInfo;
    912             break;
    913 
    914         case RTFSOBJATTRADD_UNIX_OWNER:
    915             *pObjInfo = pThis->ObjInfo;
    916             pObjInfo->Attr.enmAdditional         = RTFSOBJATTRADD_UNIX_OWNER;
    917             pObjInfo->Attr.u.UnixOwner.uid       = pThis->ObjInfo.Attr.u.Unix.uid;
    918             pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
    919             if (rtZipTarReaderHasUserName(pThis->pTarReader))
    920                 RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName),
    921                           pThis->pTarReader->Hdr.Common.uname);
    922             break;
    923 
    924         case RTFSOBJATTRADD_UNIX_GROUP:
    925             *pObjInfo = pThis->ObjInfo;
    926             pObjInfo->Attr.enmAdditional         = RTFSOBJATTRADD_UNIX_GROUP;
    927             pObjInfo->Attr.u.UnixGroup.gid       = pThis->ObjInfo.Attr.u.Unix.gid;
    928             pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
    929             if (rtZipTarReaderHasGroupName(pThis->pTarReader))
    930                 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),
    931                           pThis->pTarReader->Hdr.Common.gname);
    932             break;
    933 
    934         case RTFSOBJATTRADD_EASIZE:
    935             *pObjInfo = pThis->ObjInfo;
    936             pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
    937             RT_ZERO(pObjInfo->Attr.u);
    938             break;
    939 
    940         default:
    941             return VERR_NOT_SUPPORTED;
    942     }
    943 
    944     return VINF_SUCCESS;
    945 }
    946 
    947 
    948 /**
    949  * Tar filesystem base object operations.
    950  */
    951 static const RTVFSOBJOPS g_rtZipTarFssBaseObjOps =
    952 {
    953     RTVFSOBJOPS_VERSION,
    954     RTVFSOBJTYPE_BASE,
    955     "TarFsStream::Obj",
    956     rtZipTarFssBaseObj_Close,
    957     rtZipTarFssBaseObj_QueryInfo,
    958     RTVFSOBJOPS_VERSION
    959 };
    960 
    961 
    962 /**
    963  * @interface_method_impl{RTVFSOBJOPS,pfnClose}
    964  */
    965 static DECLCALLBACK(int) rtZipTarFssIos_Close(void *pvThis)
    966 {
    967     PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
    968 
    969     RTVfsIoStrmRelease(pThis->hVfsIos);
    970     pThis->hVfsIos = NIL_RTVFSIOSTREAM;
    971 
    972     return rtZipTarFssBaseObj_Close(&pThis->BaseObj);
    973 }
    974 
    975 
    976 /**
    977  * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
    978  */
    979 static DECLCALLBACK(int) rtZipTarFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
    980 {
    981     PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
    982     return rtZipTarFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);
    983 }
    984 
    985 
    986 /**
    987  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
    988  */
    989 static DECLCALLBACK(int) rtZipTarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
    990 {
    991     PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
    992     Assert(pSgBuf->cSegs == 1);
    993 
    994     /*
    995      * Make offset into a real offset so it's possible to do random access
    996      * on TAR files that are seekable.  Fend of reads beyond the end of the
    997      * stream.
    998      */
    999     if (off < 0)
    1000         off = pThis->offFile;
    1001     if (off >= pThis->cbFile)
    1002         return pcbRead ? VINF_EOF : VERR_EOF;
    1003 
    1004 
    1005     Assert(pThis->cbFile >= pThis->offFile);
    1006     uint64_t cbLeft   = (uint64_t)(pThis->cbFile - off);
    1007     size_t   cbToRead = pSgBuf->paSegs[0].cbSeg;
    1008     if (cbToRead > cbLeft)
    1009     {
    1010         if (!pcbRead)
    1011             return VERR_EOF;
    1012         cbToRead = (size_t)cbLeft;
    1013     }
    1014 
    1015     /*
    1016      * Do the reading.
    1017      */
    1018     size_t cbReadStack = 0;
    1019     if (!pcbRead)
    1020         pcbRead = &cbReadStack;
    1021     int rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offStart + off, pSgBuf->paSegs[0].pvSeg, cbToRead, fBlocking, pcbRead);
    1022     pThis->offFile = off + *pcbRead;
    1023     if (pThis->offFile >= pThis->cbFile)
    1024     {
    1025         Assert(pThis->offFile == pThis->cbFile);
    1026         pThis->fEndOfStream = true;
    1027         RTVfsIoStrmSkip(pThis->hVfsIos, pThis->cbPadding);
    1028     }
    1029 
    1030     return rc;
    1031 }
    1032 
    1033 
    1034 /**
    1035  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
    1036  */
    1037 static DECLCALLBACK(int) rtZipTarFssIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
    1038 {
    1039     /* Cannot write to a read-only I/O stream. */
    1040     NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
    1041     return VERR_ACCESS_DENIED;
    1042 }
    1043 
    1044 
    1045 /**
    1046  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
    1047  */
    1048 static DECLCALLBACK(int) rtZipTarFssIos_Flush(void *pvThis)
    1049 {
    1050     /* It's a read only stream, nothing dirty to flush. */
    1051     NOREF(pvThis);
    1052     return VINF_SUCCESS;
    1053 }
    1054 
    1055 
    1056 /**
    1057  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
    1058  */
    1059 static DECLCALLBACK(int) rtZipTarFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
    1060                                                 uint32_t *pfRetEvents)
    1061 {
    1062     PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
    1063 
    1064     /* When we've reached the end, read will be set to indicate it. */
    1065     if (   (fEvents & RTPOLL_EVT_READ)
    1066         && pThis->fEndOfStream)
    1067     {
    1068         int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);
    1069         if (RT_SUCCESS(rc))
    1070             *pfRetEvents |= RTPOLL_EVT_READ;
    1071         else
    1072             *pfRetEvents = RTPOLL_EVT_READ;
    1073         return VINF_SUCCESS;
    1074     }
    1075 
    1076     return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
    1077 }
    1078 
    1079 
    1080 /**
    1081  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
    1082  */
    1083 static DECLCALLBACK(int) rtZipTarFssIos_Tell(void *pvThis, PRTFOFF poffActual)
    1084 {
    1085     PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
    1086     *poffActual = pThis->offFile;
    1087     return VINF_SUCCESS;
    1088 }
    1089 
    1090 
    1091 /**
    1092  * Tar I/O stream operations.
    1093  */
    1094 static const RTVFSIOSTREAMOPS g_rtZipTarFssIosOps =
    1095 {
    1096     { /* Obj */
    1097         RTVFSOBJOPS_VERSION,
    1098         RTVFSOBJTYPE_IO_STREAM,
    1099         "TarFsStream::IoStream",
    1100         rtZipTarFssIos_Close,
    1101         rtZipTarFssIos_QueryInfo,
    1102         RTVFSOBJOPS_VERSION
    1103     },
    1104     RTVFSIOSTREAMOPS_VERSION,
    1105     RTVFSIOSTREAMOPS_FEAT_NO_SG,
    1106     rtZipTarFssIos_Read,
    1107     rtZipTarFssIos_Write,
    1108     rtZipTarFssIos_Flush,
    1109     rtZipTarFssIos_PollOne,
    1110     rtZipTarFssIos_Tell,
    1111     NULL /*Skip*/,
    1112     NULL /*ZeroFill*/,
    1113     RTVFSIOSTREAMOPS_VERSION
    1114 };
    1115 
    1116 
    1117 /**
    1118  * @interface_method_impl{RTVFSOBJOPS,pfnClose}
    1119  */
    1120 static DECLCALLBACK(int) rtZipTarFssSym_Close(void *pvThis)
    1121 {
    1122     PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
    1123     return rtZipTarFssBaseObj_Close(pThis);
    1124 }
    1125 
    1126 
    1127 /**
    1128  * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
    1129  */
    1130 static DECLCALLBACK(int) rtZipTarFssSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
    1131 {
    1132     PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
    1133     return rtZipTarFssBaseObj_QueryInfo(pThis, pObjInfo, enmAddAttr);
    1134 }
    1135 
    1136 /**
    1137  * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
    1138  */
    1139 static DECLCALLBACK(int) rtZipTarFssSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
    1140 {
    1141     NOREF(pvThis); NOREF(fMode); NOREF(fMask);
    1142     return VERR_ACCESS_DENIED;
    1143 }
    1144 
    1145 
    1146 /**
    1147  * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
    1148  */
    1149 static DECLCALLBACK(int) rtZipTarFssSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
    1150                                                  PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
    1151 {
    1152     NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
    1153     return VERR_ACCESS_DENIED;
    1154 }
    1155 
    1156 
    1157 /**
    1158  * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
    1159  */
    1160 static DECLCALLBACK(int) rtZipTarFssSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
    1161 {
    1162     NOREF(pvThis); NOREF(uid); NOREF(gid);
    1163     return VERR_ACCESS_DENIED;
    1164 }
    1165 
    1166 
    1167 /**
    1168  * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
    1169  */
    1170 static DECLCALLBACK(int) rtZipTarFssSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
    1171 {
    1172     PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
    1173     return RTStrCopy(pszTarget, cbTarget, pThis->pTarReader->szTarget);
    1174 }
    1175 
    1176 
    1177 /**
    1178  * Tar symbolic (and hardlink) operations.
    1179  */
    1180 static const RTVFSSYMLINKOPS g_rtZipTarFssSymOps =
    1181 {
    1182     { /* Obj */
    1183         RTVFSOBJOPS_VERSION,
    1184         RTVFSOBJTYPE_SYMLINK,
    1185         "TarFsStream::Symlink",
    1186         rtZipTarFssSym_Close,
    1187         rtZipTarFssSym_QueryInfo,
    1188         RTVFSOBJOPS_VERSION
    1189     },
    1190     RTVFSSYMLINKOPS_VERSION,
    1191     0,
    1192     { /* ObjSet */
    1193         RTVFSOBJSETOPS_VERSION,
    1194         RT_UOFFSETOF(RTVFSSYMLINKOPS, ObjSet) - RT_UOFFSETOF(RTVFSSYMLINKOPS, Obj),
    1195         rtZipTarFssSym_SetMode,
    1196         rtZipTarFssSym_SetTimes,
    1197         rtZipTarFssSym_SetOwner,
    1198         RTVFSOBJSETOPS_VERSION
    1199     },
    1200     rtZipTarFssSym_Read,
    1201     RTVFSSYMLINKOPS_VERSION
    1202 };
    1203 
    1204 
    1205 /**
    1206  * @interface_method_impl{RTVFSOBJOPS,pfnClose}
    1207  */
    1208 static DECLCALLBACK(int) rtZipTarFss_Close(void *pvThis)
    1209 {
    1210     PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
    1211 
    1212     RTVfsObjRelease(pThis->hVfsCurObj);
    1213     pThis->hVfsCurObj  = NIL_RTVFSOBJ;
    1214     pThis->pCurIosData = NULL;
    1215 
    1216     RTVfsIoStrmRelease(pThis->hVfsIos);
    1217     pThis->hVfsIos = NIL_RTVFSIOSTREAM;
    1218 
    1219     return VINF_SUCCESS;
    1220 }
    1221 
    1222 
    1223 /**
    1224  * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
    1225  */
    1226 static DECLCALLBACK(int) rtZipTarFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
    1227 {
    1228     PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
    1229     /* Take the lazy approach here, with the sideffect of providing some info
    1230        that is actually kind of useful. */
    1231     return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
    1232 }
    1233 
    1234 
    1235 /**
    1236  * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
    1237  */
    1238 static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
    1239 {
    1240     PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
    1241 
    1242     /*
    1243      * Dispense with the current object.
    1244      */
    1245     if (pThis->hVfsCurObj != NIL_RTVFSOBJ)
    1246     {
    1247         if (pThis->pCurIosData)
    1248         {
    1249             pThis->pCurIosData->fEndOfStream = true;
    1250             pThis->pCurIosData->offFile      = pThis->pCurIosData->cbFile;
    1251             pThis->pCurIosData = NULL;
    1252         }
    1253 
    1254         RTVfsObjRelease(pThis->hVfsCurObj);
    1255         pThis->hVfsCurObj = NIL_RTVFSOBJ;
    1256     }
    1257 
    1258     /*
    1259      * Check if we've already reached the end in some way.
    1260      */
    1261     if (pThis->fEndOfStream)
    1262         return VERR_EOF;
    1263     if (pThis->rcFatal != VINF_SUCCESS)
    1264         return pThis->rcFatal;
    1265 
    1266     /*
    1267      * Make sure the input stream is in the right place.
    1268      */
    1269     RTFOFF offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
    1270     while (   offHdr >= 0
    1271            && offHdr < pThis->offNextHdr)
    1272     {
    1273         int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - offHdr);
    1274         if (RT_FAILURE(rc))
    1275         {
    1276             /** @todo Ignore if we're at the end of the stream? */
    1277             return pThis->rcFatal = rc;
    1278         }
    1279 
    1280         offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
    1281     }
    1282 
    1283     if (offHdr < 0)
    1284         return pThis->rcFatal = (int)offHdr;
    1285     if (offHdr > pThis->offNextHdr)
    1286         return pThis->rcFatal = VERR_INTERNAL_ERROR_3;
    1287 
    1288     /*
    1289      * Consume TAR headers.
    1290      */
    1291     size_t cbHdrs = 0;
    1292     int rc;
    1293     do
    1294     {
    1295         /*
    1296          * Read the next header.
    1297          */
    1298         RTZIPTARHDR Hdr;
    1299         size_t cbRead;
    1300         rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
    1301         if (RT_FAILURE(rc))
    1302             return pThis->rcFatal = rc;
    1303         if (rc == VINF_EOF && cbRead == 0)
    1304         {
    1305             pThis->fEndOfStream = true;
    1306             return rtZipTarReaderIsAtEnd(&pThis->TarReader) ? VERR_EOF : VERR_TAR_UNEXPECTED_EOS;
    1307         }
    1308         if (cbRead != sizeof(Hdr))
    1309             return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
    1310 
    1311         cbHdrs += sizeof(Hdr);
    1312 
    1313         /*
    1314          * Parse the it.
    1315          */
    1316         rc = rtZipTarReaderParseHeader(&pThis->TarReader, &Hdr);
    1317         if (RT_FAILURE(rc))
    1318             return pThis->rcFatal = rc;
    1319     } while (rtZipTarReaderExpectingMoreHeaders(&pThis->TarReader));
    1320 
    1321     pThis->offNextHdr = offHdr + cbHdrs;
    1322 
    1323     /*
    1324      * Fill an object info structure from the current TAR state.
    1325      */
    1326     RTFSOBJINFO Info;
    1327     rc = rtZipTarReaderGetFsObjInfo(&pThis->TarReader, &Info);
    1328     if (RT_FAILURE(rc))
    1329         return pThis->rcFatal = rc;
    1330 
    1331     /*
    1332      * Create an object of the appropriate type.
    1333      */
    1334     RTVFSOBJTYPE    enmType;
    1335     RTVFSOBJ        hVfsObj;
    1336     RTFMODE         fType = Info.Attr.fMode & RTFS_TYPE_MASK;
    1337     if (rtZipTarReaderIsHardlink(&pThis->TarReader))
    1338         fType = RTFS_TYPE_SYMLINK;
    1339     switch (fType)
    1340     {
    1341         /*
    1342          * Files are represented by a VFS I/O stream.
    1343          */
    1344         case RTFS_TYPE_FILE:
    1345         {
    1346             RTVFSIOSTREAM       hVfsIos;
    1347             PRTZIPTARIOSTREAM   pIosData;
    1348             rc = RTVfsNewIoStream(&g_rtZipTarFssIosOps,
    1349                                   sizeof(*pIosData),
    1350                                   RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
    1351                                   NIL_RTVFS,
    1352                                   NIL_RTVFSLOCK,
    1353                                   &hVfsIos,
    1354                                   (void **)&pIosData);
    1355             if (RT_FAILURE(rc))
    1356                 return pThis->rcFatal = rc;
    1357 
    1358             pIosData->BaseObj.offHdr    = offHdr;
    1359             pIosData->BaseObj.pTarReader= &pThis->TarReader;
    1360             pIosData->BaseObj.ObjInfo   = Info;
    1361             pIosData->cbFile            = Info.cbObject;
    1362             pIosData->offFile           = 0;
    1363             pIosData->offStart          = RTVfsIoStrmTell(pThis->hVfsIos);
    1364             pIosData->cbPadding         = (uint32_t)(Info.cbAllocated - Info.cbObject);
    1365             pIosData->fEndOfStream      = false;
    1366             pIosData->hVfsIos           = pThis->hVfsIos;
    1367             RTVfsIoStrmRetain(pThis->hVfsIos);
    1368 
    1369             pThis->pCurIosData = pIosData;
    1370             pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;
    1371 
    1372             enmType = RTVFSOBJTYPE_IO_STREAM;
    1373             hVfsObj = RTVfsObjFromIoStream(hVfsIos);
    1374             RTVfsIoStrmRelease(hVfsIos);
    1375             break;
    1376         }
    1377 
    1378         /*
    1379          * We represent hard links using a symbolic link object.  This fits
    1380          * best with the way TAR stores it and there is currently no better
    1381          * fitting VFS type alternative.
    1382          */
    1383         case RTFS_TYPE_SYMLINK:
    1384         {
    1385             RTVFSSYMLINK        hVfsSym;
    1386             PRTZIPTARBASEOBJ    pBaseObjData;
    1387             rc = RTVfsNewSymlink(&g_rtZipTarFssSymOps,
    1388                                  sizeof(*pBaseObjData),
    1389                                  NIL_RTVFS,
    1390                                  NIL_RTVFSLOCK,
    1391                                  &hVfsSym,
    1392                                  (void **)&pBaseObjData);
    1393             if (RT_FAILURE(rc))
    1394                 return pThis->rcFatal = rc;
    1395 
    1396             pBaseObjData->offHdr    = offHdr;
    1397             pBaseObjData->pTarReader= &pThis->TarReader;
    1398             pBaseObjData->ObjInfo   = Info;
    1399 
    1400             enmType = RTVFSOBJTYPE_SYMLINK;
    1401             hVfsObj = RTVfsObjFromSymlink(hVfsSym);
    1402             RTVfsSymlinkRelease(hVfsSym);
    1403             break;
    1404         }
    1405 
    1406         /*
    1407          * All other objects are repesented using a VFS base object since they
    1408          * carry no data streams (unless some TAR extension implements extended
    1409          * attributes / alternative streams).
    1410          */
    1411         case RTFS_TYPE_DEV_BLOCK:
    1412         case RTFS_TYPE_DEV_CHAR:
    1413         case RTFS_TYPE_DIRECTORY:
    1414         case RTFS_TYPE_FIFO:
    1415         {
    1416             PRTZIPTARBASEOBJ pBaseObjData;
    1417             rc = RTVfsNewBaseObj(&g_rtZipTarFssBaseObjOps,
    1418                                  sizeof(*pBaseObjData),
    1419                                  NIL_RTVFS,
    1420                                  NIL_RTVFSLOCK,
    1421                                  &hVfsObj,
    1422                                  (void **)&pBaseObjData);
    1423             if (RT_FAILURE(rc))
    1424                 return pThis->rcFatal = rc;
    1425 
    1426             pBaseObjData->offHdr    = offHdr;
    1427             pBaseObjData->pTarReader= &pThis->TarReader;
    1428             pBaseObjData->ObjInfo   = Info;
    1429 
    1430             enmType = RTVFSOBJTYPE_BASE;
    1431             break;
    1432         }
    1433 
    1434         default:
    1435             AssertFailed();
    1436             return pThis->rcFatal = VERR_INTERNAL_ERROR_5;
    1437     }
    1438     pThis->hVfsCurObj = hVfsObj;
    1439 
    1440     /*
    1441      * Set the return data and we're done.
    1442      */
    1443     if (ppszName)
    1444     {
    1445         rc = RTStrDupEx(ppszName, pThis->TarReader.szName);
    1446         if (RT_FAILURE(rc))
    1447             return rc;
    1448     }
    1449 
    1450     if (phVfsObj)
    1451     {
    1452         RTVfsObjRetain(hVfsObj);
    1453         *phVfsObj = hVfsObj;
    1454     }
    1455 
    1456     if (penmType)
    1457         *penmType = enmType;
    1458 
    1459     return VINF_SUCCESS;
    1460 }
    1461 
    1462 
    1463 
    1464 /**
    1465  * Tar filesystem stream operations.
    1466  */
    1467 static const RTVFSFSSTREAMOPS rtZipTarFssOps =
    1468 {
    1469     { /* Obj */
    1470         RTVFSOBJOPS_VERSION,
    1471         RTVFSOBJTYPE_FS_STREAM,
    1472         "TarFsStream",
    1473         rtZipTarFss_Close,
    1474         rtZipTarFss_QueryInfo,
    1475         RTVFSOBJOPS_VERSION
    1476     },
    1477     RTVFSFSSTREAMOPS_VERSION,
    1478     0,
    1479     rtZipTarFss_Next,
    1480     NULL,
    1481     NULL,
    1482     NULL,
    1483     RTVFSFSSTREAMOPS_VERSION
    1484 };
    1485 
    1486 
    1487 RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
    1488 {
    1489     /*
    1490      * Input validation.
    1491      */
    1492     AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
    1493     *phVfsFss = NIL_RTVFSFSSTREAM;
    1494     AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
    1495     AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
    1496 
    1497     RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn);
    1498     AssertReturn(offStart >= 0, (int)offStart);
    1499 
    1500     uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
    1501     AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
    1502 
    1503     /*
    1504      * Retain the input stream and create a new filesystem stream handle.
    1505      */
    1506     PRTZIPTARFSSTREAM pThis;
    1507     RTVFSFSSTREAM     hVfsFss;
    1508     int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,
    1509                               &hVfsFss, (void **)&pThis);
    1510     if (RT_SUCCESS(rc))
    1511     {
    1512         pThis->hVfsIos              = hVfsIosIn;
    1513         pThis->hVfsCurObj           = NIL_RTVFSOBJ;
    1514         pThis->pCurIosData          = NULL;
    1515         pThis->offStart             = offStart;
    1516         pThis->offNextHdr           = offStart;
    1517         pThis->fEndOfStream         = false;
    1518         pThis->rcFatal              = VINF_SUCCESS;
    1519         pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID;
    1520         pThis->TarReader.enmType    = RTZIPTARTYPE_INVALID;
    1521         pThis->TarReader.enmState   = RTZIPTARREADERSTATE_FIRST;
    1522 
    1523         /* Don't check if it's a TAR stream here, do that in the
    1524            rtZipTarFss_Next. */
    1525 
    1526         *phVfsFss = hVfsFss;
    1527         return VINF_SUCCESS;
    1528     }
    1529 
    1530     RTVfsIoStrmRelease(hVfsIosIn);
    1531     return rc;
    1532 }
    1533 
  • trunk/src/VBox/Runtime/common/zip/tarvfswriter.cpp

    r82968 r84192  
    4444
    4545#include "tar.h"
     46
     47#include "tarvfsreader.h"
    4648
    4749
     
    161163    /** Set if we've encountered a fatal error. */
    162164    int                     rcFatal;
    163     /** Flags. */
     165    /** Flags, RTZIPTAR_C_XXX. */
    164166    uint32_t                fFlags;
    165167
     
    183185    RTFMODE                 fDirModeOrMask;     /**< Directory mode OR mask. */
    184186    /** @} */
     187
     188    /** When in update mode (RTZIPTAR_C_UPDATE) we have an reader FSS instance,
     189     * though w/o the RTVFSFSSTREAM bits. (Allocated after this structure.) */
     190    PRTZIPTARFSSTREAM       pRead;
     191    /** Set if we're in writing mode and pfnNext shall fail. */
     192    bool                    fWriting;
    185193
    186194
     
    909917
    910918/**
     919 * Does the actual work for rtZipTarFssWriter_SwitchToWriteMode().
     920 *
     921 * @note    We won't be here if we've truncate the tar file.   Truncation
     922 *          switches it into write mode.
     923 */
     924DECL_NO_INLINE(static, int) rtZipTarFssWriter_SwitchToWriteModeSlow(PRTZIPTARFSSTREAMWRITER pThis)
     925{
     926    /* Always go thru rtZipTarFssWriter_SwitchToWriteMode(). */
     927    AssertRCReturn(pThis->rcFatal, pThis->rcFatal);
     928    AssertReturn(!pThis->fWriting, VINF_SUCCESS);
     929    AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_INTERNAL_ERROR_3);
     930
     931    /*
     932     * If we're not at the end, locate the end of the tar file.
     933     * Because I'm lazy, we do that using rtZipTarFss_Next.  This isn't entirely
     934     * optimial as it involves VFS object instantations and such.
     935     */
     936    /** @todo Optimize skipping to end of tar file in update mode. */
     937    while (!pThis->pRead->fEndOfStream)
     938    {
     939        int rc = rtZipTarFss_Next(pThis->pRead, NULL, NULL, NULL);
     940        if (rc == VERR_EOF)
     941            break;
     942        AssertRCReturn(rc, rc);
     943    }
     944
     945    /*
     946     * Seek to the desired cut-off point and indicate that we've switched to writing.
     947     */
     948    Assert(pThis->pRead->offNextHdr == pThis->pRead->offCurHdr);
     949    int rc = RTVfsFileSeek(pThis->hVfsFile, pThis->pRead->offNextHdr, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
     950    if (RT_SUCCESS(rc))
     951        pThis->fWriting = true;
     952    else
     953        pThis->rcFatal = rc;
     954
     955    return rc;
     956}
     957
     958
     959/**
     960 * Switches the stream into writing mode if necessary.
     961 *
     962 * @returns VBox status code.
     963 * @param   pThis           The TAR writer instance.
     964 *
     965 */
     966DECLINLINE(int) rtZipTarFssWriter_SwitchToWriteMode(PRTZIPTARFSSTREAMWRITER pThis)
     967{
     968    if (pThis->fWriting)
     969        return VINF_SUCCESS; /* ASSUMES caller already checked pThis->rcFatal. */
     970    return rtZipTarFssWriter_SwitchToWriteModeSlow(pThis);
     971}
     972
     973
     974/**
    911975 * Allocates a buffer for transfering file data.
    912976 *
     
    922986 * @param   cbFile          The file size.  Used as a buffer size hint.
    923987 */
    924 static uint8_t *rtZipTarFssWrite_AllocBuf(PRTZIPTARFSSTREAMWRITER pThis, size_t *pcbBuf, void **ppvFree, uint64_t cbObject)
     988static uint8_t *rtZipTarFssWriter_AllocBuf(PRTZIPTARFSSTREAMWRITER pThis, size_t *pcbBuf, void **ppvFree, uint64_t cbObject)
    925989{
    926990    uint8_t *pbBuf;
     
    12741338    void    *pvBufFree;
    12751339    size_t   cbBuf;
    1276     uint8_t *pbBuf = rtZipTarFssWrite_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);
     1340    uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);
    12771341
    12781342    PRTZIPTARSPARSE pSparse;
     
    13991463                void    *pvBufFree;
    14001464                size_t   cbBuf;
    1401                 uint8_t *pbBuf = rtZipTarFssWrite_AllocBuf(pThis, &cbBuf, &pvBufFree,
    1402                                                            pObjInfo->cbObject > 0 && pObjInfo->cbObject != RTFOFF_MAX
    1403                                                            ? pObjInfo->cbObject : _1G);
     1465                uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree,
     1466                                                            pObjInfo->cbObject > 0 && pObjInfo->cbObject != RTFOFF_MAX
     1467                                                            ? pObjInfo->cbObject : _1G);
    14041468
    14051469                uint64_t cbReadTotal = 0;
     
    15021566            void    *pvBufFree;
    15031567            size_t   cbBuf;
    1504             uint8_t *pbBuf = rtZipTarFssWrite_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);
     1568            uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);
    15051569
    15061570            uint64_t cbLeft = pObjInfo->cbObject;
     
    16841748
    16851749/**
     1750 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
     1751 */
     1752static DECLCALLBACK(int) rtZipTarFssWriter_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
     1753{
     1754    PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
     1755
     1756    /*
     1757     * This only works in update mode and up to the point where
     1758     * modifications takes place (truncating the archive or appending files).
     1759     */
     1760    AssertReturn(pThis->pRead, VERR_ACCESS_DENIED);
     1761    AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_ACCESS_DENIED);
     1762
     1763    AssertReturn(!pThis->fWriting, VERR_WRONG_ORDER);
     1764
     1765    return rtZipTarFss_Next(pThis->pRead, ppszName, penmType, phVfsObj);
     1766}
     1767
     1768
     1769/**
    16861770 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnAdd}
    16871771 */
     
    16941778     */
    16951779    int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
    1696     if (RT_FAILURE(rc))
    1697         return rc;
     1780    AssertRCReturn(rc, rc);
    16981781
    16991782    /*
     
    17131796    if (RT_FAILURE(rc) || ObjGrpName.Attr.u.UnixGroup.szName[0] == '\0')
    17141797        strcpy(ObjGrpName.Attr.u.UnixGroup.szName, "somegroup");
     1798
     1799    /*
     1800     * Switch the stream into write mode if necessary.
     1801     */
     1802    rc = rtZipTarFssWriter_SwitchToWriteMode(pThis);
     1803    AssertRCReturn(rc, rc);
    17151804
    17161805    /*
     
    17801869     */
    17811870    int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
    1782     if (RT_FAILURE(rc))
    1783         return rc;
     1871    AssertRCReturn(rc, rc);
    17841872
    17851873    /*
     
    18331921
    18341922    /*
     1923     * Switch the stream into write mode if necessary.
     1924     */
     1925    rc = rtZipTarFssWriter_SwitchToWriteMode(pThis);
     1926    AssertRCReturn(rc, rc);
     1927
     1928    /*
    18351929     * Create an I/O stream object for the caller to use.
    18361930     */
     
    19252019             */
    19262020            rc = RTVfsIoStrmFlush(pThis->hVfsIos);
     2021
     2022            /*
     2023             * If we're in update mode, set the end-of-file here to make sure
     2024             * unwanted bytes are really discarded.
     2025             */
     2026            if (RT_SUCCESS(rc) && (pThis->fFlags & RTZIPTAR_C_UPDATE))
     2027            {
     2028                RTFOFF cbTarFile = RTVfsFileTell(pThis->hVfsFile);
     2029                if (cbTarFile >= 0)
     2030                    rc =  RTVfsFileSetSize(pThis->hVfsFile, (uint64_t)cbTarFile, RTVFSFILE_SIZE_F_NORMAL);
     2031                else
     2032                    rc = (int)cbTarFile;
     2033            }
     2034
     2035            /*
     2036             * Success?
     2037             */
    19272038            if (RT_SUCCESS(rc))
    19282039                return rc;
     
    19492060    RTVFSFSSTREAMOPS_VERSION,
    19502061    0,
    1951     NULL,
     2062    rtZipTarFssWriter_Next,
    19522063    rtZipTarFssWriter_Add,
    19532064    rtZipTarFssWriter_PushFile,
     
    19682079    AssertReturn(enmFormat > RTZIPTARFORMAT_INVALID && enmFormat < RTZIPTARFORMAT_END, VERR_INVALID_PARAMETER);
    19692080    AssertReturn(!(fFlags & ~RTZIPTAR_C_VALID_MASK), VERR_INVALID_FLAGS);
     2081    AssertReturn(!(fFlags & RTZIPTAR_C_UPDATE), VERR_NOT_SUPPORTED); /* Must use RTZipTarFsStreamForFile! */
    19702082
    19712083    if (enmFormat == RTZIPTARFORMAT_DEFAULT)
     
    19832095    PRTZIPTARFSSTREAMWRITER pThis;
    19842096    RTVFSFSSTREAM           hVfsFss;
    1985     int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, false /*fReadOnly*/,
     2097    int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE,
    19862098                              &hVfsFss, (void **)&pThis);
    19872099    if (RT_SUCCESS(rc))
     
    20042116        pThis->fDirModeAndMask  = ~(RTFMODE)0;
    20052117        pThis->fDirModeOrMask   = 0;
     2118        pThis->fWriting         = true;
    20062119
    20072120        *phVfsFss = hVfsFss;
     
    20102123
    20112124    RTVfsIoStrmRelease(hVfsIosOut);
     2125    return rc;
     2126}
     2127
     2128
     2129RTDECL(int) RTZipTarFsStreamForFile(RTVFSFILE hVfsFile, RTZIPTARFORMAT enmFormat, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
     2130{
     2131    /*
     2132     * Input validation.
     2133     */
     2134    AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
     2135    *phVfsFss = NIL_RTVFSFSSTREAM;
     2136    AssertPtrReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
     2137    AssertReturn(enmFormat > RTZIPTARFORMAT_INVALID && enmFormat < RTZIPTARFORMAT_END, VERR_INVALID_PARAMETER);
     2138    AssertReturn(!(fFlags & ~RTZIPTAR_C_VALID_MASK), VERR_INVALID_FLAGS);
     2139
     2140    if (enmFormat == RTZIPTARFORMAT_DEFAULT)
     2141        enmFormat = RTZIPTARFORMAT_GNU;
     2142    AssertReturn(   enmFormat == RTZIPTARFORMAT_GNU
     2143                 || enmFormat == RTZIPTARFORMAT_USTAR
     2144                 , VERR_NOT_IMPLEMENTED); /* Only implementing GNU and USTAR output at the moment. */
     2145
     2146    RTFOFF const offStart = RTVfsFileTell(hVfsFile);
     2147    AssertReturn(offStart >= 0, (int)offStart);
     2148
     2149    uint32_t cRefs = RTVfsFileRetain(hVfsFile);
     2150    AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
     2151
     2152    RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile);
     2153    AssertReturnStmt(hVfsIos != NIL_RTVFSIOSTREAM, RTVfsFileRelease(hVfsFile), VERR_INVALID_HANDLE);
     2154
     2155    /*
     2156     * Retain the input stream and create a new filesystem stream handle.
     2157     */
     2158    PRTZIPTARFSSTREAMWRITER pThis;
     2159    size_t const            cbThis = sizeof(*pThis) + (fFlags & RTZIPTAR_C_UPDATE ? sizeof(*pThis->pRead) : 0);
     2160    RTVFSFSSTREAM           hVfsFss;
     2161    int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, cbThis, NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE,
     2162                              &hVfsFss, (void **)&pThis);
     2163    if (RT_SUCCESS(rc))
     2164    {
     2165        pThis->hVfsIos          = hVfsIos;
     2166        pThis->hVfsFile         = hVfsFile;
     2167
     2168        pThis->enmFormat        = enmFormat;
     2169        pThis->fFlags           = fFlags;
     2170        pThis->rcFatal          = VINF_SUCCESS;
     2171
     2172        pThis->uidOwner         = NIL_RTUID;
     2173        pThis->pszOwner         = NULL;
     2174        pThis->gidGroup         = NIL_RTGID;
     2175        pThis->pszGroup         = NULL;
     2176        pThis->pszPrefix        = NULL;
     2177        pThis->pModTime         = NULL;
     2178        pThis->fFileModeAndMask = ~(RTFMODE)0;
     2179        pThis->fFileModeOrMask  = 0;
     2180        pThis->fDirModeAndMask  = ~(RTFMODE)0;
     2181        pThis->fDirModeOrMask   = 0;
     2182        if (!(fFlags & RTZIPTAR_C_UPDATE))
     2183            pThis->fWriting     = true;
     2184        else
     2185        {
     2186            pThis->fWriting     = false;
     2187            pThis->pRead        = (PRTZIPTARFSSTREAM)(pThis + 1);
     2188            rtZipTarReaderInit(pThis->pRead, hVfsIos, (uint64_t)offStart);
     2189        }
     2190
     2191        *phVfsFss = hVfsFss;
     2192        return VINF_SUCCESS;
     2193    }
     2194
     2195    RTVfsIoStrmRelease(hVfsIos);
     2196    RTVfsFileRelease(hVfsFile);
    20122197    return rc;
    20132198}
     
    21362321}
    21372322
     2323
     2324RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter)
     2325{
     2326    /*
     2327     * Translate and validate the input.
     2328     */
     2329    PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
     2330    AssertReturn(pThis, VERR_WRONG_TYPE);
     2331
     2332    AssertReturn(hVfsObj != NIL_RTVFSOBJ, VERR_INVALID_HANDLE);
     2333    PRTZIPTARBASEOBJ pThisObj = rtZipTarFsStreamBaseObjToPrivate(pThis->pRead, hVfsObj);
     2334    AssertReturn(pThis, VERR_NOT_OWNER);
     2335
     2336    AssertReturn(pThis->pRead, VERR_ACCESS_DENIED);
     2337    AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_ACCESS_DENIED);
     2338    AssertReturn(!pThis->fWriting, VERR_WRONG_ORDER);
     2339
     2340    /*
     2341     * Seek to the desired cut-off point and indicate that we've switched to writing.
     2342     */
     2343    int rc = RTVfsFileSeek(pThis->hVfsFile, fAfter ? pThisObj->offNextHdr : pThisObj->offHdr,
     2344                           RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
     2345    if (RT_SUCCESS(rc))
     2346        pThis->fWriting = true;
     2347    else
     2348        pThis->rcFatal = rc;
     2349    return rc;
     2350}
     2351
  • trunk/src/VBox/Runtime/common/zip/xarvfs.cpp

    r82968 r84192  
    20902090                    PRTZIPXARFSSTREAM pThis;
    20912091                    RTVFSFSSTREAM     hVfsFss;
    2092                     rc = RTVfsNewFsStream(&rtZipXarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,
     2092                    rc = RTVfsNewFsStream(&rtZipXarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ,
    20932093                                          &hVfsFss, (void **)&pThis);
    20942094                    if (RT_SUCCESS(rc))
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