Changeset 94280 in vbox
- Timestamp:
- Mar 17, 2022 1:35:42 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/isovfs.cpp
r93510 r94280 33 33 #include <iprt/fsvfs.h> 34 34 35 #include <iprt/alloca.h> 35 36 #include <iprt/asm.h> 36 37 #include <iprt/assert.h> 37 38 #include <iprt/err.h> 38 39 #include <iprt/crc.h> 40 #include <iprt/critsect.h> 39 41 #include <iprt/ctype.h> 40 42 #include <iprt/file.h> … … 142 144 /** @} */ 143 145 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) ) 144 152 145 153 … … 155 163 typedef struct RTFSISODIRSHRD *PRTFSISODIRSHRD; 156 164 165 166 /** 167 * Output structure for rock ridge directory entry parsing. 168 */ 169 typedef 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. */ 195 typedef RTFSISOROCKINFO *PRTFSISOROCKINFO; 196 /** Const rock ridge info for a directory entry. */ 197 typedef RTFSISOROCKINFO const *PCRTFSISOROCKINFO; 198 199 /** 200 * Rock ridge name compare data. 201 */ 202 typedef 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. */ 213 typedef RTFSISOROCKNAMECOMP *PRTFSISOROCKNAMECOMP; 157 214 158 215 … … 195 252 /** Attributes. */ 196 253 RTFMODE fAttrib; 254 /** Set if there is rock ridge info for this directory entry. */ 255 bool fHaveRockInfo; 197 256 /** The object size. */ 198 257 uint64_t cbObject; … … 423 482 /** The root directory shared data. */ 424 483 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 /** @} */ 425 498 } RTFSISOVOL; 426 499 … … 458 531 static int rtFsIsoDir_NewWithShared(PRTFSISOVOL pThis, PRTFSISODIRSHRD pShared, PRTVFSDIR phVfsDir); 459 532 static int rtFsIsoDir_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec, 460 uint32_t cDirRecs, uint64_t offDirRec, P RTVFSDIR phVfsDir);533 uint32_t cDirRecs, uint64_t offDirRec, PCRTFSISOROCKINFO pRockInfo, PRTVFSDIR phVfsDir); 461 534 static int rtFsIsoDir_NewUdf(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCUDFFILEIDDESC pFid, PRTVFSDIR phVfsDir); 462 535 static PRTFSISOCORE rtFsIsoDir_LookupShared(PRTFSISODIRSHRD pThis, uint64_t offDirRec); … … 704 777 if (RT_ABS(pIso9660->offUtc) <= 13*4) 705 778 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 */ 789 static 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; 706 852 } 707 853 … … 758 904 * @param offDirRec The offset of the primary directory record. 759 905 * @param uVersion The file version number. 906 * @param pRockInfo Optional rock ridge info for the entry. 760 907 * @param pVol The volume. 761 908 */ 762 909 static int rtFsIsoCore_InitFrom9660DirRec(PRTFSISOCORE pCore, PCISO9660DIRREC pDirRec, uint32_t cDirRecs, 763 uint64_t offDirRec, uint32_t uVersion, P RTFSISOVOL pVol)910 uint64_t offDirRec, uint32_t uVersion, PCRTFSISOROCKINFO pRockInfo, PRTFSISOVOL pVol) 764 911 { 765 912 RTListInit(&pCore->Entry); … … 769 916 pCore->offDirRec = offDirRec; 770 917 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 772 923 ? 0755 | RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY 773 924 : 0644 | RTFS_TYPE_FILE; … … 782 933 pCore->FirstExtent.uReserved = 0; 783 934 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 } 788 949 789 950 /* … … 1877 2038 return VERR_INVALID_PARAMETER; 1878 2039 } 2040 2041 if ( pCore->fHaveRockInfo 2042 && enmAddAttr != RTFSOBJATTRADD_NOTHING) 2043 { 2044 /** @todo Read the the rock info for this entry. */ 2045 } 2046 1879 2047 return VINF_SUCCESS; 1880 2048 } … … 2173 2341 * parsed the filename, we don't want to repeat the 2174 2342 * effort here). 2343 * @param pRockInfo Optional rock ridge info for the file. 2175 2344 * @param phVfsFile Where to return the file handle. 2176 2345 */ 2177 2346 static 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) 2179 2349 { 2180 2350 AssertPtr(pParentDir); … … 2204 2374 if (pShared) 2205 2375 { 2206 rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, uVersion, p This);2376 rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, uVersion, pRockInfo, pThis); 2207 2377 if (RT_SUCCESS(rc)) 2208 2378 { … … 2359 2529 2360 2530 /** 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 */ 2543 static 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 */ 2988 static 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 3025 static 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 3043 static 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 */ 3078 static 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 */ 3252 static 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 /** 2361 3275 * Worker for rtFsIsoDir_FindEntry9660 that compares a UTF-16BE name with a 2362 3276 * directory record. … … 2488 3402 * @param pfMode Where to return the file type, rock ridge adjusted. 2489 3403 * @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 */ 3407 static int rtFsIsoDir_FindEntry9660(PRTFSISODIRSHRD pThis, const char *pszEntry, uint64_t *poffDirRec, PCISO9660DIRREC *ppDirRec, 3408 uint32_t *pcDirRecs, PRTFMODE pfMode, uint32_t *puVersion, PRTFSISOROCKINFO pRockInfo) 2493 3409 { 2494 3410 Assert(pThis->Core.pVol->enmType != RTFSISOVOLTYPE_UDF); … … 2500 3416 *pfMode = UINT32_MAX; 2501 3417 *puVersion = 0; 3418 if (pRockInfo) 3419 pRockInfo->fValid = false; 2502 3420 2503 3421 /* … … 2506 3424 */ 2507 3425 int rc; 2508 bool const fIsUtf16 2509 size_t cwcEntry 2510 size_t cbEntry 2511 size_t cchUpper 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; 2512 3430 union 2513 3431 { … … 2534 3452 RTStrToUpper(uBuf.s.szUpper); 2535 3453 cchUpper = strlen(uBuf.s.szUpper); 3454 cbEntry = strlen(pszEntry) + 1; 2536 3455 } 2537 3456 … … 2550 3469 else 2551 3470 { 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) )) 2554 3482 { 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; 2561 3486 } 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; 2562 3495 else 2563 3496 { 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; 2574 3499 } 2575 2576 3500 *poffDirRec = pThis->Core.FirstExtent.off + offEntryInDir; 2577 3501 *ppDirRec = pDirRec; 2578 *pfMode = pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY2579 ? 0755 | RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY2580 : 0644 | RTFS_TYPE_FILE;2581 3502 2582 3503 /* … … 2878 3799 * ISO 9660 2879 3800 */ 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); 2886 3810 Log2(("rtFsIsoDir_Open: FindEntry9660(,%s,) -> %Rrc\n", pszEntry, rc)); 2887 3811 if (RT_SUCCESS(rc)) … … 2893 3817 { 2894 3818 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); 2897 3821 if (RT_SUCCESS(rc)) 2898 3822 { … … 2910 3834 { 2911 3835 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); 2913 3838 if (RT_SUCCESS(rc)) 2914 3839 { … … 3060 3985 RTFSOBJATTRADD enmAddAttr) 3061 3986 { 3987 PRTFSISOROCKINFO pRockInfo = NULL; 3988 if (pShared->Core.pVol->fHaveRock) 3989 pRockInfo = (PRTFSISOROCKINFO)alloca(sizeof(*pRockInfo)); 3990 3062 3991 while (pThis->offDir + RT_UOFFSETOF(ISO9660DIRREC, achFileId) <= pShared->cbDir) 3063 3992 { … … 3148 4077 pDirEntry->szName[cchName] = '\0'; 3149 4078 RTStrPurgeEncoding(pDirEntry->szName); 3150 3151 /** @todo check for rock ridge names here. */3152 4079 } 3153 4080 pDirEntry->cwcShortName = 0; … … 3161 4088 RT_ZERO(TmpObj); 3162 4089 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); 3164 4091 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 } 3165 4126 3166 4127 /* … … 3168 4129 * 3169 4130 * Multi extent records only affect the file size and the directory location, 3170 * so we deal with it here instead of involving *rtFsIsoCore_InitFrom9660DirRec4131 * so we deal with it here instead of involving rtFsIsoCore_InitFrom9660DirRec 3171 4132 * which would potentially require freeing memory and such. 3172 4133 */ … … 3570 4531 * @param cDirRecs Number of directory records if more than one. 3571 4532 * @param offDirRec The byte offset of the directory record. 4533 * @param pRockInfo Optional pointer to rock ridge info for the entry. 3572 4534 * @param ppShared Where to return the shared directory structure. 3573 4535 */ 3574 4536 static int rtFsIsoDirShrd_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec, 3575 uint32_t cDirRecs, uint64_t offDirRec, P RTFSISODIRSHRD *ppShared)4537 uint32_t cDirRecs, uint64_t offDirRec, PCRTFSISOROCKINFO pRockInfo, PRTFSISODIRSHRD *ppShared) 3576 4538 { 3577 4539 /* … … 3582 4544 if (pShared) 3583 4545 { 3584 rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, 0 /*uVersion*/, p This);4546 rc = rtFsIsoCore_InitFrom9660DirRec(&pShared->Core, pDirRec, cDirRecs, offDirRec, 0 /*uVersion*/, pRockInfo, pThis); 3585 4547 if (RT_SUCCESS(rc)) 3586 4548 { … … 3596 4558 rtFsIsoDirShrd_Log9660Content(pShared); 3597 4559 #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 } 3598 4574 3599 4575 /* … … 3816 4792 * @param cDirRecs Number of directory records if more than one. 3817 4793 * @param offDirRec The byte offset of the directory record. 4794 * @param pRockInfo Optional pointer to rock ridge info for the entry. 3818 4795 * @param phVfsDir Where to return the directory handle. 3819 4796 */ 3820 4797 static int rtFsIsoDir_New9660(PRTFSISOVOL pThis, PRTFSISODIRSHRD pParentDir, PCISO9660DIRREC pDirRec, 3821 uint32_t cDirRecs, uint64_t offDirRec, P RTVFSDIR phVfsDir)4798 uint32_t cDirRecs, uint64_t offDirRec, PCRTFSISOROCKINFO pRockInfo, PRTVFSDIR phVfsDir) 3822 4799 { 3823 4800 /* … … 3827 4804 if (!pShared) 3828 4805 { 3829 int rc = rtFsIsoDirShrd_New9660(pThis, pParentDir, pDirRec, cDirRecs, offDirRec, &pShared);4806 int rc = rtFsIsoDirShrd_New9660(pThis, pParentDir, pDirRec, cDirRecs, offDirRec, pRockInfo, &pShared); 3830 4807 if (RT_FAILURE(rc)) 3831 4808 { … … 3890 4867 RTVfsFileRelease(pThis->hVfsBacking); 3891 4868 pThis->hVfsBacking = NIL_RTVFSFILE; 4869 4870 if (RTCritSectIsInitialized(&pThis->RockBufLock)) 4871 RTCritSectDelete(&pThis->RockBufLock); 3892 4872 3893 4873 return VINF_SUCCESS; … … 5598 6578 5599 6579 /* 5600 * First initialize the state so that rtFsIsoVol_ Destroywon't trip up.6580 * First initialize the state so that rtFsIsoVol_Close won't trip up. 5601 6581 */ 5602 6582 pThis->hVfsSelf = hVfsSelf; 5603 pThis->hVfsBacking = hVfsBacking; /* Caller referenced it for us, we consume it; rtFsIsoVol_ Destroyreleases it. */6583 pThis->hVfsBacking = hVfsBacking; /* Caller referenced it for us, we consume it; rtFsIsoVol_Close releases it. */ 5604 6584 pThis->cbBacking = 0; 5605 6585 pThis->cBackingSectors = 0; … … 5613 6593 pThis->fIsUtf16 = false; 5614 6594 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); 5620 6606 if (RT_SUCCESS(rc)) 5621 6607 pThis->cBackingSectors = pThis->cbBacking / pThis->cbSector; … … 5782 6768 { 5783 6769 #if 1 5784 /* The warp server for ebusiness update ISOs known sas ACP2 & MCP2 ends up here,6770 /* The warp server for ebusiness update ISOs known as ACP2 & MCP2 ends up here, 5785 6771 as they do in deed miss a terminator volume descriptor and we're now at the 5786 6772 root directory already. Just detect this, ignore it and get on with things. */ … … 5821 6807 * no way to override this without using the RTFSISO9660_F_NO_XXX options. 5822 6808 * 5823 * If there isn't UDF, we may faced with choosing between joliet and rock5824 * r idge. The joliet option is generally favorable as we don't have to5825 * 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. 5826 6812 * 5827 6813 * Note! Should we change this preference for joliet, there fun wrt making sure … … 5841 6827 pThis->enmType = RTFSISOVOLTYPE_JOLIET; 5842 6828 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); 5844 6830 } 5845 6831 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); 5847 6833 } 5848 6834 … … 5872 6858 * Create a new ISO VFS instance and try initialize it using the given input file. 5873 6859 */ 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); 5877 6863 if (RT_SUCCESS(rc)) 5878 6864 { 5879 rc = rtFsIsoVolTryInit( (PRTFSISOVOL)pvThis, hVfs, hVfsFileIn, fFlags, pErrInfo);6865 rc = rtFsIsoVolTryInit(pThis, hVfs, hVfsFileIn, fFlags, pErrInfo); 5880 6866 if (RT_SUCCESS(rc)) 5881 6867 *phVfs = hVfs;
Note:
See TracChangeset
for help on using the changeset viewer.