VirtualBox

Changeset 69910 in vbox


Ignore:
Timestamp:
Dec 3, 2017 5:06:56 PM (7 years ago)
Author:
vboxsync
Message:

IPRT/ntfsvfs.cpp: More on the subject of directories (indexes).

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/formats/fat.h

    r69849 r69910  
    468468    /** 0x41 / 0x36: Reserved. */
    469469    uint8_t         abReserved3[3];
    470     /** 0x44 / 0x39: Logical clusters pre index block.
     470    /** 0x44 / 0x39: The default logical clusters count per index node.
    471471     * This is a shift count if negative.  */
    472     int8_t          cClusterPerIndexBlock;
     472    int8_t          cClustersPerIndexNode;
    473473    /** 0x45 / 0x3a: Reserved. */
    474474    uint8_t         abReserved4[3];
  • trunk/include/iprt/formats/ntfs.h

    r69902 r69910  
    139139/** Pointer to a const NTFS record header. */
    140140typedef 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
    141147
    142148
     
    332338#define NTFSATTRIBHDR_GET_NAME(a_pAttrHdr)          ( (PRTUTF16)((uintptr_t)(a_pAttrHdr) + (a_pAttrHdr)->offName) )
    333339
     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
    334344
    335345/** @name NTFS_RES_AF_XXX
     
    549559 * NTFS index header.
    550560 *
    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 */
     564typedef struct NTFSINDEXHDR
    554565{
    555566    /** 0x00: Offset of the first entry relative to this header. */
    556567    uint32_t        offFirstEntry;
    557     /** 0x04: Size of the index in bytes, including this header.  */
    558     uint32_t        cbIndex;
     568    /** 0x04: Current index size in bytes, including this header.  */
     569    uint32_t        cbUsed;
    559570    /** 0x08: Number of bytes allocated for the index (including this header). */
    560571    uint32_t        cbAllocated;
    561     /** 0x0c: Flags (NTFSINDEXHEADER_F_XXX).   */
     572    /** 0x0c: Flags (NTFSINDEXHDR_F_XXX).   */
    562573    uint8_t         fFlags;
    563574    /** 0x0d: Reserved bytes. */
    564575    uint8_t         abReserved[3];
    565 } NTFSINDEXHEADER;
    566 AssertCompileSize(NTFSINDEXHEADER, 16);
     576    /* NTFSIDXENTRYHDR sequence typically follows here */
     577} NTFSINDEXHDR;
     578AssertCompileSize(NTFSINDEXHDR, 16);
    567579/** Pointer to a NTFS index header. */
    568 typedef NTFSINDEXHEADER *PNTFSINDEXHEADER;
     580typedef NTFSINDEXHDR *PNTFSINDEXHDR;
    569581/** 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).
     582typedef 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).
    581594 *
    582595 * 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.
    584605 */
    585606typedef struct NTFSATINDEXROOT
     
    589610    /** 0x04: The sorting rules to use (NTFS_COLLATION_XXX). */
    590611    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;
    596623    /** 0x0d: Reserved padding or something. */
    597624    uint8_t         abReserved[3];
    598625    /** 0x10: Index header detailing the entries that follows. */
    599     NTFSINDEXHEADER Hdr;
    600     /* NTFSINDEXENTRYHDR array typically follows */
     626    NTFSINDEXHDR    Hdr;
     627    /*  0x20: NTFSIDXENTRYHDR sequence typically follows here */
    601628} NTFSATINDEXROOT;
    602629AssertCompileSize(NTFSATINDEXROOT, 32);
     
    611638#define NTFSATINDEXROOT_TYPE_VIEW           RT_H2LE_U32_C(UINT32_C(0x00000000))
    612639/** Directory index, NTFSATFILENAME follows NTFSINDEXENTRY. */
    613 #define NTFSATINDEXROOT_TYPE_DIRECTORY      RT_H2LE_U32_C(UINT32_C(0x00000030))
     640#define NTFSATINDEXROOT_TYPE_DIR            RT_H2LE_U32_C(UINT32_C(0x00000030))
    614641/** @} */
    615642
     
    631658/** Sequence of little endian 32-bit unsigned integer values used as sorting key. */
    632659#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 */
     666typedef 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;
     680AssertCompileSize(NTFSATINDEXALLOC, 40);
     681/** Pointer to a NTFS index non-root node. */
     682typedef NTFSATINDEXALLOC *PNTFSATINDEXALLOC;
     683/** Pointer to a const NTFS index non-root node. */
     684typedef 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))
    635689
    636690
    637691/**
    638692 * 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 */
     698typedef struct NTFSIDXENTRYHDR
    641699{
    642700    union
    643701    {
    644         /** 0x00: Non-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). */
    646704        NTFSMFTREF      FileMftRec;
    647         /** 0x00: View  */
     705        /** 0x00: NTFSATINDEXROOT_TYPE_VIEW: Go figure later if necessary. */
    648706        struct
    649707        {
    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). */
    651710            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). */
    653713            uint16_t    cbData;
    654714            /** 0x04: Reserved.   */
     
    661721    /** 0x0a: Key length (unaligned). */
    662722    uint16_t        cbKey;
    663     /** 0x0c: Entry flags, NTFSINDEX_EF_XXX. */
     723    /** 0x0c: Entry flags, NTFSIDXENTRYHDR_F_XXX. */
    664724    uint16_t        fFlags;
    665     /** 0x0d: Entry flags, NTFSINDEX_EF_XXX. */
     725    /** 0x0e: Reserved. */
    666726    uint16_t        uReserved;
    667 } NTFSINDEXENTRYHDR;
    668 AssertCompileSize(NTFSINDEXENTRYHDR, 16);
     727} NTFSIDXENTRYHDR;
     728AssertCompileSize(NTFSIDXENTRYHDR, 16);
    669729/** Pointer to a NTFS index entry header. */
    670 typedef NTFSINDEXENTRYHDR *PNTFSINDEXENTRYHDR;
     730typedef NTFSIDXENTRYHDR *PNTFSIDXENTRYHDR;
    671731/** 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))
     732typedef 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))
    680747/** @}  */
    681748
     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
    682758/** @} */
    683759
  • trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp

    r69903 r69910  
    265265    /** The MFT record size. */
    266266    uint32_t        cbMftRecord;
    267     /** The index record size. */
    268     uint32_t        cbIndexRecord;
     267    /** The default index (B-tree) node size. */
     268    uint32_t        cbDefaultIndexNode;
    269269
    270270    /** The volume serial number. */
     
    306306*********************************************************************************************************************************/
    307307static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis);
     308#ifdef LOG_ENABLED
     309static void     rtFsNtfsVol_LogIndexRoot(PCNTFSATINDEXROOT pIdxRoot, uint32_t cbIdxRoot);
     310#endif
    308311
    309312
     
    580583                            //case NTFS_AT_VOLUME_INFORMATION:
    581584                            //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
    583590                            //case NTFS_AT_INDEX_ALLOCATION:
    584591                            //case NTFS_AT_BITMAP:
     
    637644                        uint32_t const cbMaxPairs = cbAttrib - offMappingPairs;
    638645                        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));
    640650                        if (!iVnc && !*pbPairs)
    641651                            Log2(("NTFS:         [0]: Empty\n"));
     
    643653                        {
    644654                            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));
    646656                            int64_t  iLnc     = 0;
    647657                            uint32_t iPair    = 0;
     
    656666                                if (offPairs + cbRun > cbMaxPairs)
    657667                                {
    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));
    660670                                    break;
    661671                                }
     672                                //Log2(("NTFS:         @%#05x: %.*Rhxs\n", offPairs, cbRun + 1, &pbPairs[offPairs]));
    662673
    663674                                /* Value 1: Number of (virtual) clusters in this run. */
     
    683694                                        cLcnDelta = (cLcnDelta << 8) + *pbNum--;
    684695                                    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));
    687698                                }
    688699                                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));
    691702
    692703                                /* Advance. */
     
    12401251                    {
    12411252                        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));
    12421254                        if (RT_FAILURE(rc))
    12431255                            break;
     
    12841296
    12851297/**
     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 */
     1307static 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/**
    12861369 * Allocate and parse an MFT record, returning a core object structure.
    12871370 *
     
    12891372 * @param   pThis               The NTFS volume instance.
    12901373 * @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.
    12911376 * @param   ppCore              Where to return the core object structure.
    12921377 * @param   pErrInfo            Where to return error details.  Optional.
    12931378 */
    1294 static int rtFsNtfsVol_NewCoreForMftIdx(PRTFSNTFSVOL pThis, uint64_t idxMft, PRTFSNTFSCORE *ppCore, PRTERRINFO pErrInfo)
     1379static int rtFsNtfsVol_NewCoreForMftIdx(PRTFSNTFSVOL pThis, uint64_t idxMft, bool fRelaxedUsa,
     1380                                        PRTFSNTFSCORE *ppCore, PRTERRINFO pErrInfo)
    12951381{
    12961382    *ppCore = NULL;
     
    13031389    uint64_t offRec = idxMft * pThis->cbMftRecord;
    13041390    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);
    13051393    if (RT_SUCCESS(rc))
    13061394    {
     
    14691557 */
    14701558
     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 */
     1571static 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
     1650static 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 */
     1678static 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
    14711712
    14721713static int rtFsNtfsVol_NewSharedDirFromCore(PRTFSNTFSVOL pThis, PRTFSNTFSCORE pCore, PRTFSNTFSDIRSHRD *ppSharedDir,
     
    14781719     * Look for the index root and do some quick checks of it first.
    14791720     */
    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));
    14821723    if (!pRootAttr)
    14831724        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: Found no INDEX_ROOT attribute named $I30", pszWhat);
    14841725    if (pRootAttr->pAttrHdr->fNonResident)
    14851726        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//    }
    14871739
    14881740#if 1 /* later */
     
    14921744     *
    14931745     */
    1494     PRTFSNTFSATTR pAllocAttr  = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
    1495                                                                       NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ALLOCATION);
    1496     PRTFSNTFSATTR pBitmapAttr = 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));
    14981750#endif
    14991751    return VINF_SUCCESS;
     
    17812033     */
    17822034    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
    17842036    if (RT_SUCCESS(rc))
    17852037    {
     
    18052057            else
    18062058            {
    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));
    18132065                if (!pIndexRoot)
    18142066                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir: Found no INDEX_ROOT attribute named $I30");
     
    18572109{
    18582110    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);
    18602112    if (RT_SUCCESS(rc))
    18612113    {
     
    19792231{
    19802232    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);
    19822234    if (RT_SUCCESS(rc))
    19832235    {
     
    21022354{
    21032355    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);
    21052357    if (RT_SUCCESS(rc))
    21062358    {
     
    21842436    AssertReturn(pRec, VERR_NO_MEMORY);
    21852437
     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
    21862452    uint64_t const offDisk = pThis->uLcnMft << pThis->cClusterShift;
    21872453    int rc = RTVfsFileReadAt(pThis->hVfsBacking, offDisk, pRec->pbRec, pThis->cbMftRecord, NULL);
    21882454    if (RT_SUCCESS(rc))
    21892455    {
     2456        rc = rtFsNtfsRec_DoMultiSectorFixups(&pRec->pFileRec->Hdr, pThis->cbMftRecord, true, pErrInfo);
     2457        if (RT_SUCCESS(rc))
     2458        {
    21902459#ifdef LOG_ENABLED
    2191         rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);
     2460            rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);
    21922461#endif
    2193         rc = rtFsNtfsVol_ParseMft(pThis, pRec, pErrInfo);
     2462            rc = rtFsNtfsVol_ParseMft(pThis, pRec, pErrInfo);
     2463        }
    21942464        if (RT_SUCCESS(rc))
    21952465        {
     
    23982668                                   "Unsupported NTFS MFT record size: %#x", pThis->cbMftRecord);
    23992669
    2400     /* NTFS BPB: Index block size */
    2401     if (pBootSector->Bpb.Ntfs.cClusterPerIndexBlock >= 0)
    2402     {
    2403         if (   !RT_IS_POWER_OF_TWO((uint32_t)pBootSector->Bpb.Ntfs.cClusterPerIndexBlock)
    2404             || pBootSector->Bpb.Ntfs.cClusterPerIndexBlock == 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)
    24052675            return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
    2406                                        "NTFS clusters-per-index-block is zero or not a power of two: %#x",
    2407                                         pBootSector->Bpb.Ntfs.cClusterPerIndexBlock);
    2408         pThis->cbIndexRecord = (uint32_t)pBootSector->Bpb.Ntfs.cClusterPerIndexBlock << pThis->cClusterShift;
    2409         Assert(pThis->cbIndexRecord == pBootSector->Bpb.Ntfs.cClusterPerIndexBlock * pThis->cbCluster);
    2410     }
    2411     else if (   pBootSector->Bpb.Ntfs.cClusterPerIndexBlock < -32
    2412              || pBootSector->Bpb.Ntfs.cClusterPerIndexBlock > -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)
    24132683        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
    2414                                    "NTFS clusters-per-index-block is out of shift range: %d",
    2415                                     pBootSector->Bpb.Ntfs.cClusterPerIndexBlock);
     2684                                   "NTFS default clusters-per-index-tree-node is out of shift range: %d",
     2685                                    pBootSector->Bpb.Ntfs.cClustersPerIndexNode);
    24162686    else
    2417         pThis->cbIndexRecord = UINT32_C(1) << -pBootSector->Bpb.Ntfs.cClustersPerMftRecord;
    2418     Log2(("NTFS BPB: cbIndexRecord=%#x\n", pThis->cbIndexRecord));
     2687        pThis->cbDefaultIndexNode = UINT32_C(1) << -pBootSector->Bpb.Ntfs.cClustersPerMftRecord;
     2688    Log2(("NTFS BPB: cbDefaultIndexNode=%#x\n", pThis->cbDefaultIndexNode));
    24192689
    24202690    pThis->uSerialNo = RT_LE2H_U64(pBootSector->Bpb.Ntfs.uSerialNumber);
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