VirtualBox

Ignore:
Timestamp:
Nov 18, 2010 3:49:17 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
67908
Message:

iprt/tarvfs: Rewrote the tar parser to deal with header sequences used by solaris, gnu and pax while being offline yesterday. Only GNU long link and long names are supported, but adding pax and solaris support is possible. This also resolves some of the ustar<space><space> vs. ustart<null>00 problems (the latter was not readable previously).

Location:
trunk/src/VBox/Runtime/common/zip
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/zip/tar.h

    r34060 r34179  
    4848
    4949#define RTZIPTAR_TF_GNU_DUMPDIR     'D'
    50 #define RTZIPTAR_TF_GNU_LONGLINK    'K'
    51 #define RTZIPTAR_TF_GNU_LONGNAME    'L'
     50#define RTZIPTAR_TF_GNU_LONGLINK    'K' /**< GNU long link header. */
     51#define RTZIPTAR_TF_GNU_LONGNAME    'L' /**< GNU long name header. */
    5252#define RTZIPTAR_TF_GNU_MULTIVOL    'M'
    5353#define RTZIPTAR_TF_GNU_SPARSE      'S'
    5454#define RTZIPTAR_TF_GNU_VOLDHR      'V'
    5555/** @} */
     56
     57
     58/**
     59 * The ancient tar header.
     60 *
     61 * The posix and gnu headers are compatible with the members up to and including
     62 * link name, from there on they differ.
     63 */
     64typedef struct RTZIPTARHDRANCIENT
     65{
     66    char    name[100];
     67    char    mode[8];
     68    char    uid[8];
     69    char    gid[8];
     70    char    size[12];
     71    char    mtime[12];
     72    char    chksum[8];
     73    char    typeflag;
     74    char    linkname[100];              /**< Was called linkflag. */
     75    char    unused[8+64+16+155+12];
     76} RTZIPTARHDRANCIENT;
     77AssertCompileSize(RTZIPTARHDRANCIENT, 512);
     78AssertCompileMemberOffset(RTZIPTARHDRANCIENT, name,        0);
     79AssertCompileMemberOffset(RTZIPTARHDRANCIENT, mode,      100);
     80AssertCompileMemberOffset(RTZIPTARHDRANCIENT, uid,       108);
     81AssertCompileMemberOffset(RTZIPTARHDRANCIENT, gid,       116);
     82AssertCompileMemberOffset(RTZIPTARHDRANCIENT, size,      124);
     83AssertCompileMemberOffset(RTZIPTARHDRANCIENT, mtime,     136);
     84AssertCompileMemberOffset(RTZIPTARHDRANCIENT, chksum,    148);
     85AssertCompileMemberOffset(RTZIPTARHDRANCIENT, typeflag,  156);
     86AssertCompileMemberOffset(RTZIPTARHDRANCIENT, linkname,  157);
     87AssertCompileMemberOffset(RTZIPTARHDRANCIENT, unused,    257);
     88
    5689
    5790/** The uniform standard tape archive format magic value. */
     
    164197
    165198/**
     199 * The bits common to posix and GNU.
     200 */
     201typedef struct RTZIPTARHDRCOMMON
     202{
     203    char    name[100];
     204    char    mode[8];
     205    char    uid[8];
     206    char    gid[8];
     207    char    size[12];
     208    char    mtime[12];
     209    char    chksum[8];
     210    char    typeflag;
     211    char    linkname[100];
     212    char    magic[6];
     213    char    version[2];
     214    char    uname[32];
     215    char    gname[32];
     216    char    devmajor[8];
     217    char    devminor[8];
     218    char    not_common[155+12];
     219} RTZIPTARHDRCOMMON;
     220
     221
     222/**
    166223 * Tar header union.
    167224 */
     
    170227    /** Byte view. */
    171228    char                ab[512];
     229    /** The standard header. */
     230    RTZIPTARHDRANCIENT  Ancient;
    172231    /** The standard header. */
    173232    RTZIPTARHDRPOSIX    Posix;
    174233    /** The GNU header. */
    175234    RTZIPTARHDRGNU      Gnu;
     235    /** The bits common to both GNU and the standard header. */
     236    RTZIPTARHDRCOMMON   Common;
    176237} RTZIPTARHDR;
    177238AssertCompileSize(RTZIPTARHDR, 512);
  • trunk/src/VBox/Runtime/common/zip/tarcmd.cpp

    r34055 r34179  
    268268    }
    269269
     270    const char *pszLinkType = NULL;
    270271    char szTarget[RTPATH_MAX];
    271272    szTarget[0] = '\0';
    272     if (RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
    273     {
    274         RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
    275         if (hVfsSymlink != NIL_RTVFSSYMLINK)
    276         {
    277             rc = RTVfsSymlinkRead(hVfsSymlink, szTarget, sizeof(szTarget));
    278             if (RT_FAILURE(rc))
    279                 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsSymlinkRead returned %Rrc on '%s'", rc, pszName);
    280             RTVfsSymlinkRelease(hVfsSymlink);
    281         }
    282         else
    283             rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get symlink object for '%s'", pszName);
    284     }
     273    RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
     274    if (hVfsSymlink != NIL_RTVFSSYMLINK)
     275    {
     276        rc = RTVfsSymlinkRead(hVfsSymlink, szTarget, sizeof(szTarget));
     277        if (RT_FAILURE(rc))
     278            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsSymlinkRead returned %Rrc on '%s'", rc, pszName);
     279        RTVfsSymlinkRelease(hVfsSymlink);
     280        pszLinkType = RTFS_IS_SYMLINK(UnixInfo.Attr.fMode) ? "->" : "link to";
     281    }
     282    else if (RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
     283        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get symlink object for '%s'", pszName);
    285284
    286285    /*
     
    300299        default:                    szMode[0] = '?'; break;
    301300    }
     301    if (pszLinkType && szMode[0] != 's')
     302        szMode[0] = 'h';
    302303
    303304    szMode[1] = UnixInfo.Attr.fMode & RTFS_UNIX_IRUSR ? 'r' : '-';
     
    370371     * Go to press.
    371372     */
    372     if (RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
    373         RTPrintf("%s %s/%s%*s %s %s %s -> %s\n",
     373    if (pszLinkType)
     374        RTPrintf("%s %s/%s%*s %s %s %s %s %s\n",
    374375                 szMode,
    375376                 Owner.Attr.u.UnixOwner.szName, Group.Attr.u.UnixGroup.szName,
     
    378379                 szModTime,
    379380                 pszName,
     381                 pszLinkType,
    380382                 szTarget);
    381383    else
  • trunk/src/VBox/Runtime/common/zip/tarvfs.cpp

    r34060 r34179  
    3434#include <iprt/asm.h>
    3535#include <iprt/assert.h>
     36#include <iprt/ctype.h>
    3637#include <iprt/err.h>
    3738#include <iprt/poll.h>
     
    4849*******************************************************************************/
    4950/**
     51 * TAR reader state machine states.
     52 */
     53typedef 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 */
     74typedef 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    RTZIPTARTYPE            enmPrevType;
     82    /** The type of the current TAR header. */
     83    RTZIPTARTYPE            enmType;
     84    /** The current header. */
     85    RTZIPTARHDR             Hdr;
     86    /** The expected long name/link length (GNU). */
     87    uint32_t                cbGnuLongExpect;
     88    /** The current long name/link length (GNU). */
     89    uint32_t                offGnuLongCur;
     90    /** The name of the current object.
     91     * This is for handling GNU and PAX long names. */
     92    char                    szName[RTPATH_MAX];
     93    /** The current link target if symlink or hardlink. */
     94    char                    szTarget[RTPATH_MAX];
     95} RTZIPTARREADER;
     96/** Pointer to the TAR reader instance data. */
     97typedef RTZIPTARREADER *PRTZIPTARREADER;
     98
     99/**
    50100 * Tar directory, character device, block device, fifo socket or symbolic link.
    51101 */
     
    53103{
    54104    /** The stream offset of the (first) header.  */
    55     RTFOFF              offHdr;
    56     /** The tar header. */
    57     RTZIPTARHDR         Hdr;
     105    RTFOFF                  offHdr;
     106    /** Pointer to the reader instance data (resides in the filesystem
     107     * stream).
     108     * @todo Fix this so it won't go stale... Back ref from this obj to fss? */
     109    PRTZIPTARREADER         pTarReader;
    58110    /** The object info with unix attributes. */
    59     RTFSOBJINFO         ObjInfo;
     111    RTFSOBJINFO             ObjInfo;
    60112} RTZIPTARBASEOBJ;
    61 /** Pointer to a tar filesystem stream base object. */
     113/** Pointer to a TAR filesystem stream base object. */
    62114typedef RTZIPTARBASEOBJ *PRTZIPTARBASEOBJ;
    63115
     
    68120typedef struct RTZIPTARIOSTREAM
    69121{
    70     /** The basic tar object data. */
    71     RTZIPTARBASEOBJ     BaseObj;
     122    /** The basic TAR object data. */
     123    RTZIPTARBASEOBJ         BaseObj;
    72124    /** The number of bytes in the file. */
    73     RTFOFF              cbFile;
     125    RTFOFF                  cbFile;
    74126    /** The current file position. */
    75     RTFOFF              offFile;
     127    RTFOFF                  offFile;
    76128    /** The number of padding bytes following the file. */
    77     uint32_t            cbPadding;
     129    uint32_t                cbPadding;
    78130    /** Set if we've reached the end of the file. */
    79     bool                fEndOfStream;
     131    bool                    fEndOfStream;
    80132    /** The input I/O stream. */
    81     RTVFSIOSTREAM       hVfsIos;
     133    RTVFSIOSTREAM           hVfsIos;
    82134} RTZIPTARIOSTREAM;
    83 /** Pointer to a the private data of a tar file I/O stream. */
     135/** Pointer to a the private data of a TAR file I/O stream. */
    84136typedef RTZIPTARIOSTREAM *PRTZIPTARIOSTREAM;
    85137
     
    91143{
    92144    /** The input I/O stream. */
    93     RTVFSIOSTREAM       hVfsIos;
     145    RTVFSIOSTREAM           hVfsIos;
    94146
    95147    /** The current object (referenced). */
    96     RTVFSOBJ            hVfsCurObj;
     148    RTVFSOBJ                hVfsCurObj;
    97149    /** Pointer to the private data if hVfsCurObj is representing a file. */
    98     PRTZIPTARIOSTREAM   pCurIosData;
     150    PRTZIPTARIOSTREAM       pCurIosData;
    99151
    100152    /** The start offset. */
    101     RTFOFF              offStart;
     153    RTFOFF                  offStart;
    102154    /** The offset of the next header. */
    103     RTFOFF              offNextHdr;
     155    RTFOFF                  offNextHdr;
    104156
    105157    /** Set if we've reached the end of the stream. */
    106     bool                fEndOfStream;
     158    bool                    fEndOfStream;
    107159    /** Set if we've encountered a fatal error. */
    108     int                 rcFatal;
     160    int                     rcFatal;
     161
     162    /** The TAR reader instance data. */
     163    RTZIPTARREADER          TarReader;
    109164} RTZIPTARFSSTREAM;
    110 /** Pointer to a the private data of a tar filesystem stream. */
     165/** Pointer to a the private data of a TAR filesystem stream. */
    111166typedef RTZIPTARFSSTREAM *PRTZIPTARFSSTREAM;
    112167
    113 
    114 /**
    115  * Checks if the TAR header is in the ustar format.
    116  *
    117  * @returns true / false.
    118  * @param   pTar                The TAR header.
    119  */
    120 DECLINLINE(bool) rtZipTarHdrIsUstar(PCRTZIPTARHDR pTar)
    121 {
    122     return pTar->Posix.magic[0] == 'u'
    123         && pTar->Posix.magic[1] == 's'
    124         && pTar->Posix.magic[2] == 't'
    125         && pTar->Posix.magic[3] == 'a'
    126         && pTar->Posix.magic[4] == 'r'
    127         && pTar->Posix.magic[5] == '\0'
    128         && pTar->Posix.version[0] == '0'
    129         && pTar->Posix.version[1] == '0';
    130 }
    131 
    132 
    133 /**
    134  * Checks if the TAR header is in the ustar format and has a regular file type.
    135  *
    136  * @returns true / false.
    137  * @param   pTar                The TAR header.
    138  */
    139 DECLINLINE(bool) rtZipTarHdrIsRegularUstar(PCRTZIPTARHDR pTar)
    140 {
    141     return rtZipTarHdrIsUstar(pTar)
    142         && (    (   pTar->Posix.typeflag >= RTZIPTAR_TF_NORMAL
    143                  && pTar->Posix.typeflag <= RTZIPTAR_TF_CONTIG)
    144             ||  pTar->Posix.typeflag == RTZIPTAR_TF_OLDNORMAL);
    145 }
    146 
    147 
    148 /**
    149  * Checks if the TAR header includes a posix user name field.
    150  *
    151  * @returns true / false.
    152  * @param   pTar                The TAR header.
    153  */
    154 DECLINLINE(bool) rtZipTarHdrHasPosixUserName(PCRTZIPTARHDR pTar)
    155 {
    156     return pTar->Posix.uname[0] != '\0'
    157         && rtZipTarHdrIsUstar(pTar);
    158 }
    159 
    160 
    161 /**
    162  * Checks if the TAR header includes a posix group name field.
    163  *
    164  * @returns true / false.
    165  * @param   pTar                The TAR header.
    166  */
    167 DECLINLINE(bool) rtZipTarHdrHasPosixGroupName(PCRTZIPTARHDR pTar)
    168 {
    169     return pTar->Posix.gname[0] != '\0'
    170         && rtZipTarHdrIsUstar(pTar);
    171 }
    172 
    173 
    174 /**
    175  * Checks if the TAR header includes a posix compatible path prefix field.
    176  *
    177  * @returns true / false.
    178  * @param   pTar                The TAR header.
    179  */
    180 DECLINLINE(bool) rtZipTarHdrHasPrefix(PCRTZIPTARHDR pTar)
    181 {
    182     return pTar->Posix.prefix[0] != '\0'
    183         && rtZipTarHdrIsUstar(pTar);
    184 }
    185168
    186169
     
    202185    {
    203186        /*
    204          * Skip leading zeros, saving a few slower loops below.
     187         * Skip leading spaces. Include zeros to save a few slower loops below.
    205188         */
    206         while (cchField > 0 && *pszField == '0')
     189        char ch;
     190        while (cchField > 0 && ((ch = *pszField) == ' '|| ch == '0'))
    207191            cchField--, pszField++;
    208192
     
    229213        while (cchField > 0)
    230214        {
    231             char ch = *pszField++;
     215            ch = *pszField++;
    232216            if (ch != 0 && ch != ' ')
    233217                return cchField < cchFieldOrg
     
    248232
    249233/**
    250  * Calculates the tar header checksums and detects if it's all zeros.
     234 * Calculates the TAR header checksums and detects if it's all zeros.
    251235 *
    252236 * @returns true if all zeros, false if not.
     
    283267    bool const fZeroHdr = i32Unsigned == 0;
    284268
    285     pch    = pHdr->Posix.chksum;
    286     pchEnd = pch + sizeof(pHdr->Posix.chksum);
     269    pch    = pHdr->Common.chksum;
     270    pchEnd = pch + sizeof(pHdr->Common.chksum);
    287271    do
    288272    {
     
    291275    } while (++pch != pchEnd);
    292276
    293     i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Posix.chksum);
    294     i32Signed   += (signed   char)' ' * sizeof(pHdr->Posix.chksum);
     277    i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Common.chksum);
     278    i32Signed   += (signed   char)' ' * sizeof(pHdr->Common.chksum);
    295279
    296280    *pi32Unsigned = i32Unsigned;
     
    304288 * Validates the TAR header.
    305289 *
    306  * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
     290 * @returns VINF_SUCCESS if valid, VERR_TAR_ZERO_HEADER if all zeros, and
     291 *          the appropriate VERR_TAR_XXX otherwise.
    307292 * @param   pTar                The TAR header.
    308293 * @param   penmType            Where to return the type of header on success.
     
    322307     */
    323308    int64_t i64HdrChkSum;
    324     int rc = rtZipTarHdrFieldToNum(pTar->Posix.chksum, sizeof(pTar->Posix.chksum), true /*fOctalOnly*/, &i64HdrChkSum);
     309    int rc = rtZipTarHdrFieldToNum(pTar->Common.chksum, sizeof(pTar->Common.chksum), true /*fOctalOnly*/, &i64HdrChkSum);
    325310    if (RT_FAILURE(rc))
    326311        return VERR_TAR_BAD_CHKSUM_FIELD;
     
    330315
    331316    /*
    332      * Detect the tar type.
     317     * Detect the TAR type.
    333318     */
    334319    RTZIPTARTYPE enmType;
    335     if (   pTar->Posix.magic[0] == 'u'
    336         && pTar->Posix.magic[1] == 's'
    337         && pTar->Posix.magic[2] == 't'
    338         && pTar->Posix.magic[3] == 'a'
    339         && pTar->Posix.magic[4] == 'r')
    340     {
    341         if (   pTar->Posix.magic[5]   == '\0'
    342             && pTar->Posix.version[0] == '0'
    343             && pTar->Posix.version[1] == '0')
     320    if (   pTar->Common.magic[0] == 'u'
     321        && pTar->Common.magic[1] == 's'
     322        && pTar->Common.magic[2] == 't'
     323        && pTar->Common.magic[3] == 'a'
     324        && pTar->Common.magic[4] == 'r')
     325    {
     326/** @todo detect star headers */
     327        if (   pTar->Common.magic[5]   == '\0'
     328            && pTar->Common.version[0] == '0'
     329            && pTar->Common.version[1] == '0')
    344330            enmType = RTZIPTARTYPE_POSIX;
    345         else if (   pTar->Posix.magic[5]   == ' '
    346                 && pTar->Posix.version[0] == ' '
    347                 && pTar->Posix.version[1] == '\0')
     331        else if (   pTar->Common.magic[5]   == ' '
     332                && pTar->Common.version[0] == ' '
     333                && pTar->Common.version[1] == '\0')
    348334            enmType = RTZIPTARTYPE_GNU;
    349335        else
     
    357343     * Perform some basic checks.
    358344     */
    359     /** @todo more/less? */
    360     switch (pTar->Posix.typeflag)
     345    switch (enmType)
     346    {
     347        case RTZIPTARTYPE_POSIX:
     348            if (   !RT_C_IS_ALNUM(pTar->Common.typeflag)
     349                && !pTar->Common.typeflag == '\0')
     350                return VERR_TAR_UNKNOWN_TYPE_FLAG;
     351            break;
     352
     353        case RTZIPTARTYPE_GNU:
     354            switch (pTar->Common.typeflag)
     355            {
     356                case RTZIPTAR_TF_OLDNORMAL:
     357                case RTZIPTAR_TF_NORMAL:
     358                case RTZIPTAR_TF_CONTIG:
     359                case RTZIPTAR_TF_DIR:
     360                case RTZIPTAR_TF_CHR:
     361                case RTZIPTAR_TF_BLK:
     362                case RTZIPTAR_TF_LINK:
     363                case RTZIPTAR_TF_SYMLINK:
     364                case RTZIPTAR_TF_FIFO:
     365                    break;
     366
     367                case RTZIPTAR_TF_GNU_LONGLINK:
     368                case RTZIPTAR_TF_GNU_LONGNAME:
     369                    break;
     370
     371                case RTZIPTAR_TF_GNU_DUMPDIR:
     372                case RTZIPTAR_TF_GNU_MULTIVOL:
     373                case RTZIPTAR_TF_GNU_SPARSE:
     374                case RTZIPTAR_TF_GNU_VOLDHR:
     375                    /** @todo Implement full GNU TAR support. .*/
     376                    return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;
     377
     378                default:
     379                    return VERR_TAR_UNKNOWN_TYPE_FLAG;
     380            }
     381            break;
     382
     383        case RTZIPTARTYPE_ANCIENT:
     384            switch (pTar->Common.typeflag)
     385            {
     386                case RTZIPTAR_TF_OLDNORMAL:
     387                case RTZIPTAR_TF_NORMAL:
     388                case RTZIPTAR_TF_CONTIG:
     389                case RTZIPTAR_TF_DIR:
     390                case RTZIPTAR_TF_LINK:
     391                case RTZIPTAR_TF_SYMLINK:
     392                case RTZIPTAR_TF_FIFO:
     393                    break;
     394                default:
     395                    return VERR_TAR_UNKNOWN_TYPE_FLAG;
     396            }
     397            break;
     398        default: /* shut up gcc */
     399            AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     400    }
     401
     402    return VINF_SUCCESS;
     403}
     404
     405
     406/**
     407 * Parses and validates the first TAR header of a archive/file/dir/whatever.
     408 *
     409 * @returns IPRT status code.
     410 * @param   pThis               The TAR reader stat.
     411 * @param   pTar                The TAR header that has been read.
     412 * @param   fFirst              Set if this is the first header, otherwise
     413 *                              clear.
     414 */
     415static int rtZipTarReaderParseNextHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr, bool fFirst)
     416{
     417    int rc;
     418
     419    /*
     420     * Basic header validation and detection first.
     421     */
     422    RTZIPTARTYPE enmType;
     423    rc = rtZipTarHdrValidate(pHdr, &enmType);
     424    if (RT_FAILURE_NP(rc))
     425    {
     426        if (rc == VERR_TAR_ZERO_HEADER)
     427        {
     428            pThis->cZeroHdrs = 1;
     429            pThis->enmState = RTZIPTARREADERSTATE_ZERO;
     430            return VINF_SUCCESS;
     431        }
     432        return rc;
     433    }
     434    if (fFirst)
     435        pThis->enmType = enmType;
     436
     437    /*
     438     * Handle the header by type.
     439     */
     440    switch (pHdr->Common.typeflag)
    361441    {
    362442        case RTZIPTAR_TF_OLDNORMAL:
     
    368448        case RTZIPTAR_TF_BLK:
    369449        case RTZIPTAR_TF_FIFO:
    370         {
    371             if (!pTar->Posix.name[0])
     450        case RTZIPTAR_TF_DIR:
     451            /*
     452             * Extract the name first.
     453             */
     454            if (!pHdr->Common.name[0])
    372455                return VERR_TAR_EMPTY_NAME;
    373 
    374             /** @todo People claim some (older and newer buggy) tar stores dirs as regular files with a trailing slash. */
    375             const char *pchEnd = RTStrEnd(&pTar->Posix.name[0], sizeof(pTar->Posix.name));
    376             pchEnd = pchEnd ? pchEnd - 1 : &pTar->Posix.name[sizeof(pTar->Posix.name) - 1];
    377             if (*pchEnd == '/')
    378                 return VERR_TAR_NON_DIR_ENDS_WITH_SLASH;
    379             break;
    380         }
    381 
    382         case RTZIPTAR_TF_DIR:
    383             if (!pTar->Posix.name[0])
    384                 return VERR_TAR_EMPTY_NAME;
     456            if (pThis->enmType == RTZIPTARTYPE_POSIX)
     457            {
     458                Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0');
     459                pThis->szName[0] = '\0';
     460                if (pHdr->Posix.prefix[0])
     461                {
     462                    rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Posix.prefix, sizeof(pHdr->Posix.prefix));
     463                    AssertRC(rc); /* shall not fail */
     464                    rc = RTStrCat(pThis->szName, sizeof(pThis->szName), "/");
     465                    AssertRC(rc); /* ditto */
     466                }
     467                rc = RTStrCatEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));
     468                AssertRCReturn(rc, rc);
     469            }
     470            else if (pThis->enmType == RTZIPTARTYPE_GNU)
     471            {
     472                if (!pThis->szName[0])
     473                {
     474                    rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));
     475                    AssertRCReturn(rc, rc);
     476                }
     477            }
     478            else
     479            {
     480                /* Old TAR */
     481                Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0');
     482                rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));
     483                AssertRCReturn(rc, rc);
     484            }
     485
     486            /*
     487             * Extract the link target.
     488             */
     489            if (   pHdr->Common.typeflag == RTZIPTAR_TF_LINK
     490                || pHdr->Common.typeflag == RTZIPTAR_TF_SYMLINK)
     491            {
     492                if (   pThis->enmType == RTZIPTARTYPE_POSIX
     493                    || pThis->enmType == RTZIPTARTYPE_ANCIENT
     494                    || (pThis->enmType == RTZIPTARTYPE_GNU && pThis->szTarget[0] == '\0')
     495                   )
     496                {
     497                    Assert(pThis->szTarget[0] == '\0');
     498                    rc = RTStrCopyEx(pThis->szTarget, sizeof(pThis->szTarget),
     499                                     pHdr->Common.linkname, sizeof(pHdr->Common.linkname));
     500                    AssertRCReturn(rc, rc);
     501                }
     502            }
     503            else
     504                pThis->szTarget[0] = '\0';
     505
     506            pThis->Hdr = *pHdr;
    385507            break;
    386508
    387509        case RTZIPTAR_TF_X_HDR:
    388510        case RTZIPTAR_TF_X_GLOBAL:
     511            /** @todo implement PAX */
    389512            return VERR_TAR_UNSUPPORTED_PAX_TYPE;
    390513
    391514        case RTZIPTAR_TF_SOLARIS_XHDR:
     515            /** @todo implement solaris / pax attribute lists. */
    392516            return VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE;
    393517
     518
     519        /*
     520         * A GNU long name or long link is a dummy record followed by one or
     521         * more 512 byte string blocks holding the long name/link.  The name
     522         * lenght is encoded in the size field, null terminator included.  If
     523         * it is a symlink or hard link the long name may be followed by a
     524         * long link sequence.
     525         */
     526        case RTZIPTAR_TF_GNU_LONGNAME:
     527        case RTZIPTAR_TF_GNU_LONGLINK:
     528        {
     529            if (strcmp(pHdr->Gnu.name, "././@LongLink"))
     530                return VERR_TAR_MALFORMED_GNU_LONGXXXX;
     531
     532            int64_t cch64;
     533            rc = rtZipTarHdrFieldToNum(pHdr->Gnu.size, sizeof(pHdr->Gnu.size), false /*fOctalOnly*/, &cch64);
     534            if (RT_FAILURE(rc) || cch64 < 0 || cch64 > _1M)
     535                return VERR_TAR_MALFORMED_GNU_LONGXXXX;
     536            if (cch64 >= sizeof(pThis->szName))
     537                return VERR_TAR_NAME_TOO_LONG;
     538
     539            pThis->cbGnuLongExpect  = (uint32_t)cch64;
     540            pThis->offGnuLongCur    = 0;
     541            pThis->enmState         = pHdr->Common.typeflag == RTZIPTAR_TF_GNU_LONGNAME
     542                                    ? RTZIPTARREADERSTATE_GNU_LONGNAME
     543                                    : RTZIPTARREADERSTATE_GNU_LONGLINK;
     544            break;
     545        }
     546
    394547        case RTZIPTAR_TF_GNU_DUMPDIR:
    395         case RTZIPTAR_TF_GNU_LONGLINK:
    396         case RTZIPTAR_TF_GNU_LONGNAME:
    397548        case RTZIPTAR_TF_GNU_MULTIVOL:
    398549        case RTZIPTAR_TF_GNU_SPARSE:
    399550        case RTZIPTAR_TF_GNU_VOLDHR:
     551            /** @todo Implement or skip GNU headers */
    400552            return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;
    401     }
    402 
     553
     554        default:
     555            return VERR_TAR_UNKNOWN_TYPE_FLAG;
     556    }
    403557
    404558    return VINF_SUCCESS;
    405559}
    406560
     561/**
     562 * Parses and validates a TAR header.
     563 *
     564 * @returns IPRT status code.
     565 * @param   pThis               The TAR reader stat.
     566 * @param   pTar                The TAR header that has been read.
     567 */
     568static int rtZipTarReaderParseHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr)
     569{
     570    switch (pThis->enmState)
     571    {
     572        /*
     573         * The first record for a file/directory/whatever.
     574         */
     575        case RTZIPTARREADERSTATE_FIRST:
     576            pThis->Hdr.Common.typeflag  = 0x7f;
     577            pThis->enmPrevType          = pThis->enmType;
     578            pThis->enmType              = RTZIPTARTYPE_INVALID;
     579            pThis->offGnuLongCur        = 0;
     580            pThis->cbGnuLongExpect      = 0;
     581            pThis->szName[0]            = '\0';
     582            pThis->szTarget[0]          = '\0';
     583            return rtZipTarReaderParseNextHeader(pThis, pHdr, true /*fFirst*/);
     584
     585        /*
     586         * There should only be so many zero headers at the end of the file as
     587         * it is a function of the block size used when writing.  Don't go on
     588         * reading them forever in case someone points us to /dev/zero.
     589         */
     590        case RTZIPTARREADERSTATE_ZERO:
     591            if (ASMMemIsAllU32(pHdr, sizeof(*pHdr), 0) != NULL)
     592                return VERR_TAR_ZERO_HEADER;
     593            pThis->cZeroHdrs++;
     594            if (pThis->cZeroHdrs <= _64K / 512 + 2)
     595                return VINF_SUCCESS;
     596            return VERR_TAR_ZERO_HEADER;
     597
     598        case RTZIPTARREADERSTATE_GNU_LONGNAME:
     599        case RTZIPTARREADERSTATE_GNU_LONGLINK:
     600        {
     601            size_t cbIncoming = RTStrNLen((const char *)pHdr->ab, sizeof(*pHdr));
     602            if (cbIncoming < sizeof(*pHdr))
     603                cbIncoming += 1;
     604
     605            if (cbIncoming + pThis->offGnuLongCur > pThis->cbGnuLongExpect)
     606                return VERR_TAR_MALFORMED_GNU_LONGXXXX;
     607            if (   cbIncoming < sizeof(*pHdr)
     608                && cbIncoming + pThis->offGnuLongCur != pThis->cbGnuLongExpect)
     609                return VERR_TAR_MALFORMED_GNU_LONGXXXX;
     610
     611            char *pszDst = pThis->enmState == RTZIPTARREADERSTATE_GNU_LONGNAME ? pThis->szName : pThis->szTarget;
     612            pszDst += pThis->offGnuLongCur;
     613            memcpy(pszDst, pHdr->ab, cbIncoming);
     614
     615            pThis->offGnuLongCur += cbIncoming;
     616            if (pThis->offGnuLongCur == pThis->cbGnuLongExpect)
     617                pThis->enmState = RTZIPTARREADERSTATE_GNU_NEXT;
     618            return VINF_SUCCESS;
     619        }
     620
     621        case RTZIPTARREADERSTATE_GNU_NEXT:
     622            pThis->enmState = RTZIPTARREADERSTATE_FIRST;
     623            return rtZipTarReaderParseNextHeader(pThis, pHdr, false /*fFirst*/);
     624
     625        default:
     626            return VERR_INTERNAL_ERROR_5;
     627    }
     628}
    407629
    408630/**
     
    413635 *
    414636 * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
    415  * @param   pTar                The TAR header (input).
     637 * @param   pThis               The TAR reader instance.
    416638 * @param   pObjInfo            The object info structure (output).
    417639 */
    418 static int rtZipTarHdrToFsObjInfo(PCRTZIPTARHDR pTar, PRTFSOBJINFO pObjInfo)
     640static int rtZipTarReaderGetFsObjInfo(PRTZIPTARREADER pThis, PRTFSOBJINFO pObjInfo)
    419641{
    420642    /*
     
    424646
    425647    /*
    426      * Convert the tar field in RTFSOBJINFO order.
     648     * Convert the TAR field in RTFSOBJINFO order.
    427649     */
    428650    int         rc;
     
    438660        } while (0)
    439661
    440     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->cbObject,        pTar->Posix.size);
     662    GET_TAR_NUMERIC_FIELD_RET(pObjInfo->cbObject,        pThis->Hdr.Common.size);
    441663    pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 512);
    442664    int64_t c64SecModTime;
    443     GET_TAR_NUMERIC_FIELD_RET(c64SecModTime,             pTar->Posix.mtime);
    444     RTTimeSpecSetSeconds(&pObjInfo->ChangeTime,           c64SecModTime);
    445     RTTimeSpecSetSeconds(&pObjInfo->ModificationTime,     c64SecModTime);
    446     RTTimeSpecSetSeconds(&pObjInfo->AccessTime,           c64SecModTime);
    447     RTTimeSpecSetSeconds(&pObjInfo->BirthTime,            c64SecModTime);
     665    GET_TAR_NUMERIC_FIELD_RET(c64SecModTime,             pThis->Hdr.Common.mtime);
     666    RTTimeSpecSetSeconds(&pObjInfo->ChangeTime,          c64SecModTime);
     667    RTTimeSpecSetSeconds(&pObjInfo->ModificationTime,    c64SecModTime);
     668    RTTimeSpecSetSeconds(&pObjInfo->AccessTime,          c64SecModTime);
     669    RTTimeSpecSetSeconds(&pObjInfo->BirthTime,           c64SecModTime);
    448670    if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
    449671        return VERR_TAR_NUM_VALUE_TOO_LARGE;
    450     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode,      pTar->Posix.mode);
     672    GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode,      pThis->Hdr.Common.mode);
    451673    pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
    452     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pTar->Posix.uid);
    453     GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pTar->Posix.gid);
     674    GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pThis->Hdr.Common.uid);
     675    GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pThis->Hdr.Common.gid);
    454676    pObjInfo->Attr.u.Unix.cHardlinks    = 1;
    455677    pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
     
    458680    pObjInfo->Attr.u.Unix.GenerationId  = 0;
    459681    pObjInfo->Attr.u.Unix.Device        = 0;
    460     if (   pTar->Posix.typeflag == RTZIPTAR_TF_CHR
    461         || pTar->Posix.typeflag == RTZIPTAR_TF_BLK)
    462     {
    463         uint32_t uMajor, uMinor;
    464         GET_TAR_NUMERIC_FIELD_RET(uMajor,               pTar->Posix.devmajor);
    465         GET_TAR_NUMERIC_FIELD_RET(uMinor,               pTar->Posix.devminor);
    466         pObjInfo->Attr.u.Unix.Device    = RTDEV_MAKE(uMajor, uMinor);
    467         if (   uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
    468             || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
    469             return VERR_TAR_DEV_VALUE_TOO_LARGE;
     682    switch (pThis->enmType)
     683    {
     684        case RTZIPTARTYPE_POSIX:
     685        case RTZIPTARTYPE_GNU:
     686            if (   pThis->Hdr.Common.typeflag == RTZIPTAR_TF_CHR
     687                || pThis->Hdr.Common.typeflag == RTZIPTAR_TF_BLK)
     688            {
     689                uint32_t uMajor, uMinor;
     690                GET_TAR_NUMERIC_FIELD_RET(uMajor,        pThis->Hdr.Common.devmajor);
     691                GET_TAR_NUMERIC_FIELD_RET(uMinor,        pThis->Hdr.Common.devminor);
     692                pObjInfo->Attr.u.Unix.Device    = RTDEV_MAKE(uMajor, uMinor);
     693                if (   uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
     694                    || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
     695                    return VERR_TAR_DEV_VALUE_TOO_LARGE;
     696            }
     697            break;
     698
     699        default:
     700            if (   pThis->Hdr.Common.typeflag == RTZIPTAR_TF_CHR
     701                || pThis->Hdr.Common.typeflag == RTZIPTAR_TF_BLK)
     702                return VERR_TAR_UNKNOWN_TYPE_FLAG;
    470703    }
    471704
     
    476709     * Also validate some more now that we've got the numbers to work with.
    477710     */
    478     if (pObjInfo->Attr.fMode & ~RTFS_UNIX_MASK)
     711    if (   (pObjInfo->Attr.fMode & ~RTFS_UNIX_MASK)
     712        && pThis->enmType == RTZIPTARTYPE_POSIX)
    479713        return VERR_TAR_BAD_MODE_FIELD;
     714    pObjInfo->Attr.fMode &= RTFS_UNIX_MASK;
    480715
    481716    RTFMODE fModeType = 0;
    482     switch (pTar->Posix.typeflag)
     717    switch (pThis->Hdr.Common.typeflag)
    483718    {
    484719        case RTZIPTAR_TF_OLDNORMAL:
    485720        case RTZIPTAR_TF_NORMAL:
    486721        case RTZIPTAR_TF_CONTIG:
    487             fModeType |= RTFS_TYPE_FILE;
    488             break;
     722        {
     723            const char *pszEnd = strchr(pThis->szName, '\0');
     724            if (pszEnd == &pThis->szName[0] || pszEnd[-1] != '/')
     725                fModeType |= RTFS_TYPE_FILE;
     726            else
     727                fModeType |= RTFS_TYPE_DIRECTORY;
     728            break;
     729        }
    489730
    490731        case RTZIPTAR_TF_LINK:
    491732            if (pObjInfo->cbObject != 0)
     733#if 0 /* too strict */
    492734                return VERR_TAR_SIZE_NOT_ZERO;
     735#else
     736                pObjInfo->cbObject = pObjInfo->cbAllocated = 0;
     737#endif
    493738            fModeType |= RTFS_TYPE_FILE; /* no better idea for now */
    494739            break;
     
    513758            fModeType |= RTFS_TYPE_FIFO;
    514759            break;
     760
     761        case RTZIPTAR_TF_GNU_LONGLINK:
     762        case RTZIPTAR_TF_GNU_LONGNAME:
     763            /* ASSUMES RTFS_TYPE_XXX uses the same values as GNU stored in the mode field. */
     764            fModeType = pObjInfo->Attr.fMode & RTFS_TYPE_MASK;
     765            switch (fModeType)
     766            {
     767                case RTFS_TYPE_FILE:
     768                case RTFS_TYPE_DIRECTORY:
     769                case RTFS_TYPE_SYMLINK:
     770                case RTFS_TYPE_DEV_BLOCK:
     771                case RTFS_TYPE_DEV_CHAR:
     772                case RTFS_TYPE_FIFO:
     773                    break;
     774
     775                default:
     776                case 0:
     777                    return VERR_TAR_UNKNOWN_TYPE_FLAG; /** @todo new status code */
     778            }
    515779
    516780        default:
     
    520784        && (pObjInfo->Attr.fMode & RTFS_TYPE_MASK) != fModeType)
    521785        return VERR_TAR_MODE_WITH_TYPE;
     786    pObjInfo->Attr.fMode &= ~RTFS_TYPE_MASK;
    522787    pObjInfo->Attr.fMode |= fModeType;
    523788
    524     switch (pTar->Posix.typeflag)
     789    switch (pThis->Hdr.Common.typeflag)
    525790    {
    526791        case RTZIPTAR_TF_CHR:
     
    537802
    538803
     804/**
     805 * Checks if the reader is expecting more headers.
     806 *
     807 * @returns true / false.
     808 * @param   pThis               The TAR reader instance.
     809 */
     810static bool rtZipTarReaderExpectingMoreHeaders(PRTZIPTARREADER pThis)
     811{
     812    return pThis->enmState != RTZIPTARREADERSTATE_FIRST;
     813}
     814
     815
     816/**
     817 * Checks if we're at the end of the TAR file.
     818 *
     819 * @returns true / false.
     820 * @param   pThis               The TAR reader instance.
     821 */
     822static bool rtZipTarReaderIsAtEnd(PRTZIPTARREADER pThis)
     823{
     824    if (!pThis->cZeroHdrs)
     825        return false;
     826
     827    /* Here is a kludge to try deal with archivers not putting at least two
     828       zero headers at the end.  Afraid it may require further relaxing
     829       later on, but let's try be strict about things for now. */
     830    return pThis->cZeroHdrs >= (pThis->enmPrevType == RTZIPTARTYPE_POSIX ? 2 : 1);
     831}
     832
     833
     834/**
     835 * Checks if the current TAR object is a hard link or not.
     836 *
     837 * @returns true if it is, false if not.
     838 * @param   pThis               The TAR reader instance.
     839 */
     840static bool rtZipTarReaderIsHardlink(PRTZIPTARREADER pThis)
     841{
     842    return pThis->Hdr.Common.typeflag == RTZIPTAR_TF_LINK;
     843}
     844
     845
     846/**
     847 * Checks if the TAR header includes a POSIX or GNU user name field.
     848 *
     849 * @returns true / false.
     850 * @param   pThis               The TAR reader instance.
     851 */
     852DECLINLINE(bool) rtZipTarReaderHasUserName(PRTZIPTARREADER pThis)
     853{
     854    return pThis->Hdr.Common.uname[0] != '\0'
     855        && (   pThis->enmType == RTZIPTARTYPE_POSIX
     856            || pThis->enmType == RTZIPTARTYPE_GNU);
     857}
     858
     859
     860/**
     861 * Checks if the TAR header includes a POSIX or GNU group name field.
     862 *
     863 * @returns true / false.
     864 * @param   pThis               The TAR reader instance.
     865 */
     866DECLINLINE(bool) rtZipTarReaderHasGroupName(PRTZIPTARREADER pThis)
     867{
     868    return pThis->Hdr.Common.gname[0] != '\0'
     869        && (   pThis->enmType == RTZIPTARTYPE_POSIX
     870            || pThis->enmType == RTZIPTARTYPE_GNU);
     871}
     872
     873
    539874/*
    540875 *
     
    581916            pObjInfo->Attr.u.UnixOwner.uid       = pThis->ObjInfo.Attr.u.Unix.uid;
    582917            pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
    583             if (rtZipTarHdrHasPosixUserName(&pThis->Hdr))
    584                 RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName), pThis->Hdr.Posix.uname);
     918            if (rtZipTarReaderHasUserName(pThis->pTarReader))
     919                RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName),
     920                          pThis->pTarReader->Hdr.Common.uname);
    585921            break;
    586922
     
    590926            pObjInfo->Attr.u.UnixGroup.gid       = pThis->ObjInfo.Attr.u.Unix.gid;
    591927            pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
    592             if (rtZipTarHdrHasPosixGroupName(&pThis->Hdr))
    593                 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName), pThis->Hdr.Posix.gname);
     928            if (rtZipTarReaderHasGroupName(pThis->pTarReader))
     929                RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),
     930                          pThis->pTarReader->Hdr.Common.gname);
    594931            break;
    595932
     
    8671204{
    8681205    PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
    869     return RTStrCopy(pszTarget, cbTarget, pThis->Hdr.Posix.linkname);
     1206    return RTStrCopy(pszTarget, cbTarget, pThis->pTarReader->szTarget);
    8701207}
    8711208
     
    9631300     * Make sure the input stream is in the right place.
    9641301     */
    965     RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos);
    966     while (   off >= 0
    967            && off < pThis->offNextHdr)
    968     {
    969         int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - off);
     1302    RTFOFF offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
     1303    while (   offHdr >= 0
     1304           && offHdr < pThis->offNextHdr)
     1305    {
     1306        int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - offHdr);
    9701307        if (RT_FAILURE(rc))
    9711308        {
     
    9741311        }
    9751312
    976         off = RTVfsIoStrmTell(pThis->hVfsIos);
    977     }
    978 
    979     if (off < 0)
    980         return pThis->rcFatal = (int)off;
    981     if (off > pThis->offNextHdr)
     1313        offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
     1314    }
     1315
     1316    if (offHdr < 0)
     1317        return pThis->rcFatal = (int)offHdr;
     1318    if (offHdr > pThis->offNextHdr)
    9821319        return pThis->rcFatal = VERR_INTERNAL_ERROR_3;
    9831320
    9841321    /*
    985      * Read the next header.
    986      */
    987     size_t      cbRead;
    988     RTZIPTARHDR Hdr;
    989     int rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
     1322     * Consume TAR headers.
     1323     */
     1324    size_t cbHdrs = 0;
     1325    int rc;
     1326    do
     1327    {
     1328        /*
     1329         * Read the next header.
     1330         */
     1331        RTZIPTARHDR Hdr;
     1332        size_t cbRead;
     1333        rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
     1334        if (RT_FAILURE(rc))
     1335            return pThis->rcFatal = rc;
     1336        if (rc == VINF_EOF && cbRead == 0)
     1337        {
     1338            pThis->fEndOfStream = true;
     1339            return rtZipTarReaderIsAtEnd(&pThis->TarReader) ? VERR_EOF : VERR_TAR_UNEXPECTED_EOS;
     1340        }
     1341        if (cbRead != sizeof(Hdr))
     1342            return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
     1343
     1344        cbHdrs += sizeof(Hdr);
     1345
     1346        /*
     1347         * Parse the it.
     1348         */
     1349        rc = rtZipTarReaderParseHeader(&pThis->TarReader, &Hdr);
     1350        if (RT_FAILURE(rc))
     1351            return pThis->rcFatal = rc;
     1352    } while (rtZipTarReaderExpectingMoreHeaders(&pThis->TarReader));
     1353
     1354    pThis->offNextHdr = offHdr + cbHdrs;
     1355
     1356    /*
     1357     * Fill an object info structure from the current TAR state.
     1358     */
     1359    RTFSOBJINFO Info;
     1360    rc = rtZipTarReaderGetFsObjInfo(&pThis->TarReader, &Info);
    9901361    if (RT_FAILURE(rc))
    9911362        return pThis->rcFatal = rc;
    992     if (rc == VINF_EOF && cbRead == 0)
    993     {
    994         pThis->fEndOfStream = true;
    995         return VERR_EOF;
    996     }
    997     if (cbRead != sizeof(Hdr))
    998         return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
    999 
    1000     pThis->offNextHdr = off + sizeof(Hdr);
    1001 
    1002     /*
    1003      * Validate the header and convert to binary object info.
    1004      * We pick up the start of the zero headers here in the failure path.
    1005      */
    1006     RTZIPTARTYPE enmTarType;
    1007     rc = rtZipTarHdrValidate(&Hdr, &enmTarType);
    1008     if (RT_FAILURE_NP(rc))
    1009     {
    1010         if (rc == VERR_TAR_ZERO_HEADER)
    1011         {
    1012             int rc2 = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
    1013             if (RT_FAILURE(rc2))
    1014                 return pThis->rcFatal = rc2;
    1015             if (ASMMemIsAllU32(&Hdr, sizeof(Hdr), 0) == NULL)
    1016             {
    1017                 pThis->fEndOfStream = true;
    1018                 if (RTVfsIoStrmIsAtEnd(pThis->hVfsIos))
    1019                     return VERR_EOF;
    1020 
    1021                 /* Just drain the stream because blocksize may dictate that
    1022                    there is a whole bunch of stuff comming up. */
    1023                 for (uint32_t i = 0; i < _32K / 512; i++)
    1024                 {
    1025                     rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
    1026                     if (rc == VINF_EOF)
    1027                         return VERR_EOF;
    1028                     if (RT_FAILURE(rc))
    1029                         break;
    1030                     Assert(cbRead == sizeof(Hdr));
    1031                 }
    1032             }
    1033         }
    1034 
    1035         return pThis->rcFatal = rc;
    1036     }
    1037 
    1038     RTFSOBJINFO Info;
    1039     rc = rtZipTarHdrToFsObjInfo(&Hdr, &Info);
    1040     if (RT_FAILURE(rc))
    1041         return pThis->rcFatal = rc;
    10421363
    10431364    /*
     
    10461367    RTVFSOBJTYPE    enmType;
    10471368    RTVFSOBJ        hVfsObj;
    1048     switch (Hdr.Posix.typeflag)
     1369    RTFMODE         fType = Info.Attr.fMode & RTFS_TYPE_MASK;
     1370    if (rtZipTarReaderIsHardlink(&pThis->TarReader))
     1371        fType = RTFS_TYPE_SYMLINK;
     1372    switch (fType)
    10491373    {
    10501374        /*
    10511375         * Files are represented by a VFS I/O stream.
    10521376         */
    1053         case RTZIPTAR_TF_NORMAL:
    1054         case RTZIPTAR_TF_OLDNORMAL:
    1055         case RTZIPTAR_TF_CONTIG:
     1377        case RTFS_TYPE_FILE:
    10561378        {
    10571379            RTVFSIOSTREAM       hVfsIos;
     
    10671389                return pThis->rcFatal = rc;
    10681390
    1069             pIosData->BaseObj.offHdr  = off;
    1070             pIosData->BaseObj.Hdr     = Hdr;
    1071             pIosData->BaseObj.ObjInfo = Info;
    1072             pIosData->cbFile          = Info.cbObject;
    1073             pIosData->offFile         = 0;
    1074             pIosData->cbPadding       = Info.cbAllocated - Info.cbObject;
    1075             pIosData->fEndOfStream    = false;
    1076             pIosData->hVfsIos         = pThis->hVfsIos;
     1391            pIosData->BaseObj.offHdr    = offHdr;
     1392            pIosData->BaseObj.pTarReader= &pThis->TarReader;
     1393            pIosData->BaseObj.ObjInfo   = Info;
     1394            pIosData->cbFile            = Info.cbObject;
     1395            pIosData->offFile           = 0;
     1396            pIosData->cbPadding         = Info.cbAllocated - Info.cbObject;
     1397            pIosData->fEndOfStream      = false;
     1398            pIosData->hVfsIos           = pThis->hVfsIos;
    10771399            RTVfsIoStrmRetain(pThis->hVfsIos);
    10781400
     
    10911413         * fitting VFS type alternative.
    10921414         */
    1093         case RTZIPTAR_TF_LINK:
    1094         case RTZIPTAR_TF_SYMLINK:
     1415        case RTFS_TYPE_SYMLINK:
    10951416        {
    10961417            RTVFSSYMLINK        hVfsSym;
     
    11051426                return pThis->rcFatal = rc;
    11061427
    1107             pBaseObjData->offHdr  = off;
    1108             pBaseObjData->Hdr     = Hdr;
    1109             pBaseObjData->ObjInfo = Info;
     1428            pBaseObjData->offHdr    = offHdr;
     1429            pBaseObjData->pTarReader= &pThis->TarReader;
     1430            pBaseObjData->ObjInfo   = Info;
    11101431
    11111432            enmType = RTVFSOBJTYPE_SYMLINK;
     
    11171438        /*
    11181439         * All other objects are repesented using a VFS base object since they
    1119          * carry no data streams (unless some tar extension implements extended
     1440         * carry no data streams (unless some TAR extension implements extended
    11201441         * attributes / alternative streams).
    11211442         */
    1122         case RTZIPTAR_TF_CHR:
    1123         case RTZIPTAR_TF_BLK:
    1124         case RTZIPTAR_TF_DIR:
    1125         case RTZIPTAR_TF_FIFO:
     1443        case RTFS_TYPE_DEV_BLOCK:
     1444        case RTFS_TYPE_DEV_CHAR:
     1445        case RTFS_TYPE_DIRECTORY:
     1446        case RTFS_TYPE_FIFO:
    11261447        {
    11271448            PRTZIPTARBASEOBJ pBaseObjData;
     
    11351456                return pThis->rcFatal = rc;
    11361457
    1137             pBaseObjData->offHdr  = off;
    1138             pBaseObjData->Hdr     = Hdr;
    1139             pBaseObjData->ObjInfo = Info;
     1458            pBaseObjData->offHdr    = offHdr;
     1459            pBaseObjData->pTarReader= &pThis->TarReader;
     1460            pBaseObjData->ObjInfo   = Info;
    11401461
    11411462            enmType = RTVFSOBJTYPE_BASE;
     
    11541475    if (ppszName)
    11551476    {
    1156         if (rtZipTarHdrHasPrefix(&Hdr))
    1157         {
    1158             *ppszName = NULL;
    1159             rc = RTStrAAppendExN(ppszName, 3,
    1160                                  Hdr.Posix.prefix, sizeof(Hdr.Posix.prefix),
    1161                                  "/", 1,
    1162                                  Hdr.Posix.name, sizeof(Hdr.Posix.name));
    1163         }
    1164         else
    1165         {
    1166             *ppszName = RTStrDupN(Hdr.Posix.name, sizeof(Hdr.Posix.name));
    1167             rc = *ppszName ? VINF_SUCCESS : VERR_NO_STR_MEMORY;
    1168         }
     1477        rc = RTStrDupEx(ppszName, pThis->TarReader.szName);
    11691478        if (RT_FAILURE(rc))
    11701479            return rc;
     
    12291538    if (RT_SUCCESS(rc))
    12301539    {
    1231         pThis->hVfsIos          = hVfsIosIn;
    1232         pThis->hVfsCurObj       = NIL_RTVFSOBJ;
    1233         pThis->pCurIosData      = NULL;
    1234         pThis->offStart         = offStart;
    1235         pThis->offNextHdr       = offStart;
    1236         pThis->fEndOfStream     = false;
    1237         pThis->rcFatal          = VINF_SUCCESS;
     1540        pThis->hVfsIos              = hVfsIosIn;
     1541        pThis->hVfsCurObj           = NIL_RTVFSOBJ;
     1542        pThis->pCurIosData          = NULL;
     1543        pThis->offStart             = offStart;
     1544        pThis->offNextHdr           = offStart;
     1545        pThis->fEndOfStream         = false;
     1546        pThis->rcFatal              = VINF_SUCCESS;
     1547        pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID;
     1548        pThis->TarReader.enmType    = RTZIPTARTYPE_INVALID;
     1549        pThis->TarReader.enmState   = RTZIPTARREADERSTATE_FIRST;
    12381550
    12391551        /* Don't check if it's a TAR stream here, do that in the
Note: See TracChangeset for help on using the changeset viewer.

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