VirtualBox

Changeset 48838 in vbox


Ignore:
Timestamp:
Oct 3, 2013 1:42:45 PM (11 years ago)
Author:
vboxsync
Message:

More or less usable XAR reader.

Location:
trunk
Files:
2 edited

Legend:

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

    r48797 r48838  
    18401840/** Bad size element in table of content sub-element. */
    18411841#define VERR_XAR_BAD_SIZE_ELEMENT                   (-22721)
     1842/** Missing length element in table of content sub-element. */
     1843#define VERR_XAR_MISSING_LENGTH_ELEMENT             (-22722)
     1844/** Bad length element in table of content sub-element. */
     1845#define VERR_XAR_BAD_LENGTH_ELEMENT                 (-22723)
    18421846/** Bad file element in XAR table of content. */
    1843 #define VERR_XAR_BAD_FILE_ELEMENT                   (-22722)
    1844 /** An data element is expected for XAR file of type file. */
    1845 #define VERR_XAR_DATA_NODE_NOT_FOUND                (-22723)
     1847#define VERR_XAR_BAD_FILE_ELEMENT                   (-22724)
     1848/** Missing data element for XAR file. */
     1849#define VERR_XAR_MISSING_DATA_ELEMENT               (-22725)
    18461850/** Unknown XAR file type value. */
    1847 #define VERR_XAR_BAD_UNKNOWN_FILE_TYPE              (-22724)
     1851#define VERR_XAR_UNKNOWN_FILE_TYPE                  (-22726)
     1852/** Missing encoding element for XAR data stream. */
     1853#define VERR_XAR_NO_ENCODING                        (-22727)
     1854/** Bad timestamp for XAR file. */
     1855#define VERR_XAR_BAD_FILE_TIMESTAMP                 (-22728)
     1856/** Bad file mode for XAR file. */
     1857#define VERR_XAR_BAD_FILE_MODE                      (-22729)
     1858/** Bad file user id for XAR file. */
     1859#define VERR_XAR_BAD_FILE_UID                       (-22730)
     1860/** Bad file group id for XAR file. */
     1861#define VERR_XAR_BAD_FILE_GID                       (-22731)
     1862/** Bad file inode device number for XAR file. */
     1863#define VERR_XAR_BAD_FILE_DEVICE_NO                 (-22732)
     1864/** Bad file inode number for XAR file. */
     1865#define VERR_XAR_BAD_FILE_INODE                     (-22733)
     1866/** Invalid name for XAR file. */
     1867#define VERR_XAR_INVALID_FILE_NAME                  (-22734)
     1868/** The message digest of the extracted data does not match the one supplied. */
     1869#define VERR_XAR_EXTRACTED_HASH_MISMATCH            (-22735)
     1870/** The extracted data has exceeded the expected size. */
     1871#define VERR_XAR_EXTRACTED_SIZE_EXCEEDED            (-22736)
     1872/** The message digest of the archived data does not match the one supplied. */
     1873#define VERR_XAR_ARCHIVED_HASH_MISMATCH             (-22737)
     1874/** The decompressor completed without using all the input data. */
     1875#define VERR_XAR_UNUSED_ARCHIVED_DATA               (-22738)
     1876/** Expected the archived and extracted XAR data sizes to be the same for
     1877 * uncompressed data. */
     1878#define VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH (-22739)
    18481879/** @} */
    18491880
  • trunk/src/VBox/Runtime/common/zip/xarvfs.cpp

    r48797 r48838  
    4747
    4848
     49/*******************************************************************************
     50*   Defined Constants And Macros                                               *
     51*******************************************************************************/
     52/** @name Hash state
     53 * @{ */
     54#define RTZIPXAR_HASH_PENDING           0
     55#define RTZIPXAR_HASH_OK                1
     56#define RTZIPXAR_HASH_FAILED_ARCHIVED   2
     57#define RTZIPXAR_HASH_FAILED_EXTRACTED  3
     58/** @} */
     59
    4960
    5061/*******************************************************************************
     
    5364/**
    5465 * Hash digest value union for the supported XAR hash functions.
     66 * @todo This could be generalized in iprt/checksum.h or somewhere.
    5567 */
    5668typedef union RTZIPXARHASHDIGEST
     
    6577
    6678/**
     79 * Hash context union.
     80 */
     81typedef union RTZIPXARHASHCTX
     82{
     83    RTMD5CONTEXT    Md5;
     84    RTSHA1CONTEXT   Sha1;
     85} RTZIPXARHASHCTX;
     86/** Pointer to a hash context union. */
     87typedef RTZIPXARHASHCTX *PRTZIPXARHASHCTX;
     88
     89/**
    6790 * XAR reader instance data.
    6891 */
     
    78101    /** The depth of the current file, with 0 being the root level. */
    79102    uint32_t                cCurDepth;
    80     /** Set if it's the first file. */
    81     bool                    fFirstFile;
    82103} RTZIPXARREADER;
    83104/** Pointer to the XAR reader instance data. */
     
    89110typedef struct RTZIPXARBASEOBJ
    90111{
    91     /** Pointer to the reader instance data (resides in the filesystem
    92      * stream).
    93      * @todo Fix this so it won't go stale... Back ref from this obj to fss? */
    94     PRTZIPXARREADER         pXarReader;
    95112    /** The file TOC element. */
    96113    xml::ElementNode const *pFileElem;
     114    /** RTFS_TYPE_XXX value for the object. */
     115    RTFMODE                 fModeType;
    97116} RTZIPXARBASEOBJ;
    98117/** Pointer to a XAR filesystem stream base object. */
     
    118137typedef struct RTZIPXARDATASTREAM
    119138{
    120     /** Offset of the data in the stream, relative to XARREADER::offZero. */
     139    /** Offset of the data in the stream.
     140     * @remarks The I/O stream and file constructor will adjust this so that it
     141     *          relative to the start of the input stream, instead of the first byte
     142     *          after the TOC. */
    121143    RTFOFF                  offData;
    122144    /** The size of the archived data. */
    123     RTFOFF                  cbDataArchived;
     145    uint64_t                cbDataArchived;
    124146    /** The size of the extracted data. */
    125     RTFOFF                  cbDataExtracted;
     147    uint64_t                cbDataExtracted;
    126148    /** The encoding of the archived ata. */
    127149    RTZIPXARENCODING        enmEncoding;
     
    147169    RTZIPXARBASEOBJ         BaseObj;
    148170    /** The attributes of the primary data stream. */
    149     RTZIPXARDATASTREAM      Data;
    150     /** The current file position. */
    151     RTFOFF                  offFile;
     171    RTZIPXARDATASTREAM      DataAttr;
     172    /** The current file position in the archived file. */
     173    RTFOFF                  offCurPos;
    152174    /** The input I/O stream. */
    153175    RTVFSIOSTREAM           hVfsIos;
    154     /** Set if we've reached the end of the file. */
     176    /** Set if we've reached the end of the file or if the next object in the
     177     * file system stream has been requested. */
    155178    bool                    fEndOfStream;
     179    /** Whether the stream is seekable. */
     180    bool                    fSeekable;
     181    /** Hash state. */
     182    uint8_t                 uHashState;
    156183    /** The size of the file that we've currently hashed.
    157184     * We use this to check whether the user skips part of the file while reading
     
    159186    RTFOFF                  cbDigested;
    160187    /** The digest of the archived data. */
    161     RTZIPXARHASHDIGEST      DigestArchived;
     188    RTZIPXARHASHCTX         CtxArchived;
    162189    /** The digest of the extracted data. */
    163     RTZIPXARHASHDIGEST      DigestExtracted;
     190    RTZIPXARHASHCTX         CtxExtracted;
    164191} RTZIPXARIOSTREAM;
    165192/** Pointer to a the private data of a XAR file I/O stream. */
     
    172199typedef struct RTZIPXARFILE
    173200{
    174     /** The XAR I/O stream object. */
    175     RTZIPXARIOSTREAM        IosObj;
     201    /** The XAR I/O stream data. */
     202    RTZIPXARIOSTREAM        Ios;
    176203    /** The input file. */
    177204    RTVFSFILE               hVfsFile;
    178205} RTZIPXARFILE;
    179 /** Pointer to a the private data of a XAR file. */
     206/** Pointer to the private data of a XAR file. */
    180207typedef RTZIPXARFILE *PRTZIPXARFILE;
     208
     209
     210/**
     211 * Decompressed I/O stream instance.
     212 *
     213 * This is just a front that checks digests and other sanity stuff.
     214 */
     215typedef struct RTZIPXARDECOMPIOS
     216{
     217    /** The decompressor I/O stream. */
     218    RTVFSIOSTREAM           hVfsIosDecompressor;
     219    /** The raw XAR I/O stream. */
     220    RTVFSIOSTREAM           hVfsIosRaw;
     221    /** Pointer to the raw XAR I/O stream instance data. */
     222    PRTZIPXARIOSTREAM       pIosRaw;
     223    /** The current file position in the archived file. */
     224    RTFOFF                  offCurPos;
     225    /** The hash function to use on the extracted data. */
     226    uint8_t                 uHashFunExtracted;
     227    /** Hash state on the extracted data. */
     228    uint8_t                 uHashState;
     229    /** The digest of the extracted data. */
     230    RTZIPXARHASHCTX         CtxExtracted;
     231    /** The expected digest of the extracted data. */
     232    RTZIPXARHASHDIGEST      DigestExtracted;
     233} RTZIPXARDECOMPIOS;
     234/** Pointer to the private data of a XAR decompressed I/O stream. */
     235typedef RTZIPXARDECOMPIOS *PRTZIPXARDECOMPIOS;
    181236
    182237
     
    190245    /** The input file, if the stream is actually a file. */
    191246    RTVFSFILE               hVfsFile;
    192 
    193     /** The current object (referenced). */
    194     RTVFSOBJ                hVfsCurObj;
    195     /** Pointer to the private data if hVfsCurObj is representing a file. */
    196     PRTZIPXARIOSTREAM       pCurIosData;
    197247
    198248    /** The start offset in the input I/O stream. */
     
    225275 * @param   pvSrc           The data to hash.
    226276 * @param   cbSrc           The size of the data to hash.
    227  * @param   pHashDigest     Where to return the hash digest.
     277 * @param   pHashDigest     Where to return the message digest.
    228278 */
    229279static void rtZipXarCalcHash(uint32_t uHashFunction, void const *pvSrc, size_t cbSrc, PRTZIPXARHASHDIGEST pHashDigest)
     
    244294
    245295
    246 static int rtZipXarGetOffsetSizeFromElem(xml::ElementNode const *pElement, PRTFOFF poff, uint64_t *pcb)
    247 {
    248     if (pElement)
    249         return VERR_XAR_DATA_NODE_NOT_FOUND;
    250 
     296/**
     297 * Initializes a hash context.
     298 *
     299 * @param   pCtx            Pointer to the context union.
     300 * @param   uHashFunction   The hash function to use.
     301 */
     302static void rtZipXarHashInit(PRTZIPXARHASHCTX pCtx, uint32_t uHashFunction)
     303{
     304    switch (uHashFunction)
     305    {
     306        case XAR_HASH_SHA1:
     307            RTSha1Init(&pCtx->Sha1);
     308            break;
     309        case XAR_HASH_MD5:
     310            RTMd5Init(&pCtx->Md5);;
     311            break;
     312        default:
     313            RT_ZERO(*pCtx);
     314            break;
     315    }
     316}
     317
     318
     319/**
     320 * Adds a block to the hash calculation.
     321 *
     322 * @param   pCtx            Pointer to the context union.
     323 * @param   uHashFunction   The hash function to use.
     324 * @param   pvSrc           The data to add to the hash.
     325 * @param   cbSrc           The size of the data.
     326 */
     327static void rtZipXarHashUpdate(PRTZIPXARHASHCTX pCtx, uint32_t uHashFunction, void const *pvSrc, size_t cbSrc)
     328{
     329    switch (uHashFunction)
     330    {
     331        case XAR_HASH_SHA1:
     332            RTSha1Update(&pCtx->Sha1, pvSrc, cbSrc);
     333            break;
     334        case XAR_HASH_MD5:
     335            RTMd5Update(&pCtx->Md5, pvSrc, cbSrc);
     336            break;
     337    }
     338}
     339
     340
     341/**
     342 * Finalizes the hash, producing the message digest.
     343 *
     344 * @param   pCtx            Pointer to the context union.
     345 * @param   uHashFunction   The hash function to use.
     346 * @param   pHashDigest     Where to return the message digest.
     347 */
     348static void rtZipXarHashFinal(PRTZIPXARHASHCTX pCtx, uint32_t uHashFunction, PRTZIPXARHASHDIGEST pHashDigest)
     349{
     350    switch (uHashFunction)
     351    {
     352        case XAR_HASH_SHA1:
     353            RTSha1Final(&pCtx->Sha1, pHashDigest->abSha1);
     354            break;
     355        case XAR_HASH_MD5:
     356            RTMd5Final(pHashDigest->abMd5, &pCtx->Md5);
     357            break;
     358        default:
     359            RT_ZERO(*pHashDigest);
     360            break;
     361    }
     362}
     363
     364
     365/**
     366 * Compares two hash digests.
     367 *
     368 * @returns true if equal, false if not.
     369 * @param   uHashFunction   The hash function to use.
     370 * @param   pHashDigest1    The first hash digest.
     371 * @param   pHashDigest2    The second hash digest.
     372 */
     373static bool rtZipXarHashIsEqual(uint32_t uHashFunction, PRTZIPXARHASHDIGEST pHashDigest1, PRTZIPXARHASHDIGEST pHashDigest2)
     374{
     375    switch (uHashFunction)
     376    {
     377        case XAR_HASH_SHA1:
     378            return memcmp(pHashDigest1->abSha1, pHashDigest2->abSha1, sizeof(pHashDigest1->abSha1)) == 0;
     379        case XAR_HASH_MD5:
     380            return memcmp(pHashDigest1->abMd5, pHashDigest2->abMd5, sizeof(pHashDigest1->abMd5)) == 0;
     381        default:
     382            return true;
     383    }
     384}
     385
     386
     387/**
     388 * Gets the 'offset', 'size' and optionally 'length' sub elements.
     389 *
     390 * @returns IPRT status code.
     391 * @param   pElement            The parent element.
     392 * @param   poff                Where to return the offset value.
     393 * @param   pcbSize             Where to return the size value.
     394 * @param   pcbLength           Where to return the length value, optional.
     395 */
     396static int rtZipXarGetOffsetSizeLengthFromElem(xml::ElementNode const *pElement,
     397                                               PRTFOFF poff, uint64_t *pcbSize, uint64_t *pcbLength)
     398{
    251399    /*
    252400     * The offset.
     
    267415
    268416    /*
    269      * The size.
     417     * The 'size' stored in the archive.
    270418     */
    271419    pElem = pElement->findChildElement("size");
     
    277425        return VERR_XAR_BAD_SIZE_ELEMENT;
    278426
    279     rc = RTStrToUInt64Full(pszValue, 0, pcb);
     427    rc = RTStrToUInt64Full(pszValue, 0, pcbSize);
    280428    if (   RT_FAILURE(rc)
    281429        || rc == VWRN_NUMBER_TOO_BIG
    282         || *pcb > UINT64_MAX / 2 /* prevent overflow should be use it for calcuations later. */)
     430        || *pcbSize >= UINT64_MAX / 2 /* prevent overflow casting to RTFOFF_MAX. */)
    283431        return VERR_XAR_BAD_SIZE_ELEMENT;
     432    AssertCompile(RTFOFF_MAX == UINT64_MAX / 2);
     433
     434    /*
     435     * The 'length' of the uncompressed data.  Not present for checksums, so
     436     * the caller might not want it.
     437     */
     438    if (pcbLength)
     439    {
     440        pElem = pElement->findChildElement("length");
     441        if (!pElem)
     442            return VERR_XAR_MISSING_LENGTH_ELEMENT;
     443
     444        pszValue = pElem->getValue();
     445        if (!pszValue)
     446            return VERR_XAR_BAD_LENGTH_ELEMENT;
     447
     448        rc = RTStrToUInt64Full(pszValue, 0, pcbLength);
     449        if (   RT_FAILURE(rc)
     450            || rc == VWRN_NUMBER_TOO_BIG
     451            || *pcbLength >= UINT64_MAX / 2 /* prevent overflow casting to RTFOFF_MAX. */)
     452            return VERR_XAR_BAD_LENGTH_ELEMENT;
     453        AssertCompile(RTFOFF_MAX == UINT64_MAX / 2);
     454    }
    284455
    285456    return VINF_SUCCESS;
     
    288459
    289460/**
    290  * Translate a XAR header to an IPRT object info structure with additional UNIX
    291  * attributes.
    292  *
    293  * This completes the validation done by rtZipXarHdrValidate.
    294  *
    295  * @returns VINF_SUCCESS if valid, appropriate VERR_XAR_XXX if not.
    296  * @param   pThis               The XAR reader instance.
    297  * @param   pObjInfo            The object info structure (output).
    298  */
    299 static int rtZipXarReaderGetFsObjInfo(PRTZIPXARREADER pThis, PRTFSOBJINFO pObjInfo)
    300 {
    301     /*
    302      * Zap the whole structure, this takes care of unused space in the union.
    303      */
    304     RT_ZERO(*pObjInfo);
    305 
    306 #if 0
    307     /*
    308      * Convert the XAR field in RTFSOBJINFO order.
    309      */
    310     int         rc;
    311     int64_t     i64Tmp;
    312 #define GET_XAR_NUMERIC_FIELD_RET(a_Var, a_Field) \
    313         do { \
    314             rc = rtZipXarHdrFieldToNum(a_Field, sizeof(a_Field), false /*fOctalOnly*/, &i64Tmp); \
    315             if (RT_FAILURE(rc)) \
    316                 return rc; \
    317             (a_Var) = i64Tmp; \
    318             if ((a_Var) != i64Tmp) \
    319                 return VERR_XAR_NUM_VALUE_TOO_LARGE; \
    320         } while (0)
    321 
    322     GET_XAR_NUMERIC_FIELD_RET(pObjInfo->cbObject,        pThis->Hdr.Common.size);
    323     pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 512);
    324     int64_t c64SecModTime;
    325     GET_XAR_NUMERIC_FIELD_RET(c64SecModTime,             pThis->Hdr.Common.mtime);
    326     RTTimeSpecSetSeconds(&pObjInfo->ChangeTime,          c64SecModTime);
    327     RTTimeSpecSetSeconds(&pObjInfo->ModificationTime,    c64SecModTime);
    328     RTTimeSpecSetSeconds(&pObjInfo->AccessTime,          c64SecModTime);
    329     RTTimeSpecSetSeconds(&pObjInfo->BirthTime,           c64SecModTime);
    330     if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
    331         return VERR_XAR_NUM_VALUE_TOO_LARGE;
    332     GET_XAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode,      pThis->Hdr.Common.mode);
    333     pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
    334     GET_XAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pThis->Hdr.Common.uid);
    335     GET_XAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pThis->Hdr.Common.gid);
    336     pObjInfo->Attr.u.Unix.cHardlinks    = 1;
    337     pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
    338     pObjInfo->Attr.u.Unix.INodeId       = 0;
    339     pObjInfo->Attr.u.Unix.fFlags        = 0;
    340     pObjInfo->Attr.u.Unix.GenerationId  = 0;
    341     pObjInfo->Attr.u.Unix.Device        = 0;
    342     switch (pThis->enmType)
    343     {
    344         case RTZIPXARTYPE_POSIX:
    345         case RTZIPXARTYPE_GNU:
    346             if (   pThis->Hdr.Common.typeflag == RTZIPXAR_TF_CHR
    347                 || pThis->Hdr.Common.typeflag == RTZIPXAR_TF_BLK)
    348             {
    349                 uint32_t uMajor, uMinor;
    350                 GET_XAR_NUMERIC_FIELD_RET(uMajor,        pThis->Hdr.Common.devmajor);
    351                 GET_XAR_NUMERIC_FIELD_RET(uMinor,        pThis->Hdr.Common.devminor);
    352                 pObjInfo->Attr.u.Unix.Device    = RTDEV_MAKE(uMajor, uMinor);
    353                 if (   uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
    354                     || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
    355                     return VERR_XAR_DEV_VALUE_TOO_LARGE;
    356             }
     461 * Convers a checksum style value into a XAR hash function number.
     462 *
     463 * @returns IPRT status code.
     464 * @param   pszStyle        The XAR checksum style.
     465 * @param   puHashFunction  Where to return the hash function number on success.
     466 */
     467static int rtZipXarParseChecksumStyle(const char *pszStyle, uint8_t *puHashFunction)
     468{
     469    if (!strcmp(pszStyle, "sha1"))
     470        *puHashFunction = XAR_HASH_SHA1;
     471    else if (!strcmp(pszStyle, "md5"))
     472        *puHashFunction = XAR_HASH_MD5;
     473    else if (!strcmp(pszStyle, "none"))
     474        *puHashFunction = XAR_HASH_NONE;
     475    else
     476    {
     477        *puHashFunction = UINT8_MAX;
     478        return VERR_XAR_BAD_CHECKSUM_ELEMENT;
     479    }
     480    return VINF_SUCCESS;
     481}
     482
     483
     484/**
     485 * Parses a checksum element typically found under 'data'.
     486 *
     487 * @returns IPRT status code.
     488 * @param   pParentElem     The parent element ('data').
     489 * @param   pszName         The name of the element, like 'checksum-archived' or
     490 *                          'checksum-extracted'.
     491 * @param   puHashFunction  Where to return the XAR hash function number.
     492 * @param   pDigest         Where to return the expected message digest.
     493 */
     494static int rtZipXarParseChecksumElem(xml::ElementNode const *pParentElem, const char *pszName,
     495                                     uint8_t *puHashFunction, PRTZIPXARHASHDIGEST pDigest)
     496{
     497    /* Default is no checksum. */
     498    *puHashFunction = XAR_HASH_NONE;
     499    RT_ZERO(*pDigest);
     500
     501    xml::ElementNode const *pChecksumElem = pParentElem->findChildElement(pszName);
     502    if (!pChecksumElem)
     503        return VINF_SUCCESS;
     504
     505    /* The style. */
     506    const char *pszStyle = pChecksumElem->findAttributeValue("style");
     507    if (!pszStyle)
     508        return VERR_XAR_BAD_CHECKSUM_ELEMENT;
     509    int rc = rtZipXarParseChecksumStyle(pszStyle, puHashFunction);
     510    if (RT_FAILURE(rc))
     511        return rc;
     512
     513    if (*puHashFunction == XAR_HASH_NONE)
     514        return VINF_SUCCESS;
     515
     516    /* The digest. */
     517    const char *pszDigest = pChecksumElem->getValue();
     518    if (!pszDigest)
     519        return VERR_XAR_BAD_CHECKSUM_ELEMENT;
     520
     521    switch (*puHashFunction)
     522    {
     523        case XAR_HASH_SHA1:
     524            rc = RTSha1FromString(pszDigest, pDigest->abSha1);
    357525            break;
    358 
     526        case XAR_HASH_MD5:
     527            rc = RTMd5FromString(pszDigest, pDigest->abMd5);
     528            break;
    359529        default:
    360             if (   pThis->Hdr.Common.typeflag == RTZIPXAR_TF_CHR
    361                 || pThis->Hdr.Common.typeflag == RTZIPXAR_TF_BLK)
    362                 return VERR_XAR_UNKNOWN_TYPE_FLAG;
    363     }
    364 
    365 #undef GET_XAR_NUMERIC_FIELD_RET
    366 
    367     /*
    368      * Massage the result a little bit.
    369      * Also validate some more now that we've got the numbers to work with.
    370      */
    371     if (   (pObjInfo->Attr.fMode & ~RTFS_UNIX_MASK)
    372         && pThis->enmType == RTZIPXARTYPE_POSIX)
    373         return VERR_XAR_BAD_MODE_FIELD;
    374     pObjInfo->Attr.fMode &= RTFS_UNIX_MASK;
    375 
    376     RTFMODE fModeType = 0;
    377     switch (pThis->Hdr.Common.typeflag)
    378     {
    379         case RTZIPXAR_TF_OLDNORMAL:
    380         case RTZIPXAR_TF_NORMAL:
    381         case RTZIPXAR_TF_CONTIG:
    382         {
    383             const char *pszEnd = strchr(pThis->szName, '\0');
    384             if (pszEnd == &pThis->szName[0] || pszEnd[-1] != '/')
    385                 fModeType |= RTFS_TYPE_FILE;
    386             else
    387                 fModeType |= RTFS_TYPE_DIRECTORY;
     530            rc = VERR_INTERNAL_ERROR_2;
     531    }
     532    return rc;
     533}
     534
     535
     536/**
     537 * Gets all the attributes of the primary data stream.
     538 *
     539 * @returns IPRT status code.
     540 * @param   pFileElem           The file element, we'll be parsing the 'data'
     541 *                              sub element of this.
     542 * @param   pDataAttr           Where to return the attributes.
     543 */
     544static int rtZipXarGetDataStreamAttributes(xml::ElementNode const *pFileElem, PRTZIPXARDATASTREAM pDataAttr)
     545{
     546    /*
     547     * Get the data element.
     548     */
     549    xml::ElementNode const *pDataElem = pFileElem->findChildElement("data");
     550    if (!pDataElem)
     551        return VERR_XAR_MISSING_DATA_ELEMENT;
     552
     553    /*
     554     * Checksums.
     555     */
     556    int rc = rtZipXarParseChecksumElem(pDataElem, "extracted-checksum",
     557                                       &pDataAttr->uHashFunExtracted, &pDataAttr->DigestExtracted);
     558    if (RT_FAILURE(rc))
     559        return rc;
     560    rc = rtZipXarParseChecksumElem(pDataElem, "archived-checksum",
     561                                   &pDataAttr->uHashFunArchived, &pDataAttr->DigestArchived);
     562    if (RT_FAILURE(rc))
     563        return rc;
     564
     565    /*
     566     * The encoding.
     567     */
     568    const char *pszEncoding = pDataElem->findChildElementAttributeValueP("encoding", "style");
     569    if (!pszEncoding)
     570        return VERR_XAR_NO_ENCODING;
     571    if (!strcmp(pszEncoding, "application/octet-stream"))
     572        pDataAttr->enmEncoding = RTZIPXARENCODING_STORE;
     573    else if (!strcmp(pszEncoding, "application/x-gzip"))
     574        pDataAttr->enmEncoding = RTZIPXARENCODING_GZIP;
     575    else
     576        pDataAttr->enmEncoding = RTZIPXARENCODING_UNSUPPORTED;
     577
     578    /*
     579     * The data offset and the compressed and uncompressed sizes.
     580     */
     581    rc = rtZipXarGetOffsetSizeLengthFromElem(pDataElem, &pDataAttr->offData,
     582                                             &pDataAttr->cbDataExtracted, &pDataAttr->cbDataArchived);
     583    if (RT_FAILURE(rc))
     584        return rc;
     585
     586    /* No zero padding or other alignment crap, please. */
     587    if (   pDataAttr->enmEncoding == RTZIPXARENCODING_STORE
     588        && pDataAttr->cbDataExtracted != pDataAttr->cbDataArchived)
     589        return VERR_XAR_ARCHIVED_AND_EXTRACTED_SIZES_MISMATCH;
     590
     591    return VINF_SUCCESS;
     592}
     593
     594
     595/**
     596 * Parses a timestamp.
     597 *
     598 * We consider all timestamps optional, and will only fail (return @c false) on
     599 * parse errors.  If the specified element isn't found, we'll return epoc time.
     600 *
     601 * @returns boolean success indicator.
     602 * @param   pParent             The parent element (typically 'file').
     603 * @param   pszChild            The name of the child element.
     604 * @param   pTimeSpec           Where to return the timespec on success.
     605 */
     606static bool rtZipXarParseTimestamp(const xml::ElementNode *pParent, const char *pszChild, PRTTIMESPEC pTimeSpec)
     607{
     608    const char *pszValue = pParent->findChildElementValueP(pszChild);
     609    if (pszValue)
     610    {
     611        if (RTTimeSpecFromString(pTimeSpec, pszValue))
     612            return true;
     613        return false;
     614    }
     615    RTTimeSpecSetNano(pTimeSpec, 0);
     616    return true;
     617}
     618
     619
     620/**
     621 * Gets the next file element in the TOC.
     622 *
     623 * @returns Pointer to the next file, NULL if we've reached the end.
     624 * @param   pCurFile            The current element.
     625 * @param   pcCurDepth          Depth gauge we update when decending and
     626 *                              acending thru the tree.
     627 */
     628static xml::ElementNode const *rtZipXarGetNextFileElement(xml::ElementNode const *pCurFile, uint32_t *pcCurDepth)
     629{
     630    /*
     631     * Consider children first.
     632     */
     633    xml::ElementNode const *pChild = pCurFile->findChildElement("file");
     634    if (pChild)
     635    {
     636        *pcCurDepth += 1;
     637        return pChild;
     638    }
     639
     640    /*
     641     * Siblings and ancestor siblings.
     642     */
     643    for (;;)
     644    {
     645        xml::ElementNode const *pSibling = pCurFile->findNextSibilingElement("file");
     646        if (pSibling != NULL)
     647            return pSibling;
     648
     649        if (*pcCurDepth == 0)
    388650            break;
    389         }
    390 
    391         case RTZIPXAR_TF_LINK:
    392             if (pObjInfo->cbObject != 0)
    393 #if 0 /* too strict */
    394                 return VERR_XAR_SIZE_NOT_ZERO;
    395 #else
    396                 pObjInfo->cbObject = pObjInfo->cbAllocated = 0;
    397 #endif
    398             fModeType |= RTFS_TYPE_FILE; /* no better idea for now */
    399             break;
    400 
    401         case RTZIPXAR_TF_SYMLINK:
    402             fModeType |= RTFS_TYPE_SYMLINK;
    403             break;
    404 
    405         case RTZIPXAR_TF_CHR:
    406             fModeType |= RTFS_TYPE_DEV_CHAR;
    407             break;
    408 
    409         case RTZIPXAR_TF_BLK:
    410             fModeType |= RTFS_TYPE_DEV_BLOCK;
    411             break;
    412 
    413         case RTZIPXAR_TF_DIR:
    414             fModeType |= RTFS_TYPE_DIRECTORY;
    415             break;
    416 
    417         case RTZIPXAR_TF_FIFO:
    418             fModeType |= RTFS_TYPE_FIFO;
    419             break;
    420 
    421         case RTZIPXAR_TF_GNU_LONGLINK:
    422         case RTZIPXAR_TF_GNU_LONGNAME:
    423             /* ASSUMES RTFS_TYPE_XXX uses the same values as GNU stored in the mode field. */
    424             fModeType = pObjInfo->Attr.fMode & RTFS_TYPE_MASK;
    425             switch (fModeType)
    426             {
    427                 case RTFS_TYPE_FILE:
    428                 case RTFS_TYPE_DIRECTORY:
    429                 case RTFS_TYPE_SYMLINK:
    430                 case RTFS_TYPE_DEV_BLOCK:
    431                 case RTFS_TYPE_DEV_CHAR:
    432                 case RTFS_TYPE_FIFO:
    433                     break;
    434 
    435                 default:
    436                 case 0:
    437                     return VERR_XAR_UNKNOWN_TYPE_FLAG; /** @todo new status code */
    438             }
    439 
    440         default:
    441             return VERR_XAR_UNKNOWN_TYPE_FLAG; /* Should've been caught in validate. */
    442     }
    443     if (   (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)
    444         && (pObjInfo->Attr.fMode & RTFS_TYPE_MASK) != fModeType)
    445         return VERR_XAR_MODE_WITH_TYPE;
    446     pObjInfo->Attr.fMode &= ~RTFS_TYPE_MASK;
    447     pObjInfo->Attr.fMode |= fModeType;
    448 
    449     switch (pThis->Hdr.Common.typeflag)
    450     {
    451         case RTZIPXAR_TF_CHR:
    452         case RTZIPXAR_TF_BLK:
    453         case RTZIPXAR_TF_DIR:
    454         case RTZIPXAR_TF_FIFO:
    455             pObjInfo->cbObject    = 0;
    456             pObjInfo->cbAllocated = 0;
    457             break;
    458     }
    459 #endif
    460 
    461     return VINF_SUCCESS;
     651        *pcCurDepth -= 1;
     652        pCurFile = static_cast<const xml::ElementNode *>(pCurFile->getParent());
     653        AssertBreak(pCurFile);
     654        Assert(pCurFile->nameEquals("file"));
     655    }
     656
     657    return NULL;
    462658}
    463659
     
    472668 */
    473669
     670
    474671/**
    475672 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
     
    493690    PRTZIPXARBASEOBJ pThis = (PRTZIPXARBASEOBJ)pvThis;
    494691
    495 #if 0
     692    /*
     693     * Get the common data.
     694     */
     695
     696    /* Sizes. */
     697    if (pThis->fModeType == RTFS_TYPE_FILE)
     698    {
     699        PRTZIPXARIOSTREAM pThisIos = RT_FROM_MEMBER(pThis, RTZIPXARIOSTREAM, BaseObj);
     700        pObjInfo->cbObject    = pThisIos->DataAttr.cbDataArchived; /* Modified by decomp ios. */
     701        pObjInfo->cbAllocated = pThisIos->DataAttr.cbDataArchived;
     702    }
     703    else
     704    {
     705        pObjInfo->cbObject    = 0;
     706        pObjInfo->cbAllocated = 0;
     707    }
     708
     709    /* The file mode. */
     710    if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("mode", 0755, &pObjInfo->Attr.fMode)))
     711        return VERR_XAR_BAD_FILE_MODE;
     712    if (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)
     713        return VERR_XAR_BAD_FILE_MODE;
     714    pObjInfo->Attr.fMode &= RTFS_UNIX_MASK & ~RTFS_TYPE_MASK;
     715    pObjInfo->Attr.fMode |= pThis->fModeType;
     716
     717    /* File times. */
     718    if (RT_UNLIKELY(!rtZipXarParseTimestamp(pThis->pFileElem, "atime", &pObjInfo->AccessTime)))
     719        return VERR_XAR_BAD_FILE_TIMESTAMP;
     720    if (RT_UNLIKELY(!rtZipXarParseTimestamp(pThis->pFileElem, "ctime", &pObjInfo->ChangeTime)))
     721        return VERR_XAR_BAD_FILE_TIMESTAMP;
     722    if (RT_UNLIKELY(!rtZipXarParseTimestamp(pThis->pFileElem, "mtime", &pObjInfo->ModificationTime)))
     723        return VERR_XAR_BAD_FILE_TIMESTAMP;
     724    pObjInfo->BirthTime = RTTimeSpecGetNano(&pObjInfo->AccessTime) <= RTTimeSpecGetNano(&pObjInfo->ChangeTime)
     725                        ? pObjInfo->AccessTime : pObjInfo->ChangeTime;
     726    if (RTTimeSpecGetNano(&pObjInfo->BirthTime) > RTTimeSpecGetNano(&pObjInfo->ModificationTime))
     727        pObjInfo->BirthTime = pObjInfo->ModificationTime;
     728
    496729    /*
    497730     * Copy the desired data.
     
    501734        case RTFSOBJATTRADD_NOTHING:
    502735        case RTFSOBJATTRADD_UNIX:
    503             *pObjInfo = pThis->ObjInfo;
     736            pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
     737            if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("uid", 0, &pObjInfo->Attr.u.Unix.uid)))
     738                return VERR_XAR_BAD_FILE_UID;
     739            if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("gid", 0, &pObjInfo->Attr.u.Unix.gid)))
     740                return VERR_XAR_BAD_FILE_GID;
     741            if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("deviceno", 0, &pObjInfo->Attr.u.Unix.INodeIdDevice)))
     742                return VERR_XAR_BAD_FILE_DEVICE_NO;
     743            if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("inode", 0, &pObjInfo->Attr.u.Unix.INodeId)))
     744                return VERR_XAR_BAD_FILE_INODE;
     745            pObjInfo->Attr.u.Unix.cHardlinks    = 1;
     746            pObjInfo->Attr.u.Unix.fFlags        = 0;
     747            pObjInfo->Attr.u.Unix.GenerationId  = 0;
     748            pObjInfo->Attr.u.Unix.Device        = 0;
    504749            break;
    505750
    506751        case RTFSOBJATTRADD_UNIX_OWNER:
    507             *pObjInfo = pThis->ObjInfo;
    508             pObjInfo->Attr.enmAdditional         = RTFSOBJATTRADD_UNIX_OWNER;
    509             pObjInfo->Attr.u.UnixOwner.uid       = pThis->ObjInfo.Attr.u.Unix.uid;
    510             pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
    511             if (rtZipXarReaderHasUserName(pThis->pXarReader))
    512                 RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName),
    513                           pThis->pXarReader->Hdr.Common.uname);
     752        {
     753            pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
     754            if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("uid", 0, &pObjInfo->Attr.u.Unix.uid)))
     755                return VERR_XAR_BAD_FILE_UID;
     756            const char *pszUser = pThis->pFileElem->findChildElementValueP("user");
     757            if (pszUser)
     758                RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName), pszUser);
     759            else
     760                pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
    514761            break;
     762        }
    515763
    516764        case RTFSOBJATTRADD_UNIX_GROUP:
    517             *pObjInfo = pThis->ObjInfo;
    518             pObjInfo->Attr.enmAdditional         = RTFSOBJATTRADD_UNIX_GROUP;
    519             pObjInfo->Attr.u.UnixGroup.gid       = pThis->ObjInfo.Attr.u.Unix.gid;
    520             pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
    521             if (rtZipXarReaderHasGroupName(pThis->pXarReader))
    522                 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),
    523                           pThis->pXarReader->Hdr.Common.gname);
     765        {
     766            pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
     767            if (RT_UNLIKELY(!pThis->pFileElem->getChildElementValueDefP("gid", 0, &pObjInfo->Attr.u.Unix.gid)))
     768                return VERR_XAR_BAD_FILE_GID;
     769            const char *pszGroup = pThis->pFileElem->findChildElementValueP("group");
     770            if (pszGroup)
     771                RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName), pszGroup);
     772            else
     773                pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
    524774            break;
     775        }
    525776
    526777        case RTFSOBJATTRADD_EASIZE:
    527             *pObjInfo = pThis->ObjInfo;
    528778            pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
    529779            RT_ZERO(pObjInfo->Attr.u);
     
    533783            return VERR_NOT_SUPPORTED;
    534784    }
    535 #endif
    536785
    537786    return VINF_SUCCESS;
     
    578827
    579828/**
    580  * Reads one segment.
    581  *
    582  * @returns IPRT status code.
    583  * @param   pThis           The instance data.
    584  * @param   pvBuf           Where to put the read bytes.
    585  * @param   cbToRead        The number of bytes to read.
    586  * @param   fBlocking       Whether to block or not.
    587  * @param   pcbRead         Where to store the number of bytes actually read.
    588  */
    589 static int rtZipXarFssIos_ReadOneSeg(PRTZIPXARIOSTREAM pThis, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
    590 {
    591     /*
    592      * Fend of reads beyond the end of the stream here.
    593      */
     829 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
     830 */
     831static DECLCALLBACK(int) rtZipXarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
     832{
     833    PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
     834    AssertReturn(off >= -1, VERR_INVALID_PARAMETER);
     835    AssertReturn(pSgBuf->cSegs == 1, VERR_INVALID_PARAMETER);
     836
     837    /*
     838     * Fend of reads beyond the end of the stream here.  If
     839     */
     840    if (off == -1)
     841        off = pThis->offCurPos;
     842    if (off < 0 || off > (RTFOFF)pThis->DataAttr.cbDataArchived)
     843        return VERR_EOF;
    594844    if (pThis->fEndOfStream)
    595         return pcbRead ? VINF_EOF : VERR_EOF;
    596 
    597     Assert(pThis->Data.cbDataExtracted >= pThis->offFile);
    598     uint64_t cbLeft = (uint64_t)(pThis->Data.cbDataExtracted - pThis->offFile);
     845    {
     846        if (off >= (RTFOFF)pThis->DataAttr.cbDataArchived)
     847            return pcbRead ? VINF_EOF : VERR_EOF;
     848        if (!pThis->fSeekable)
     849            return VERR_SEEK_ON_DEVICE;
     850        pThis->fEndOfStream = false;
     851    }
     852
     853    size_t cbToRead = pSgBuf->paSegs[0].cbSeg;
     854    uint64_t cbLeft = (uint64_t)(pThis->DataAttr.cbDataArchived - off);
    599855    if (cbToRead > cbLeft)
    600856    {
     
    610866    if (!pcbRead)
    611867        pcbRead = &cbReadStack;
    612     int rc = RTVfsIoStrmRead(pThis->hVfsIos, pvBuf, cbToRead, fBlocking, pcbRead);
    613     pThis->offFile += *pcbRead;
    614     if (pThis->offFile >= pThis->Data.cbDataExtracted)
    615     {
    616         Assert(pThis->offFile == pThis->Data.cbDataExtracted);
     868    int rc = RTVfsIoStrmReadAt(pThis->hVfsIos, off + pThis->DataAttr.offData, pSgBuf->paSegs[0].pvSeg,
     869                               cbToRead, fBlocking, pcbRead);
     870
     871    /* Feed the hashes. */
     872    size_t cbActuallyRead = *pcbRead;
     873    if (pThis->uHashState == RTZIPXAR_HASH_PENDING)
     874    {
     875        if (pThis->offCurPos == pThis->cbDigested)
     876        {
     877            rtZipXarHashUpdate(&pThis->CtxArchived,  pThis->DataAttr.uHashFunArchived,  pSgBuf->paSegs[0].pvSeg, cbActuallyRead);
     878            rtZipXarHashUpdate(&pThis->CtxExtracted, pThis->DataAttr.uHashFunExtracted, pSgBuf->paSegs[0].pvSeg, cbActuallyRead);
     879            pThis->cbDigested += cbActuallyRead;
     880        }
     881        else if (   pThis->cbDigested > pThis->offCurPos
     882                 && pThis->cbDigested < (RTFOFF)(pThis->offCurPos + cbActuallyRead))
     883        {
     884            size_t      off    = pThis->cbDigested - pThis->offCurPos;
     885            void const *pvHash = (uint8_t const *)pSgBuf->paSegs[0].pvSeg + off;
     886            size_t      cbHash = cbActuallyRead - off;
     887            rtZipXarHashUpdate(&pThis->CtxArchived,  pThis->DataAttr.uHashFunArchived,  pvHash, cbHash);
     888            rtZipXarHashUpdate(&pThis->CtxExtracted, pThis->DataAttr.uHashFunExtracted, pvHash, cbHash);
     889            pThis->cbDigested += cbHash;
     890        }
     891    }
     892
     893    /* Update the file position. */
     894    pThis->offCurPos += cbActuallyRead;
     895
     896    /*
     897     * Check for end of stream, also check the hash.
     898     */
     899    if (pThis->offCurPos >= (RTFOFF)pThis->DataAttr.cbDataArchived)
     900    {
     901        Assert(pThis->offCurPos == pThis->DataAttr.cbDataArchived);
    617902        pThis->fEndOfStream = true;
    618         /// @todo RTVfsIoStrmSkip(pThis->hVfsIos, pThis->cbPadding);
    619     }
    620 
    621     return rc;
    622 }
    623 
    624 
    625 /**
    626  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
    627  */
    628 static DECLCALLBACK(int) rtZipXarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
    629 {
    630     PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
    631     int               rc;
    632     AssertReturn(off == -1, VERR_INVALID_PARAMETER);
    633 
    634     if (pSgBuf->cSegs == 1)
    635         rc = rtZipXarFssIos_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
    636     else
    637     {
    638         rc = VINF_SUCCESS;
    639         size_t  cbRead = 0;
    640         size_t  cbReadSeg;
    641         size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
    642         for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
     903
     904        /* Check hash. */
     905        if (   pThis->uHashState == RTZIPXAR_HASH_PENDING
     906            && pThis->cbDigested == pThis->DataAttr.cbDataArchived)
    643907        {
    644             cbReadSeg = 0;
    645             rc = rtZipXarFssIos_ReadOneSeg(pThis, pSgBuf->paSegs[iSeg].pvSeg, pSgBuf->paSegs[iSeg].cbSeg, fBlocking, pcbReadSeg);
    646             if (RT_FAILURE(rc))
    647                 break;
    648             if (pcbRead)
     908            RTZIPXARHASHDIGEST Digest;
     909            rtZipXarHashFinal(&pThis->CtxArchived, pThis->DataAttr.uHashFunArchived, &Digest);
     910            if (rtZipXarHashIsEqual(pThis->DataAttr.uHashFunArchived, &Digest, &pThis->DataAttr.DigestArchived))
    649911            {
    650                 cbRead += cbReadSeg;
    651                 if (cbReadSeg != pSgBuf->paSegs[iSeg].cbSeg)
    652                     break;
     912                rtZipXarHashFinal(&pThis->CtxExtracted, pThis->DataAttr.uHashFunExtracted, &Digest);
     913                if (rtZipXarHashIsEqual(pThis->DataAttr.uHashFunExtracted, &Digest, &pThis->DataAttr.DigestExtracted))
     914                    pThis->uHashState = RTZIPXAR_HASH_OK;
     915                else
     916                {
     917                    pThis->uHashState = RTZIPXAR_HASH_FAILED_EXTRACTED;
     918                    rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
     919                }
     920            }
     921            else
     922            {
     923                pThis->uHashState = RTZIPXAR_HASH_FAILED_ARCHIVED;
     924                rc = VERR_XAR_ARCHIVED_HASH_MISMATCH;
    653925            }
    654926        }
    655         if (pcbRead)
    656             *pcbRead = cbRead;
     927        else if (pThis->uHashState == RTZIPXAR_HASH_FAILED_ARCHIVED)
     928            rc = VERR_XAR_ARCHIVED_HASH_MISMATCH;
     929        else if (pThis->uHashState == RTZIPXAR_HASH_FAILED_EXTRACTED)
     930            rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
    657931    }
    658932
     
    713987{
    714988    PRTZIPXARIOSTREAM pThis = (PRTZIPXARIOSTREAM)pvThis;
    715     *poffActual = pThis->offFile;
     989    *poffActual = pThis->offCurPos;
    716990    return VINF_SUCCESS;
    717991}
     
    7421016    RTVFSIOSTREAMOPS_VERSION
    7431017};
     1018
     1019
     1020/**
     1021 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
     1022 */
     1023static DECLCALLBACK(int) rtZipXarFssFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
     1024{
     1025    NOREF(pvThis);
     1026    NOREF(fMode);
     1027    NOREF(fMask);
     1028    return VERR_NOT_SUPPORTED;
     1029}
     1030
     1031
     1032/**
     1033 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
     1034 */
     1035static DECLCALLBACK(int) rtZipXarFssFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
     1036                                                  PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
     1037{
     1038    NOREF(pvThis);
     1039    NOREF(pAccessTime);
     1040    NOREF(pModificationTime);
     1041    NOREF(pChangeTime);
     1042    NOREF(pBirthTime);
     1043    return VERR_NOT_SUPPORTED;
     1044}
     1045
     1046
     1047/**
     1048 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
     1049 */
     1050static DECLCALLBACK(int) rtZipXarFssFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
     1051{
     1052    NOREF(pvThis);
     1053    NOREF(uid);
     1054    NOREF(gid);
     1055    return VERR_NOT_SUPPORTED;
     1056}
     1057
     1058
     1059/**
     1060 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
     1061 */
     1062static DECLCALLBACK(int) rtZipXarFssFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
     1063{
     1064    PRTZIPXARFILE pThis = (PRTZIPXARFILE)pvThis;
     1065
     1066    /* Recalculate the request to RTFILE_SEEK_BEGIN. */
     1067    switch (uMethod)
     1068    {
     1069        case RTFILE_SEEK_BEGIN:
     1070            break;
     1071        case RTFILE_SEEK_CURRENT:
     1072            offSeek += pThis->Ios.offCurPos;
     1073            break;
     1074        case RTFILE_SEEK_END:
     1075            offSeek = pThis->Ios.DataAttr.cbDataArchived + offSeek;
     1076            break;
     1077        default:
     1078            AssertFailedReturn(VERR_INVALID_PARAMETER);
     1079    }
     1080
     1081    /* Do limit checks. */
     1082    if (offSeek < 0)
     1083        offSeek = 0;
     1084    else if (offSeek > (RTFOFF)pThis->Ios.DataAttr.cbDataArchived)
     1085        offSeek = pThis->Ios.DataAttr.cbDataArchived;
     1086
     1087    /* Apply and return. */
     1088    pThis->Ios.fEndOfStream = (offSeek >= (RTFOFF)pThis->Ios.DataAttr.cbDataArchived);
     1089    pThis->Ios.offCurPos    = offSeek;
     1090    if (poffActual)
     1091        *poffActual = offSeek;
     1092
     1093    return VINF_SUCCESS;
     1094}
     1095
     1096
     1097/**
     1098 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
     1099 */
     1100static DECLCALLBACK(int) rtZipXarFssFile_QuerySize(void *pvThis, uint64_t *pcbFile)
     1101{
     1102    PRTZIPXARFILE pThis = (PRTZIPXARFILE)pvThis;
     1103    *pcbFile = pThis->Ios.DataAttr.cbDataArchived;
     1104    return VINF_SUCCESS;
     1105}
     1106
     1107
     1108/**
     1109 * Xar file operations.
     1110 */
     1111static const RTVFSFILEOPS g_rtZipXarFssFileOps =
     1112{
     1113    { /* I/O stream */
     1114        { /* Obj */
     1115            RTVFSOBJOPS_VERSION,
     1116            RTVFSOBJTYPE_FILE,
     1117            "XarFsStream::File",
     1118            rtZipXarFssIos_Close,
     1119            rtZipXarFssIos_QueryInfo,
     1120            RTVFSOBJOPS_VERSION
     1121        },
     1122        RTVFSIOSTREAMOPS_VERSION,
     1123        RTVFSIOSTREAMOPS_FEAT_NO_SG,
     1124        rtZipXarFssIos_Read,
     1125        rtZipXarFssIos_Write,
     1126        rtZipXarFssIos_Flush,
     1127        rtZipXarFssIos_PollOne,
     1128        rtZipXarFssIos_Tell,
     1129        NULL /*Skip*/,
     1130        NULL /*ZeroFill*/,
     1131        RTVFSIOSTREAMOPS_VERSION
     1132    },
     1133    RTVFSFILEOPS_VERSION,
     1134    0,
     1135    { /* ObjSet */
     1136        RTVFSOBJSETOPS_VERSION,
     1137        RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
     1138        rtZipXarFssFile_SetMode,
     1139        rtZipXarFssFile_SetTimes,
     1140        rtZipXarFssFile_SetOwner,
     1141        RTVFSOBJSETOPS_VERSION
     1142    },
     1143    rtZipXarFssFile_Seek,
     1144    rtZipXarFssFile_QuerySize,
     1145    RTVFSFILEOPS_VERSION,
     1146};
     1147
     1148
     1149
     1150
     1151/**
     1152 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
     1153 */
     1154static DECLCALLBACK(int) rtZipXarFssDecompIos_Close(void *pvThis)
     1155{
     1156    PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
     1157
     1158    RTVfsIoStrmRelease(pThis->hVfsIosDecompressor);
     1159    pThis->hVfsIosDecompressor = NIL_RTVFSIOSTREAM;
     1160
     1161    int rc = RTVfsIoStrmRelease(pThis->hVfsIosRaw);
     1162    pThis->hVfsIosRaw = NIL_RTVFSIOSTREAM;
     1163    pThis->pIosRaw = NULL;
     1164
     1165    return rc;
     1166}
     1167
     1168
     1169/**
     1170 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
     1171 */
     1172static DECLCALLBACK(int) rtZipXarFssDecompIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
     1173{
     1174    PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
     1175
     1176    int rc = rtZipXarFssBaseObj_QueryInfo(&pThis->pIosRaw->BaseObj, pObjInfo, enmAddAttr);
     1177    pObjInfo->cbObject = pThis->pIosRaw->DataAttr.cbDataExtracted;
     1178    return rc;
     1179}
     1180
     1181
     1182/**
     1183 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
     1184 */
     1185static DECLCALLBACK(int) rtZipXarFssDecompIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
     1186{
     1187    PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
     1188    AssertReturn(pSgBuf->cSegs == 1, VERR_INVALID_PARAMETER);
     1189
     1190    /*
     1191     * Enforce the cbDataExtracted limit.
     1192     */
     1193    if (pThis->offCurPos > (RTFOFF)pThis->pIosRaw->DataAttr.cbDataExtracted)
     1194        return VERR_XAR_EXTRACTED_SIZE_EXCEEDED;
     1195
     1196    /*
     1197     * Read the data.
     1198     *
     1199     * ASSUMES the decompressor stream isn't seekable, so we don't have to
     1200     * validate off wrt data digest updating.
     1201     */
     1202    int rc = RTVfsIoStrmReadAt(pThis->hVfsIosDecompressor, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg,
     1203                               fBlocking, pcbRead);
     1204    if (RT_FAILURE(rc))
     1205        return rc;
     1206
     1207    /*
     1208     * Hash the data.  When reaching the end match against the expected digest.
     1209     */
     1210    size_t cbActuallyRead = pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
     1211    pThis->offCurPos += cbActuallyRead;
     1212    rtZipXarHashUpdate(&pThis->CtxExtracted, pThis->uHashFunExtracted, pSgBuf->paSegs[0].pvSeg, cbActuallyRead);
     1213    if (rc == VINF_EOF)
     1214    {
     1215        if (pThis->offCurPos == (RTFOFF)pThis->pIosRaw->DataAttr.cbDataExtracted)
     1216        {
     1217            if (pThis->uHashState == RTZIPXAR_HASH_PENDING)
     1218            {
     1219                RTZIPXARHASHDIGEST Digest;
     1220                rtZipXarHashFinal(&pThis->CtxExtracted, pThis->uHashFunExtracted, &Digest);
     1221                if (rtZipXarHashIsEqual(pThis->uHashFunExtracted, &Digest, &pThis->DigestExtracted))
     1222                    pThis->uHashState = RTZIPXAR_HASH_OK;
     1223                else
     1224                {
     1225                    pThis->uHashState = RTZIPXAR_HASH_FAILED_EXTRACTED;
     1226                    rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
     1227                }
     1228            }
     1229            else if (pThis->uHashState != RTZIPXAR_HASH_OK)
     1230                rc = VERR_XAR_EXTRACTED_HASH_MISMATCH;
     1231        }
     1232        else
     1233            rc = VERR_XAR_EXTRACTED_SIZE_EXCEEDED;
     1234
     1235        /* Ensure that the raw stream is also at the end so that both
     1236           message digests are checked. */
     1237        if (RT_SUCCESS(rc))
     1238        {
     1239            if (   pThis->pIosRaw->offCurPos < (RTFOFF)pThis->pIosRaw->DataAttr.cbDataArchived
     1240                || pThis->pIosRaw->uHashState == RTZIPXAR_HASH_PENDING)
     1241                rc = VERR_XAR_UNUSED_ARCHIVED_DATA;
     1242            else if (pThis->pIosRaw->uHashState != RTZIPXAR_HASH_OK)
     1243                rc = VERR_XAR_ARCHIVED_HASH_MISMATCH;
     1244        }
     1245    }
     1246
     1247    return rc;
     1248}
     1249
     1250
     1251/**
     1252 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
     1253 */
     1254static DECLCALLBACK(int) rtZipXarFssDecompIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
     1255{
     1256    /* Cannot write to a read-only I/O stream. */
     1257    NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
     1258    return VERR_ACCESS_DENIED;
     1259}
     1260
     1261
     1262/**
     1263 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
     1264 */
     1265static DECLCALLBACK(int) rtZipXarFssDecompIos_Flush(void *pvThis)
     1266{
     1267    /* It's a read only stream, nothing dirty to flush. */
     1268    NOREF(pvThis);
     1269    return VINF_SUCCESS;
     1270}
     1271
     1272
     1273/**
     1274 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
     1275 */
     1276static DECLCALLBACK(int) rtZipXarFssDecompIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
     1277                                                      uint32_t *pfRetEvents)
     1278{
     1279    PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
     1280    return RTVfsIoStrmPoll(pThis->hVfsIosDecompressor, fEvents, cMillies, fIntr, pfRetEvents);
     1281}
     1282
     1283
     1284/**
     1285 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
     1286 */
     1287static DECLCALLBACK(int) rtZipXarFssDecompIos_Tell(void *pvThis, PRTFOFF poffActual)
     1288{
     1289    PRTZIPXARDECOMPIOS pThis = (PRTZIPXARDECOMPIOS)pvThis;
     1290    *poffActual = pThis->offCurPos;
     1291    return VINF_SUCCESS;
     1292}
     1293
     1294
     1295/**
     1296 * Xar I/O stream operations.
     1297 */
     1298static const RTVFSIOSTREAMOPS g_rtZipXarFssDecompIosOps =
     1299{
     1300    { /* Obj */
     1301        RTVFSOBJOPS_VERSION,
     1302        RTVFSOBJTYPE_IO_STREAM,
     1303        "XarFsStream::DecompIoStream",
     1304        rtZipXarFssDecompIos_Close,
     1305        rtZipXarFssDecompIos_QueryInfo,
     1306        RTVFSOBJOPS_VERSION
     1307    },
     1308    RTVFSIOSTREAMOPS_VERSION,
     1309    0,
     1310    rtZipXarFssDecompIos_Read,
     1311    rtZipXarFssDecompIos_Write,
     1312    rtZipXarFssDecompIos_Flush,
     1313    rtZipXarFssDecompIos_PollOne,
     1314    rtZipXarFssDecompIos_Tell,
     1315    NULL /*Skip*/,
     1316    NULL /*ZeroFill*/,
     1317    RTVFSIOSTREAMOPS_VERSION
     1318};
     1319
     1320
    7441321
    7451322
     
    8431420    PRTZIPXARFSSTREAM pThis = (PRTZIPXARFSSTREAM)pvThis;
    8441421
    845     RTVfsObjRelease(pThis->hVfsCurObj);
    846     pThis->hVfsCurObj  = NIL_RTVFSOBJ;
    847     pThis->pCurIosData = NULL;
    848 
    8491422    RTVfsIoStrmRelease(pThis->hVfsIos);
    8501423    pThis->hVfsIos = NIL_RTVFSIOSTREAM;
     
    8691442
    8701443
    871 static xml::ElementNode const *rtZipXarGetNextFileElement(xml::ElementNode const *pCurFile, uint32_t *pcCurDepth)
    872 {
    873     /*
    874      * Consider children first.
    875      */
    876     xml::ElementNode const *pChild = pCurFile->findChildElement("file");
    877     if (pChild)
    878     {
    879         *pcCurDepth += 1;
    880         return pChild;
    881     }
    882 
    883     /*
    884      * Then siblings.
    885      */
    886     xml::ElementNode const *pSibling = pCurFile->findNextSibilingElement("file");
    887     if (pSibling != NULL)
    888         return pSibling;
    889 
    890     /*
    891      * Ascend and see if some parent has more siblings.
    892      */
    893     while (*pcCurDepth > 0)
    894     {
    895         pCurFile = static_cast<const xml::ElementNode *>(pCurFile->getParent());
    896         AssertBreak(pCurFile);
    897         Assert(pCurFile->nameEquals("file"));
    898         *pcCurDepth -= 1;
    899 
    900         pSibling = pCurFile->findNextSibilingElement("file");
    901         if (pSibling != NULL)
    902             return pSibling;
    903     }
    904 
    905     return NULL;
    906 }
    907 
    908 
    9091444/**
    9101445 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
     
    9131448{
    9141449    PRTZIPXARFSSTREAM pThis = (PRTZIPXARFSSTREAM)pvThis;
    915 
    916     /*
    917      * Dispense with the current object.
    918      */
    919     if (pThis->hVfsCurObj != NIL_RTVFSOBJ)
    920     {
    921         if (pThis->pCurIosData)
    922         {
    923             pThis->pCurIosData->fEndOfStream = true;
    924 /// @todo            pThis->pCurIosData->offFile      = pThis->pCurIosData->cbFile;
    925             pThis->pCurIosData = NULL;
    926         }
    927 
    928         RTVfsObjRelease(pThis->hVfsCurObj);
    929         pThis->hVfsCurObj = NIL_RTVFSOBJ;
    930     }
    9311450
    9321451    /*
     
    9411460     * Get the next file element.
    9421461     */
    943     if (pThis->XarReader.fFirstFile)
    944     {
    945         pThis->XarReader.pCurFile  = pThis->XarReader.pToc->findChildElement("file");
    946         pThis->XarReader.cCurDepth = 0;
    947     }
    948     else if (pThis->XarReader.pCurFile)
    949         pThis->XarReader.pCurFile = rtZipXarGetNextFileElement(pThis->XarReader.pCurFile, &pThis->XarReader.cCurDepth);
    950     if (!pThis->XarReader.pCurFile)
     1462    xml::ElementNode const *pCurFile = pThis->XarReader.pCurFile;
     1463    if (pCurFile)
     1464        pThis->XarReader.pCurFile = pCurFile = rtZipXarGetNextFileElement(pCurFile, &pThis->XarReader.cCurDepth);
     1465    else if (!pThis->fEndOfStream)
     1466    {
     1467        pThis->XarReader.cCurDepth  = 0;
     1468        pThis->XarReader.pCurFile   = pCurFile = pThis->XarReader.pToc->findChildElement("file");
     1469    }
     1470    if (!pCurFile)
    9511471    {
    9521472        pThis->fEndOfStream = true;
     
    9571477     * Retrive the fundamental attributes (elements actually).
    9581478     */
    959     const char *pszName = pThis->XarReader.pCurFile->findChildElementValueP("name");
    960     const char *pszType = pThis->XarReader.pCurFile->findChildElementValueP("type");
     1479    const char *pszName = pCurFile->findChildElementValueP("name");
     1480    const char *pszType = pCurFile->findChildElementValueP("type");
    9611481    if (RT_UNLIKELY(!pszName || !pszType))
    9621482        return pThis->rcFatal = VERR_XAR_BAD_FILE_ELEMENT;
     1483
     1484    /*
     1485     * Validate the filename.  Being a little too paranoid here, perhaps, wrt
     1486     * path separators and escapes...
     1487     */
     1488    if (   !*pszName
     1489        || strchr(pszName, '/')
     1490        || strchr(pszName, '\\')
     1491        || strchr(pszName, ':')
     1492        || !strcmp(pszName, "..") )
     1493        return pThis->rcFatal = VERR_XAR_INVALID_FILE_NAME;
    9631494
    9641495    /*
     
    9711502    if (!strcmp(pszType, "file"))
    9721503    {
    973 #if 0 /// @todo continue hacking here
    974         rc = rtZipXarGetDataStreamAttributes(pThis->XarReader.pCurFile, &offData, &cbData);
     1504        RTZIPXARDATASTREAM DataAttr;
     1505        rc = rtZipXarGetDataStreamAttributes(pCurFile, &DataAttr);
    9751506        if (RT_FAILURE(rc))
    9761507            return pThis->rcFatal = rc;
    977 
    978 
    979         if (pThis->hVfsFile != NIL_RTVFSFILE)
     1508        DataAttr.offData += pThis->offZero + pThis->offStart;
     1509
     1510        if (   pThis->hVfsFile != NIL_RTVFSFILE
     1511            && DataAttr.enmEncoding == RTZIPXARENCODING_STORE)
    9801512        {
    981 
     1513            /*
     1514             * The input is seekable and the XAR file isn't compressed, so we
     1515             * can provide a seekable file to the user.
     1516             */
     1517            RTVFSFILE           hVfsFile;
     1518            PRTZIPXARFILE       pFileData;
     1519            rc = RTVfsNewFile(&g_rtZipXarFssFileOps,
     1520                              sizeof(*pFileData),
     1521                              RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
     1522                              NIL_RTVFS,
     1523                              NIL_RTVFSLOCK,
     1524                              &hVfsFile,
     1525                              (void **)&pFileData);
     1526            if (RT_FAILURE(rc))
     1527                return pThis->rcFatal = rc;
     1528
     1529            pFileData->Ios.BaseObj.pFileElem    = pCurFile;
     1530            pFileData->Ios.BaseObj.fModeType    = RTFS_TYPE_FILE;
     1531            pFileData->Ios.DataAttr             = DataAttr;
     1532            pFileData->Ios.offCurPos            = 0;
     1533            pFileData->Ios.fEndOfStream         = false;
     1534            pFileData->Ios.fSeekable            = true;
     1535            pFileData->Ios.uHashState           = RTZIPXAR_HASH_PENDING;
     1536            pFileData->Ios.cbDigested           = 0;
     1537            rtZipXarHashInit(&pFileData->Ios.CtxArchived,  pFileData->Ios.DataAttr.uHashFunArchived);
     1538            rtZipXarHashInit(&pFileData->Ios.CtxExtracted, pFileData->Ios.DataAttr.uHashFunExtracted);
     1539
     1540            pFileData->Ios.hVfsIos              = pThis->hVfsIos;
     1541            RTVfsIoStrmRetain(pFileData->Ios.hVfsIos);
     1542            pFileData->hVfsFile                 = pThis->hVfsFile;
     1543            RTVfsFileRetain(pFileData->hVfsFile);
     1544
     1545            /* Try avoid double content hashing. */
     1546            if (pFileData->Ios.DataAttr.uHashFunArchived == pFileData->Ios.DataAttr.uHashFunExtracted)
     1547                pFileData->Ios.DataAttr.uHashFunExtracted = XAR_HASH_NONE;
     1548
     1549            enmType = RTVFSOBJTYPE_FILE;
     1550            hVfsObj = RTVfsObjFromFile(hVfsFile);
     1551            RTVfsFileRelease(hVfsFile);
    9821552        }
    9831553        else
    9841554        {
    985             RTVFSIOSTREAM       hVfsIos;
     1555            RTVFSIOSTREAM       hVfsIosRaw;
    9861556            PRTZIPXARIOSTREAM   pIosData;
    9871557            rc = RTVfsNewIoStream(&g_rtZipXarFssIosOps,
     
    9901560                                  NIL_RTVFS,
    9911561                                  NIL_RTVFSLOCK,
    992                                   &hVfsIos,
     1562                                  &hVfsIosRaw,
    9931563                                  (void **)&pIosData);
    9941564            if (RT_FAILURE(rc))
    9951565                return pThis->rcFatal = rc;
    9961566
    997             pIosData->BaseObj.pXarReader = &pThis->XarReader;
    998             pIosData->BaseObj.pFileElem  = pThis->XarReader.pCurFile;
    999             pIosData->cbFile            = cbData;
    1000             pIosData->offFile           = 0;
    1001             pIosData->cbPadding         = (uint32_t)(Info.cbAllocated - Info.cbObject);
    1002             pIosData->fEndOfStream      = false;
    1003             pIosData->hVfsIos           = pThis->hVfsIos;
     1567            pIosData->BaseObj.pFileElem     = pCurFile;
     1568            pIosData->BaseObj.fModeType     = RTFS_TYPE_FILE;
     1569            pIosData->DataAttr              = DataAttr;
     1570            pIosData->offCurPos             = 0;
     1571            pIosData->fEndOfStream          = false;
     1572            pIosData->fSeekable             = pThis->hVfsFile != NIL_RTVFSFILE;
     1573            pIosData->uHashState            = RTZIPXAR_HASH_PENDING;
     1574            pIosData->cbDigested            = 0;
     1575            rtZipXarHashInit(&pIosData->CtxArchived,  pIosData->DataAttr.uHashFunArchived);
     1576            rtZipXarHashInit(&pIosData->CtxExtracted, pIosData->DataAttr.uHashFunExtracted);
     1577
     1578            pIosData->hVfsIos               = pThis->hVfsIos;
    10041579            RTVfsIoStrmRetain(pThis->hVfsIos);
    10051580
    1006             pThis->pCurIosData = pIosData;
    1007             pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;
    1008 
     1581            if (   pIosData->DataAttr.enmEncoding != RTZIPXARENCODING_STORE
     1582                && pIosData->DataAttr.enmEncoding != RTZIPXARENCODING_UNSUPPORTED)
     1583            {
     1584                /*
     1585                 * We need to set up a decompression chain.
     1586                 */
     1587                RTVFSIOSTREAM       hVfsIosDecomp;
     1588                PRTZIPXARDECOMPIOS  pIosDecompData;
     1589                rc = RTVfsNewIoStream(&g_rtZipXarFssDecompIosOps,
     1590                                      sizeof(*pIosDecompData),
     1591                                      RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
     1592                                      NIL_RTVFS,
     1593                                      NIL_RTVFSLOCK,
     1594                                      &hVfsIosDecomp,
     1595                                      (void **)&pIosDecompData);
     1596                if (RT_FAILURE(rc))
     1597                {
     1598                    RTVfsIoStrmRelease(hVfsIosRaw);
     1599                    return pThis->rcFatal = rc;
     1600                }
     1601
     1602                pIosDecompData->hVfsIosDecompressor = NIL_RTVFSIOSTREAM;
     1603                pIosDecompData->hVfsIosRaw          = hVfsIosRaw;
     1604                pIosDecompData->pIosRaw             = pIosData;
     1605                pIosDecompData->offCurPos           = 0;
     1606                pIosDecompData->uHashFunExtracted   = DataAttr.uHashFunExtracted;
     1607                pIosDecompData->uHashState = RTZIPXAR_HASH_PENDING;
     1608                rtZipXarHashInit(&pIosDecompData->CtxExtracted, pIosDecompData->uHashFunExtracted);
     1609                pIosDecompData->DigestExtracted     = DataAttr.DigestExtracted;
     1610
     1611                /* Tell the raw end to only hash the archived data. */
     1612                pIosData->DataAttr.uHashFunExtracted = XAR_HASH_NONE;
     1613
     1614                /*
     1615                 * Hook up the decompressor.
     1616                 */
     1617                switch (DataAttr.enmEncoding)
     1618                {
     1619                    case RTZIPXARENCODING_GZIP:
     1620                        /* Must allow zlib header, all examples I've got seems
     1621                           to be using it rather than the gzip one.  Makes
     1622                           sense as there is no need to repeat the file name
     1623                           and the attributes. */
     1624                        rc = RTZipGzipDecompressIoStream(hVfsIosRaw, RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR,
     1625                                                         &pIosDecompData->hVfsIosDecompressor);
     1626                        break;
     1627                    default:
     1628                        rc = VERR_INTERNAL_ERROR_5;
     1629                        break;
     1630                }
     1631                if (RT_FAILURE(rc))
     1632                {
     1633                    RTVfsIoStrmRelease(hVfsIosDecomp);
     1634                    return pThis->rcFatal = rc;
     1635                }
     1636
     1637                /* What to return. */
     1638                hVfsObj = RTVfsObjFromIoStream(hVfsIosDecomp);
     1639                RTVfsIoStrmRelease(hVfsIosDecomp);
     1640            }
     1641            else
     1642            {
     1643                /* Try avoid double content hashing. */
     1644                if (pIosData->DataAttr.uHashFunArchived == pIosData->DataAttr.uHashFunExtracted)
     1645                    pIosData->DataAttr.uHashFunExtracted = XAR_HASH_NONE;
     1646
     1647                /* What to return. */
     1648                hVfsObj = RTVfsObjFromIoStream(hVfsIosRaw);
     1649                RTVfsIoStrmRelease(hVfsIosRaw);
     1650            }
    10091651            enmType = RTVFSOBJTYPE_IO_STREAM;
    1010             hVfsObj = RTVfsObjFromIoStream(hVfsIos);
    1011             RTVfsIoStrmRelease(hVfsIos);
    10121652        }
    1013 #endif
    10141653    }
    10151654    else if (!strcmp(pszType, "directory"))
     
    10251664            return pThis->rcFatal = rc;
    10261665
    1027         pBaseObjData->pXarReader = &pThis->XarReader;
    1028         pBaseObjData->pFileElem  = pThis->XarReader.pCurFile;
     1666        pBaseObjData->pFileElem  = pCurFile;
     1667        pBaseObjData->fModeType  = RTFS_TYPE_DIRECTORY;
    10291668
    10301669        enmType = RTVFSOBJTYPE_BASE;
    10311670    }
    1032     else
    1033         return pThis->rcFatal = VERR_XAR_BAD_UNKNOWN_FILE_TYPE;
    1034 
    1035 #if 0
    1036     /*
    1037      * Consume XAR headers.
    1038      */
    1039     size_t cbHdrs = 0;
    1040     int rc;
    1041     do
    1042     {
    1043         /*
    1044          * Read the next header.
    1045          */
    1046         RTZIPXARHDR Hdr;
    1047         size_t cbRead;
    1048         rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
     1671    else if (!strcmp(pszType, "symlink"))
     1672    {
     1673        RTVFSSYMLINK        hVfsSym;
     1674        PRTZIPXARBASEOBJ    pBaseObjData;
     1675        rc = RTVfsNewSymlink(&g_rtZipXarFssSymOps,
     1676                             sizeof(*pBaseObjData),
     1677                             NIL_RTVFS,
     1678                             NIL_RTVFSLOCK,
     1679                             &hVfsSym,
     1680                             (void **)&pBaseObjData);
    10491681        if (RT_FAILURE(rc))
    10501682            return pThis->rcFatal = rc;
    1051         if (rc == VINF_EOF && cbRead == 0)
     1683
     1684        pBaseObjData->pFileElem  = pCurFile;
     1685        pBaseObjData->fModeType  = RTFS_TYPE_SYMLINK;
     1686
     1687        enmType = RTVFSOBJTYPE_SYMLINK;
     1688        hVfsObj = RTVfsObjFromSymlink(hVfsSym);
     1689        RTVfsSymlinkRelease(hVfsSym);
     1690    }
     1691    else
     1692        return pThis->rcFatal = VERR_XAR_UNKNOWN_FILE_TYPE;
     1693
     1694    /*
     1695     * Set the return data and we're done.
     1696     */
     1697    if (ppszName)
     1698    {
     1699        /* Figure the length. */
     1700        size_t const            cbCurName  = strlen(pszName) + 1;
     1701        size_t                  cbFullName = cbCurName;
     1702        const xml::ElementNode *pAncestor  = pCurFile;
     1703        uint32_t                cLeft      = pThis->XarReader.cCurDepth;
     1704        while (cLeft-- > 0)
    10521705        {
    1053             pThis->fEndOfStream = true;
    1054             return rtZipXarReaderIsAtEnd(&pThis->XarReader) ? VERR_EOF : VERR_XAR_UNEXPECTED_EOS;
     1706            pAncestor = (const xml::ElementNode *)pAncestor->getParent();               Assert(pAncestor);
     1707            const char *pszAncestorName = pAncestor->findChildElementValueP("name");    Assert(pszAncestorName);
     1708            cbFullName += strlen(pszAncestorName) + 1;
    10551709        }
    1056         if (cbRead != sizeof(Hdr))
    1057             return pThis->rcFatal = VERR_XAR_UNEXPECTED_EOS;
    1058 
    1059         cbHdrs += sizeof(Hdr);
    1060 
    1061         /*
    1062          * Parse the it.
    1063          */
    1064         rc = rtZipXarReaderParseHeader(&pThis->XarReader, &Hdr);
    1065         if (RT_FAILURE(rc))
    1066             return pThis->rcFatal = rc;
    1067     } while (rtZipXarReaderExpectingMoreHeaders(&pThis->XarReader));
    1068 
    1069     pThis->offNextHdr = offHdr + cbHdrs;
    1070 
    1071     /*
    1072      * Fill an object info structure from the current XAR state.
    1073      */
    1074     RTFSOBJINFO Info;
    1075     rc = rtZipXarReaderGetFsObjInfo(&pThis->XarReader, &Info);
    1076     if (RT_FAILURE(rc))
    1077         return pThis->rcFatal = rc;
    1078 
    1079     /*
    1080      * Create an object of the appropriate type.
    1081      */
    1082     RTVFSOBJTYPE    enmType;
    1083     RTVFSOBJ        hVfsObj;
    1084     RTFMODE         fType = Info.Attr.fMode & RTFS_TYPE_MASK;
    1085     if (rtZipXarReaderIsHardlink(&pThis->XarReader))
    1086         fType = RTFS_TYPE_SYMLINK;
    1087     switch (fType)
    1088     {
    1089         /*
    1090          * Files are represented by a VFS I/O stream.
    1091          */
    1092         case RTFS_TYPE_FILE:
     1710
     1711        /* Allocate a buffer. */
     1712        char *psz = *ppszName = RTStrAlloc(cbFullName);
     1713        if (!psz)
    10931714        {
    1094             break;
     1715            RTVfsObjRelease(hVfsObj);
     1716            return VERR_NO_STR_MEMORY;
    10951717        }
    10961718
    1097         /*
    1098          * We represent hard links using a symbolic link object.  This fits
    1099          * best with the way XAR stores it and there is currently no better
    1100          * fitting VFS type alternative.
    1101          */
    1102         case RTFS_TYPE_SYMLINK:
     1719        /* Construct it, from the end. */
     1720        psz += cbFullName;
     1721        psz -= cbCurName;
     1722        memcpy(psz, pszName, cbCurName);
     1723
     1724        pAncestor = pCurFile;
     1725        cLeft = pThis->XarReader.cCurDepth;
     1726        while (cLeft-- > 0)
    11031727        {
    1104             RTVFSSYMLINK        hVfsSym;
    1105             PRTZIPXARBASEOBJ    pBaseObjData;
    1106             rc = RTVfsNewSymlink(&g_rtZipXarFssSymOps,
    1107                                  sizeof(*pBaseObjData),
    1108                                  NIL_RTVFS,
    1109                                  NIL_RTVFSLOCK,
    1110                                  &hVfsSym,
    1111                                  (void **)&pBaseObjData);
    1112             if (RT_FAILURE(rc))
    1113                 return pThis->rcFatal = rc;
    1114 
    1115             pBaseObjData->offHdr    = offHdr;
    1116             pBaseObjData->pXarReader= &pThis->XarReader;
    1117             pBaseObjData->ObjInfo   = Info;
    1118 
    1119             enmType = RTVFSOBJTYPE_SYMLINK;
    1120             hVfsObj = RTVfsObjFromSymlink(hVfsSym);
    1121             RTVfsSymlinkRelease(hVfsSym);
    1122             break;
     1728            pAncestor = (const xml::ElementNode *)pAncestor->getParent();             Assert(pAncestor);
     1729            const char *pszAncestorName = pAncestor->findChildElementValueP("name");  Assert(pszAncestorName);
     1730            *--psz = '/';
     1731            size_t cchAncestorName = strlen(pszAncestorName);
     1732            psz -= cchAncestorName;
     1733            memcpy(psz, pszAncestorName, cchAncestorName);
    11231734        }
    1124 
    1125         /*
    1126          * All other objects are repesented using a VFS base object since they
    1127          * carry no data streams (unless some XAR extension implements extended
    1128          * attributes / alternative streams).
    1129          */
    1130         case RTFS_TYPE_DEV_BLOCK:
    1131         case RTFS_TYPE_DEV_CHAR:
    1132         case RTFS_TYPE_DIRECTORY:
    1133         case RTFS_TYPE_FIFO:
    1134         {
    1135             PRTZIPXARBASEOBJ pBaseObjData;
    1136             rc = RTVfsNewBaseObj(&g_rtZipXarFssBaseObjOps,
    1137                                  sizeof(*pBaseObjData),
    1138                                  NIL_RTVFS,
    1139                                  NIL_RTVFSLOCK,
    1140                                  &hVfsObj,
    1141                                  (void **)&pBaseObjData);
    1142             if (RT_FAILURE(rc))
    1143                 return pThis->rcFatal = rc;
    1144 
    1145             pBaseObjData->offHdr    = offHdr;
    1146             pBaseObjData->pXarReader= &pThis->XarReader;
    1147             pBaseObjData->ObjInfo   = Info;
    1148 
    1149             enmType = RTVFSOBJTYPE_BASE;
    1150             break;
    1151         }
    1152 
    1153         default:
    1154             AssertFailed();
    1155             return pThis->rcFatal = VERR_INTERNAL_ERROR_5;
    1156     }
    1157     pThis->hVfsCurObj = hVfsObj;
    1158 #endif
    1159 
    1160     /*
    1161      * Set the return data and we're done.
    1162      */
    1163     if (ppszName)
    1164     {
    1165         rc = RTStrDupEx(ppszName, pszName); /** @todo fixme */
    1166         if (RT_FAILURE(rc))
    1167             return rc;
     1735        Assert(*ppszName == psz);
    11681736    }
    11691737
     
    12321800
    12331801        uint8_t uHashFunction;
    1234         if (!strcmp(pszStyle, "sha1"))
    1235             uHashFunction = XAR_HASH_SHA1;
    1236         else if (!strcmp(pszStyle, "md5"))
    1237             uHashFunction = XAR_HASH_MD5;
    1238         else if (!strcmp(pszStyle, "none"))
    1239             uHashFunction = XAR_HASH_NONE;
    1240         else
    1241             return VERR_XAR_BAD_CHECKSUM_ELEMENT;
     1802        rc = rtZipXarParseChecksumStyle(pszStyle, &uHashFunction);
     1803        if (RT_FAILURE(rc))
     1804            return rc;
    12421805        if (uHashFunction != pThis->uHashFunction)
    12431806            return VERR_XAR_HASH_FUNCTION_MISMATCH;
     
    12501813            RTFOFF   offChecksum;
    12511814            uint64_t cbChecksum;
    1252             rc = rtZipXarGetOffsetSizeFromElem(pChecksumElem, &offChecksum, &cbChecksum);
     1815            rc = rtZipXarGetOffsetSizeLengthFromElem(pChecksumElem, &offChecksum, &cbChecksum, NULL);
    12531816            if (RT_FAILURE(rc))
    12541817                return rc;
     
    14902053                        pThis->hVfsIos              = hVfsIosIn;
    14912054                        pThis->hVfsFile             = RTVfsIoStrmToFile(hVfsIosIn);
    1492                         pThis->hVfsCurObj           = NIL_RTVFSOBJ;
    1493                         pThis->pCurIosData          = NULL;
    14942055                        pThis->offStart             = offStart;
    14952056                        pThis->offZero              = offZero;
     
    15072068                        pThis->XarReader.pCurFile   = 0;
    15082069                        pThis->XarReader.cCurDepth  = 0;
    1509                         pThis->XarReader.fFirstFile = true;
    15102070
    15112071                        /*
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