Changeset 69910 in vbox
- Timestamp:
- Dec 3, 2017 5:06:56 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/formats/fat.h
r69849 r69910 468 468 /** 0x41 / 0x36: Reserved. */ 469 469 uint8_t abReserved3[3]; 470 /** 0x44 / 0x39: Logical clusters pre index block.470 /** 0x44 / 0x39: The default logical clusters count per index node. 471 471 * This is a shift count if negative. */ 472 int8_t cCluster PerIndexBlock;472 int8_t cClustersPerIndexNode; 473 473 /** 0x45 / 0x3a: Reserved. */ 474 474 uint8_t abReserved4[3]; -
trunk/include/iprt/formats/ntfs.h
r69902 r69910 139 139 /** Pointer to a const NTFS record header. */ 140 140 typedef NTFSRECHDR const *PCNTFSRECHDR; 141 142 /** The multi-sector update sequence stride. 143 * @see https://msdn.microsoft.com/en-us/library/bb470212%28v=vs.85%29.aspx 144 * @see NTFSRECHDR::offUpdateSeqArray, NTFSRECHDR::cUpdateSeqEntries 145 */ 146 #define NTFS_MULTI_SECTOR_STRIDE 512 141 147 142 148 … … 332 338 #define NTFSATTRIBHDR_GET_NAME(a_pAttrHdr) ( (PRTUTF16)((uintptr_t)(a_pAttrHdr) + (a_pAttrHdr)->offName) ) 333 339 340 /** Get the pointer to resident value. 341 * @note ASSUMES the caller checks that it's resident and valid. */ 342 #define NTFSATTRIBHDR_GET_RES_VALUE_PTR(a_pAttrHdr) ( (uint8_t *)(a_pAttrHdr) + (a_pAttrHdr)->u.Res.offValue ) 343 334 344 335 345 /** @name NTFS_RES_AF_XXX … … 549 559 * NTFS index header. 550 560 * 551 * This is used by NTFSATINDEXROOT and NTFSATINDEXALLOC. 552 */ 553 typedef struct NTFSINDEXHEADER 561 * This is used by NTFSATINDEXROOT and NTFSATINDEXALLOC as a prelude to the 562 * sequence of entries in a node. 563 */ 564 typedef struct NTFSINDEXHDR 554 565 { 555 566 /** 0x00: Offset of the first entry relative to this header. */ 556 567 uint32_t offFirstEntry; 557 /** 0x04: Size of the indexin bytes, including this header. */558 uint32_t cb Index;568 /** 0x04: Current index size in bytes, including this header. */ 569 uint32_t cbUsed; 559 570 /** 0x08: Number of bytes allocated for the index (including this header). */ 560 571 uint32_t cbAllocated; 561 /** 0x0c: Flags (NTFSINDEXH EADER_F_XXX). */572 /** 0x0c: Flags (NTFSINDEXHDR_F_XXX). */ 562 573 uint8_t fFlags; 563 574 /** 0x0d: Reserved bytes. */ 564 575 uint8_t abReserved[3]; 565 } NTFSINDEXHEADER; 566 AssertCompileSize(NTFSINDEXHEADER, 16); 576 /* NTFSIDXENTRYHDR sequence typically follows here */ 577 } NTFSINDEXHDR; 578 AssertCompileSize(NTFSINDEXHDR, 16); 567 579 /** Pointer to a NTFS index header. */ 568 typedef NTFSINDEXH EADER *PNTFSINDEXHEADER;580 typedef NTFSINDEXHDR *PNTFSINDEXHDR; 569 581 /** Pointer to a const NTFS index header. */ 570 typedef NTFSINDEXHEADER const *PCNTFSINDEXHEADER; 571 572 /** Index root only: Small enough to fit inside the index root attrib. */ 573 #define NTFSINDEXHEADER_F_ROOT_SMALL UINT8_C(0x00) 574 /** Index root only: Too large to fit inside the index root attrib and/or an 575 * index allocation attribute is present. */ 576 #define NTFSINDEXHEADER_F_ROOT_LARGE UINT8_C(0x01) 577 578 579 /** 580 * NTFS index root (NTFS_AT_INDEX_ROOT). 582 typedef NTFSINDEXHDR const *PCNTFSINDEXHDR; 583 584 /** @name NTFSINDEXHDR_F_XXX 585 * @{ */ 586 /** An internal node (as opposed to a leaf node if clear). 587 * This means that the entries will have trailing node references (VCN). */ 588 #define NTFSINDEXHDR_F_INTERNAL UINT8_C(0x01) 589 /** @} */ 590 591 592 /** 593 * NTFS index root node (NTFS_AT_INDEX_ROOT). 581 594 * 582 595 * This is a generic index structure, but is most prominently used for 583 * implementating directories. 596 * implementating directories. The index is structured like B-tree, meaning 597 * each node contains multiple entries, and each entry contains data regardless 598 * of whether it's a leaf node or not. 599 * 600 * The index is sorted in ascending order according to the collation rules 601 * defined by the root node (NTFSATINDEXROOT::uCollationRules, see also (see 602 * NTFS_COLLATION_XXX). 603 * 604 * @note The root directory contains a '.' entry, others don't. 584 605 */ 585 606 typedef struct NTFSATINDEXROOT … … 589 610 /** 0x04: The sorting rules to use (NTFS_COLLATION_XXX). */ 590 611 uint32_t uCollationRules; 591 /** 0x08: Index buffer size (in bytes). */ 592 uint32_t cbIndexBuffer; 593 /** 0x0c: Number of clusters allocated for each index buffer if 594 * cbIndexBuffer is larger than a cluster, otherwise log2(cbIndexBuffer)? */ 595 uint8_t cClustersPerBuffer; 612 /** 0x08: Number of bytes in 613 * Index node size (in bytes). */ 614 uint32_t cbIndexNode; 615 /** 0x0c: Number of node addresses per node. 616 * This sounds weird right? A subnode is generally addressed as a virtual 617 * cluster when cbIndexNode >= cbCluster, but when clusters are large NTFS uses 618 * 512 bytes chunks. 619 * 620 * (You would've thought it would be simpler to just use cbIndexNode as the 621 * addressing unit, maybe storing the log2 here to avoid a ffs call.) */ 622 uint8_t cAddressesPerIndexNode; 596 623 /** 0x0d: Reserved padding or something. */ 597 624 uint8_t abReserved[3]; 598 625 /** 0x10: Index header detailing the entries that follows. */ 599 NTFSINDEXH EADERHdr;600 /* NTFSINDEXENTRYHDR array typically follows*/626 NTFSINDEXHDR Hdr; 627 /* 0x20: NTFSIDXENTRYHDR sequence typically follows here */ 601 628 } NTFSATINDEXROOT; 602 629 AssertCompileSize(NTFSATINDEXROOT, 32); … … 611 638 #define NTFSATINDEXROOT_TYPE_VIEW RT_H2LE_U32_C(UINT32_C(0x00000000)) 612 639 /** Directory index, NTFSATFILENAME follows NTFSINDEXENTRY. */ 613 #define NTFSATINDEXROOT_TYPE_DIR ECTORYRT_H2LE_U32_C(UINT32_C(0x00000030))640 #define NTFSATINDEXROOT_TYPE_DIR RT_H2LE_U32_C(UINT32_C(0x00000030)) 614 641 /** @} */ 615 642 … … 631 658 /** Sequence of little endian 32-bit unsigned integer values used as sorting key. */ 632 659 #define NTFS_COLLATION_UINT32_SEQ RT_H2LE_U32_C(UINT32_C(0x00000013)) 633 634 /** @} */ 660 /** @} */ 661 662 663 /** 664 * NTFS index non-root node. 665 */ 666 typedef struct NTFSATINDEXALLOC 667 { 668 /** 0x00: Header with NTFSREC_MAGIC_INDEX_ALLOC. */ 669 NTFSRECHDR RecHdr; 670 /** 0x08: Log file sequence number. */ 671 uint64_t uLsn; 672 /** 0x10: The node address of this node (for consistency checking and 673 * perhaps data reconstruction). 674 * @see NTFSATINDEXROOT::cAddressesPerIndexNode for node addressing. */ 675 int64_t iSelfAddress; 676 /** 0x18: Index header detailing the entries that follows. */ 677 NTFSINDEXHDR Hdr; 678 /* 0x28: NTFSIDXENTRYHDR sequence typically follows here */ 679 } NTFSATINDEXALLOC; 680 AssertCompileSize(NTFSATINDEXALLOC, 40); 681 /** Pointer to a NTFS index non-root node. */ 682 typedef NTFSATINDEXALLOC *PNTFSATINDEXALLOC; 683 /** Pointer to a const NTFS index non-root node. */ 684 typedef NTFSATINDEXALLOC const *PCNTFSATINDEXALLOC; 685 686 /** NTFS 'INDX' attribute magic value (NTFSATINDEXALLOC). 687 * @todo sort out the record / attribute name clash here. */ 688 #define NTFSREC_MAGIC_INDEX_ALLOC RT_H2LE_U32_C(UINT32_C(0x58444e49)) 635 689 636 690 637 691 /** 638 692 * NTFS index entry header. 639 */ 640 typedef struct NTFSINDEXENTRYHDR 693 * 694 * Each entry in a node starts with this header. It is immediately followed by 695 * the key data (NTFSIDXENTRYHDR::cbKey). When 696 * 697 */ 698 typedef struct NTFSIDXENTRYHDR 641 699 { 642 700 union 643 701 { 644 /** 0x00: N on-View: Reference to the MFT record being indexed here.645 * This is invalid if NTFSINDEX_EF_LAST is set.*/702 /** 0x00: NTFSATINDEXROOT_TYPE_DIR: Reference to the MFT record being indexed here. 703 * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ 646 704 NTFSMFTREF FileMftRec; 647 /** 0x00: View*/705 /** 0x00: NTFSATINDEXROOT_TYPE_VIEW: Go figure later if necessary. */ 648 706 struct 649 707 { 650 /** 0x00: Offset to the data relative to this header. */ 708 /** 0x00: Offset to the data relative to this header. 709 * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ 651 710 uint16_t offData; 652 /** 0x02: Size of data at offData. */ 711 /** 0x02: Size of data at offData. 712 * @note This is invalid if NTFSIDXENTRYHDR_F_END is set (no key data). */ 653 713 uint16_t cbData; 654 714 /** 0x04: Reserved. */ … … 661 721 /** 0x0a: Key length (unaligned). */ 662 722 uint16_t cbKey; 663 /** 0x0c: Entry flags, NTFSI NDEX_EF_XXX. */723 /** 0x0c: Entry flags, NTFSIDXENTRYHDR_F_XXX. */ 664 724 uint16_t fFlags; 665 /** 0x0 d: Entry flags, NTFSINDEX_EF_XXX. */725 /** 0x0e: Reserved. */ 666 726 uint16_t uReserved; 667 } NTFSI NDEXENTRYHDR;668 AssertCompileSize(NTFSI NDEXENTRYHDR, 16);727 } NTFSIDXENTRYHDR; 728 AssertCompileSize(NTFSIDXENTRYHDR, 16); 669 729 /** Pointer to a NTFS index entry header. */ 670 typedef NTFSI NDEXENTRYHDR *PNTFSINDEXENTRYHDR;730 typedef NTFSIDXENTRYHDR *PNTFSIDXENTRYHDR; 671 731 /** Pointer to a const NTFS index entry header. */ 672 typedef NTFSINDEXENTRYHDR const *PCNTFSINDEXENTRYHDR; 673 674 /** @name NTFSINDEX_EF_XXX - NTFSINDEXENTRYHDR::fFlags 675 * @{ */ 676 /** Indicates an internal node, as opposed to a leaf node. */ 677 #define NTFSINDEX_EF_NODE RT_H2LE_U16_C(UINT16_C(0x0001)) 678 /** Last entry in a block, may point to the next node. */ 679 #define NTFSINDEX_EF_LAST RT_H2LE_U16_C(UINT16_C(0x0002)) 732 typedef NTFSIDXENTRYHDR const *PCNTFSIDXENTRYHDR; 733 734 /** @name NTFSIDXENTRYHDR_F_XXX - NTFSIDXENTRYHDR::fFlags 735 * @{ */ 736 /** Indicates an internal node (as opposed to a leaf node). 737 * This indicates that there is a 64-bit integer value at the very end of the 738 * entry (NTFSIDXENTRYHDR::cbEntry - 8) giving the virtual cluster number of the 739 * subnode. The subnode and all its decendants contain keys that are lower than 740 * the key in this entry. 741 */ 742 #define NTFSIDXENTRYHDR_F_INTERNAL RT_H2LE_U16_C(UINT16_C(0x0001)) 743 /** Set if special end entry in a node. 744 * This does not have any key data, but can point to a subnode with 745 * higher keys. */ 746 #define NTFSIDXENTRYHDR_F_END RT_H2LE_U16_C(UINT16_C(0x0002)) 680 747 /** @} */ 681 748 749 /** Gets the pointer to the next index entry header. */ 750 #define NTFSIDXENTRYHDR_GET_NEXT(a_pEntryHdr) \ 751 ( (PNTFSIDXENTRYHDR)((uintptr_t)(a_pEntryHdr) + RT_LE2H_U16((a_pEntryHdr)->cbEntry)) ) 752 /** Gets the subnode address from an index entry. 753 * @see NTFSATINDEXROOT::cAddressesPerIndexNode for node addressing. 754 * @note Only invoke when NTFSIDXENTRYHDR_F_INTERNAL is set! */ 755 #define NTFSIDXENTRYHDR_GET_SUBNODE(a_pEntryHdr) \ 756 ( *(int64_t *)((uintptr_t)(a_pEntryHdr) + RT_LE2H_U16((a_pEntryHdr)->cbEntry) - sizeof(int64_t)) ) 757 682 758 /** @} */ 683 759 -
trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp
r69903 r69910 265 265 /** The MFT record size. */ 266 266 uint32_t cbMftRecord; 267 /** The index recordsize. */268 uint32_t cb IndexRecord;267 /** The default index (B-tree) node size. */ 268 uint32_t cbDefaultIndexNode; 269 269 270 270 /** The volume serial number. */ … … 306 306 *********************************************************************************************************************************/ 307 307 static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis); 308 #ifdef LOG_ENABLED 309 static void rtFsNtfsVol_LogIndexRoot(PCNTFSATINDEXROOT pIdxRoot, uint32_t cbIdxRoot); 310 #endif 308 311 309 312 … … 580 583 //case NTFS_AT_VOLUME_INFORMATION: 581 584 //case NTFS_AT_DATA: 582 //case NTFS_AT_INDEX_ROOT: 585 586 case NTFS_AT_INDEX_ROOT: 587 rtFsNtfsVol_LogIndexRoot((PCNTFSATINDEXROOT)pbValue, cbValue); 588 break; 589 583 590 //case NTFS_AT_INDEX_ALLOCATION: 584 591 //case NTFS_AT_BITMAP: … … 637 644 uint32_t const cbMaxPairs = cbAttrib - offMappingPairs; 638 645 int64_t iVnc = pHdr->u.NonRes.iVcnFirst; 639 Log2(("NTFS: Mapping Pairs: %.*Rhxsd\n", cbMaxPairs, pbPairs)); 646 if (cbMaxPairs < 48) 647 Log2(("NTFS: Mapping Pairs: cbMaxPairs=%#x %.*Rhxs\n", cbMaxPairs, cbMaxPairs, pbPairs)); 648 else 649 Log2(("NTFS: Mapping Pairs: cbMaxPairs=%#x\n%.*Rhxd\n", cbMaxPairs, cbMaxPairs, pbPairs)); 640 650 if (!iVnc && !*pbPairs) 641 651 Log2(("NTFS: [0]: Empty\n")); … … 643 653 { 644 654 if (iVnc != 0) 645 Log2(("NTFS: [0 ]: VCN=%#012RX64 L %#012RX64 - not mapped\n", 0, iVnc));655 Log2(("NTFS: [00/0x000]: VCN=%#012RX64 L %#012RX64 - not mapped\n", 0, iVnc)); 646 656 int64_t iLnc = 0; 647 657 uint32_t iPair = 0; … … 656 666 if (offPairs + cbRun > cbMaxPairs) 657 667 { 658 Log2(("NTFS: [% d]: run overrun! cbRun=%#x bLengths=%#x offPairs=%#x cbMaxPairs=%#x\n",659 iPair, cbRun, bLengths, offPairs, cbMaxPairs));668 Log2(("NTFS: [%02d/%#05x]: run overrun! cbRun=%#x bLengths=%#x offPairs=%#x cbMaxPairs=%#x\n", 669 iPair, offPairs, cbRun, bLengths, offPairs, cbMaxPairs)); 660 670 break; 661 671 } 672 //Log2(("NTFS: @%#05x: %.*Rhxs\n", offPairs, cbRun + 1, &pbPairs[offPairs])); 662 673 663 674 /* Value 1: Number of (virtual) clusters in this run. */ … … 683 694 cLcnDelta = (cLcnDelta << 8) + *pbNum--; 684 695 iLnc += cLcnDelta; 685 Log2(("NTFS: [% d]: VNC=%#012RX64 L %#012RX64 => LNC=%#012RX64\n",686 iPair, iVnc, cClustersInRun, iLnc));696 Log2(("NTFS: [%02d/%#05x]: VNC=%#012RX64 L %#012RX64 => LNC=%#012RX64\n", 697 iPair, offPairs, iVnc, cClustersInRun, iLnc)); 687 698 } 688 699 else 689 Log2(("NTFS: [% d]: VNC=%#012RX64 L %#012RX64 => HOLE\n",690 iPair, iVnc, cClustersInRun));700 Log2(("NTFS: [%02d/%#05x]: VNC=%#012RX64 L %#012RX64 => HOLE\n", 701 iPair, offPairs, iVnc, cClustersInRun)); 691 702 692 703 /* Advance. */ … … 1240 1251 { 1241 1252 rc = RTVfsFileReadAt(pVol->hVfsBacking, pTable->paExtents[iExtent].off + off, pvBuf, cbThisRead, NULL); 1253 Log4(("NTFS: Volume read: @%#RX64 LB %#zx -> %Rrc\n", pTable->paExtents[iExtent].off + off, cbThisRead, rc)); 1242 1254 if (RT_FAILURE(rc)) 1243 1255 break; … … 1284 1296 1285 1297 /** 1298 * 1299 * @returns 1300 * @param pRecHdr . 1301 * @param cbRec . 1302 * @param fRelaxedUsa . 1303 * @param pErrInfo . 1304 * 1305 * @see https://msdn.microsoft.com/en-us/library/bb470212%28v=vs.85%29.aspx 1306 */ 1307 static int rtFsNtfsRec_DoMultiSectorFixups(PNTFSRECHDR pRecHdr, uint32_t cbRec, bool fRelaxedUsa, PRTERRINFO pErrInfo) 1308 { 1309 /* 1310 * Do sanity checking. 1311 */ 1312 uint16_t offUpdateSeqArray = RT_LE2H_U16(pRecHdr->offUpdateSeqArray); 1313 uint16_t cUpdateSeqEntries = RT_LE2H_U16(pRecHdr->cUpdateSeqEntries); 1314 if ( !(cbRec & (NTFS_MULTI_SECTOR_STRIDE - 1)) 1315 && !(offUpdateSeqArray & 1) /* two byte aligned */ 1316 && cUpdateSeqEntries == 1 + cbRec / NTFS_MULTI_SECTOR_STRIDE 1317 && offUpdateSeqArray + (uint32_t)cUpdateSeqEntries * 2U < NTFS_MULTI_SECTOR_STRIDE - 2U) 1318 { 1319 uint16_t const *pauUsa = (uint16_t const *)((uint8_t *)pRecHdr + offUpdateSeqArray); 1320 1321 /* 1322 * The first update seqence array entry is the value stored at 1323 * the fixup locations at the end of the blocks. We read this 1324 * and check each of the blocks. 1325 */ 1326 uint16_t const uCheck = *pauUsa++; 1327 cUpdateSeqEntries--; 1328 for (uint16_t iBlock = 0; iBlock < cUpdateSeqEntries; iBlock++) 1329 { 1330 uint16_t const *puBlockCheck = (uint16_t const *)((uint8_t *)pRecHdr + (iBlock + 1) * NTFS_MULTI_SECTOR_STRIDE - 2U); 1331 if (*puBlockCheck == uCheck) 1332 { /* likely */ } 1333 else if (!fRelaxedUsa) 1334 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_OFFSET, 1335 "Multisector transfer error: block #%u ends with %#x instead of %#x (fixup: %#x)", 1336 iBlock, RT_LE2H_U16(*puBlockCheck), RT_LE2H_U16(uCheck), RT_LE2H_U16(pauUsa[iBlock]) ); 1337 else 1338 { 1339 Log(("NTFS: Multisector transfer warning: block #%u ends with %#x instead of %#x (fixup: %#x)\n", 1340 iBlock, RT_LE2H_U16(*puBlockCheck), RT_LE2H_U16(uCheck), RT_LE2H_U16(pauUsa[iBlock]) )); 1341 return VINF_SUCCESS; 1342 } 1343 } 1344 1345 /* 1346 * Apply the fixups. 1347 * Note! We advanced pauUsa above, so it's now at the fixup values. 1348 */ 1349 for (uint16_t iBlock = 0; iBlock < cUpdateSeqEntries; iBlock++) 1350 { 1351 uint16_t *puFixup = (uint16_t *)((uint8_t *)pRecHdr + (iBlock + 1) * NTFS_MULTI_SECTOR_STRIDE - 2U); 1352 *puFixup = pauUsa[iBlock]; 1353 } 1354 return VINF_SUCCESS; 1355 } 1356 if (fRelaxedUsa) 1357 { 1358 Log(("NTFS: Ignoring bogus multisector update sequence: cbRec=%#x uMagic=%#RX32 offUpdateSeqArray=%#x cUpdateSeqEntries=%#x\n", 1359 cbRec, RT_LE2H_U32(pRecHdr->uMagic), offUpdateSeqArray, cUpdateSeqEntries )); 1360 return VINF_SUCCESS; 1361 } 1362 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_OFFSET, 1363 "Bogus multisector update sequence: cbRec=%#x uMagic=%#RX32 offUpdateSeqArray=%#x cUpdateSeqEntries=%#x", 1364 cbRec, RT_LE2H_U32(pRecHdr->uMagic), offUpdateSeqArray, cUpdateSeqEntries); 1365 } 1366 1367 1368 /** 1286 1369 * Allocate and parse an MFT record, returning a core object structure. 1287 1370 * … … 1289 1372 * @param pThis The NTFS volume instance. 1290 1373 * @param idxMft The index of the MTF record. 1374 * @param fRelaxedUsa Relaxed update sequence checking. Won't fail if 1375 * checks doesn't work or not present. 1291 1376 * @param ppCore Where to return the core object structure. 1292 1377 * @param pErrInfo Where to return error details. Optional. 1293 1378 */ 1294 static int rtFsNtfsVol_NewCoreForMftIdx(PRTFSNTFSVOL pThis, uint64_t idxMft, PRTFSNTFSCORE *ppCore, PRTERRINFO pErrInfo) 1379 static int rtFsNtfsVol_NewCoreForMftIdx(PRTFSNTFSVOL pThis, uint64_t idxMft, bool fRelaxedUsa, 1380 PRTFSNTFSCORE *ppCore, PRTERRINFO pErrInfo) 1295 1381 { 1296 1382 *ppCore = NULL; … … 1303 1389 uint64_t offRec = idxMft * pThis->cbMftRecord; 1304 1390 int rc = rtFsNtfsAttr_Read(pThis->pMftData, offRec, pRec->pbRec, pThis->cbMftRecord); 1391 if (RT_SUCCESS(rc)) 1392 rc = rtFsNtfsRec_DoMultiSectorFixups(&pRec->pFileRec->Hdr, pThis->cbMftRecord, fRelaxedUsa, pErrInfo); 1305 1393 if (RT_SUCCESS(rc)) 1306 1394 { … … 1469 1557 */ 1470 1558 1559 #ifdef LOG_ENABLED 1560 1561 /** 1562 * Logs an index header and all the entries. 1563 * 1564 * @param pIdxHdr The index header. 1565 * @param cbIndex The number of valid bytes starting with the header. 1566 * @param offIndex The offset of the index header into the parent 1567 * structure. 1568 * @param pszPrefix The log prefix. 1569 * @param uIdxType The index type. 1570 */ 1571 static void rtFsNtfsVol_LogIndexHdrAndEntries(PCNTFSINDEXHDR pIdxHdr, uint32_t cbIndex, uint32_t offIndex, 1572 const char *pszPrefix, uint32_t uIdxType) 1573 { 1574 if (!LogIs2Enabled()) 1575 return; 1576 1577 /* 1578 * Do the header. 1579 */ 1580 if (cbIndex <= sizeof(*pIdxHdr)) 1581 { 1582 Log2(("NTFS: %s: Error! Not enough space for the index header! cbIndex=%#x, index head needs %#x\n", 1583 pszPrefix, cbIndex, sizeof(*pIdxHdr))); 1584 return; 1585 } 1586 1587 Log2(("NTFS: %s: offFirstEntry %#x%s\n", pszPrefix, RT_LE2H_U32(pIdxHdr->offFirstEntry), 1588 RT_LE2H_U32(pIdxHdr->offFirstEntry) >= cbIndex ? " !out-of-bounds!" : "")); 1589 Log2(("NTFS: %s: cbUsed %#x%s\n", pszPrefix, RT_LE2H_U32(pIdxHdr->cbUsed), 1590 RT_LE2H_U32(pIdxHdr->cbUsed) > cbIndex ? " !out-of-bounds!" : "")); 1591 Log2(("NTFS: %s: cbAllocated %#x%s\n", pszPrefix, RT_LE2H_U32(pIdxHdr->cbAllocated), 1592 RT_LE2H_U32(pIdxHdr->cbAllocated) > cbIndex ? " !out-of-bounds!" : "")); 1593 Log2(("NTFS: %s: fFlags %#x (%s%s)\n", pszPrefix, pIdxHdr->fFlags, 1594 pIdxHdr->fFlags & NTFSINDEXHDR_F_INTERNAL ? "internal" : "leaf", 1595 pIdxHdr->fFlags & ~NTFSINDEXHDR_F_INTERNAL ? " !!unknown-flags!!" : "")); 1596 if (pIdxHdr->abReserved[0]) Log2(("NTFS: %s: abReserved[0] %#x\n", pszPrefix, pIdxHdr->abReserved[0])); 1597 if (pIdxHdr->abReserved[1]) Log2(("NTFS: %s: abReserved[0] %#x\n", pszPrefix, pIdxHdr->abReserved[1])); 1598 if (pIdxHdr->abReserved[2]) Log2(("NTFS: %s: abReserved[0] %#x\n", pszPrefix, pIdxHdr->abReserved[2])); 1599 1600 /* 1601 * The entries. 1602 */ 1603 bool fSeenEnd = false; 1604 uint32_t iEntry = 0; 1605 uint32_t offCurEntry = RT_LE2H_U32(pIdxHdr->offFirstEntry); 1606 while (offCurEntry < cbIndex) 1607 { 1608 if (offCurEntry + sizeof(NTFSIDXENTRYHDR) > cbIndex) 1609 { 1610 Log2(("NTFS: Entry[%#04x]: Out of bounds: %#x LB %#x, max %#x\n", 1611 iEntry, offCurEntry, sizeof(NTFSIDXENTRYHDR), cbIndex)); 1612 break; 1613 } 1614 PCNTFSIDXENTRYHDR pEntryHdr = (PCNTFSIDXENTRYHDR)((uint8_t const *)pIdxHdr + offCurEntry); 1615 Log2(("NTFS: [%#04x]: @%#05x/@%#05x cbEntry=%#x cbKey=%#x fFlags=%#x (%s%s%s)\n", 1616 iEntry, offCurEntry, offCurEntry + offIndex, RT_LE2H_U16(pEntryHdr->cbEntry), RT_LE2H_U16(pEntryHdr->cbKey), 1617 RT_LE2H_U16(pEntryHdr->fFlags), 1618 pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_INTERNAL ? "internal" : "leaf", 1619 pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_END ? " end" : "", 1620 pEntryHdr->fFlags & ~(NTFSIDXENTRYHDR_F_INTERNAL | NTFSIDXENTRYHDR_F_END) ? " !unknown!" : "")); 1621 if (uIdxType == NTFSATINDEXROOT_TYPE_DIR) 1622 Log2(("NTFS: FileMftRec %#RX64 sqn %#x\n", 1623 NTFSMFTREF_GET_IDX(&pEntryHdr->u.FileMftRec), NTFSMFTREF_GET_SEQ(&pEntryHdr->u.FileMftRec) )); 1624 else 1625 Log2(("NTFS: offData=%#x cbData=%#x uReserved=%#x\n", 1626 RT_LE2H_U16(pEntryHdr->u.View.offData), RT_LE2H_U16(pEntryHdr->u.View.cbData), 1627 RT_LE2H_U32(pEntryHdr->u.View.uReserved) )); 1628 if (pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_INTERNAL) 1629 Log2(("NTFS: Subnode=%#RX64\n", RT_LE2H_U64(NTFSIDXENTRYHDR_GET_SUBNODE(pEntryHdr)) )); 1630 1631 if ( RT_LE2H_U16(pEntryHdr->cbKey) >= sizeof(NTFSATFILENAME) 1632 && uIdxType == NTFSATINDEXROOT_TYPE_DIR) 1633 { 1634 PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)(pEntryHdr + 1); 1635 Log2(("NTFS: Filename=%.*ls\n", pFilename->cwcFilename, pFilename->wszFilename)); 1636 } 1637 1638 1639 /* next */ 1640 iEntry++; 1641 offCurEntry += RT_LE2H_U16(pEntryHdr->cbEntry); 1642 fSeenEnd = RT_BOOL(pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_END); 1643 if (fSeenEnd || RT_LE2H_U16(pEntryHdr->cbEntry) < sizeof(*pEntryHdr)) 1644 break; 1645 } 1646 if (!fSeenEnd) 1647 Log2(("NTFS: %s: Warning! Missing NTFSIDXENTRYHDR_F_END node!\n", pszPrefix)); 1648 } 1649 1650 static void rtFsNtfsVol_LogIndexNode(PCNTFSATINDEXALLOC pIdxNode, uint32_t cbIdxNode, uint32_t uType) 1651 { 1652 if (!LogIs2Enabled()) 1653 return; 1654 if (cbIdxNode < sizeof(*pIdxNode)) 1655 Log2(("NTFS: Index Node: Error! Too small! cbIdxNode=%#x, index node needs %#x\n", cbIdxNode, sizeof(*pIdxNode))); 1656 else 1657 { 1658 Log2(("NTFS: Index Node: uMagic %#x\n", RT_LE2H_U32(pIdxNode->RecHdr.uMagic))); 1659 Log2(("NTFS: Index Node: UpdateSeqArray %#x L %#x\n", 1660 RT_LE2H_U16(pIdxNode->RecHdr.offUpdateSeqArray), RT_LE2H_U16(pIdxNode->RecHdr.cUpdateSeqEntries) )); 1661 Log2(("NTFS: Index Node: uLsn %#RX64\n", RT_LE2H_U64(pIdxNode->uLsn) )); 1662 Log2(("NTFS: Index Node: iSelfAddress %#RX64\n", RT_LE2H_U64(pIdxNode->iSelfAddress) )); 1663 if (pIdxNode->RecHdr.uMagic == NTFSREC_MAGIC_INDEX_ALLOC) 1664 rtFsNtfsVol_LogIndexHdrAndEntries(&pIdxNode->Hdr, cbIdxNode - RT_UOFFSETOF(NTFSATINDEXALLOC, Hdr), 1665 RT_UOFFSETOF(NTFSATINDEXALLOC, Hdr), "Index Node Hdr", uType); 1666 else 1667 Log2(("NTFS: Index Node: !Error! Invalid magic!\n")); 1668 } 1669 } 1670 1671 1672 /** 1673 * Logs a index root structure and what follows (index header + entries). 1674 * 1675 * @param pIdxRoot The index root. 1676 * @param cbIdxRoot Number of valid bytes starting with @a pIdxRoot. 1677 */ 1678 static void rtFsNtfsVol_LogIndexRoot(PCNTFSATINDEXROOT pIdxRoot, uint32_t cbIdxRoot) 1679 { 1680 if (!LogIs2Enabled()) 1681 return; 1682 if (cbIdxRoot < sizeof(*pIdxRoot)) 1683 Log2(("NTFS: Index Root: Error! Too small! cbIndex=%#x, index head needs %#x\n", cbIdxRoot, sizeof(*pIdxRoot))); 1684 else 1685 { 1686 Log2(("NTFS: Index Root: cbIdxRoot %#x\n", cbIdxRoot)); 1687 Log2(("NTFS: Index Root: uType %#x %s\n", RT_LE2H_U32(pIdxRoot->uType), 1688 pIdxRoot->uType == NTFSATINDEXROOT_TYPE_VIEW ? "view" 1689 : pIdxRoot->uType == NTFSATINDEXROOT_TYPE_DIR ? "directory" : "!unknown!")); 1690 Log2(("NTFS: Index Root: uCollationRules %#x %s\n", RT_LE2H_U32(pIdxRoot->uCollationRules), 1691 pIdxRoot->uCollationRules == NTFS_COLLATION_BINARY ? "binary" 1692 : pIdxRoot->uCollationRules == NTFS_COLLATION_FILENAME ? "filename" 1693 : pIdxRoot->uCollationRules == NTFS_COLLATION_UNICODE_STRING ? "unicode-string" 1694 : pIdxRoot->uCollationRules == NTFS_COLLATION_UINT32 ? "uint32" 1695 : pIdxRoot->uCollationRules == NTFS_COLLATION_SID ? "sid" 1696 : pIdxRoot->uCollationRules == NTFS_COLLATION_UINT32_PAIR ? "uint32-pair" 1697 : pIdxRoot->uCollationRules == NTFS_COLLATION_UINT32_SEQ ? "uint32-sequence" : "!unknown!")); 1698 Log2(("NTFS: Index Root: cbIndexNode %#x\n", RT_LE2H_U32(pIdxRoot->cbIndexNode) )); 1699 Log2(("NTFS: Index Root: cAddressesPerIndexNode %#x => cbNodeAddressingUnit=%#x\n", 1700 pIdxRoot->cAddressesPerIndexNode, RT_LE2H_U32(pIdxRoot->cbIndexNode) / RT_MAX(1, pIdxRoot->cAddressesPerIndexNode) )); 1701 if (pIdxRoot->abReserved[0]) Log2(("NTFS: Index Root: abReserved[0] %#x\n", pIdxRoot->abReserved[0])); 1702 if (pIdxRoot->abReserved[1]) Log2(("NTFS: Index Root: abReserved[1] %#x\n", pIdxRoot->abReserved[1])); 1703 if (pIdxRoot->abReserved[2]) Log2(("NTFS: Index Root: abReserved[2] %#x\n", pIdxRoot->abReserved[2])); 1704 1705 rtFsNtfsVol_LogIndexHdrAndEntries(&pIdxRoot->Hdr, cbIdxRoot - RT_UOFFSETOF(NTFSATINDEXROOT, Hdr), 1706 RT_UOFFSETOF(NTFSATINDEXROOT, Hdr), "Index Root Hdr", pIdxRoot->uType); 1707 } 1708 } 1709 1710 #endif /* LOG_ENABLED */ 1711 1471 1712 1472 1713 static int rtFsNtfsVol_NewSharedDirFromCore(PRTFSNTFSVOL pThis, PRTFSNTFSCORE pCore, PRTFSNTFSDIRSHRD *ppSharedDir, … … 1478 1719 * Look for the index root and do some quick checks of it first. 1479 1720 */ 1480 PRTFSNTFSATTR pRootAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_ FILENAME,1481 NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ROOT);1721 PRTFSNTFSATTR pRootAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ROOT, 1722 RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME)); 1482 1723 if (!pRootAttr) 1483 1724 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: Found no INDEX_ROOT attribute named $I30", pszWhat); 1484 1725 if (pRootAttr->pAttrHdr->fNonResident) 1485 1726 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: INDEX_ROOT is is not resident", pszWhat); 1486 1727 if (pRootAttr->cbResident < sizeof(NTFSATINDEXROOT)) 1728 return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: INDEX_ROOT is too small: %#x, min %#x ", 1729 pRootAttr->cbResident, sizeof(pRootAttr->cbResident)); 1730 1731 PCNTFSATINDEXROOT pIdxRoot = (PCNTFSATINDEXROOT)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pRootAttr->pAttrHdr); 1732 #ifdef LOG_ENABLED 1733 rtFsNtfsVol_LogIndexRoot(pIdxRoot, pRootAttr->cbResident); 1734 #endif 1735 NOREF(pIdxRoot); 1736 // if (pIdxRoot->uType) 1737 // { 1738 // } 1487 1739 1488 1740 #if 1 /* later */ … … 1492 1744 * 1493 1745 */ 1494 PRTFSNTFSATTR p AllocAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,1495 NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ALLOCATION);1496 PRTFSNTFSATTR p BitmapAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,1497 NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_BITMAP);1746 PRTFSNTFSATTR pIndexAlloc = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ALLOCATION, 1747 RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME)); 1748 PRTFSNTFSATTR pIndexBitmap = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_BITMAP, 1749 RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME)); 1498 1750 #endif 1499 1751 return VINF_SUCCESS; … … 1781 2033 */ 1782 2034 PRTFSNTFSCORE pCore; 1783 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_ROOT, &pCore, pErrInfo);2035 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_ROOT, false /*fRelaxedUsa*/, &pCore, pErrInfo); // DON'T COMMIT 1784 2036 if (RT_SUCCESS(rc)) 1785 2037 { … … 1805 2057 else 1806 2058 { 1807 PRTFSNTFSATTR pIndexRoot = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_ FILENAME,1808 NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ROOT);1809 PRTFSNTFSATTR pIndexAlloc = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_ FILENAME,1810 NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ALLOCATION);1811 PRTFSNTFSATTR pIndexBitmap = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_ FILENAME,1812 NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_BITMAP);2059 PRTFSNTFSATTR pIndexRoot = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ROOT, 2060 RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME)); 2061 PRTFSNTFSATTR pIndexAlloc = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ALLOCATION, 2062 RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME)); 2063 PRTFSNTFSATTR pIndexBitmap = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_BITMAP, 2064 RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME)); 1813 2065 if (!pIndexRoot) 1814 2066 rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir: Found no INDEX_ROOT attribute named $I30"); … … 1857 2109 { 1858 2110 PRTFSNTFSCORE pCore; 1859 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_UP_CASE, &pCore, pErrInfo);2111 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_UP_CASE, false /*fRelaxedUsa*/, &pCore, pErrInfo); 1860 2112 if (RT_SUCCESS(rc)) 1861 2113 { … … 1979 2231 { 1980 2232 PRTFSNTFSCORE pCore; 1981 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_BITMAP, &pCore, pErrInfo);2233 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_BITMAP, false /*fRelaxedUsa*/, &pCore, pErrInfo); 1982 2234 if (RT_SUCCESS(rc)) 1983 2235 { … … 2102 2354 { 2103 2355 PRTFSNTFSCORE pCore; 2104 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_VOLUME, &pCore, pErrInfo);2356 int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_VOLUME, false /*fRelaxedUsa*/, &pCore, pErrInfo); 2105 2357 if (RT_SUCCESS(rc)) 2106 2358 { … … 2184 2436 AssertReturn(pRec, VERR_NO_MEMORY); 2185 2437 2438 #if 0 && defined(LOG_ENABLED) 2439 for (uint32_t i = 0; i < 128; i++) 2440 { 2441 uint64_t const offDisk = (pThis->uLcnMft << pThis->cClusterShift) + i * pThis->cbMftRecord; 2442 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offDisk, pRec->pbRec, pThis->cbMftRecord, NULL); 2443 if (RT_SUCCESS(rc)) 2444 { 2445 pRec->TreeNode.Key = i; 2446 rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord); 2447 pRec->TreeNode.Key = 0; 2448 } 2449 } 2450 #endif 2451 2186 2452 uint64_t const offDisk = pThis->uLcnMft << pThis->cClusterShift; 2187 2453 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offDisk, pRec->pbRec, pThis->cbMftRecord, NULL); 2188 2454 if (RT_SUCCESS(rc)) 2189 2455 { 2456 rc = rtFsNtfsRec_DoMultiSectorFixups(&pRec->pFileRec->Hdr, pThis->cbMftRecord, true, pErrInfo); 2457 if (RT_SUCCESS(rc)) 2458 { 2190 2459 #ifdef LOG_ENABLED 2191 rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);2460 rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord); 2192 2461 #endif 2193 rc = rtFsNtfsVol_ParseMft(pThis, pRec, pErrInfo); 2462 rc = rtFsNtfsVol_ParseMft(pThis, pRec, pErrInfo); 2463 } 2194 2464 if (RT_SUCCESS(rc)) 2195 2465 { … … 2398 2668 "Unsupported NTFS MFT record size: %#x", pThis->cbMftRecord); 2399 2669 2400 /* NTFS BPB: Index blocksize */2401 if (pBootSector->Bpb.Ntfs.cCluster PerIndexBlock>= 0)2402 { 2403 if ( !RT_IS_POWER_OF_TWO((uint32_t)pBootSector->Bpb.Ntfs.cCluster PerIndexBlock)2404 || pBootSector->Bpb.Ntfs.cCluster PerIndexBlock== 0)2670 /* NTFS BPB: Default index node size */ 2671 if (pBootSector->Bpb.Ntfs.cClustersPerIndexNode >= 0) 2672 { 2673 if ( !RT_IS_POWER_OF_TWO((uint32_t)pBootSector->Bpb.Ntfs.cClustersPerIndexNode) 2674 || pBootSector->Bpb.Ntfs.cClustersPerIndexNode == 0) 2405 2675 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, 2406 "NTFS clusters-per-index-blockis zero or not a power of two: %#x",2407 pBootSector->Bpb.Ntfs.cCluster PerIndexBlock);2408 pThis->cb IndexRecord = (uint32_t)pBootSector->Bpb.Ntfs.cClusterPerIndexBlock<< pThis->cClusterShift;2409 Assert(pThis->cb IndexRecord == pBootSector->Bpb.Ntfs.cClusterPerIndexBlock* pThis->cbCluster);2410 } 2411 else if ( pBootSector->Bpb.Ntfs.cCluster PerIndexBlock< -322412 || pBootSector->Bpb.Ntfs.cCluster PerIndexBlock> -9)2676 "NTFS default clusters-per-index-tree-node is zero or not a power of two: %#x", 2677 pBootSector->Bpb.Ntfs.cClustersPerIndexNode); 2678 pThis->cbDefaultIndexNode = (uint32_t)pBootSector->Bpb.Ntfs.cClustersPerIndexNode << pThis->cClusterShift; 2679 Assert(pThis->cbDefaultIndexNode == pBootSector->Bpb.Ntfs.cClustersPerIndexNode * pThis->cbCluster); 2680 } 2681 else if ( pBootSector->Bpb.Ntfs.cClustersPerIndexNode < -32 2682 || pBootSector->Bpb.Ntfs.cClustersPerIndexNode > -9) 2413 2683 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, 2414 "NTFS clusters-per-index-blockis out of shift range: %d",2415 pBootSector->Bpb.Ntfs.cCluster PerIndexBlock);2684 "NTFS default clusters-per-index-tree-node is out of shift range: %d", 2685 pBootSector->Bpb.Ntfs.cClustersPerIndexNode); 2416 2686 else 2417 pThis->cb IndexRecord= UINT32_C(1) << -pBootSector->Bpb.Ntfs.cClustersPerMftRecord;2418 Log2(("NTFS BPB: cb IndexRecord=%#x\n", pThis->cbIndexRecord));2687 pThis->cbDefaultIndexNode = UINT32_C(1) << -pBootSector->Bpb.Ntfs.cClustersPerMftRecord; 2688 Log2(("NTFS BPB: cbDefaultIndexNode=%#x\n", pThis->cbDefaultIndexNode)); 2419 2689 2420 2690 pThis->uSerialNo = RT_LE2H_U64(pBootSector->Bpb.Ntfs.uSerialNumber);
Note:
See TracChangeset
for help on using the changeset viewer.