VirtualBox

Changeset 69885 in vbox


Ignore:
Timestamp:
Nov 30, 2017 4:41:37 PM (7 years ago)
Author:
vboxsync
Message:

iprt/ntfsvfs.cpp: Got the code to the point where compaction works with an XP VM.

Location:
trunk
Files:
3 edited

Legend:

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

    r69873 r69885  
    272272        struct
    273273        {
    274             /** 0x10: The first virtual cluster containing data. */
     274            /** 0x10: The first virtual cluster containing data.
     275             *
     276             * This is mainly for internal checking when the run list doesn't fit in one
     277             * MFT record.  It can also be used to avoid recording a sparse run at the
     278             * beginning of the data covered by this attribute record. */
    275279            int64_t         iVcnFirst;
    276280            /** 0x18: The last virtual cluster containing data (inclusive). */
     
    284288            /** 0x23: Reserved */
    285289            uint8_t         abReserved[5];
    286             /** 0x28: Allocated size. */
     290            /** 0x28: Allocated size (rouneded to cluster).
     291             * @note Only set in the first attribute record (iVcnFirst == 0). */
    287292            int64_t         cbAllocated;
    288             /** 0x30: Initialized size. */
     293            /** 0x30: The exact length of the data.
     294             * @note Only set in the first attribute record (iVcnFirst == 0). */
     295            int64_t         cbData;
     296            /** 0x38: The length of the initialized data (rounded to cluster).
     297             * @note Only set in the first attribute record (iVcnFirst == 0). */
    289298            int64_t         cbInitialized;
    290             /** 0x38: Compressed size if compressed, otherwise absent. */
     299            /** 0x40: Compressed size if compressed, otherwise absent. */
    291300            int64_t         cbCompressed;
    292301        } NonRes;
    293302    } u;
    294303} NTFSATTRIBHDR;
    295 AssertCompileSize(NTFSATTRIBHDR, 0x40);
     304AssertCompileSize(NTFSATTRIBHDR, 0x48);
    296305AssertCompileMemberOffset(NTFSATTRIBHDR, u.Res, 0x10);
    297306AssertCompileMemberOffset(NTFSATTRIBHDR, u.Res.bReserved, 0x17);
    298307AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes, 0x10);
    299 AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes.cbCompressed, 0x38);
     308AssertCompileMemberOffset(NTFSATTRIBHDR, u.NonRes.cbCompressed, 0x40);
    300309/** Pointer to a NTFS attribute header. */
    301310typedef NTFSATTRIBHDR *PNTFSATTRIBHDR;
     
    308317#define NTFSATTRIBHDR_SIZE_RESIDENT                 (0x18)
    309318/** Attribute header size for uncompressed non-resident values. */
    310 #define NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED      (0x38)
     319#define NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED      (0x40)
    311320/** Attribute header size for compressed non-resident values. */
    312 #define NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED        (0x40)
     321#define NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED        (0x48)
    313322/** @} */
    314323
  • trunk/src/VBox/Runtime/Makefile.kmk

    r69854 r69885  
    558558        common/string/RTUtf16ICmpAscii.cpp \
    559559        common/string/RTUtf16End.cpp \
     560        common/string/RTUtf16NICmpAscii.cpp \
    560561        common/string/RTUtf16NLen.cpp \
    561562        common/string/RTUtf16NLenEx.cpp \
  • trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp

    r69875 r69885  
    4141#include <iprt/vfs.h>
    4242#include <iprt/vfslowlevel.h>
     43#include <iprt/utf16.h>
    4344#include <iprt/formats/ntfs.h>
    4445
     
    4748*   Defined Constants And Macros                                                                                                 *
    4849*********************************************************************************************************************************/
    49 /** Max clusters in an allocation run.
    50  * This ASSUMES that the cluster size is at most 64KB. */
    51 #define RTFSNTFS_MAX_CLUSTER_IN_RUN     UINT64_C(0x00007fffffffffff)
     50/** The maximum bitmap cache size. */
     51#define RTFSNTFS_MAX_BITMAP_CACHE           _64K
    5252
    5353
     
    122122    /** Set if this is a base MFT record. */
    123123    bool                fIsBase;
    124     /** The disk offset of this MFT entry. */
    125     uint64_t            offDisk;
    126124} RTFSNTFSMFTREC;
    127125
     
    159157     * The MFT is held down by RTFSNTFSCORE via pMftEntry. */
    160158    PNTFSATTRIBHDR      pAttrHdr;
     159    /** The offset of the attribute header in the MFT record.
     160     * This is needed to validate header relative offsets. */
     161    uint32_t            offAttrHdrInMftRec;
    161162    /** Disk space allocation if non-resident. */
    162163    RTFSNTFSEXTENTS     Extents;
     
    229230    uint64_t        uSerialNo;
    230231
    231     /** The MFT data attribute. */
     232    /** The '$Mft' data attribute. */
    232233    PRTFSNTFSATTR   pMftData;
     234
     235
     236    /** @name Allocation bitmap and cache.
     237     * @{ */
     238    /** The '$Bitmap' data attribute. */
     239    PRTFSNTFSATTR   pMftBitmap;
     240    /** The first cluster currently loaded into the bitmap cache . */
     241    uint64_t        iFirstBitmapCluster;
     242    /** The number of clusters currently loaded into the bitmap cache */
     243    uint32_t        cBitmapClusters;
     244    /** The size of the pvBitmap allocation. */
     245    uint32_t        cbBitmapAlloc;
     246    /** Allocation bitmap cache buffer. */
     247    void           *pvBitmap;
     248    /** @} */
    233249
    234250    /** Root of the MFT record tree (RTFSNTFSMFTREC). */
     
    237253
    238254
    239 static PRTFSNTFSMFTREC rtFsNtfsMftVol_New(PRTFSNTFSVOL pVol, uint64_t idMft)
     255
     256/*********************************************************************************************************************************
     257*   Internal Functions                                                                                                           *
     258*********************************************************************************************************************************/
     259static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis);
     260
     261
     262
     263/**
     264 * Checks if a bit is set in an NTFS bitmap (little endian).
     265 *
     266 * @returns true if set, false if not.
     267 * @param   pvBitmap            The bitmap buffer.
     268 * @param   iBit                The bit.
     269 */
     270DECLINLINE(bool) rtFsNtfsBitmap_IsSet(void *pvBitmap, uint32_t iBit)
     271{
     272#if 0 //def RT_LITTLE_ENDIAN
     273    return ASMBitTest(pvBitmap, iBit);
     274#else
     275    uint8_t b = ((uint8_t const *)pvBitmap)[iBit >> 3];
     276    return RT_BOOL(b & (1 << (iBit & 7)));
     277#endif
     278}
     279
     280
     281
     282static PRTFSNTFSMFTREC rtFsNtfsVol_NewMftRec(PRTFSNTFSVOL pVol, uint64_t idMft)
    240283{
    241284    PRTFSNTFSMFTREC pRec = (PRTFSNTFSMFTREC)RTMemAllocZ(sizeof(*pRec));
     
    247290            pRec->TreeNode.Key = idMft;
    248291            pRec->pNext        = NULL;
    249             pRec->offDisk      = UINT64_MAX;
    250292            pRec->cRefs        = 1;
    251293            if (RTAvlU64Insert(&pVol->MftRoot, &pRec->TreeNode))
     
    301343    {
    302344        PCNTFSRECFILE  pFileRec = pRec->pFileRec;
    303         Log2(("NTFS: MFT #%#RX64 at %#RX64\n", pRec->TreeNode.Key, pRec->offDisk));
     345        Log2(("NTFS: MFT #%#RX64\n", pRec->TreeNode.Key));
    304346        if (pFileRec->Hdr.uMagic == NTFSREC_MAGIC_FILE)
    305347        {
     
    518560                    Log2(("NTFS:     cbAllocated        %#RX64 (%Rhcb)\n",
    519561                          RT_LE2H_U64(pHdr->u.NonRes.cbAllocated), RT_LE2H_U64(pHdr->u.NonRes.cbAllocated)));
     562                    Log2(("NTFS:     cbData             %#RX64 (%Rhcb)\n",
     563                          RT_LE2H_U64(pHdr->u.NonRes.cbData), RT_LE2H_U64(pHdr->u.NonRes.cbData)));
    520564                    Log2(("NTFS:     cbInitialized      %#RX64 (%Rhcb)\n",
    521565                          RT_LE2H_U64(pHdr->u.NonRes.cbInitialized), RT_LE2H_U64(pHdr->u.NonRes.cbInitialized)));
     
    528572                        Log2(("NTFS:     Compression unit   2^%u clusters\n", pHdr->u.NonRes.uCompressionUnit));
    529573
    530                     if (   NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED <= cbMaxAttrib
    531                         && NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED <= cbAttrib
     574                    if (   cbMaxAttrib >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED
     575                        && cbAttrib    >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED
    532576                        && (   offMappingPairs >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED
    533577                            || offMappingPairs <  NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED))
    534578                        Log2(("NTFS:     cbCompressed       %#RX64 (%Rhcb)\n",
    535579                              RT_LE2H_U64(pHdr->u.NonRes.cbCompressed), RT_LE2H_U64(pHdr->u.NonRes.cbCompressed)));
    536                     else if (pHdr->u.NonRes.uCompressionUnit != 0 && pHdr->u.NonRes.uCompressionUnit != 64)
     580                    else if (   pHdr->u.NonRes.uCompressionUnit != 0
     581                             && pHdr->u.NonRes.uCompressionUnit != 64
     582                             && pHdr->u.NonRes.iVcnFirst == 0)
    537583                        Log2(("NTFS:     !Error! Compressed attrib fields are out of bound!\n"));
    538584
     
    632678
    633679static int rtFsNtfsAttr_ParseExtents(PRTFSNTFSATTR pAttrib, PRTFSNTFSEXTENTS pExtents, uint8_t cClusterShift, int64_t iVcnFirst,
    634                                      PRTERRINFO pErrInfo, uint64_t idxMft, uint32_t offAttrib)
     680                                     uint64_t cbVolume, PRTERRINFO pErrInfo, uint64_t idxMft, uint32_t offAttrib)
    635681{
    636682    PCNTFSATTRIBHDR pAttrHdr = pAttrib->pAttrHdr;
     
    777823                                                                     "Bad MFT record %#RX64: Extent #%#x for attribute (@%#x): iLcn %RX64 overflows when shifted by %u",
    778824                                                                     idxMft, iExtent, offAttrib, iLcn, cClusterShift));
     825                        AssertBreakStmt(   paExtents[iExtent].off < cbVolume
     826                                        || paExtents[iExtent].cbExtent < cbVolume
     827                                        || paExtents[iExtent].off + paExtents[iExtent].cbExtent <= cbVolume,
     828                                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     829                                                                     "Bad MFT record %#RX64: Extent #%#x for attribute (@%#x) outside volume: %#RX64 LB %#RX64, cbVolume=%#RX64",
     830                                                                     idxMft, iExtent, offAttrib, paExtents[iExtent].off,
     831                                                                     paExtents[iExtent].cbExtent, cbVolume));
    779832                    }
    780833                    else
     
    804857
    805858
     859/**
     860 * Parses the given MTF record and all related records, putting the result in
     861 * pRec->pCore (with one reference for the caller).
     862 *
     863 * ASSUMES caller will release pRec->pCore on failure.
     864 *
     865 * @returns IPRT status code.
     866 * @param   pThis       The volume.
     867 * @param   pRec        The MFT record to parse.
     868 * @param   pErrInfo    Where to return additional error information.  Optional.
     869 */
    806870static int rtFsNtfsVol_ParseMft(PRTFSNTFSVOL pThis, PRTFSNTFSMFTREC pRec, PRTERRINFO pErrInfo)
    807871{
     
    862926        AssertReturn(pAttrib, VERR_NO_MEMORY);
    863927        pAttrib->pAttrHdr           = pAttrHdr;
     928        pAttrib->offAttrHdrInMftRec = offRec;
    864929        pAttrib->pCore              = pCore;
    865930        //pAttrib->Extents.cExtents   = 0;
     
    869934        {
    870935            int rc = rtFsNtfsAttr_ParseExtents(pAttrib, &pAttrib->Extents, pThis->cClusterShift, 0 /*iVncFirst*/,
    871                                                pErrInfo, pRec->TreeNode.Key, offRec);
     936                                               pThis->cbVolume, pErrInfo, pRec->TreeNode.Key, offRec);
    872937            if (RT_FAILURE(rc))
    873938            {
     
    895960    return VINF_SUCCESS;
    896961}
     962
     963
     964static int rtFsNtfsAttr_Read(PRTFSNTFSATTR pAttr, uint64_t off, void *pvBuf, size_t cbToRead)
     965{
     966    PRTFSNTFSVOL pVol = pAttr->pCore->pVol;
     967    int          rc;
     968    if (!pAttr->pAttrHdr->fNonResident)
     969    {
     970        /*
     971         * The attribute is resident.
     972         */
     973        uint32_t cbAttrib = RT_LE2H_U32(pAttr->pAttrHdr->cbAttrib);
     974        uint32_t cbValue  = RT_LE2H_U32(pAttr->pAttrHdr->u.Res.cbValue);
     975        uint16_t offValue = RT_LE2H_U16(pAttr->pAttrHdr->u.Res.offValue);
     976        if (   off            <  cbValue
     977            && cbToRead       <= cbValue
     978            && off + cbToRead <= cbValue)
     979        {
     980            if (offValue <= cbAttrib)
     981            {
     982                cbAttrib -= offValue;
     983                if (off < cbAttrib)
     984                {
     985                    /** @todo check if its possible to have cbValue larger than the attribute and
     986                     *        reading those extra bytes as zero. */
     987                    if (   pAttr->offAttrHdrInMftRec + offValue + cbAttrib <= pVol->cbMftRecord
     988                        && cbAttrib <= pVol->cbMftRecord)
     989                    {
     990                        size_t cbToCopy = cbAttrib - off;
     991                        if (cbToCopy > cbToRead)
     992                            cbToCopy = cbToRead;
     993                        memcpy(pvBuf, (uint8_t *)pAttr->pAttrHdr + offValue, cbToCopy);
     994                        pvBuf     = (uint8_t *)pvBuf + cbToCopy;
     995                        cbToRead -= cbToCopy;
     996                        rc = VINF_SUCCESS;
     997                    }
     998                    else
     999                    {
     1000                        rc = VERR_VFS_BOGUS_OFFSET;
     1001                        Log(("rtFsNtfsAttr_Read: bad resident attribute!\n"));
     1002                    }
     1003                }
     1004                else
     1005                    rc = VINF_SUCCESS;
     1006            }
     1007            else
     1008                rc = VERR_VFS_BOGUS_FORMAT;
     1009        }
     1010        else
     1011            rc = VERR_EOF;
     1012    }
     1013    else if (pAttr->pAttrHdr->u.NonRes.uCompressionUnit == 0)
     1014    {
     1015        /*
     1016         * Uncompressed non-resident attribute.
     1017         */
     1018        uint64_t const cbAllocated   = RT_LE2H_U64(pAttr->pAttrHdr->u.NonRes.cbAllocated);
     1019        if (   off >= cbAllocated
     1020            || cbToRead > cbAllocated
     1021            || off + cbToRead > cbAllocated)
     1022            rc = VERR_EOF;
     1023        else
     1024        {
     1025            rc = VINF_SUCCESS;
     1026
     1027            uint64_t const cbInitialized = RT_LE2H_U64(pAttr->pAttrHdr->u.NonRes.cbInitialized);
     1028            if (   off < cbInitialized
     1029                && cbToRead > 0)
     1030            {
     1031                /*
     1032                 * Locate the first extent.  This is a tad complicated.
     1033                 *
     1034                 * We move off along as we traverse the extent tables, so that it is relative
     1035                 * to the start of the current extent.
     1036                 */
     1037                PRTFSNTFSEXTENTS    pTable   = &pAttr->Extents;
     1038                uint32_t            iExtent  = 0;
     1039                PRTFSNTFSATTRSUBREC pCurSub  = NULL;
     1040                for (;;)
     1041                {
     1042                    if (off < pTable->cbData)
     1043                    {
     1044                        while (   iExtent < pTable->cExtents
     1045                               && off >= pTable->paExtents[iExtent].cbExtent)
     1046                        {
     1047                            off -= pTable->paExtents[iExtent].cbExtent;
     1048                            iExtent++;
     1049                        }
     1050                        AssertReturn(iExtent < pTable->cExtents, VERR_INTERNAL_ERROR_2);
     1051                        break;
     1052                    }
     1053
     1054                    /* Next table. */
     1055                    off -= pTable->cbData;
     1056                    if (!pCurSub)
     1057                        pCurSub = pAttr->pSubRecHead;
     1058                    else
     1059                        pCurSub = pCurSub->pNext;
     1060                    if (!pCurSub)
     1061                    {
     1062                        iExtent = UINT32_MAX;
     1063                        break;
     1064                    }
     1065                    pTable  = &pCurSub->Extents;
     1066                    iExtent = 0;
     1067                }
     1068
     1069                /*
     1070                 * The read loop.
     1071                 */
     1072                while (iExtent != UINT32_MAX)
     1073                {
     1074                    uint64_t cbMaxRead = pTable->paExtents[iExtent].cbExtent;
     1075                    Assert(off < cbMaxRead);
     1076                    cbMaxRead -= off;
     1077                    size_t const cbThisRead = cbMaxRead >= cbToRead ? cbToRead : (size_t)cbMaxRead;
     1078                    if (pTable->paExtents[iExtent].off == UINT64_MAX)
     1079                        RT_BZERO(pvBuf, cbThisRead);
     1080                    else
     1081                    {
     1082                        rc = RTVfsFileReadAt(pVol->hVfsBacking, pTable->paExtents[iExtent].off + off, pvBuf, cbThisRead, NULL);
     1083                        if (RT_FAILURE(rc))
     1084                            break;
     1085                    }
     1086                    pvBuf     = (uint8_t *)pvBuf + cbThisRead;
     1087                    cbToRead -= cbThisRead;
     1088                    if (!cbToRead)
     1089                        break;
     1090
     1091                    /*
     1092                     * Advance to the next extent.
     1093                     */
     1094                    iExtent++;
     1095                    if (iExtent >= pTable->cExtents)
     1096                    {
     1097                        pCurSub = pCurSub ? pCurSub->pNext : pAttr->pSubRecHead;
     1098                        if (!pCurSub)
     1099                            break;
     1100                        pTable  = &pCurSub->Extents;
     1101                        iExtent = 0;
     1102                    }
     1103                }
     1104            }
     1105        }
     1106    }
     1107    else
     1108    {
     1109        LogRel(("rtFsNtfsAttr_Read: Compressed files are not supported\n"));
     1110        rc = VERR_NOT_SUPPORTED;
     1111    }
     1112
     1113    /*
     1114     * Anything else beyond the end of what's stored/initialized?
     1115     */
     1116    if (   cbToRead > 0
     1117        && RT_SUCCESS(rc))
     1118    {
     1119        RT_BZERO(pvBuf, cbToRead);
     1120    }
     1121
     1122    return rc;
     1123}
     1124
     1125
     1126static int rtFsNtfsVol_NewCoreForMftIdx(PRTFSNTFSVOL pThis, uint64_t idxMft, PRTFSNTFSCORE *ppCore, PRTERRINFO pErrInfo)
     1127{
     1128    Assert(pThis->pMftData);
     1129    Assert(RTAvlU64Get(&pThis->MftRoot, idxMft) == NULL);
     1130
     1131    PRTFSNTFSMFTREC pRec = rtFsNtfsVol_NewMftRec(pThis, idxMft);
     1132    AssertReturn(pRec, VERR_NO_MEMORY);
     1133
     1134    uint64_t offRec = idxMft * pThis->cbMftRecord;
     1135    int rc = rtFsNtfsAttr_Read(pThis->pMftData, offRec, pRec->pbRec, pThis->cbMftRecord);
     1136    if (RT_SUCCESS(rc))
     1137    {
     1138#ifdef LOG_ENABLED
     1139        rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);
     1140#endif
     1141        rc = rtFsNtfsVol_ParseMft(pThis, pRec, pErrInfo);
     1142        if (RT_SUCCESS(rc))
     1143        {
     1144            rtFsNtfsMftRec_Release(pRec, pThis);
     1145            *ppCore = pRec->pCore;
     1146            return VINF_SUCCESS;
     1147        }
     1148        rtFsNtfsCore_Release(pRec->pCore);
     1149        rtFsNtfsMftRec_Release(pRec, pThis);
     1150    }
     1151    return rc;
     1152}
     1153
    8971154
    8981155
     
    9601217static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis)
    9611218{
    962     uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
    963     Assert(cRefs < 128);
    964     if (cRefs != 0)
    965         return cRefs;
    966     return rtFsNtfsCore_Destroy(pThis);
     1219    if (pThis)
     1220    {
     1221        uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     1222        Assert(cRefs < 128);
     1223        if (cRefs != 0)
     1224            return cRefs;
     1225        return rtFsNtfsCore_Destroy(pThis);
     1226    }
     1227    return 0;
    9671228}
    9681229
     
    10051266
    10061267
     1268/**
     1269 * Slow path for querying the allocation state of a cluster.
     1270 *
     1271 * @returns IPRT status code.
     1272 * @param   pThis               The NTFS volume instance.
     1273 * @param   iCluster            The cluster to query.
     1274 * @param   pfState             Where to return the state.
     1275 */
     1276static int rtFsNtfsVol_QueryClusterStateSlow(PRTFSNTFSVOL pThis, uint64_t iCluster, bool *pfState)
     1277{
     1278    int rc;
     1279    uint64_t const cbWholeBitmap = RT_LE2H_U64(pThis->pMftBitmap->pAttrHdr->u.NonRes.cbData);
     1280    uint64_t const offInBitmap   = iCluster >> 3;
     1281    if (offInBitmap < cbWholeBitmap)
     1282    {
     1283        if (!pThis->pvBitmap)
     1284        {
     1285            /*
     1286             * Try cache the whole bitmap if it's not too large.
     1287             */
     1288            if (   cbWholeBitmap <= RTFSNTFS_MAX_BITMAP_CACHE
     1289                && cbWholeBitmap >= RT_ALIGN_64(pThis->cClusters >> 3, 8))
     1290            {
     1291                pThis->cbBitmapAlloc = RT_ALIGN_Z((uint32_t)cbWholeBitmap, 8);
     1292                pThis->pvBitmap      = RTMemAlloc(pThis->cbBitmapAlloc);
     1293                if (pThis->pvBitmap)
     1294                {
     1295                    memset(pThis->pvBitmap, 0xff, pThis->cbBitmapAlloc);
     1296                    rc = rtFsNtfsAttr_Read(pThis->pMftBitmap, 0, pThis->pvBitmap, (uint32_t)cbWholeBitmap);
     1297                    if (RT_SUCCESS(rc))
     1298                    {
     1299                        pThis->iFirstBitmapCluster = 0;
     1300                        pThis->cBitmapClusters     = pThis->cClusters;
     1301                        *pfState = rtFsNtfsBitmap_IsSet(pThis->pvBitmap, (uint32_t)iCluster);
     1302                        return VINF_SUCCESS;
     1303                    }
     1304                    RTMemFree(pThis->pvBitmap);
     1305                    pThis->pvBitmap      = NULL;
     1306                    pThis->cbBitmapAlloc = 0;
     1307                    return rc;
     1308                }
     1309            }
     1310
     1311            /*
     1312             * Do a cluster/4K cache.
     1313             */
     1314            pThis->cbBitmapAlloc = RT_MAX(pThis->cbCluster, _4K);
     1315            pThis->pvBitmap      = RTMemAlloc(pThis->cbBitmapAlloc);
     1316            if (!pThis->pvBitmap)
     1317            {
     1318                pThis->cbBitmapAlloc = 0;
     1319                return VERR_NO_MEMORY;
     1320            }
     1321        }
     1322
     1323        /*
     1324         * Load a cache line.
     1325         */
     1326        Assert(RT_IS_POWER_OF_TWO(pThis->cbBitmapAlloc));
     1327        uint64_t offLoad = offInBitmap & ~(pThis->cbBitmapAlloc - 1);
     1328        uint32_t cbLoad  = (uint32_t)RT_MIN(cbWholeBitmap - offLoad, pThis->cbBitmapAlloc);
     1329
     1330        memset(pThis->pvBitmap, 0xff, pThis->cbBitmapAlloc);
     1331        rc = rtFsNtfsAttr_Read(pThis->pMftBitmap, offLoad, pThis->pvBitmap, cbLoad);
     1332        if (RT_SUCCESS(rc))
     1333        {
     1334            pThis->iFirstBitmapCluster = offLoad << 3;
     1335            pThis->cBitmapClusters     = cbLoad  << 3;
     1336            *pfState = rtFsNtfsBitmap_IsSet(pThis->pvBitmap, (uint32_t)(iCluster - pThis->iFirstBitmapCluster));
     1337            return VINF_SUCCESS;
     1338        }
     1339        pThis->cBitmapClusters = 0;
     1340    }
     1341    else
     1342    {
     1343        LogRel(("rtFsNtfsVol_QueryClusterStateSlow: iCluster=%#RX64 is outside the bitmap (%#RX64)\n", iCluster, cbWholeBitmap));
     1344        rc = VERR_OUT_OF_RANGE;
     1345    }
     1346    return rc;
     1347}
     1348
     1349
     1350/**
     1351 * Query the allocation state of the given cluster.
     1352 *
     1353 * @returns IPRT status code.
     1354 * @param   pThis               The NTFS volume instance.
     1355 * @param   iCluster            The cluster to query.
     1356 * @param   pfState             Where to return the state.
     1357 */
     1358static int rtFsNtfsVol_QueryClusterState(PRTFSNTFSVOL pThis, uint64_t iCluster, bool *pfState)
     1359{
     1360    uint64_t iClusterInCache = iCluster - pThis->iFirstBitmapCluster;
     1361    if (iClusterInCache < pThis->cBitmapClusters)
     1362    {
     1363        *pfState = rtFsNtfsBitmap_IsSet(pThis->pvBitmap, (uint32_t)iClusterInCache);
     1364        return VINF_SUCCESS;
     1365    }
     1366    return rtFsNtfsVol_QueryClusterStateSlow(pThis, iCluster, pfState);
     1367}
     1368
     1369
    10071370
    10081371/**
     
    10461409static DECLCALLBACK(int) rtFsNtfsVol_QueryRangeState(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)
    10471410{
    1048     NOREF(pvThis); NOREF(off); NOREF(cb); NOREF(pfUsed);
    1049     return VERR_NOT_IMPLEMENTED;
     1411    PRTFSNTFSVOL pThis = (PRTFSNTFSVOL)pvThis;
     1412    *pfUsed = true;
     1413
     1414    /*
     1415     * Round to a cluster range.
     1416     */
     1417    uint64_t iCluster  = off >> pThis->cClusterShift;
     1418
     1419    Assert(RT_IS_POWER_OF_TWO(pThis->cbCluster));
     1420    cb += off & (pThis->cbCluster - 1);
     1421    cb = RT_ALIGN_Z(cb, pThis->cbCluster);
     1422    size_t   cClusters = cb >> pThis->cClusterShift;
     1423
     1424    /*
     1425     * Check the clusters one-by-one.
     1426     * Just to be cautious, we will always check the cluster at off, even when cb is zero.
     1427     */
     1428    do
     1429    {
     1430        bool fState = true;
     1431        int rc = rtFsNtfsVol_QueryClusterState(pThis, iCluster, &fState);
     1432        if (RT_FAILURE(rc))
     1433            return rc;
     1434        if (fState)
     1435        {
     1436            *pfUsed = true;
     1437            LogFlow(("rtFsNtfsVol_QueryRangeState: %RX64 LB %#x - used\n", off, cb));
     1438            return VINF_SUCCESS;
     1439        }
     1440
     1441        iCluster++;
     1442    } while (cClusters-- > 0);
     1443
     1444    LogFlow(("rtFsNtfsVol_QueryRangeState: %RX64 LB %#x - unused\n", off, cb));
     1445    *pfUsed = false;
     1446    return VINF_SUCCESS;
    10501447}
    10511448
     
    10701467
    10711468
    1072 
    1073 static int rtFsNtfsVolLoadMft(PRTFSNTFSVOL pThis, void *pvBuf, size_t cbBuf, PRTERRINFO pErrInfo)
    1074 {
    1075     AssertReturn(cbBuf >= _64K, VERR_INTERNAL_ERROR_2);
    1076     NOREF(pThis); NOREF(pvBuf); NOREF(cbBuf); NOREF(pErrInfo);
    1077     /** @todo read MFT, find bitmap allocation, implement
    1078      *        rtFsNtfsVol_QueryRangeState. */
    1079 
     1469/**
     1470 * Checks that the storage for the given attribute is all marked allocated in
     1471 * the allocation bitmap of the volume.
     1472 *
     1473 * @returns IPRT status code.
     1474 * @param   pThis               The NTFS volume instance.
     1475 * @param   pAttr               The attribute to check.
     1476 * @param   pszDesc             Description of the attribute.
     1477 * @param   pErrInfo            Where to return error details.
     1478 */
     1479static int rtFsNtfsVolCheckBitmap(PRTFSNTFSVOL pThis, PRTFSNTFSATTR pAttr, const char *pszDesc, PRTERRINFO pErrInfo)
     1480{
     1481    PRTFSNTFSATTRSUBREC pSubRec = NULL;
     1482    PRTFSNTFSEXTENTS    pTable  = &pAttr->Extents;
     1483    uint64_t            offFile = 0;
     1484    for (;;)
     1485    {
     1486        uint32_t const  cExtents  = pTable->cExtents;
     1487        PRTFSNTFSEXTENT paExtents = pTable->paExtents;
     1488        for (uint32_t iExtent = 0; iExtent < cExtents; iExtent++)
     1489        {
     1490            uint64_t const off = paExtents[iExtent].off;
     1491            if (off == UINT64_MAX)
     1492                offFile += paExtents[iExtent].cbExtent;
     1493            else
     1494            {
     1495                uint64_t iCluster  = off >> pThis->cClusterShift;
     1496                uint64_t cClusters = paExtents[iExtent].cbExtent >> pThis->cClusterShift;
     1497                Assert((cClusters << pThis->cClusterShift) == paExtents[iExtent].cbExtent);
     1498                Assert(cClusters != 0);
     1499
     1500                while (cClusters-- > 0)
     1501                {
     1502                    bool fState = false;
     1503                    int rc = rtFsNtfsVol_QueryClusterState(pThis, iCluster, &fState);
     1504                    if (RT_FAILURE(rc))
     1505                        return RTERRINFO_LOG_REL_SET_F(pErrInfo, rc,
     1506                                                       "Error querying allocation bitmap entry %#RX64 (for %s offset %#RX64)",
     1507                                                       iCluster, pszDesc, offFile);
     1508                    if (!fState)
     1509                        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1510                                                       "Cluster %#RX64 at offset %#RX64 in %s is not marked allocated",
     1511                                                       iCluster, offFile, pszDesc);
     1512                    offFile += pThis->cbCluster;
     1513                }
     1514            }
     1515        }
     1516
     1517        /* Next table. */
     1518        pSubRec = pSubRec ? pSubRec->pNext : pAttr->pSubRecHead;
     1519        if (!pSubRec)
     1520            return VINF_SUCCESS;
     1521        pTable = &pSubRec->Extents;
     1522    }
     1523}
     1524
     1525
     1526/**
     1527 * Loads the allocation bitmap and does basic validation of.
     1528 *
     1529 * @returns IPRT status code.
     1530 * @param   pThis               The NTFS volume instance.  Will set up the
     1531 *                              'Allocation bitmap and cache' fields.
     1532 * @param   pErrInfo            Where to return error details.
     1533 */
     1534static int rtFsNtfsVolLoadBitmap(PRTFSNTFSVOL pThis, PRTERRINFO pErrInfo)
     1535{
     1536    PRTFSNTFSCORE pCore;
     1537    int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_BITMAP, &pCore, pErrInfo);
     1538    if (RT_SUCCESS(rc))
     1539    {
     1540        PRTFSNTFSATTR pMftBitmap;
     1541        pThis->pMftBitmap = pMftBitmap = rtFsNtfsCore_FindUnnamedAttribute(pCore, NTFS_AT_DATA);
     1542        if (pMftBitmap)
     1543        {
     1544            /*
     1545             * Validate the '$Bitmap' MFT record.
     1546             * We expect the bitmap to be fully initialized and be sized according to the
     1547             * formatted volume size.  Allegedly, NTFS pads it to an even 8 byte in size.
     1548             */
     1549            uint64_t const cbMinBitmap      = RT_ALIGN_64(pThis->cbVolume >> (pThis->cClusterShift + 3), 8);
     1550            uint64_t const cbMaxBitmap      = RT_ALIGN_64(cbMinBitmap, pThis->cbCluster);
     1551            //uint64_t const cbMinInitialized = RT_ALIGN_64((RT_MAX(pThis->uLcnMft, pThis->uLcnMftMirror) + 16) >> 3, 8);
     1552            if (!pMftBitmap->pAttrHdr->fNonResident)
     1553                rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #6 unnamed DATA attribute is resident!");
     1554            else if (   (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) < cbMinBitmap
     1555                     || (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) > cbMaxBitmap)
     1556                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1557                                             "MFT record #6 unnamed DATA attribute allocated size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
     1558                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated), cbMinBitmap, cbMaxBitmap);
     1559            else if (   (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData) < cbMinBitmap
     1560                     ||    (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData)
     1561                         > (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData))
     1562                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1563                                             "MFT record #6 unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
     1564                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData), cbMinBitmap,
     1565                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) );
     1566            else if (   (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbInitialized) < cbMinBitmap
     1567                     ||    (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbInitialized)
     1568                         > (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated))
     1569                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1570                                             "MFT record #6 unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
     1571                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbInitialized), cbMinBitmap,
     1572                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) );
     1573            else if (pMftBitmap->pAttrHdr->u.NonRes.uCompressionUnit != 0)
     1574                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1575                                             "MFT record #6 unnamed DATA attribute is compressed: %#x",
     1576                                             pMftBitmap->pAttrHdr->u.NonRes.uCompressionUnit);
     1577            else if (pMftBitmap->Extents.cExtents != 1) /* paranoia for now */
     1578                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1579                                             "MFT record #6 unnamed DATA attribute is expected to have a single extent: %u extents",
     1580                                             pMftBitmap->Extents.cExtents);
     1581            else if (pMftBitmap->Extents.paExtents[0].off == UINT64_MAX)
     1582                rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #6 unnamed DATA attribute is sparse");
     1583            else
     1584            {
     1585                PRTFSNTFSATTR pFilenameAttr = rtFsNtfsCore_FindUnnamedAttribute(pCore, NTFS_AT_FILENAME);
     1586                if (!pFilenameAttr)
     1587                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #6 has no FILENAME attribute!");
     1588                else if (pFilenameAttr->pAttrHdr->fNonResident)
     1589                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #6 FILENAME attribute is non-resident!");
     1590                else if (pFilenameAttr->pAttrHdr->u.Res.cbValue < RT_UOFFSETOF(NTFSATFILENAME, wszFilename[7]))
     1591                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1592                                                 "MFT record #6 FILENAME attribute value size is too small: %#x",
     1593                                                 pFilenameAttr->pAttrHdr->u.Res.cbValue);
     1594                else
     1595                {
     1596                    PNTFSATFILENAME pFilename = (PNTFSATFILENAME)(  (uint8_t *)pFilenameAttr->pAttrHdr
     1597                                                                  + pFilenameAttr->pAttrHdr->u.Res.offValue);
     1598                    if (   pFilename->cwcFilename != 7
     1599                        || RTUtf16NICmpAscii(pFilename->wszFilename, "$Bitmap", 7) != 0)
     1600                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1601                                                     "MFT record #6 FILENAME isn't '$Bitmap': '%.*ls'",
     1602                                                     pFilename->cwcFilename, pFilename->wszFilename);
     1603                    else
     1604                    {
     1605                        /*
     1606                         * Read some of it into the buffer and check that essential stuff is flagged as allocated.
     1607                         */
     1608                        /* The boot sector. */
     1609                        bool fState = false;
     1610                        rc = rtFsNtfsVol_QueryClusterState(pThis, 0, &fState);
     1611                        if (RT_SUCCESS(rc) && !fState)
     1612                            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1613                                                       "MFT allocation bitmap error: Bootsector isn't marked allocated!");
     1614                        else if (RT_FAILURE(rc))
     1615                            rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1616                                                         "MFT allocation bitmap (offset 0) read error: %Rrc", rc);
     1617
     1618                        /* The bitmap ifself, the MFT data, and the MFT bitmap. */
     1619                        if (RT_SUCCESS(rc))
     1620                            rc = rtFsNtfsVolCheckBitmap(pThis, pThis->pMftBitmap, "allocation bitmap", pErrInfo);
     1621                        if (RT_SUCCESS(rc))
     1622                            rc = rtFsNtfsVolCheckBitmap(pThis, pThis->pMftData, "MFT", pErrInfo);
     1623                        if (RT_SUCCESS(rc))
     1624                            rc = rtFsNtfsVolCheckBitmap(pThis,
     1625                                                        rtFsNtfsCore_FindUnnamedAttribute(pThis->pMftData->pCore, NTFS_AT_BITMAP),
     1626                                                        "MFT Bitmap", pErrInfo);
     1627                        if (RT_SUCCESS(rc))
     1628                        {
     1629                            /*
     1630                             * Looks like the bitmap is good.
     1631                             */
     1632                            return VINF_SUCCESS;
     1633                        }
     1634                    }
     1635                }
     1636            }
     1637            pThis->pMftBitmap = NULL;
     1638        }
     1639        else
     1640            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed DATA attribute!");
     1641        rtFsNtfsCore_Release(pCore);
     1642    }
     1643    else
     1644        rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "Error reading MFT record #6");
     1645    return rc;
     1646}
     1647
     1648
     1649
     1650/**
     1651 * Loads, validates and setups the '$Mft' (NTFS_MFT_IDX_MFT) MFT entry.
     1652 *
     1653 * This is the first thing we do after we've checked out the boot sector and
     1654 * extracted information from it, since everything else depends on us being able
     1655 * to access the MFT data.
     1656 *
     1657 * @returns IPRT status code
     1658 * @param   pThis               The NTFS volume instance.  Will set pMftData.
     1659 * @param   pErrInfo            Where to return additional error info.
     1660 */
     1661static int rtFsNtfsVolLoadMft(PRTFSNTFSVOL pThis, PRTERRINFO pErrInfo)
     1662{
    10801663    /*
    10811664     * Bootstrap the MFT data stream.
    10821665     */
    1083     PRTFSNTFSMFTREC pRec = rtFsNtfsMftVol_New(pThis, 0);
     1666    PRTFSNTFSMFTREC pRec = rtFsNtfsVol_NewMftRec(pThis, NTFS_MFT_IDX_MFT);
    10841667    AssertReturn(pRec, VERR_NO_MEMORY);
    10851668
    1086 #if 0 //def LOG_ENABLED
    1087     for (uint32_t i = 0; i < 64; i++)
    1088     {
    1089         RTVfsFileReadAt(pThis->hVfsBacking, (pThis->uLcnMft << pThis->cClusterShift) + i * pThis->cbMftRecord,
    1090                         pRec->pbRec, pThis->cbMftRecord, NULL);
    1091         pRec->TreeNode.Key = i;
    1092         Log(("\n"));
    1093         rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);
    1094     }
    1095     pRec->TreeNode.Key = 0;
    1096 #endif
    1097 
    1098     pRec->offDisk = pThis->uLcnMft << pThis->cClusterShift;
    1099     int rc = RTVfsFileReadAt(pThis->hVfsBacking, pRec->offDisk, pRec->pbRec, pThis->cbMftRecord, NULL);
     1669    uint64_t const offDisk = pThis->uLcnMft << pThis->cClusterShift;
     1670    int rc = RTVfsFileReadAt(pThis->hVfsBacking, offDisk, pRec->pbRec, pThis->cbMftRecord, NULL);
    11001671    if (RT_SUCCESS(rc))
    11011672    {
     
    11091680            if (pThis->pMftData)
    11101681            {
    1111                 /** @todo sanity check the attribute. */
    1112                 rtFsNtfsMftRec_Release(pRec, pThis);
    1113                 return rc;
     1682                /*
     1683                 * Validate the '$Mft' MFT record.
     1684                 */
     1685                if (!pThis->pMftData->pAttrHdr->fNonResident)
     1686                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 unnamed DATA attribute is resident!");
     1687                else if (   (uint64_t)RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbAllocated) <  pThis->cbMftRecord * 16U
     1688                         || (uint64_t)RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbAllocated) >= pThis->cbBacking)
     1689                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1690                                                 "MFT record #0 unnamed DATA attribute allocated size is out of range: %#RX64",
     1691                                                 RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbAllocated));
     1692                else if (   (uint64_t)RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbInitialized) <  pThis->cbMftRecord * 16U
     1693                         || (uint64_t)RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbInitialized) >= pThis->cbBacking)
     1694                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1695                                                 "MFT record #0 unnamed DATA attribute initialized size is out of range: %#RX64",
     1696                                                 RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbInitialized));
     1697                else if (   (uint64_t)RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbData) <  pThis->cbMftRecord * 16U
     1698                         || (uint64_t)RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbData) >= pThis->cbBacking)
     1699                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1700                                                 "MFT record #0 unnamed DATA attribute allocated size is out of range: %#RX64",
     1701                                                 RT_LE2H_U64(pThis->pMftData->pAttrHdr->u.NonRes.cbData));
     1702                else if (pThis->pMftData->pAttrHdr->u.NonRes.uCompressionUnit != 0)
     1703                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1704                                                 "MFT record #0 unnamed DATA attribute is compressed: %#x",
     1705                                                 pThis->pMftData->pAttrHdr->u.NonRes.uCompressionUnit);
     1706                else if (pThis->pMftData->Extents.cExtents == 0)
     1707                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1708                                               "MFT record #0 unnamed DATA attribute has no data on the disk");
     1709                else if (pThis->pMftData->Extents.paExtents[0].off != offDisk)
     1710                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1711                                                 "MFT record #0 unnamed DATA attribute has a bogus disk offset: %#RX64, expected %#RX64",
     1712                                                 pThis->pMftData->Extents.paExtents[0].off, offDisk);
     1713                else if (!rtFsNtfsCore_FindUnnamedAttribute(pRec->pCore, NTFS_AT_BITMAP))
     1714                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed BITMAP attribute!");
     1715                else
     1716                {
     1717                    PRTFSNTFSATTR pFilenameAttr = rtFsNtfsCore_FindUnnamedAttribute(pRec->pCore, NTFS_AT_FILENAME);
     1718                    if (!pFilenameAttr)
     1719                        rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no FILENAME attribute!");
     1720                    else if (pFilenameAttr->pAttrHdr->fNonResident)
     1721                        rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 FILENAME attribute is non-resident!");
     1722                    else if (pFilenameAttr->pAttrHdr->u.Res.cbValue < RT_UOFFSETOF(NTFSATFILENAME, wszFilename[4]))
     1723                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1724                                                     "MFT record #0 FILENAME attribute value size is too small: %#x",
     1725                                                     pFilenameAttr->pAttrHdr->u.Res.cbValue);
     1726                    else
     1727                    {
     1728                        PNTFSATFILENAME pFilename = (PNTFSATFILENAME)(  (uint8_t *)pFilenameAttr->pAttrHdr
     1729                                                                      + pFilenameAttr->pAttrHdr->u.Res.offValue);
     1730                        if (   pFilename->cwcFilename != 4
     1731                            || RTUtf16NICmpAscii(pFilename->wszFilename, "$Mft", 4) != 0)
     1732                            rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1733                                                         "MFT record #0 FILENAME isn't '$Mft': '%.*ls'",
     1734                                                         pFilename->cwcFilename, pFilename->wszFilename);
     1735                        else
     1736                        {
     1737                            /*
     1738                             * Looks like we're good.
     1739                             */
     1740                            return VINF_SUCCESS;
     1741                        }
     1742                    }
     1743                }
     1744                pThis->pMftData = NULL;
    11141745            }
    1115             rc = RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed DATA attribute!");
     1746            else
     1747                rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed DATA attribute!");
    11161748        }
    1117         if (pRec->pCore)
    1118             rtFsNtfsCore_Release(pRec->pCore);
     1749        rtFsNtfsCore_Release(pRec->pCore);
    11191750        rtFsNtfsMftRec_Release(pRec, pThis);
    11201751    }
    11211752    else
    1122         rc = RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading MFT record #0");
     1753        rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "Error reading MFT record #0");
    11231754    return rc;
    11241755}
     
    13061937                rc = rtFsNtfsVolLoadAndParseBootsector(pThis, pvBuf, _64K, pErrInfo);
    13071938                if (RT_SUCCESS(rc))
    1308                     rc = rtFsNtfsVolLoadMft(pThis, pvBuf, _64K, pErrInfo);
     1939                    rc = rtFsNtfsVolLoadMft(pThis, pErrInfo);
     1940                if (RT_SUCCESS(rc))
     1941                    rc = rtFsNtfsVolLoadBitmap(pThis, pErrInfo);
    13091942                RTMemTmpFree(pvBuf);
    13101943                if (RT_SUCCESS(rc))
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