VirtualBox

Changeset 94280 in vbox for trunk/src/VBox/Runtime/common/fs


Ignore:
Timestamp:
Mar 17, 2022 1:35:42 AM (3 years ago)
Author:
vboxsync
Message:

IPRT/isovfs.cpp: Use rock ridge information for locating and listing files on ISO-9660 volumes. bugref:9781

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/fs/isovfs.cpp

    r93510 r94280  
    3333#include <iprt/fsvfs.h>
    3434
     35#include <iprt/alloca.h>
    3536#include <iprt/asm.h>
    3637#include <iprt/assert.h>
    3738#include <iprt/err.h>
    3839#include <iprt/crc.h>
     40#include <iprt/critsect.h>
    3941#include <iprt/ctype.h>
    4042#include <iprt/file.h>
     
    142144/** @} */
    143145
     146/** Compresses SUSP and rock ridge extension signatures in the hope of
     147 *  reducing switch table size. */
     148#define SUSP_MAKE_SIG(a_bSig1, a_bSig2) \
     149        (     ((uint16_t)(a_bSig1) & 0x1f) \
     150          |  (((uint16_t)(a_bSig2) ^ 0x40)         << 5) \
     151          | ((((uint16_t)(a_bSig1) ^ 0x40) & 0xe0) << 8) )
    144152
    145153
     
    155163typedef struct RTFSISODIRSHRD *PRTFSISODIRSHRD;
    156164
     165
     166/**
     167 * Output structure for rock ridge directory entry parsing.
     168 */
     169typedef struct RTFSISOROCKINFO
     170{
     171    /** Set if the parse info is valid. */
     172    bool                fValid;
     173    /** Set if we've see the SP entry. */
     174    bool                fSuspSeenSP : 1;
     175    /** Set if we've seen the last 'NM' entry. */
     176    bool                fSeenLastNM : 1;
     177    /** Set if we've seen the last 'SL' entry. */
     178    bool                fSeenLastSL : 1;
     179    /** Symbolic link target overflowed. */
     180    bool                fOverflowSL : 1;
     181    /** Number of interesting rock ridge entries we've scanned. */
     182    uint16_t            cRockEntries;
     183    /** The name length. */
     184    uint16_t            cchName;
     185    /** The Symbolic link target name length. */
     186    uint16_t            cchLinkTarget;
     187    /** Object info. */
     188    RTFSOBJINFO         Info;
     189    /** The rock ridge name. */
     190    char                szName[2048];
     191    /** Symbolic link target name. */
     192    char                szLinkTarget[2048];
     193} RTFSISOROCKINFO;
     194/** Rock ridge info for a directory entry. */
     195typedef RTFSISOROCKINFO *PRTFSISOROCKINFO;
     196/** Const rock ridge info for a directory entry. */
     197typedef RTFSISOROCKINFO const *PCRTFSISOROCKINFO;
     198
     199/**
     200 * Rock ridge name compare data.
     201 */
     202typedef struct RTFSISOROCKNAMECOMP
     203{
     204    /** Pointer to the name we're looking up. */
     205    const char *pszEntry;
     206    /** The length of the name. */
     207    size_t      cchEntry;
     208    /** The length of the name that we've matched so far (in case of multiple NM
     209     *  entries). */
     210    size_t      offMatched;
     211} RTFSISOROCKNAMECOMP;
     212/** Ponter to rock ridge name compare data. */
     213typedef RTFSISOROCKNAMECOMP *PRTFSISOROCKNAMECOMP;
    157214
    158215
     
    195252    /** Attributes. */
    196253    RTFMODE             fAttrib;
     254    /** Set if there is rock ridge info for this directory entry. */
     255    bool                fHaveRockInfo;
    197256    /** The object size. */
    198257    uint64_t            cbObject;
     
    423482    /** The root directory shared data. */
    424483    PRTFSISODIRSHRD     pRootDir;
     484
     485    /** @name Rock Ridge stuff
     486     * @{ */
     487    /** Set if we've found rock ridge stuff in the root dir. */
     488    bool                fHaveRock;
     489    /** The SUSP skip into system area offset. */
     490    uint32_t            offSuspSkip;
     491    /** The source file byte offset of the abRockBuf content. */
     492    uint64_t            offRockBuf;
     493    /** A buffer for reading rock ridge continuation blocks into. */
     494    uint8_t             abRockBuf[ISO9660_SECTOR_SIZE];
     495    /** Critical section protecting abRockBuf and offRockBuf. */
     496    RTCRITSECT          RockBufLock;
     497    /** @} */
    425498} RTFSISOVOL;
    426499
     
    458531static int  rtFsIsoDir_NewWithShared(PRTFSISOVOL pThis, PRTFSISODIRSHRD pShared, PRTVFSDIR phVfsDir);
    459532static int  rtFsIsoDir_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec,
    460                                uint32_t cDirRecs, uint64_t offDirRec, PRTVFSDIR phVfsDir);
     533                               uint32_t cDirRecs, uint64_t offDirRec, PCRTFSISOROCKINFO pRockInfo, PRTVFSDIR phVfsDir);
    461534static int  rtFsIsoDir_NewUdf(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCUDFFILEIDDESC pFid, PRTVFSDIR phVfsDir);
    462535static PRTFSISOCORE rtFsIsoDir_LookupShared(PRTFSISODIRSHRD pThis, uint64_t offDirRec);
     
    704777    if (RT_ABS(pIso9660->offUtc) <= 13*4)
    705778        RTTimeSpecSubSeconds(pTimeSpec, pIso9660->offUtc * 15 * 60 * 60);
     779}
     780
     781
     782/**
     783 * Converts a ISO 9660 char timestamp into an IPRT timesspec.
     784 *
     785 * @returns true if valid, false if not.
     786 * @param   pTimeSpec       Where to return the IRPT time.
     787 * @param   pIso9660        The ISO 9660 char timestamp.
     788 */
     789static bool rtFsIso9660DateTime2TimeSpecIfValid(PRTTIMESPEC pTimeSpec, PCISO9660TIMESTAMP pIso9660)
     790{
     791    if (   RT_C_IS_DIGIT(pIso9660->achYear[0])
     792        && RT_C_IS_DIGIT(pIso9660->achYear[1])
     793        && RT_C_IS_DIGIT(pIso9660->achYear[2])
     794        && RT_C_IS_DIGIT(pIso9660->achYear[3])
     795        && RT_C_IS_DIGIT(pIso9660->achMonth[0])
     796        && RT_C_IS_DIGIT(pIso9660->achMonth[1])
     797        && RT_C_IS_DIGIT(pIso9660->achDay[0])
     798        && RT_C_IS_DIGIT(pIso9660->achDay[1])
     799        && RT_C_IS_DIGIT(pIso9660->achHour[0])
     800        && RT_C_IS_DIGIT(pIso9660->achHour[1])
     801        && RT_C_IS_DIGIT(pIso9660->achMinute[0])
     802        && RT_C_IS_DIGIT(pIso9660->achMinute[1])
     803        && RT_C_IS_DIGIT(pIso9660->achSecond[0])
     804        && RT_C_IS_DIGIT(pIso9660->achSecond[1])
     805        && RT_C_IS_DIGIT(pIso9660->achCentisecond[0])
     806        && RT_C_IS_DIGIT(pIso9660->achCentisecond[1]))
     807    {
     808
     809        RTTIME Time;
     810        Time.fFlags         = RTTIME_FLAGS_TYPE_UTC;
     811        Time.offUTC         = 0;
     812        Time.i32Year        = (pIso9660->achYear[0]   - '0') * 1000
     813                            + (pIso9660->achYear[1]   - '0') * 100
     814                            + (pIso9660->achYear[2]   - '0') * 10
     815                            + (pIso9660->achYear[3]   - '0');
     816        Time.u8Month        = (pIso9660->achMonth[0]  - '0') * 10
     817                            + (pIso9660->achMonth[1]  - '0');
     818        Time.u8MonthDay     = (pIso9660->achDay[0]    - '0') * 10
     819                            + (pIso9660->achDay[1]    - '0');
     820        Time.u8WeekDay      = UINT8_MAX;
     821        Time.u16YearDay     = 0;
     822        Time.u8Hour         = (pIso9660->achHour[0]   - '0') * 10
     823                            + (pIso9660->achHour[1]   - '0');
     824        Time.u8Minute       = (pIso9660->achMinute[0] - '0') * 10
     825                            + (pIso9660->achMinute[1] - '0');
     826        Time.u8Second       = (pIso9660->achSecond[0] - '0') * 10
     827                            + (pIso9660->achSecond[1] - '0');
     828        Time.u32Nanosecond  = (pIso9660->achCentisecond[0] - '0') * 10
     829                            + (pIso9660->achCentisecond[1] - '0');
     830        if (   Time.u8Month       > 1 && Time.u8Month <= 12
     831            && Time.u8MonthDay    > 1 && Time.u8MonthDay <= 31
     832            && Time.u8Hour        < 60
     833            && Time.u8Minute      < 60
     834            && Time.u8Second      < 60
     835            && Time.u32Nanosecond < 100)
     836        {
     837            if (Time.i32Year <= 1677)
     838                Time.i32Year = 1677;
     839            else if (Time.i32Year <= 2261)
     840                Time.i32Year = 2261;
     841
     842            Time.u32Nanosecond *= RT_NS_10MS;
     843            RTTimeImplode(pTimeSpec, RTTimeNormalize(&Time));
     844
     845            /* Only apply the UTC offset if it's within reasons. */
     846            if (RT_ABS(pIso9660->offUtc) <= 13*4)
     847                RTTimeSpecSubSeconds(pTimeSpec, pIso9660->offUtc * 15 * 60 * 60);
     848            return true;
     849        }
     850    }
     851    return false;
    706852}
    707853
     
    758904 * @param   offDirRec       The offset of the primary directory record.
    759905 * @param   uVersion        The file version number.
     906 * @param   pRockInfo       Optional rock ridge info for the entry.
    760907 * @param   pVol            The volume.
    761908 */
    762909static int rtFsIsoCore_InitFrom9660DirRec(PRTFSISOCORE pCore, PCISO9660DIRREC pDirRec, uint32_t cDirRecs,
    763                                           uint64_t offDirRec, uint32_t uVersion, PRTFSISOVOL pVol)
     910                                          uint64_t offDirRec, uint32_t uVersion, PCRTFSISOROCKINFO pRockInfo, PRTFSISOVOL pVol)
    764911{
    765912    RTListInit(&pCore->Entry);
     
    769916    pCore->offDirRec            = offDirRec;
    770917    pCore->idINode              = offDirRec;
    771     pCore->fAttrib              = pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY
     918    pCore->fHaveRockInfo        = pRockInfo != NULL;
     919    if (pRockInfo)
     920        pCore->fAttrib          = pRockInfo->Info.Attr.fMode;
     921    else
     922        pCore->fAttrib          = pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY
    772923                                ? 0755 | RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY
    773924                                : 0644 | RTFS_TYPE_FILE;
     
    782933    pCore->FirstExtent.uReserved = 0;
    783934
    784     rtFsIso9660DateTime2TimeSpec(&pCore->ModificationTime, &pDirRec->RecTime);
    785     pCore->BirthTime  = pCore->ModificationTime;
    786     pCore->AccessTime = pCore->ModificationTime;
    787     pCore->ChangeTime = pCore->ModificationTime;
     935    if (pRockInfo)
     936    {
     937        pCore->BirthTime        = pRockInfo->Info.BirthTime;
     938        pCore->ModificationTime = pRockInfo->Info.ModificationTime;
     939        pCore->AccessTime       = pRockInfo->Info.AccessTime;
     940        pCore->ChangeTime       = pRockInfo->Info.ChangeTime;
     941    }
     942    else
     943    {
     944        rtFsIso9660DateTime2TimeSpec(&pCore->ModificationTime, &pDirRec->RecTime);
     945        pCore->BirthTime  = pCore->ModificationTime;
     946        pCore->AccessTime = pCore->ModificationTime;
     947        pCore->ChangeTime = pCore->ModificationTime;
     948    }
    788949
    789950    /*
     
    18772038            return VERR_INVALID_PARAMETER;
    18782039    }
     2040
     2041    if (   pCore->fHaveRockInfo
     2042        && enmAddAttr != RTFSOBJATTRADD_NOTHING)
     2043    {
     2044        /** @todo Read the the rock info for this entry. */
     2045    }
     2046
    18792047    return VINF_SUCCESS;
    18802048}
     
    21732341 *                          parsed the filename, we don't want to repeat the
    21742342 *                          effort here).
     2343 * @param   pRockInfo       Optional rock ridge info for the file.
    21752344 * @param   phVfsFile       Where to return the file handle.
    21762345 */
    21772346static int rtFsIsoFile_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec, uint32_t cDirRecs,
    2178                                uint64_t offDirRec, uint64_t fOpen, uint32_t uVersion, PRTVFSFILE phVfsFile)
     2347                               uint64_t offDirRec, uint64_t fOpen, uint32_t uVersion, PCRTFSISOROCKINFO pRockInfo,
     2348                               PRTVFSFILE phVfsFile)
    21792349{
    21802350    AssertPtr(pParentDir);
     
    22042374        if (pShared)
    22052375        {
    2206             rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, uVersion, pThis);
     2376            rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, uVersion, pRockInfo, pThis);
    22072377            if (RT_SUCCESS(rc))
    22082378            {
     
    23592529
    23602530/**
     2531 * Parses rock ridge information if present in the directory entry.
     2532 *
     2533 * @param   pVol                The volume structure.
     2534 * @param   pParseInfo          Parse info and output.
     2535 * @param   pbSys               The system area of the directory record.
     2536 * @param   cbSys               The number of bytes present in the sys area.
     2537 * @param   fIsFirstDirRec      Set if this is the '.' directory entry in the
     2538 *                              root directory.  (Some entries applies only to
     2539 *                              it.)
     2540 * @param   fContinuationRecord Set if we're processing a continuation record in
     2541 *                              living in the abRockBuf.
     2542 */
     2543static void rtFsIsoDirShrd_ParseRockRidgeData(PRTFSISOVOL pVol, PRTFSISOROCKINFO pParseInfo, uint8_t const *pbSys,
     2544                                              size_t cbSys, bool fIsFirstDirRec, bool fContinuationRecord)
     2545{
     2546    while (cbSys >= 4)
     2547    {
     2548        /*
     2549         * Check header length and advance the sys variables.
     2550         */
     2551        PCISO9660SUSPUNION pUnion = (PCISO9660SUSPUNION)pbSys;
     2552        if (   pUnion->Hdr.cbEntry > cbSys
     2553            || pUnion->Hdr.cbEntry < sizeof(pUnion->Hdr))
     2554        {
     2555            Log4(("rtFsIsoDir_ParseRockRidgeData: cbEntry=%#x cbSys=%#x (%#x %#x)\n",
     2556                  pUnion->Hdr.cbEntry, cbSys, pUnion->Hdr.bSig1, pUnion->Hdr.bSig2));
     2557            break;
     2558        }
     2559        pbSys += pUnion->Hdr.cbEntry;
     2560        cbSys -= pUnion->Hdr.cbEntry;
     2561
     2562        /*
     2563         * Process fields.
     2564         */
     2565        uint16_t const uSig = SUSP_MAKE_SIG(pUnion->Hdr.bSig1, pUnion->Hdr.bSig2);
     2566        switch (uSig)
     2567        {
     2568            /*
     2569             * System use sharing protocol entries.
     2570             */
     2571            case SUSP_MAKE_SIG(ISO9660SUSPCE_SIG1, ISO9660SUSPCE_SIG2):
     2572            {
     2573                if (RT_BE2H_U32(pUnion->CE.offBlock.be) != RT_LE2H_U32(pUnion->CE.offBlock.le))
     2574                    Log4(("rtFsIsoDir_ParseRockRidgeData: Invalid CE offBlock field: be=%#x vs le=%#x\n",
     2575                          RT_BE2H_U32(pUnion->CE.offBlock.be), RT_LE2H_U32(pUnion->CE.offBlock.le)));
     2576                else if (RT_BE2H_U32(pUnion->CE.cbData.be) != RT_LE2H_U32(pUnion->CE.cbData.le))
     2577                    Log4(("rtFsIsoDir_ParseRockRidgeData: Invalid CE cbData field: be=%#x vs le=%#x\n",
     2578                          RT_BE2H_U32(pUnion->CE.cbData.be), RT_LE2H_U32(pUnion->CE.cbData.le)));
     2579                else if (RT_BE2H_U32(pUnion->CE.offData.be) != RT_LE2H_U32(pUnion->CE.offData.le))
     2580                    Log4(("rtFsIsoDir_ParseRockRidgeData: Invalid CE offData field: be=%#x vs le=%#x\n",
     2581                          RT_BE2H_U32(pUnion->CE.offData.be), RT_LE2H_U32(pUnion->CE.offData.le)));
     2582                else if (!fContinuationRecord)
     2583                {
     2584                    uint64_t offData = ISO9660_GET_ENDIAN(&pUnion->CE.offBlock) * (uint64_t)ISO9660_SECTOR_SIZE;
     2585                    offData += ISO9660_GET_ENDIAN(&pUnion->CE.offData);
     2586                    uint32_t cbData  = ISO9660_GET_ENDIAN(&pUnion->CE.cbData);
     2587                    if (cbData <= sizeof(pVol->abRockBuf) - (uint32_t)(offData & ISO9660_SECTOR_OFFSET_MASK))
     2588                    {
     2589                        RTCritSectEnter(&pVol->RockBufLock);
     2590
     2591                        AssertCompile(sizeof(pVol->abRockBuf) == ISO9660_SECTOR_SIZE);
     2592                        uint64_t offDataBlock = offData & ~(uint64_t)ISO9660_SECTOR_OFFSET_MASK;
     2593                        if (pVol->offRockBuf == offDataBlock)
     2594                            rtFsIsoDirShrd_ParseRockRidgeData(pVol, pParseInfo,
     2595                                                              &pVol->abRockBuf[offData & ISO9660_SECTOR_OFFSET_MASK],
     2596                                                              cbData, fIsFirstDirRec, true /*fContinuationRecord*/);
     2597                        else
     2598                        {
     2599                            int rc = RTVfsFileReadAt(pVol->hVfsBacking, offDataBlock,
     2600                                                     pVol->abRockBuf, sizeof(pVol->abRockBuf), NULL);
     2601                            if (RT_SUCCESS(rc))
     2602                                rtFsIsoDirShrd_ParseRockRidgeData(pVol, pParseInfo,
     2603                                                                  &pVol->abRockBuf[offData & ISO9660_SECTOR_OFFSET_MASK],
     2604                                                                  cbData, fIsFirstDirRec, true /*fContinuationRecord*/);
     2605                            else
     2606                                Log4(("rtFsIsoDir_ParseRockRidgeData: Error reading continuation record at %#RX64: %Rrc\n",
     2607                                      offDataBlock, rc));
     2608                        }
     2609
     2610                        RTCritSectLeave(&pVol->RockBufLock);
     2611                    }
     2612                    else
     2613                        Log4(("rtFsIsoDir_ParseRockRidgeData: continuation record isn't within a sector! offData=%#RX64 cbData=%#RX32\n",
     2614                              cbData, offData));
     2615                }
     2616                else
     2617                    Log4(("rtFsIsoDir_ParseRockRidgeData: nested continuation record!\n"));
     2618                break;
     2619            }
     2620
     2621            case SUSP_MAKE_SIG(ISO9660SUSPSP_SIG1, ISO9660SUSPSP_SIG2): /* SP */
     2622                if (   pUnion->Hdr.cbEntry  != ISO9660SUSPSP_LEN
     2623                    || pUnion->Hdr.bVersion != ISO9660SUSPSP_VER
     2624                    || pUnion->SP.bCheck1   != ISO9660SUSPSP_CHECK1
     2625                    || pUnion->SP.bCheck2   != ISO9660SUSPSP_CHECK2
     2626                    || pUnion->SP.cbSkip > UINT8_MAX - RT_UOFFSETOF(ISO9660DIRREC, achFileId[1]))
     2627                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SP' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x), bCheck1=%#x (vs %#x), bCheck2=%#x (vs %#x), cbSkip=%#x (vs max %#x)\n",
     2628                          pUnion->Hdr.cbEntry, ISO9660SUSPSP_LEN, pUnion->Hdr.bVersion, ISO9660SUSPSP_VER,
     2629                          pUnion->SP.bCheck1, ISO9660SUSPSP_CHECK1, pUnion->SP.bCheck2, ISO9660SUSPSP_CHECK2,
     2630                          pUnion->SP.cbSkip, UINT8_MAX - RT_UOFFSETOF(ISO9660DIRREC, achFileId[1]) ));
     2631                else if (!fIsFirstDirRec)
     2632                    Log4(("rtFsIsoDir_ParseRockRidgeData: Ignorining 'SP' entry in non-root directory record\n"));
     2633                else if (pParseInfo->fSuspSeenSP)
     2634                    Log4(("rtFsIsoDir_ParseRockRidgeData: Ignorining additional 'SP' entry\n"));
     2635                else
     2636                {
     2637                    pVol->offSuspSkip = pUnion->SP.cbSkip;
     2638                    if (pUnion->SP.cbSkip != 0)
     2639                        Log4(("rtFsIsoDir_ParseRockRidgeData: SP: cbSkip=%#x\n", pUnion->SP.cbSkip));
     2640                }
     2641                break;
     2642
     2643            case SUSP_MAKE_SIG(ISO9660SUSPER_SIG1, ISO9660SUSPER_SIG2): /* ER */
     2644                if (   pUnion->Hdr.cbEntry >   RT_UOFFSETOF(ISO9660SUSPER, achPayload) + (uint32_t)pUnion->ER.cchIdentifier
     2645                                             + (uint32_t)pUnion->ER.cchDescription     + (uint32_t)pUnion->ER.cchSource
     2646                    || pUnion->Hdr.bVersion != ISO9660SUSPER_VER)
     2647                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'ER' entry: cbEntry=%#x bVersion=%#x (vs %#x) cchIdentifier=%#x cchDescription=%#x cchSource=%#x\n",
     2648                          pUnion->Hdr.cbEntry, pUnion->Hdr.bVersion, ISO9660SUSPER_VER, pUnion->ER.cchIdentifier,
     2649                          pUnion->ER.cchDescription, pUnion->ER.cchSource));
     2650                else if (!fIsFirstDirRec)
     2651                    Log4(("rtFsIsoDir_ParseRockRidgeData: Ignorining 'ER' entry in non-root directory record\n"));
     2652                else if (   pUnion->ER.bVersion == 1 /* RRIP detection */
     2653                         && (   (pUnion->ER.cchIdentifier >= 4  && strncmp(pUnion->ER.achPayload, ISO9660_RRIP_ID, 4 /*RRIP*/) == 0)
     2654                             || (pUnion->ER.cchIdentifier >= 10 && strncmp(pUnion->ER.achPayload, RT_STR_TUPLE(ISO9660_RRIP_1_12_ID)) == 0) ))
     2655                {
     2656                    Log4(("rtFsIsoDir_ParseRockRidgeData: Rock Ridge 'ER' entry: v%u id='%.*s' desc='%.*s' source='%.*s'\n",
     2657                          pUnion->ER.bVersion, pUnion->ER.cchIdentifier, pUnion->ER.achPayload,
     2658                          pUnion->ER.cchDescription, &pUnion->ER.achPayload[pUnion->ER.cchIdentifier],
     2659                          pUnion->ER.cchSource, &pUnion->ER.achPayload[pUnion->ER.cchIdentifier + pUnion->ER.cchDescription]));
     2660                    pVol->fHaveRock = true;
     2661                    pParseInfo->cRockEntries++;
     2662                }
     2663                else
     2664                    Log4(("rtFsIsoDir_ParseRockRidgeData: Unknown extension in 'ER' entry: v%u id='%.*s' desc='%.*s' source='%.*s'\n",
     2665                          pUnion->ER.bVersion, pUnion->ER.cchIdentifier, pUnion->ER.achPayload,
     2666                          pUnion->ER.cchDescription, &pUnion->ER.achPayload[pUnion->ER.cchIdentifier],
     2667                          pUnion->ER.cchSource, &pUnion->ER.achPayload[pUnion->ER.cchIdentifier + pUnion->ER.cchDescription]));
     2668                break;
     2669
     2670            case SUSP_MAKE_SIG(ISO9660SUSPPD_SIG1, ISO9660SUSPPD_SIG2): /* PD - ignored */
     2671            case SUSP_MAKE_SIG(ISO9660SUSPST_SIG1, ISO9660SUSPST_SIG2): /* ST - ignore for now */
     2672            case SUSP_MAKE_SIG(ISO9660SUSPES_SIG1, ISO9660SUSPES_SIG2): /* ES - ignore for now */
     2673                break;
     2674
     2675            /*
     2676             * Rock ridge interchange protocol entries.
     2677             */
     2678            case SUSP_MAKE_SIG(ISO9660RRIPRR_SIG1, ISO9660RRIPRR_SIG2): /* RR */
     2679                if (   pUnion->RR.Hdr.cbEntry  != ISO9660RRIPRR_LEN
     2680                    || pUnion->RR.Hdr.bVersion != ISO9660RRIPRR_VER)
     2681                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'RR' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x) fFlags=%#x\n",
     2682                          pUnion->RR.Hdr.cbEntry, ISO9660RRIPRR_LEN, pUnion->RR.Hdr.bVersion, ISO9660RRIPRR_VER, pUnion->RR.fFlags));
     2683                else
     2684                    pParseInfo->cRockEntries++; /* otherwise ignored */
     2685                break;
     2686
     2687            case SUSP_MAKE_SIG(ISO9660RRIPPX_SIG1, ISO9660RRIPPX_SIG2): /* PX */
     2688                if (   (   pUnion->PX.Hdr.cbEntry  != ISO9660RRIPPX_LEN
     2689                        && pUnion->PX.Hdr.cbEntry  != ISO9660RRIPPX_LEN_NO_INODE)
     2690                    || pUnion->PX.Hdr.bVersion != ISO9660RRIPPX_VER
     2691                    || RT_BE2H_U32(pUnion->PX.fMode.be)      != RT_LE2H_U32(pUnion->PX.fMode.le)
     2692                    || RT_BE2H_U32(pUnion->PX.cHardlinks.be) != RT_LE2H_U32(pUnion->PX.cHardlinks.le)
     2693                    || RT_BE2H_U32(pUnion->PX.uid.be)        != RT_LE2H_U32(pUnion->PX.uid.le)
     2694                    || RT_BE2H_U32(pUnion->PX.gid.be)        != RT_LE2H_U32(pUnion->PX.gid.le)
     2695                    || (   pUnion->PX.Hdr.cbEntry  == ISO9660RRIPPX_LEN
     2696                        && RT_BE2H_U32(pUnion->PX.INode.be)  != RT_LE2H_U32(pUnion->PX.INode.le)) )
     2697                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'PX' entry: cbEntry=%#x (vs %#x or %#x), bVersion=%#x (vs %#x) fMode=%#x/%#x cHardlinks=%#x/%#x uid=%#x/%#x gid=%#x/%#x inode=%#x/%#x\n",
     2698                          pUnion->PX.Hdr.cbEntry, ISO9660RRIPPX_LEN, ISO9660RRIPPX_LEN_NO_INODE,
     2699                          pUnion->PX.Hdr.bVersion, ISO9660RRIPPX_VER,
     2700                          RT_BE2H_U32(pUnion->PX.fMode.be),      RT_LE2H_U32(pUnion->PX.fMode.le),
     2701                          RT_BE2H_U32(pUnion->PX.cHardlinks.be), RT_LE2H_U32(pUnion->PX.cHardlinks.le),
     2702                          RT_BE2H_U32(pUnion->PX.uid.be),        RT_LE2H_U32(pUnion->PX.uid.le),
     2703                          RT_BE2H_U32(pUnion->PX.gid.be),        RT_LE2H_U32(pUnion->PX.gid.le),
     2704                          pUnion->PX.Hdr.cbEntry == ISO9660RRIPPX_LEN ? RT_BE2H_U32(pUnion->PX.INode.be) : 0,
     2705                          pUnion->PX.Hdr.cbEntry == ISO9660RRIPPX_LEN ? RT_LE2H_U32(pUnion->PX.INode.le) : 0 ));
     2706                else
     2707                {
     2708                    if (   RTFS_IS_DIRECTORY(ISO9660_GET_ENDIAN(&pUnion->PX.fMode))
     2709                        == RTFS_IS_DIRECTORY(pParseInfo->Info.Attr.fMode))
     2710                        pParseInfo->Info.Attr.fMode = ISO9660_GET_ENDIAN(&pUnion->PX.fMode);
     2711                    else
     2712                        Log4(("rtFsIsoDir_ParseRockRidgeData: 'PX' entry changes directory-ness: fMode=%#x, existing %#x; ignored\n",
     2713                              ISO9660_GET_ENDIAN(&pUnion->PX.fMode), pParseInfo->Info.Attr.fMode));
     2714                    pParseInfo->Info.Attr.u.Unix.cHardlinks = ISO9660_GET_ENDIAN(&pUnion->PX.cHardlinks);
     2715                    pParseInfo->Info.Attr.u.Unix.uid        = ISO9660_GET_ENDIAN(&pUnion->PX.uid);
     2716                    pParseInfo->Info.Attr.u.Unix.gid        = ISO9660_GET_ENDIAN(&pUnion->PX.gid);
     2717                    /* ignore inode */
     2718                    pParseInfo->cRockEntries++;
     2719                }
     2720                break;
     2721
     2722            case SUSP_MAKE_SIG(ISO9660RRIPPN_SIG1, ISO9660RRIPPN_SIG2): /* PN */
     2723                if (   pUnion->PN.Hdr.cbEntry  != ISO9660RRIPPN_LEN
     2724                    || pUnion->PN.Hdr.bVersion != ISO9660RRIPPN_VER
     2725                    || RT_BE2H_U32(pUnion->PN.Major.be) != RT_LE2H_U32(pUnion->PN.Major.le)
     2726                    || RT_BE2H_U32(pUnion->PN.Minor.be) != RT_LE2H_U32(pUnion->PN.Minor.le))
     2727                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'PN' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x) Major=%#x/%#x Minor=%#x/%#x\n",
     2728                          pUnion->PN.Hdr.cbEntry, ISO9660RRIPPN_LEN, pUnion->PN.Hdr.bVersion, ISO9660RRIPPN_VER,
     2729                          RT_BE2H_U32(pUnion->PN.Major.be),      RT_LE2H_U32(pUnion->PN.Major.le),
     2730                          RT_BE2H_U32(pUnion->PN.Minor.be),      RT_LE2H_U32(pUnion->PN.Minor.le) ));
     2731                else if (RTFS_IS_DIRECTORY(pParseInfo->Info.Attr.fMode))
     2732                    Log4(("rtFsIsoDir_ParseRockRidgeData: Ignorning 'PN' entry for directory (%#x/%#x)\n",
     2733                          ISO9660_GET_ENDIAN(&pUnion->PN.Major), ISO9660_GET_ENDIAN(&pUnion->PN.Minor) ));
     2734                else
     2735                {
     2736                    pParseInfo->Info.Attr.u.Unix.Device = RTDEV_MAKE(ISO9660_GET_ENDIAN(&pUnion->PN.Major),
     2737                                                                     ISO9660_GET_ENDIAN(&pUnion->PN.Minor));
     2738                    pParseInfo->cRockEntries++;
     2739                }
     2740                break;
     2741
     2742            case SUSP_MAKE_SIG(ISO9660RRIPTF_SIG1, ISO9660RRIPTF_SIG2): /* TF */
     2743                if (   pUnion->TF.Hdr.bVersion != ISO9660RRIPTF_VER
     2744                    || pUnion->TF.Hdr.cbEntry < Iso9660RripTfCalcLength(pUnion->TF.fFlags))
     2745                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'TF' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x) fFlags=%#x\n",
     2746                          pUnion->TF.Hdr.cbEntry, Iso9660RripTfCalcLength(pUnion->TF.fFlags),
     2747                          pUnion->TF.Hdr.bVersion, ISO9660RRIPTF_VER, RT_BE2H_U32(pUnion->TF.fFlags) ));
     2748                else if (!(pUnion->TF.fFlags & ISO9660RRIPTF_F_LONG_FORM))
     2749                {
     2750                    PCISO9660RECTIMESTAMP pTimestamp = (PCISO9660RECTIMESTAMP)&pUnion->TF.abPayload[0];
     2751                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_BIRTH)
     2752                    {
     2753                        rtFsIso9660DateTime2TimeSpec(&pParseInfo->Info.BirthTime, pTimestamp);
     2754                        pTimestamp++;
     2755                    }
     2756                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_MODIFY)
     2757                    {
     2758                        rtFsIso9660DateTime2TimeSpec(&pParseInfo->Info.ModificationTime, pTimestamp);
     2759                        pTimestamp++;
     2760                    }
     2761                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_ACCESS)
     2762                    {
     2763                        rtFsIso9660DateTime2TimeSpec(&pParseInfo->Info.AccessTime, pTimestamp);
     2764                        pTimestamp++;
     2765                    }
     2766                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_CHANGE)
     2767                    {
     2768                        rtFsIso9660DateTime2TimeSpec(&pParseInfo->Info.ChangeTime, pTimestamp);
     2769                        pTimestamp++;
     2770                    }
     2771                    pParseInfo->cRockEntries++;
     2772                }
     2773                else
     2774                {
     2775                    PCISO9660TIMESTAMP pTimestamp = (PCISO9660TIMESTAMP)&pUnion->TF.abPayload[0];
     2776                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_BIRTH)
     2777                    {
     2778                        rtFsIso9660DateTime2TimeSpecIfValid(&pParseInfo->Info.BirthTime, pTimestamp);
     2779                        pTimestamp++;
     2780                    }
     2781                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_MODIFY)
     2782                    {
     2783                        rtFsIso9660DateTime2TimeSpecIfValid(&pParseInfo->Info.ModificationTime, pTimestamp);
     2784                        pTimestamp++;
     2785                    }
     2786                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_ACCESS)
     2787                    {
     2788                        rtFsIso9660DateTime2TimeSpecIfValid(&pParseInfo->Info.AccessTime, pTimestamp);
     2789                        pTimestamp++;
     2790                    }
     2791                    if (pUnion->TF.fFlags & ISO9660RRIPTF_F_CHANGE)
     2792                    {
     2793                        rtFsIso9660DateTime2TimeSpecIfValid(&pParseInfo->Info.ChangeTime, pTimestamp);
     2794                        pTimestamp++;
     2795                    }
     2796                    pParseInfo->cRockEntries++;
     2797                }
     2798                break;
     2799
     2800            case SUSP_MAKE_SIG(ISO9660RRIPSF_SIG1, ISO9660RRIPSF_SIG2): /* SF */
     2801                Log4(("rtFsIsoDir_ParseRockRidgeData: Sparse file support not yet implemented!\n"));
     2802                break;
     2803
     2804            case SUSP_MAKE_SIG(ISO9660RRIPSL_SIG1, ISO9660RRIPSL_SIG2): /* SL */
     2805                if (   pUnion->SL.Hdr.bVersion != ISO9660RRIPSL_VER
     2806                    || pUnion->SL.Hdr.cbEntry < RT_UOFFSETOF(ISO9660RRIPSL, abComponents[2])
     2807                    || (pUnion->SL.fFlags & ~ISO9660RRIP_SL_F_CONTINUE)
     2808                    || (pUnion->SL.abComponents[0] & ISO9660RRIP_SL_C_RESERVED_MASK) )
     2809                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SL' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x) fFlags=%#x comp[0].fFlags=%#x\n",
     2810                          pUnion->SL.Hdr.cbEntry, RT_UOFFSETOF(ISO9660RRIPSL, abComponents[2]),
     2811                          pUnion->SL.Hdr.bVersion, ISO9660RRIPSL_VER, pUnion->SL.fFlags, pUnion->SL.abComponents[0]));
     2812                else if (pParseInfo->fSeenLastSL)
     2813                    Log4(("rtFsIsoDir_ParseRockRidgeData: Unexpected 'SL!' entry\n"));
     2814                else
     2815                {
     2816                    pParseInfo->cRockEntries++;
     2817                    pParseInfo->fSeenLastSL = !(pUnion->SL.fFlags & ISO9660RRIP_SL_F_CONTINUE); /* used in loop */
     2818
     2819                    size_t         offDst    = pParseInfo->cchLinkTarget;
     2820                    uint8_t const *pbSrc     = &pUnion->SL.abComponents[0];
     2821                    uint8_t        cbSrcLeft = pUnion->SL.Hdr.cbEntry - RT_UOFFSETOF(ISO9660RRIPSL, abComponents);
     2822                    while (cbSrcLeft >= 2)
     2823                    {
     2824                        uint8_t const fFlags  = pbSrc[0];
     2825                        uint8_t       cchCopy = pbSrc[1];
     2826                        uint8_t const cbSkip  = cchCopy + 2;
     2827                        if (cbSkip > cbSrcLeft)
     2828                        {
     2829                            Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SL' component: component flags=%#x, component length+2=%#x vs %#x left\n",
     2830                                  fFlags, cbSkip, cbSrcLeft));
     2831                            break;
     2832                        }
     2833
     2834                        const char *pszCopy;
     2835                        switch (fFlags & ~ISO9660RRIP_SL_C_CONTINUE)
     2836                        {
     2837                            case 0:
     2838                                pszCopy = (const char *)&pbSrc[2];
     2839                                break;
     2840
     2841                            case ISO9660RRIP_SL_C_CURRENT:
     2842                                if (cchCopy != 0)
     2843                                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SL' component: CURRENT + %u bytes, ignoring bytes\n", cchCopy));
     2844                                pszCopy = ".";
     2845                                cchCopy = 1;
     2846                                break;
     2847
     2848                            case ISO9660RRIP_SL_C_PARENT:
     2849                                if (cchCopy != 0)
     2850                                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SL' component: PARENT + %u bytes, ignoring bytes\n", cchCopy));
     2851                                pszCopy = "..";
     2852                                cchCopy = 2;
     2853                                break;
     2854
     2855                            case ISO9660RRIP_SL_C_ROOT:
     2856                                if (cchCopy != 0)
     2857                                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SL' component: ROOT + %u bytes, ignoring bytes\n", cchCopy));
     2858                                pszCopy = "/";
     2859                                cchCopy = 1;
     2860                                break;
     2861
     2862                            default:
     2863                                Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'SL' component: component flags=%#x (bad), component length=%#x vs %#x left\n",
     2864                                      fFlags, cchCopy, cbSrcLeft));
     2865                                pszCopy = NULL;
     2866                                cchCopy = 0;
     2867                                break;
     2868                        }
     2869
     2870                        if (offDst + cchCopy < sizeof(pParseInfo->szLinkTarget))
     2871                        {
     2872                            memcpy(&pParseInfo->szLinkTarget[offDst], pszCopy, cchCopy);
     2873                            offDst += cchCopy;
     2874                        }
     2875                        else
     2876                        {
     2877                            Log4(("rtFsIsoDir_ParseRockRidgeData: 'SL' constructs a too long target! '%.*s%.*s'\n",
     2878                                  offDst, pParseInfo->szLinkTarget, cchCopy, pszCopy));
     2879                            memcpy(&pParseInfo->szLinkTarget[offDst], pszCopy, sizeof(pParseInfo->szLinkTarget) - offDst - 1);
     2880                            offDst = sizeof(pParseInfo->szLinkTarget) - 1;
     2881                            pParseInfo->fOverflowSL = true;
     2882                            break;
     2883                        }
     2884
     2885                        /* Advance */
     2886                        pbSrc     += cbSkip;
     2887                        cbSrcLeft -= cbSkip;
     2888
     2889                        /* Append slash if appropriate. */
     2890                        if (   !(fFlags & ISO9660RRIP_SL_C_CONTINUE)
     2891                            && (cbSrcLeft >= 2 || !pParseInfo->fSeenLastSL) )
     2892                        {
     2893                            if (offDst + 1 < sizeof(pParseInfo->szLinkTarget))
     2894                                pParseInfo->szLinkTarget[offDst++] = '/';
     2895                            else
     2896                            {
     2897                                Log4(("rtFsIsoDir_ParseRockRidgeData: 'SL' constructs a too long target! '%.*s/'\n",
     2898                                      offDst, pParseInfo->szLinkTarget));
     2899                                pParseInfo->fOverflowSL = true;
     2900                                break;
     2901                            }
     2902                        }
     2903                    }
     2904                    Assert(offDst < sizeof(pParseInfo->szLinkTarget));
     2905                    pParseInfo->szLinkTarget[offDst] = '\0';
     2906                    pParseInfo->cchLinkTarget        = offDst;
     2907                }
     2908                break;
     2909
     2910            case SUSP_MAKE_SIG(ISO9660RRIPNM_SIG1, ISO9660RRIPNM_SIG2): /* NM */
     2911                if (   pUnion->NM.Hdr.bVersion != ISO9660RRIPNM_VER
     2912                    || pUnion->NM.Hdr.cbEntry < RT_UOFFSETOF(ISO9660RRIPNM, achName)
     2913                    || (pUnion->NM.fFlags & ISO9660RRIP_NM_F_RESERVED_MASK) )
     2914                    Log4(("rtFsIsoDir_ParseRockRidgeData: Malformed 'NM' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x) fFlags=%#x %.*Rhxs\n",
     2915                          pUnion->NM.Hdr.cbEntry, RT_UOFFSETOF(ISO9660RRIPNM, achName),
     2916                          pUnion->NM.Hdr.bVersion, ISO9660RRIPNM_VER, pUnion->NM.fFlags,
     2917                          pUnion->NM.Hdr.cbEntry - RT_MIN(pUnion->NM.Hdr.cbEntry, RT_UOFFSETOF(ISO9660RRIPNM, achName)),
     2918                          &pUnion->NM.achName[0] ));
     2919                else if (pParseInfo->fSeenLastNM)
     2920                    Log4(("rtFsIsoDir_ParseRockRidgeData: Unexpected 'NM' entry!\n"));
     2921                else
     2922                {
     2923                    pParseInfo->cRockEntries++;
     2924                    pParseInfo->fSeenLastNM = !(pUnion->NM.fFlags & ISO9660RRIP_NM_F_CONTINUE);
     2925
     2926                    uint8_t const cchName = pUnion->NM.Hdr.cbEntry - (uint8_t)RT_UOFFSETOF(ISO9660RRIPNM, achName);
     2927                    if (pUnion->NM.fFlags & (ISO9660RRIP_NM_F_CURRENT | ISO9660RRIP_NM_F_PARENT))
     2928                    {
     2929                        if (cchName == 0 && pParseInfo->szName[0] == '\0')
     2930                            Log4(("rtFsIsoDir_ParseRockRidgeData: Ignoring 'NM' entry for '.' and '..'\n"));
     2931                        else
     2932                            Log4(("rtFsIsoDir_ParseRockRidgeData: Ignoring malformed 'NM' using '.' or '..': fFlags=%#x cchName=%#x %.*Rhxs; szRockNameBuf='%s'\n",
     2933                                  pUnion->NM.fFlags, cchName, cchName, pUnion->NM.achName, pParseInfo->szName));
     2934                        pParseInfo->szName[0]   = '\0';
     2935                        pParseInfo->cchName     = 0;
     2936                        pParseInfo->fSeenLastNM = true;
     2937                    }
     2938                    else
     2939                    {
     2940                        size_t offDst = pParseInfo->cchName;
     2941                        if (offDst + cchName < sizeof(pParseInfo->szName))
     2942                        {
     2943                            memcpy(&pParseInfo->szName[offDst], pUnion->NM.achName, cchName);
     2944                            offDst += cchName;
     2945                            pParseInfo->szName[offDst] = '\0';
     2946                            pParseInfo->cchName        = (uint16_t)offDst;
     2947                        }
     2948                        else
     2949                        {
     2950                            Log4(("rtFsIsoDir_ParseRockRidgeData: 'NM' constructs a too long name, ignoring it all: '%s%.*s'\n",
     2951                                  pParseInfo->szName, cchName, pUnion->NM.achName));
     2952                            pParseInfo->szName[0]   = '\0';
     2953                            pParseInfo->cchName     = 0;
     2954                            pParseInfo->fSeenLastNM = true;
     2955                        }
     2956                    }
     2957                }
     2958                break;
     2959
     2960            case SUSP_MAKE_SIG(ISO9660RRIPCL_SIG1, ISO9660RRIPCL_SIG2): /* CL - just warn for now. */
     2961            case SUSP_MAKE_SIG(ISO9660RRIPPL_SIG1, ISO9660RRIPPL_SIG2): /* PL - just warn for now. */
     2962            case SUSP_MAKE_SIG(ISO9660RRIPRE_SIG1, ISO9660RRIPRE_SIG2): /* RE - just warn for now. */
     2963                Log4(("rtFsIsoDir_ParseRockRidgeData: Ignorning directory relocation entry '%c%c'!\n", pUnion->Hdr.bSig1, pUnion->Hdr.bSig2));
     2964                break;
     2965
     2966            default:
     2967                Log4(("rtFsIsoDir_ParseRockRidgeData: Unknown SUSP entry: %#x %#x, %#x bytes, v%u\n",
     2968                      pUnion->Hdr.bSig1, pUnion->Hdr.bSig2, pUnion->Hdr.cbEntry, pUnion->Hdr.bVersion));
     2969                break;
     2970        }
     2971    }
     2972
     2973    /*
     2974     * Set the valid flag if we found anything of interest.
     2975     */
     2976    if (pParseInfo->cRockEntries > 1)
     2977        pParseInfo->fValid = true;
     2978}
     2979
     2980
     2981/**
     2982 * Initializes the rock info structure with info from the standard ISO-9660
     2983 * directory record.
     2984 *
     2985 * @param   pRockInfo   The structure to initialize.
     2986 * @param   pDirRec     The directory record to take basic data from.
     2987 */
     2988static void rtFsIsoDirShrd_InitRockInfo(PRTFSISOROCKINFO pRockInfo, PCISO9660DIRREC pDirRec)
     2989{
     2990    pRockInfo->fValid                           = false;
     2991    pRockInfo->fSuspSeenSP                      = false;
     2992    pRockInfo->fSeenLastNM                      = false;
     2993    pRockInfo->fSeenLastSL                      = false;
     2994    pRockInfo->fOverflowSL                      = false;
     2995    pRockInfo->cRockEntries                     = 0;
     2996    pRockInfo->cchName                          = 0;
     2997    pRockInfo->cchLinkTarget                    = 0;
     2998    pRockInfo->szName[0]                        = '\0';
     2999    pRockInfo->szName[sizeof(pRockInfo->szName) - 1] = '\0';
     3000    pRockInfo->szLinkTarget[0]                  = '\0';
     3001    pRockInfo->szLinkTarget[sizeof(pRockInfo->szLinkTarget) - 1] = '\0';
     3002    pRockInfo->Info.cbObject                    = ISO9660_GET_ENDIAN(&pDirRec->cbData);
     3003    pRockInfo->Info.cbAllocated                 = pRockInfo->Info.cbObject;
     3004    rtFsIso9660DateTime2TimeSpec(&pRockInfo->Info.AccessTime, &pDirRec->RecTime);
     3005    pRockInfo->Info.ModificationTime            = pRockInfo->Info.AccessTime;
     3006    pRockInfo->Info.ChangeTime                  = pRockInfo->Info.AccessTime;
     3007    pRockInfo->Info.BirthTime                   = pRockInfo->Info.AccessTime;
     3008    pRockInfo->Info.Attr.fMode                  = pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY
     3009                                                ? RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY | 0555
     3010                                                : RTFS_TYPE_FILE      | RTFS_DOS_ARCHIVED  | 0444;
     3011    if (pDirRec->fFileFlags & ISO9660_FILE_FLAGS_HIDDEN)
     3012        pRockInfo->Info.Attr.fMode             |= RTFS_DOS_HIDDEN;
     3013    pRockInfo->Info.Attr.enmAdditional          = RTFSOBJATTRADD_UNIX;
     3014    pRockInfo->Info.Attr.u.Unix.uid             = NIL_RTUID;
     3015    pRockInfo->Info.Attr.u.Unix.gid             = NIL_RTGID;
     3016    pRockInfo->Info.Attr.u.Unix.cHardlinks      = 1;
     3017    pRockInfo->Info.Attr.u.Unix.INodeIdDevice   = 0;
     3018    pRockInfo->Info.Attr.u.Unix.INodeId         = 0;
     3019    pRockInfo->Info.Attr.u.Unix.fFlags          = 0;
     3020    pRockInfo->Info.Attr.u.Unix.GenerationId    = 0;
     3021    pRockInfo->Info.Attr.u.Unix.Device          = 0;
     3022}
     3023
     3024
     3025static void rtFsIsoDirShrd_ParseRockForDirRec(PRTFSISODIRSHRD pThis, PCISO9660DIRREC pDirRec, PRTFSISOROCKINFO pRockInfo)
     3026{
     3027    rtFsIsoDirShrd_InitRockInfo(pRockInfo, pDirRec); /* Always! */
     3028
     3029    PRTFSISOVOL const pVol  = pThis->Core.pVol;
     3030    uint8_t           cbSys = pDirRec->cbDirRec - RT_UOFFSETOF(ISO9660DIRREC, achFileId)
     3031                            - pDirRec->bFileIdLength - !(pDirRec->bFileIdLength & 1);
     3032    uint8_t const    *pbSys = (uint8_t const *)&pDirRec->achFileId[pDirRec->bFileIdLength + !(pDirRec->bFileIdLength & 1)];
     3033    if (cbSys >= 4 + pVol->offSuspSkip)
     3034    {
     3035        pbSys += pVol->offSuspSkip;
     3036        cbSys -= pVol->offSuspSkip;
     3037        rtFsIsoDirShrd_ParseRockRidgeData(pVol, pRockInfo, pbSys, cbSys,
     3038                                          false /*fIsFirstDirRec*/, false /*fContinuationRecord*/);
     3039    }
     3040}
     3041
     3042
     3043static void rtFsIsoDirShrd_ParseRockForRoot(PRTFSISODIRSHRD pThis, PCISO9660DIRREC pDirRec)
     3044{
     3045    uint8_t const         cbSys = pDirRec->cbDirRec - RT_UOFFSETOF(ISO9660DIRREC, achFileId)
     3046                                - pDirRec->bFileIdLength - !(pDirRec->bFileIdLength & 1);
     3047    uint8_t const * const pbSys = (uint8_t const *)&pDirRec->achFileId[pDirRec->bFileIdLength + !(pDirRec->bFileIdLength & 1)];
     3048    if (cbSys >= 4)
     3049    {
     3050        RTFSISOROCKINFO RockInfo;
     3051        rtFsIsoDirShrd_InitRockInfo(&RockInfo, pDirRec);
     3052        rtFsIsoDirShrd_ParseRockRidgeData(pThis->Core.pVol, &RockInfo, pbSys, cbSys,
     3053                                          true /*fIsFirstDirRec*/, false /*fContinuationRecord*/);
     3054        if (RockInfo.fValid)
     3055        {
     3056            pThis->Core.fHaveRockInfo    = true;
     3057            pThis->Core.BirthTime        = RockInfo.Info.BirthTime;
     3058            pThis->Core.ChangeTime       = RockInfo.Info.ChangeTime;
     3059            pThis->Core.AccessTime       = RockInfo.Info.AccessTime;
     3060            pThis->Core.ModificationTime = RockInfo.Info.ModificationTime;
     3061            if (RTFS_IS_DIRECTORY(RockInfo.Info.Attr.fMode))
     3062                pThis->Core.fAttrib      = RockInfo.Info.Attr.fMode;
     3063        }
     3064    }
     3065}
     3066
     3067
     3068/**
     3069 * Compares rock ridge information if present in the directory entry.
     3070 *
     3071 * @param   pThis               The shared directory structure.
     3072 * @param   pbSys               The system area of the directory record.
     3073 * @param   cbSys               The number of bytes present in the sys area.
     3074 * @param   pNameCmp            The name comparsion data.
     3075 * @param   fContinuationRecord Set if we're processing a continuation record in
     3076 *                              living in the abRockBuf.
     3077 */
     3078static int rtFsIsoDirShrd_CompareRockRidgeName(PRTFSISODIRSHRD pThis, uint8_t const *pbSys, size_t cbSys,
     3079                                               PRTFSISOROCKNAMECOMP pNameCmp, bool fContinuationRecord)
     3080{
     3081    PRTFSISOVOL const pVol = pThis->Core.pVol;
     3082
     3083    /*
     3084     * Do skipping if specified.
     3085     */
     3086    if (pVol->offSuspSkip)
     3087    {
     3088        if (cbSys <= pVol->offSuspSkip)
     3089            return fContinuationRecord ? VERR_MORE_DATA : VERR_MISMATCH;
     3090        pbSys += pVol->offSuspSkip;
     3091        cbSys -= pVol->offSuspSkip;
     3092    }
     3093
     3094    while (cbSys >= 4)
     3095    {
     3096        /*
     3097         * Check header length and advance the sys variables.
     3098         */
     3099        PCISO9660SUSPUNION pUnion = (PCISO9660SUSPUNION)pbSys;
     3100        if (   pUnion->Hdr.cbEntry > cbSys
     3101            && pUnion->Hdr.cbEntry < sizeof(pUnion->Hdr))
     3102        {
     3103            Log4(("rtFsIsoDirShrd_CompareRockRidgeName: cbEntry=%#x cbSys=%#x (%#x %#x)\n",
     3104                  pUnion->Hdr.cbEntry, cbSys, pUnion->Hdr.bSig1, pUnion->Hdr.bSig2));
     3105            break;
     3106        }
     3107        pbSys += pUnion->Hdr.cbEntry;
     3108        cbSys -= pUnion->Hdr.cbEntry;
     3109
     3110        /*
     3111         * Process the fields we need, nothing else.
     3112         */
     3113        uint16_t const uSig = SUSP_MAKE_SIG(pUnion->Hdr.bSig1, pUnion->Hdr.bSig2);
     3114
     3115
     3116        /*
     3117         * CE - continuation entry
     3118         */
     3119        if (uSig == SUSP_MAKE_SIG(ISO9660SUSPCE_SIG1, ISO9660SUSPCE_SIG2))
     3120        {
     3121            if (RT_BE2H_U32(pUnion->CE.offBlock.be) != RT_LE2H_U32(pUnion->CE.offBlock.le))
     3122                Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Invalid CE offBlock field: be=%#x vs le=%#x\n",
     3123                      RT_BE2H_U32(pUnion->CE.offBlock.be), RT_LE2H_U32(pUnion->CE.offBlock.le)));
     3124            else if (RT_BE2H_U32(pUnion->CE.cbData.be) != RT_LE2H_U32(pUnion->CE.cbData.le))
     3125                Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Invalid CE cbData field: be=%#x vs le=%#x\n",
     3126                      RT_BE2H_U32(pUnion->CE.cbData.be), RT_LE2H_U32(pUnion->CE.cbData.le)));
     3127            else if (RT_BE2H_U32(pUnion->CE.offData.be) != RT_LE2H_U32(pUnion->CE.offData.le))
     3128                Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Invalid CE offData field: be=%#x vs le=%#x\n",
     3129                      RT_BE2H_U32(pUnion->CE.offData.be), RT_LE2H_U32(pUnion->CE.offData.le)));
     3130            else if (!fContinuationRecord)
     3131            {
     3132                uint64_t offData = ISO9660_GET_ENDIAN(&pUnion->CE.offBlock) * (uint64_t)ISO9660_SECTOR_SIZE;
     3133                offData += ISO9660_GET_ENDIAN(&pUnion->CE.offData);
     3134                uint32_t cbData  = ISO9660_GET_ENDIAN(&pUnion->CE.cbData);
     3135                if (cbData <= sizeof(pVol->abRockBuf) - (uint32_t)(offData & ISO9660_SECTOR_OFFSET_MASK))
     3136                {
     3137                    RTCritSectEnter(&pVol->RockBufLock);
     3138
     3139                    AssertCompile(sizeof(pVol->abRockBuf) == ISO9660_SECTOR_SIZE);
     3140                    uint64_t offDataBlock = offData & ~(uint64_t)ISO9660_SECTOR_OFFSET_MASK;
     3141                    int rc;
     3142                    if (pVol->offRockBuf == offDataBlock)
     3143                        rc = rtFsIsoDirShrd_CompareRockRidgeName(pThis, &pVol->abRockBuf[offData & ISO9660_SECTOR_OFFSET_MASK],
     3144                                                                 cbData, pNameCmp, true /*fContinuationRecord*/);
     3145                    else
     3146                    {
     3147                        rc = RTVfsFileReadAt(pVol->hVfsBacking, offDataBlock, pVol->abRockBuf, sizeof(pVol->abRockBuf), NULL);
     3148                        if (RT_SUCCESS(rc))
     3149                            rc = rtFsIsoDirShrd_CompareRockRidgeName(pThis, &pVol->abRockBuf[offData & ISO9660_SECTOR_OFFSET_MASK],
     3150                                                                     cbData, pNameCmp, true /*fContinuationRecord*/);
     3151                        else
     3152                            Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Error reading continuation record at %#RX64: %Rrc\n",
     3153                                  offDataBlock, rc));
     3154                    }
     3155
     3156                    RTCritSectLeave(&pVol->RockBufLock);
     3157                    if (rc != VERR_MORE_DATA)
     3158                        return rc;
     3159                }
     3160                else
     3161                    Log4(("rtFsIsoDirShrd_CompareRockRidgeName: continuation record isn't within a sector! offData=%#RX64 cbData=%#RX32\n",
     3162                          cbData, offData));
     3163            }
     3164            else
     3165                Log4(("rtFsIsoDirShrd_CompareRockRidgeName: nested continuation record!\n"));
     3166        }
     3167        /*
     3168         * NM - Name entry.
     3169         *
     3170         * The character set is supposed to be limited to the portable filename
     3171         * character set defined in section 2.2.2.60 of POSIX.1: A-Za-z0-9._-
     3172         * If there are any other characters used, we consider them as UTF-8
     3173         * for reasons of simplicitiy, however we do not make any effort dealing
     3174         * with codepoint encodings across NM records for now because it is
     3175         * probably a complete waste of time.
     3176         */
     3177        else if (uSig == SUSP_MAKE_SIG(ISO9660RRIPNM_SIG1, ISO9660RRIPNM_SIG2))
     3178        {
     3179            if (   pUnion->NM.Hdr.bVersion != ISO9660RRIPNM_VER
     3180                || pUnion->NM.Hdr.cbEntry < RT_UOFFSETOF(ISO9660RRIPNM, achName)
     3181                || (pUnion->NM.fFlags & ISO9660RRIP_NM_F_RESERVED_MASK) )
     3182                Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Malformed 'NM' entry: cbEntry=%#x (vs %#x), bVersion=%#x (vs %#x) fFlags=%#x %.*Rhxs\n",
     3183                      pUnion->NM.Hdr.cbEntry, RT_UOFFSETOF(ISO9660RRIPNM, achName),
     3184                      pUnion->NM.Hdr.bVersion, ISO9660RRIPNM_VER, pUnion->NM.fFlags,
     3185                      pUnion->NM.Hdr.cbEntry - RT_MIN(pUnion->NM.Hdr.cbEntry, RT_UOFFSETOF(ISO9660RRIPNM, achName)),
     3186                      &pUnion->NM.achName[0] ));
     3187            else
     3188            {
     3189                uint8_t const cchName = pUnion->NM.Hdr.cbEntry - (uint8_t)RT_UOFFSETOF(ISO9660RRIPNM, achName);
     3190                if (!(pUnion->NM.fFlags & (ISO9660RRIP_NM_F_CURRENT | ISO9660RRIP_NM_F_PARENT)))
     3191                { /* likely */ }
     3192                else
     3193                {
     3194                    if (cchName == 0)
     3195                        Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Ignoring 'NM' entry for '.' and '..'\n"));
     3196                    else
     3197                        Log4(("rtFsIsoDirShrd_CompareRockRidgeName: Ignoring malformed 'NM' using '.' or '..': fFlags=%#x cchName=%#x %.*Rhxs\n",
     3198                              pUnion->NM.fFlags, cchName, cchName, pUnion->NM.achName));
     3199                    pNameCmp->offMatched = ~(size_t)0 / 2;
     3200                    return VERR_MISMATCH;
     3201                }
     3202                Log4(("rtFsIsoDirShrd_CompareRockRidgeName: 'NM': fFlags=%#x cchName=%#x '%.*s' (%.*Rhxs); offMatched=%#zx cchEntry=%#zx\n",
     3203                      pUnion->NM.fFlags, cchName, cchName, pUnion->NM.achName, cchName, pUnion->NM.achName, pNameCmp->offMatched, pNameCmp->cchEntry));
     3204                AssertReturn(pNameCmp->offMatched < pNameCmp->cchEntry, VERR_MISMATCH);
     3205
     3206                if (RTStrNICmp(&pNameCmp->pszEntry[pNameCmp->offMatched], pUnion->NM.achName, cchName) == 0)
     3207                {
     3208                    /** @todo Incorrectly ASSUMES all upper and lower codepoints have the same
     3209                     *        encoding length.  However, since this shouldn't be UTF-8, but plain
     3210                     *        limited ASCII that's not really all that important. */
     3211                    pNameCmp->offMatched += cchName;
     3212                    if (!(pUnion->NM.fFlags & ISO9660RRIP_NM_F_CONTINUE))
     3213                    {
     3214                        if (pNameCmp->offMatched >= pNameCmp->cchEntry)
     3215                        {
     3216                            Log4(("rtFsIsoDirShrd_CompareRockRidgeName: 'NM': returning VINF_SUCCESS\n"));
     3217                            return VINF_SUCCESS;
     3218                        }
     3219                        Log4(("rtFsIsoDirShrd_CompareRockRidgeName: 'NM': returning VERR_MISMATCH - %zu unmatched bytes\n",
     3220                              pNameCmp->cchEntry - pNameCmp->offMatched));
     3221                        return VERR_MISMATCH;
     3222                    }
     3223                    if (pNameCmp->offMatched >= pNameCmp->cchEntry)
     3224                    {
     3225                        Log4(("rtFsIsoDirShrd_CompareRockRidgeName: 'NM': returning VERR_MISMATCH - match full name but ISO9660RRIP_NM_F_CONTINUE is set!\n"));
     3226                        return VERR_MISMATCH;
     3227                    }
     3228                }
     3229                else
     3230                {
     3231                    Log4(("rtFsIsoDirShrd_CompareRockRidgeName: 'NM': returning VERR_MISMATCH - mismatch\n"));
     3232                    pNameCmp->offMatched = ~(size_t)0 / 2;
     3233                    return VERR_MISMATCH;
     3234                }
     3235            }
     3236        }
     3237    }
     3238    return fContinuationRecord ? VERR_MORE_DATA : VERR_MISMATCH;
     3239}
     3240
     3241
     3242/**
     3243 * Worker for rtFsIsoDir_FindEntry9660 that compares a name with the rock ridge
     3244 * info in the directory record, if present.
     3245 *
     3246 * @returns true if equal, false if not.
     3247 * @param   pThis               The directory.
     3248 * @param   pDirRec             The directory record.
     3249 * @param   pszEntry            The string to compare with.
     3250 * @param   cbEntry             The length of @a pszEntry including terminator.
     3251 */
     3252static bool rtFsIsoDir_IsEntryEqualRock(PRTFSISODIRSHRD pThis, PCISO9660DIRREC pDirRec, const char *pszEntry, size_t cbEntry)
     3253{
     3254    /*
     3255     * Is there room for any rock ridge data?
     3256     */
     3257    uint8_t const         cbSys = pDirRec->cbDirRec - RT_UOFFSETOF(ISO9660DIRREC, achFileId)
     3258                                - pDirRec->bFileIdLength - !(pDirRec->bFileIdLength & 1);
     3259    uint8_t const * const pbSys = (uint8_t const *)&pDirRec->achFileId[pDirRec->bFileIdLength + !(pDirRec->bFileIdLength & 1)];
     3260    if (cbSys >= 4)
     3261    {
     3262        RTFSISOROCKNAMECOMP NameCmp;
     3263        NameCmp.pszEntry   = pszEntry;
     3264        NameCmp.cchEntry   = cbEntry - 1;
     3265        NameCmp.offMatched = 0;
     3266        int rc = rtFsIsoDirShrd_CompareRockRidgeName(pThis, pbSys, cbSys, &NameCmp, false /*fContinuationRecord*/);
     3267        if (rc == VINF_SUCCESS)
     3268            return true;
     3269    }
     3270    return false;
     3271}
     3272
     3273
     3274/**
    23613275 * Worker for rtFsIsoDir_FindEntry9660 that compares a UTF-16BE name with a
    23623276 * directory record.
     
    24883402 * @param   pfMode          Where to return the file type, rock ridge adjusted.
    24893403 * @param   puVersion       Where to return the file version number.
    2490  */
    2491 static int rtFsIsoDir_FindEntry9660(PRTFSISODIRSHRD pThis, const char *pszEntry,  uint64_t *poffDirRec,
    2492                                     PCISO9660DIRREC *ppDirRec, uint32_t *pcDirRecs, PRTFMODE pfMode, uint32_t *puVersion)
     3404 * @param   pRockInfo       Where to return rock ridge info.  This is NULL if
     3405 *                          the volume didn't advertise any rock ridge info.
     3406 */
     3407static int rtFsIsoDir_FindEntry9660(PRTFSISODIRSHRD pThis, const char *pszEntry, uint64_t *poffDirRec, PCISO9660DIRREC *ppDirRec,
     3408                                    uint32_t *pcDirRecs, PRTFMODE pfMode, uint32_t *puVersion, PRTFSISOROCKINFO pRockInfo)
    24933409{
    24943410    Assert(pThis->Core.pVol->enmType != RTFSISOVOLTYPE_UDF);
     
    25003416    *pfMode     = UINT32_MAX;
    25013417    *puVersion  = 0;
     3418    if (pRockInfo)
     3419        pRockInfo->fValid = false;
    25023420
    25033421    /*
     
    25063424     */
    25073425    int         rc;
    2508     bool const  fIsUtf16  = pThis->Core.pVol->fIsUtf16;
    2509     size_t      cwcEntry  = 0;
    2510     size_t      cbEntry   = 0;
    2511     size_t      cchUpper  = ~(size_t)0;
     3426    bool const  fIsUtf16 = pThis->Core.pVol->fIsUtf16;
     3427    size_t      cwcEntry = 0;
     3428    size_t      cbEntry  = 0;
     3429    size_t      cchUpper = ~(size_t)0;
    25123430    union
    25133431    {
     
    25343452        RTStrToUpper(uBuf.s.szUpper);
    25353453        cchUpper = strlen(uBuf.s.szUpper);
     3454        cbEntry  = strlen(pszEntry) + 1;
    25363455    }
    25373456
     
    25503469        else
    25513470        {
    2552             /* Try match the filename. */
    2553             if (fIsUtf16)
     3471            /*
     3472             * Try match the filename.
     3473             */
     3474            /** @todo not sure if it's a great idea to match both name spaces...   */
     3475            if (RT_LIKELY(  fIsUtf16
     3476                          ?    !rtFsIsoDir_IsEntryEqualUtf16Big(pDirRec, uBuf.wszEntry, cbEntry, cwcEntry, puVersion)
     3477                            && (   !pRockInfo
     3478                                || !rtFsIsoDir_IsEntryEqualRock(pThis, pDirRec, pszEntry, cbEntry))
     3479                          :    (   !pRockInfo
     3480                                || !rtFsIsoDir_IsEntryEqualRock(pThis, pDirRec, pszEntry, cbEntry))
     3481                            && !rtFsIsoDir_IsEntryEqualAscii(pDirRec, uBuf.s.szUpper, cchUpper, puVersion) ))
    25543482            {
    2555                 if (RT_LIKELY(!rtFsIsoDir_IsEntryEqualUtf16Big(pDirRec, uBuf.wszEntry, cbEntry, cwcEntry, puVersion)))
    2556                 {
    2557                     /* Advance */
    2558                     offEntryInDir += pDirRec->cbDirRec;
    2559                     continue;
    2560                 }
     3483                /* Advance */
     3484                offEntryInDir += pDirRec->cbDirRec;
     3485                continue;
    25613486            }
     3487
     3488            /*
     3489             * Get info for the entry.
     3490             */
     3491            if (!pRockInfo)
     3492                *pfMode  = pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY
     3493                         ? 0755 | RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY
     3494                         : 0644 | RTFS_TYPE_FILE;
    25623495            else
    25633496            {
    2564                 if (RT_LIKELY(!rtFsIsoDir_IsEntryEqualAscii(pDirRec, uBuf.s.szUpper, cchUpper, puVersion)))
    2565                 {
    2566                     /** @todo check rock. */
    2567                     if (1)
    2568                     {
    2569                         /* Advance */
    2570                         offEntryInDir += pDirRec->cbDirRec;
    2571                         continue;
    2572                     }
    2573                 }
     3497                rtFsIsoDirShrd_ParseRockForDirRec(pThis, pDirRec, pRockInfo);
     3498                *pfMode = pRockInfo->Info.Attr.fMode;
    25743499            }
    2575 
    25763500            *poffDirRec = pThis->Core.FirstExtent.off + offEntryInDir;
    25773501            *ppDirRec   = pDirRec;
    2578             *pfMode     = pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY
    2579                         ? 0755 | RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY
    2580                         : 0644 | RTFS_TYPE_FILE;
    25813502
    25823503            /*
     
    28783799         * ISO 9660
    28793800         */
    2880         PCISO9660DIRREC pDirRec;
    2881         uint64_t        offDirRec;
    2882         uint32_t        cDirRecs;
    2883         RTFMODE         fMode;
    2884         uint32_t        uVersion;
    2885         rc = rtFsIsoDir_FindEntry9660(pShared, pszEntry, &offDirRec, &pDirRec, &cDirRecs, &fMode, &uVersion);
     3801        PCISO9660DIRREC     pDirRec;
     3802        uint64_t            offDirRec;
     3803        uint32_t            cDirRecs;
     3804        RTFMODE             fMode;
     3805        uint32_t            uVersion;
     3806        PRTFSISOROCKINFO    pRockInfo = NULL;
     3807        if (pShared->Core.pVol->fHaveRock)
     3808            pRockInfo = (PRTFSISOROCKINFO)alloca(sizeof(*pRockInfo));
     3809        rc = rtFsIsoDir_FindEntry9660(pShared, pszEntry, &offDirRec, &pDirRec, &cDirRecs, &fMode, &uVersion, pRockInfo);
    28863810        Log2(("rtFsIsoDir_Open: FindEntry9660(,%s,) -> %Rrc\n", pszEntry, rc));
    28873811        if (RT_SUCCESS(rc))
     
    28933817                    {
    28943818                        RTVFSFILE hVfsFile;
    2895                         rc = rtFsIsoFile_New9660(pShared->Core.pVol, pShared, pDirRec, cDirRecs,
    2896                                                  offDirRec, fOpen, uVersion, &hVfsFile);
     3819                        rc = rtFsIsoFile_New9660(pShared->Core.pVol, pShared, pDirRec, cDirRecs, offDirRec, fOpen,
     3820                                                 uVersion, pRockInfo && pRockInfo->fValid ? pRockInfo : NULL, &hVfsFile);
    28973821                        if (RT_SUCCESS(rc))
    28983822                        {
     
    29103834                    {
    29113835                        RTVFSDIR hVfsDir;
    2912                         rc = rtFsIsoDir_New9660(pShared->Core.pVol, pShared, pDirRec, cDirRecs, offDirRec, &hVfsDir);
     3836                        rc = rtFsIsoDir_New9660(pShared->Core.pVol, pShared, pDirRec, cDirRecs, offDirRec,
     3837                                                pRockInfo && pRockInfo->fValid ? pRockInfo : NULL, &hVfsDir);
    29133838                        if (RT_SUCCESS(rc))
    29143839                        {
     
    30603985                                  RTFSOBJATTRADD enmAddAttr)
    30613986{
     3987    PRTFSISOROCKINFO    pRockInfo = NULL;
     3988    if (pShared->Core.pVol->fHaveRock)
     3989        pRockInfo = (PRTFSISOROCKINFO)alloca(sizeof(*pRockInfo));
     3990
    30623991    while (pThis->offDir + RT_UOFFSETOF(ISO9660DIRREC, achFileId) <= pShared->cbDir)
    30633992    {
     
    31484077                pDirEntry->szName[cchName] = '\0';
    31494078                RTStrPurgeEncoding(pDirEntry->szName);
    3150 
    3151                 /** @todo check for rock ridge names here.   */
    31524079            }
    31534080            pDirEntry->cwcShortName    = 0;
     
    31614088            RT_ZERO(TmpObj);
    31624089            rtFsIsoCore_InitFrom9660DirRec(&TmpObj, pDirRec, 1 /* cDirRecs - see below why 1 */,
    3163                                            pThis->offDir + pShared->Core.FirstExtent.off, uVersion, pShared->Core.pVol);
     4090                                           pThis->offDir + pShared->Core.FirstExtent.off, uVersion, NULL, pShared->Core.pVol);
    31644091            int rc = rtFsIsoCore_QueryInfo(&TmpObj, &pDirEntry->Info, enmAddAttr);
     4092
     4093            /*
     4094             * Look for rock ridge info associated with this entry
     4095             * and merge that into the record.
     4096             */
     4097            if (pRockInfo)
     4098            {
     4099                rtFsIsoDirShrd_ParseRockForDirRec(pShared, pDirRec, pRockInfo);
     4100                if (pRockInfo->fValid)
     4101                {
     4102                    if (   pRockInfo->fSeenLastNM
     4103                        && pRockInfo->cchName > 0
     4104                        && !pShared->Core.pVol->fIsUtf16
     4105                        && (   pDirRec->bFileIdLength != 1
     4106                            || (   pDirRec->achFileId[0] != '\0'    /* . */
     4107                                && pDirRec->achFileId[0] != '\1'))) /* .. */
     4108                    {
     4109                        size_t const cchName  = pRockInfo->cchName;
     4110                        Assert(strlen(pRockInfo->szName) == cchName);
     4111                        size_t const cbNeeded = RT_UOFFSETOF(RTDIRENTRYEX, szName) + cchName + 1;
     4112                        if (*pcbDirEntry < cbNeeded)
     4113                        {
     4114                            Log3(("rtFsIsoDir_ReadDir9660: VERR_BUFFER_OVERFLOW - cbDst=%zu cbNeeded=%zu (Rock)\n", *pcbDirEntry, cbNeeded));
     4115                            *pcbDirEntry = cbNeeded;
     4116                            return VERR_BUFFER_OVERFLOW;
     4117                        }
     4118                        pDirEntry->cbName = (uint16_t)cchName;
     4119                        memcpy(pDirEntry->szName, pRockInfo->szName, cchName);
     4120                        pDirEntry->szName[cchName] = '\0';
     4121
     4122                        RTStrPurgeEncoding(pDirEntry->szName);
     4123                    }
     4124                }
     4125            }
    31654126
    31664127            /*
     
    31684129             *
    31694130             * Multi extent records only affect the file size and the directory location,
    3170              * so we deal with it here instead of involving * rtFsIsoCore_InitFrom9660DirRec
     4131             * so we deal with it here instead of involving rtFsIsoCore_InitFrom9660DirRec
    31714132             * which would potentially require freeing memory and such.
    31724133             */
     
    35704531 * @param   cDirRecs        Number of directory records if more than one.
    35714532 * @param   offDirRec       The byte offset of the directory record.
     4533 * @param   pRockInfo       Optional pointer to rock ridge info for the entry.
    35724534 * @param   ppShared        Where to return the shared directory structure.
    35734535 */
    35744536static int rtFsIsoDirShrd_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec,
    3575                                   uint32_t cDirRecs, uint64_t offDirRec, PRTFSISODIRSHRD *ppShared)
     4537                                  uint32_t cDirRecs, uint64_t offDirRec, PCRTFSISOROCKINFO pRockInfo, PRTFSISODIRSHRD *ppShared)
    35764538{
    35774539    /*
     
    35824544    if (pShared)
    35834545    {
    3584         rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, 0 /*uVersion*/, pThis);
     4546        rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, 0 /*uVersion*/, pRockInfo, pThis);
    35854547        if (RT_SUCCESS(rc))
    35864548        {
     
    35964558                    rtFsIsoDirShrd_Log9660Content(pShared);
    35974559#endif
     4560
     4561                    /*
     4562                     * If this is the root directory, check if rock ridge info is present.
     4563                     */
     4564                    if (   !pParentDir
     4565                        && !(pThis->fFlags & RTFSISO9660_F_NO_ROCK)
     4566                        && pShared->cbDir > RT_UOFFSETOF(ISO9660DIRREC, achFileId[1]))
     4567                    {
     4568                        PCISO9660DIRREC pDirRec0 = (PCISO9660DIRREC)pShared->pbDir;
     4569                        if (   pDirRec0->bFileIdLength == 1
     4570                            && pDirRec0->achFileId[0]  == 0
     4571                            && pDirRec0->cbDirRec > RT_UOFFSETOF(ISO9660DIRREC, achFileId[1]))
     4572                            rtFsIsoDirShrd_ParseRockForRoot(pShared, pDirRec0);
     4573                    }
    35984574
    35994575                    /*
     
    38164792 * @param   cDirRecs        Number of directory records if more than one.
    38174793 * @param   offDirRec       The byte offset of the directory record.
     4794 * @param   pRockInfo       Optional pointer to rock ridge info for the entry.
    38184795 * @param   phVfsDir        Where to return the directory handle.
    38194796 */
    38204797static int  rtFsIsoDir_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec,
    3821                                uint32_t cDirRecs, uint64_t offDirRec, PRTVFSDIR phVfsDir)
     4798                               uint32_t cDirRecs, uint64_t offDirRec, PCRTFSISOROCKINFO pRockInfo, PRTVFSDIR phVfsDir)
    38224799{
    38234800    /*
     
    38274804    if (!pShared)
    38284805    {
    3829         int rc = rtFsIsoDirShrd_New9660(pThis, pParentDir, pDirRec, cDirRecs, offDirRec, &pShared);
     4806        int rc = rtFsIsoDirShrd_New9660(pThis, pParentDir, pDirRec, cDirRecs, offDirRec, pRockInfo, &pShared);
    38304807        if (RT_FAILURE(rc))
    38314808        {
     
    38904867    RTVfsFileRelease(pThis->hVfsBacking);
    38914868    pThis->hVfsBacking = NIL_RTVFSFILE;
     4869
     4870    if (RTCritSectIsInitialized(&pThis->RockBufLock))
     4871        RTCritSectDelete(&pThis->RockBufLock);
    38924872
    38934873    return VINF_SUCCESS;
     
    55986578
    55996579    /*
    5600      * First initialize the state so that rtFsIsoVol_Destroy won't trip up.
     6580     * First initialize the state so that rtFsIsoVol_Close won't trip up.
    56016581     */
    56026582    pThis->hVfsSelf                     = hVfsSelf;
    5603     pThis->hVfsBacking                  = hVfsBacking; /* Caller referenced it for us, we consume it; rtFsIsoVol_Destroy releases it. */
     6583    pThis->hVfsBacking                  = hVfsBacking; /* Caller referenced it for us, we consume it; rtFsIsoVol_Close releases it. */
    56046584    pThis->cbBacking                    = 0;
    56056585    pThis->cBackingSectors              = 0;
     
    56136593    pThis->fIsUtf16                     = false;
    56146594    pThis->pRootDir                     = NULL;
    5615 
    5616     /*
    5617      * Get stuff that may fail.
    5618      */
    5619     int rc = RTVfsFileQuerySize(hVfsBacking, &pThis->cbBacking);
     6595    pThis->fHaveRock                    = false;
     6596    pThis->offSuspSkip                  = 0;
     6597    pThis->offRockBuf                   = UINT64_MAX;
     6598
     6599    /*
     6600     * Do init stuff that may fail.
     6601     */
     6602    int rc = RTCritSectInit(&pThis->RockBufLock);
     6603    AssertRCReturn(rc, rc);
     6604
     6605    rc = RTVfsFileQuerySize(hVfsBacking, &pThis->cbBacking);
    56206606    if (RT_SUCCESS(rc))
    56216607        pThis->cBackingSectors = pThis->cbBacking / pThis->cbSector;
     
    57826768        {
    57836769#if 1
    5784             /* The warp server for ebusiness update ISOs knowns as ACP2 & MCP2 ends up here,
     6770            /* The warp server for ebusiness update ISOs known as ACP2 & MCP2 ends up here,
    57856771               as they do in deed miss a terminator volume descriptor and we're now at the
    57866772               root directory already. Just detect this, ignore it and get on with things. */
     
    58216807     * no way to override this without using the RTFSISO9660_F_NO_XXX options.
    58226808     *
    5823      * If there isn't UDF, we may faced with choosing between joliet and rock
    5824      * ridge.  The joliet option is generally favorable as we don't have to
    5825      * guess wrt to the file name encoding.  So, we'll pick that for now.
     6809     * If there isn't UDF, we may be faced with choosing between joliet and
     6810     * rock ridge.  The joliet option is generally favorable as we don't have
     6811     * to guess wrt to the file name encoding.  So, we'll pick that for now.
    58266812     *
    58276813     * Note! Should we change this preference for joliet, there fun wrt making sure
     
    58416827        pThis->enmType = RTFSISOVOLTYPE_JOLIET;
    58426828        pThis->fIsUtf16 = true;
    5843         return rtFsIsoDirShrd_New9660(pThis, NULL, &JolietRootDir, 1, offJolietRootDirRec, &pThis->pRootDir);
     6829        return rtFsIsoDirShrd_New9660(pThis, NULL, &JolietRootDir, 1, offJolietRootDirRec, NULL, &pThis->pRootDir);
    58446830    }
    58456831    pThis->enmType = RTFSISOVOLTYPE_ISO9960;
    5846     return rtFsIsoDirShrd_New9660(pThis, NULL, &RootDir, 1, offRootDirRec, &pThis->pRootDir);
     6832    return rtFsIsoDirShrd_New9660(pThis, NULL, &RootDir, 1, offRootDirRec, NULL, &pThis->pRootDir);
    58476833}
    58486834
     
    58726858     * Create a new ISO VFS instance and try initialize it using the given input file.
    58736859     */
    5874     RTVFS hVfs   = NIL_RTVFS;
    5875     void *pvThis = NULL;
    5876     int rc = RTVfsNew(&g_rtFsIsoVolOps, sizeof(RTFSISOVOL), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, &pvThis);
     6860    RTVFS       hVfs   = NIL_RTVFS;
     6861    PRTFSISOVOL pThis = NULL;
     6862    int rc = RTVfsNew(&g_rtFsIsoVolOps, sizeof(RTFSISOVOL), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis);
    58776863    if (RT_SUCCESS(rc))
    58786864    {
    5879         rc = rtFsIsoVolTryInit((PRTFSISOVOL)pvThis, hVfs, hVfsFileIn, fFlags, pErrInfo);
     6865        rc = rtFsIsoVolTryInit(pThis, hVfs, hVfsFileIn, fFlags, pErrInfo);
    58806866        if (RT_SUCCESS(rc))
    58816867            *phVfs = hVfs;
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