VirtualBox

Changeset 69873 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Nov 29, 2017 10:38:53 PM (7 years ago)
Author:
vboxsync
Message:

iprt/ntfsvfs.cpp: updates

File:
1 edited

Legend:

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

    r69868 r69873  
    4545
    4646/*********************************************************************************************************************************
     47*   Defined Constants And Macros                                                                                                 *
     48*********************************************************************************************************************************/
     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)
     52
     53
     54/*********************************************************************************************************************************
    4755*   Structures and Typedefs                                                                                                      *
    4856*********************************************************************************************************************************/
     
    5159/** Pointer to a NTFS MFT record. */
    5260typedef struct RTFSNTFSMFTREC *PRTFSNTFSMFTREC;
     61/** Poitner to a NTFS core object record.   */
     62typedef struct RTFSNTFSCORE *PRTFSNTFSCORE;
     63
     64
     65/**
     66 * NTFS disk allocation extent (internal representation).
     67 */
     68typedef struct RTFSNTFSEXTENT
     69{
     70    /** The disk or partition byte offset.
     71     * This is set to UINT64_MAX for parts of sparse files that aren't recorded. */
     72    uint64_t            off;
     73    /** The size of the extent in bytes. */
     74    uint64_t            cbExtent;
     75} RTFSNTFSEXTENT;
     76/** Pointer to an NTFS 9660 extent. */
     77typedef RTFSNTFSEXTENT *PRTFSNTFSEXTENT;
     78/** Pointer to a const NTFS 9660 extent. */
     79typedef RTFSNTFSEXTENT const *PCRTFSNTFSEXTENT;
     80
     81/**
     82 * An array of zero or more extents.
     83 */
     84typedef struct RTFSNTFSEXTENTS
     85{
     86    /** Number of bytes covered by the extents. */
     87    uint64_t            cbData;
     88    /** Number of allocation extents. */
     89    uint32_t            cExtents;
     90    /** Array of allocation extents. */
     91    PRTFSNTFSEXTENT     paExtents;
     92} RTFSNTFSEXTENTS;
     93/** Pointer to an extent array. */
     94typedef RTFSNTFSEXTENTS *PRTFSNTFSEXTENTS;
     95/** Pointer to a const extent array. */
     96typedef RTFSNTFSEXTENTS const *PCRTFSNTFSEXTENTS;
     97
    5398
    5499/**
    55100 * NTFS MFT record.
     101 *
     102 * These are kept in a tree to , so
    56103 */
    57104typedef struct RTFSNTFSMFTREC
    58105{
    59     /** MFT record number as key. */
    60     AVLU64NODECORE      Core;
    61     /** Pointer to the next MFT record if chained. */
     106    /** MFT record number (index) as key. */
     107    AVLU64NODECORE      TreeNode;
     108    /** Pointer to the next MFT record if chained.  Holds a reference.  */
    62109    PRTFSNTFSMFTREC     pNext;
    63     /** Pointer back to the volume. */
    64     PRTFSNTFSVOL        pVol;
    65     /** The disk offset of this MFT entry. */
    66     uint64_t            offDisk;
    67110    union
    68111    {
    69         /** Generic pointer. */
     112        /** Generic record pointer.  RTFSNTFSVOL::cbMftRecord in size. */
    70113        uint8_t        *pbRec;
    71114        /** Pointer to the file record. */
    72115        PNTFSRECFILE    pFileRec;
    73116    } RT_UNION_NM(u);
    74 
     117    /** Pointer to the core object with the parsed data.
     118     * This is a weak reference.  Non-base MFT record all point to the base one. */
     119    PRTFSNTFSCORE       pCore;
    75120    /** Reference counter. */
    76121    uint32_t volatile   cRefs;
    77 
    78     // ....
     122    /** Set if this is a base MFT record. */
     123    bool                fIsBase;
     124    /** The disk offset of this MFT entry. */
     125    uint64_t            offDisk;
    79126} RTFSNTFSMFTREC;
     127
     128
     129/** Pointer to a attribute subrecord structure. */
     130typedef struct RTFSNTFSATTRSUBREC *PRTFSNTFSATTRSUBREC;
     131
     132/**
     133 * An attribute subrecord.
     134 *
     135 * This is for covering non-resident attributes that have had their allocation
     136 * list split.
     137 */
     138typedef struct RTFSNTFSATTRSUBREC
     139{
     140    /** Pointer to the next one. */
     141    PRTFSNTFSATTRSUBREC pNext;
     142    /** Pointer to the attribute header.
     143     * The MFT is held down by RTFSNTFSCORE via pMftEntry. */
     144    PNTFSATTRIBHDR      pAttrHdr;
     145    /** Disk space allocation if non-resident. */
     146    RTFSNTFSEXTENTS     Extents;
     147} RTFSNTFSATTRSUBREC;
     148
     149/**
     150 * An attribute.
     151 */
     152typedef struct RTFSNTFSATTR
     153{
     154    /** List entry (head RTFSNTFSCORE::AttribHead). */
     155    RTLISTNODE          ListEntry;
     156    /** Pointer to the core object this attribute belongs to. */
     157    PRTFSNTFSCORE       pCore;
     158    /** Pointer to the attribute header.
     159     * The MFT is held down by RTFSNTFSCORE via pMftEntry. */
     160    PNTFSATTRIBHDR      pAttrHdr;
     161    /** Disk space allocation if non-resident. */
     162    RTFSNTFSEXTENTS     Extents;
     163    /** Pointer to any subrecords containing further allocation extents. */
     164    PRTFSNTFSATTRSUBREC pSubRecHead;
     165} RTFSNTFSATTR;
     166/** Pointer to a attribute structure. */
     167typedef RTFSNTFSATTR *PRTFSNTFSATTR;
     168
     169
     170/**
     171 * NTFS file system object, shared part.
     172 */
     173typedef struct RTFSNTFSCORE
     174{
     175    /** Reference counter.   */
     176    uint32_t volatile   cRefs;
     177    /** Pointer to the volume. */
     178    PRTFSNTFSVOL        pVol;
     179    /** Pointer to the head of the MFT record chain for this object.
     180     * Holds a reference.  */
     181    PRTFSNTFSMFTREC     pMftRec;
     182    /** List of attributes (RTFSNTFSATTR). */
     183    RTLISTANCHOR        AttribHead;
     184} RTFSNTFSCORE;
     185
    80186
    81187/**
     
    123229    uint64_t        uSerialNo;
    124230
    125     /** Pointer to the MFT record for the MFT. */
    126     PRTFSNTFSMFTREC pMft;
     231    /** The MFT data attribute. */
     232    PRTFSNTFSATTR   pMftData;
    127233
    128234    /** Root of the MFT record tree (RTFSNTFSMFTREC). */
     
    131237
    132238
    133 static PRTFSNTFSMFTREC rtFsNtfsMftRec_New(PRTFSNTFSVOL pVol, uint64_t idMft)
     239static PRTFSNTFSMFTREC rtFsNtfsMftVol_New(PRTFSNTFSVOL pVol, uint64_t idMft)
    134240{
    135241    PRTFSNTFSMFTREC pRec = (PRTFSNTFSMFTREC)RTMemAllocZ(sizeof(*pRec));
     
    139245        if (pRec->pbRec)
    140246        {
    141             pRec->Core.Key = idMft;
    142             pRec->pNext    = NULL;
    143             pRec->offDisk  = UINT64_MAX / 2;
    144             pRec->pVol     = pVol;
    145             pRec->cRefs    = 1;
    146             return pRec;
     247            pRec->TreeNode.Key = idMft;
     248            pRec->pNext        = NULL;
     249            pRec->offDisk      = UINT64_MAX;
     250            pRec->cRefs        = 1;
     251            if (RTAvlU64Insert(&pVol->MftRoot, &pRec->TreeNode))
     252                return pRec;
     253            RTMemFree(pRec);
    147254        }
    148255    }
     
    151258
    152259
    153 #if 0 /* currently unused */
    154 static uint32_t rtFsNtfsMftRec_Destroy(PRTFSNTFSMFTREC pThis)
     260static uint32_t rtFsNtfsMftRec_Destroy(PRTFSNTFSMFTREC pThis, PRTFSNTFSVOL pVol)
    155261{
    156262    RTMemFree(pThis->pbRec);
    157263    pThis->pbRec = NULL;
    158264
    159     PAVLU64NODECORE pRemoved = RTAvlU64Remove(&pThis->pVol->MftRoot, pThis->Core.Key);
    160     Assert(pRemoved == &pThis->Core); NOREF(pRemoved);
    161 
    162     pThis->pVol = NULL;
     265    PAVLU64NODECORE pRemoved = RTAvlU64Remove(&pVol->MftRoot, pThis->TreeNode.Key);
     266    Assert(pRemoved == &pThis->TreeNode); NOREF(pRemoved);
     267
    163268    RTMemFree(pThis);
    164269
     
    174279}
    175280
    176 
    177 static uint32_t rtFsNtfsMftRec_Release(PRTFSNTFSMFTREC pThis)
     281static uint32_t rtFsNtfsMftRec_Release(PRTFSNTFSMFTREC pThis, PRTFSNTFSVOL pVol)
    178282{
    179283    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     
    181285    if (cRefs != 0)
    182286        return cRefs;
    183     return rtFsNtfsMftRec_Destroy(pThis);
    184 }
    185 #endif
     287    return rtFsNtfsMftRec_Destroy(pThis, pVol);
     288}
    186289
    187290
     
    190293 * Logs the MFT record
    191294 *
    192  * @param   pRec        The MFT record to log.
    193  */
    194 static void rtfsNtfsMftRec_Log(PRTFSNTFSMFTREC pRec)
     295 * @param   pRec            The MFT record to log.
     296 * @param   cbMftRecord     MFT record size (from RTFSNTFSVOL).
     297 */
     298static void rtfsNtfsMftRec_Log(PRTFSNTFSMFTREC pRec, uint32_t cbMftRecord)
    195299{
    196300    if (LogIs2Enabled())
    197301    {
    198302        PCNTFSRECFILE  pFileRec = pRec->pFileRec;
    199         Log2(("NTFS: MFT #%#RX64 at %#RX64\n", pRec->Core.Key, pRec->offDisk));
     303        Log2(("NTFS: MFT #%#RX64 at %#RX64\n", pRec->TreeNode.Key, pRec->offDisk));
    200304        if (pFileRec->Hdr.uMagic == NTFSREC_MAGIC_FILE)
    201305        {
    202             size_t const          cbRec = pRec->pVol->cbMftRecord;
     306            size_t const          cbRec = cbMftRecord;
    203307            uint8_t const * const pbRec = pRec->pbRec;
    204308
     
    316420                            }
    317421
    318                             //case NTFS_AT_ATTRIBUTE_LIST:
     422                            case NTFS_AT_ATTRIBUTE_LIST:
     423                            {
     424                                uint32_t iEntry   = 0;
     425                                uint32_t offEntry = 0;
     426                                while (offEntry + NTFSATLISTENTRY_SIZE_MINIMAL < cbValue)
     427                                {
     428                                    PCNTFSATLISTENTRY pInfo = (PCNTFSATLISTENTRY)&pbValue[offEntry];
     429                                    Log2(("NTFS:     attr[%u]: %#x in %#RX64 (sqn %#x), instance %#x, VNC=%#RX64-, name %#x L %#x\n",
     430                                          iEntry, RT_LE2H_U32(pInfo->uAttrType),  NTFSMFTREF_GET_IDX(&pInfo->InMftRec),
     431                                          NTFSMFTREF_GET_SEQ(&pInfo->InMftRec), RT_LE2H_U16(pInfo->idAttrib),
     432                                          RT_LE2H_U64(pInfo->iVcnFirst), pInfo->offName, pInfo->cwcName));
     433                                    if (   pInfo->cwcName > 0
     434                                        && pInfo->offName < pInfo->cbEntry)
     435                                        Log2(("NTFS:               name '%.*ls'\n", pInfo->cwcName, (uint8_t *)pInfo + pInfo->offName));
     436
     437                                    /* next */
     438                                    if (pInfo->cbEntry < NTFSATLISTENTRY_SIZE_MINIMAL)
     439                                    {
     440                                        Log2(("NTFS:     cbEntry is too small! cbEntry=%#x, min %#x\n",
     441                                              pInfo->cbEntry, NTFSATLISTENTRY_SIZE_MINIMAL));
     442                                        break;
     443                                    }
     444                                    iEntry++;
     445                                    offEntry += RT_ALIGN_32(pInfo->cbEntry, 8);
     446                                }
     447                                break;
     448                            }
    319449
    320450                            case NTFS_AT_FILENAME:
     
    442572                                if (cbNum)
    443573                                {
    444                                     int8_t const *pbNum = (int8_t const *)&pbPairs[offPairs + cbNum]; /* last byte */
    445                                     cClustersInRun = *pbNum--;
     574                                    uint8_t const *pbNum = &pbPairs[offPairs + cbNum]; /* last byte */
     575                                    cClustersInRun = (int8_t)*pbNum--;
    446576                                    while (cbNum-- > 1)
    447577                                        cClustersInRun = (cClustersInRun << 8) + *pbNum--;
     
    454584                                if (cbNum)
    455585                                {
    456                                     int8_t const *pbNum  = (int8_t const *)&pbPairs[offPairs + cbNum + (bLengths & 0xf)]; /* last byte */
    457                                     int64_t cLcnDelta = *pbNum--;
     586                                    uint8_t const *pbNum = &pbPairs[offPairs + cbNum + (bLengths & 0xf)]; /* last byte */
     587                                    int64_t cLcnDelta = (int8_t)*pbNum--;
    458588                                    while (cbNum-- > 1)
    459589                                        cLcnDelta = (cLcnDelta << 8) + *pbNum--;
     
    501631
    502632
     633static int rtFsNtfsAttr_ParseExtents(PRTFSNTFSATTR pAttrib, PRTFSNTFSEXTENTS pExtents, uint8_t cClusterShift, int64_t iVcnFirst,
     634                                     PRTERRINFO pErrInfo, uint64_t idxMft, uint32_t offAttrib)
     635{
     636    PCNTFSATTRIBHDR pAttrHdr = pAttrib->pAttrHdr;
     637    Assert(pAttrHdr->fNonResident);
     638    Assert(pExtents->cExtents  == 0);
     639    Assert(pExtents->paExtents == NULL);
     640
     641    /** @todo Not entirely sure how to best detect empty mapping pair program.
     642     *        Not sure if this is a real problem as zero length stuff can be
     643     *        resident.  */
     644    uint16_t const offMappingPairs = RT_LE2H_U16(pAttrHdr->u.NonRes.offMappingPairs);
     645    uint32_t const cbAttrib        = RT_LE2H_U32(pAttrHdr->cbAttrib);
     646    if (   offMappingPairs != cbAttrib
     647        && offMappingPairs != 0)
     648    {
     649        if (pAttrHdr->u.NonRes.iVcnFirst < iVcnFirst)
     650            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     651                                           "Bad MFT record %#RX64: Attribute (@%#x) has a lower starting VNC than expected: %#RX64, %#RX64",
     652                                           idxMft, offAttrib, pAttrHdr->u.NonRes.iVcnFirst, iVcnFirst);
     653
     654        if (   offMappingPairs >= cbAttrib
     655            || offMappingPairs < NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED)
     656            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     657                                           "Bad MFT record %#RX64: Mapping pair program for attribute (@%#x) is out of bounds: %#x, cbAttrib=%#x",
     658                                           idxMft, offAttrib, offMappingPairs, cbAttrib);
     659
     660        /*
     661         * Count the pairs.
     662         */
     663        uint8_t const  * const  pbPairs  = (const uint8_t *)pAttrHdr + pAttrHdr->u.NonRes.offMappingPairs;
     664        uint32_t const          cbPairs  = cbAttrib - offMappingPairs;
     665        uint32_t                offPairs = 0;
     666        uint32_t                cPairs   = 0;
     667        while (offPairs < cbPairs)
     668        {
     669            uint8_t const bLengths = pbPairs[offPairs];
     670            if (bLengths)
     671            {
     672                uint8_t const cbRunField = bLengths & 0x0f;
     673                uint8_t const cbLcnField = bLengths >> 4;
     674                if (   cbRunField > 0
     675                    && cbRunField <= 8)
     676                {
     677                    if (cbLcnField <= 8)
     678                    {
     679                        cPairs++;
     680
     681                        /* Advance and check for overflow/end. */
     682                        offPairs += 1 + cbRunField + cbLcnField;
     683                        if (offPairs <= cbAttrib)
     684                            continue;
     685                        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     686                                                       "Bad MFT record %#RX64: Mapping pair #%#x for attribute (@%#x) is out of bounds",
     687                                                       idxMft, cPairs - 1, offAttrib);
     688                    }
     689                    return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     690                                                   "Bad MFT record %#RX64: Mapping pair #%#x for attribute (@%#x): cbLcnField is out of bound: %u",
     691                                                   idxMft, cPairs - 1, offAttrib, cbLcnField);
     692
     693                }
     694                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     695                                               "Bad MFT record %#RX64: Mapping pair #%#x for attribute (@%#x): cbRunField is out of bound: %u",
     696                                               idxMft, cPairs - 1, offAttrib, cbRunField);
     697            }
     698            break;
     699        }
     700
     701        /*
     702         * Allocate an the extent table for them.
     703         */
     704        uint32_t const cExtents  = cPairs + (pAttrHdr->u.NonRes.iVcnFirst != iVcnFirst);
     705        if (cExtents)
     706        {
     707            PRTFSNTFSEXTENT paExtents = (PRTFSNTFSEXTENT)RTMemAllocZ(sizeof(paExtents[0]) * cExtents);
     708            AssertReturn(paExtents, VERR_NO_MEMORY);
     709
     710            /*
     711             * Fill the table.
     712             */
     713            uint32_t iExtent = 0;
     714
     715            /* A sparse hole between this and the previous extent table? */
     716            if (pAttrHdr->u.NonRes.iVcnFirst != iVcnFirst)
     717            {
     718                paExtents[iExtent].off      = UINT64_MAX;
     719                paExtents[iExtent].cbExtent = (pAttrHdr->u.NonRes.iVcnFirst - iVcnFirst) << cClusterShift;
     720                Log3(("   paExtent[%#04x]: %#018RX64 LB %#010RX64\n", iExtent, paExtents[iExtent].off, paExtents[iExtent].cbExtent));
     721                iExtent++;
     722            }
     723
     724            /* Run the program again, now with values and without verbose error checking. */
     725            uint64_t cMaxClustersInRun = (INT64_MAX >> cClusterShift) - pAttrHdr->u.NonRes.iVcnFirst;
     726            uint64_t cbData            = 0;
     727            int64_t  iLcn              = 0;
     728            int      rc                = VINF_SUCCESS;
     729            offPairs = 0;
     730            for (; iExtent < cExtents; iExtent++)
     731            {
     732                uint8_t const bLengths = pbPairs[offPairs++];
     733                uint8_t const cbRunField = bLengths & 0x0f;
     734                uint8_t const cbLcnField = bLengths >> 4;
     735                AssertBreakStmt((unsigned)cbRunField - 1U <= 7U, rc = VERR_VFS_BOGUS_FORMAT);
     736                AssertBreakStmt((unsigned)cbLcnField      <= 8U, rc = VERR_VFS_BOGUS_FORMAT);
     737
     738                AssertBreakStmt(!(pbPairs[offPairs + cbRunField - 1] & 0x80),
     739                                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     740                                                             "Bad MFT record %#RX64: Extent #%#x for attribute (@%#x): Negative runlength value",
     741                                                             idxMft, iExtent, offAttrib));
     742                uint64_t cClustersInRun = 0;
     743                switch (cbRunField)
     744                {
     745                    case 8: cClustersInRun |= (uint64_t)pbPairs[offPairs + 7] << 56; RT_FALL_THRU();
     746                    case 7: cClustersInRun |= (uint64_t)pbPairs[offPairs + 6] << 48; RT_FALL_THRU();
     747                    case 6: cClustersInRun |= (uint64_t)pbPairs[offPairs + 5] << 40; RT_FALL_THRU();
     748                    case 5: cClustersInRun |= (uint64_t)pbPairs[offPairs + 4] << 32; RT_FALL_THRU();
     749                    case 4: cClustersInRun |= (uint32_t)pbPairs[offPairs + 3] << 24; RT_FALL_THRU();
     750                    case 3: cClustersInRun |= (uint32_t)pbPairs[offPairs + 2] << 16; RT_FALL_THRU();
     751                    case 2: cClustersInRun |= (uint16_t)pbPairs[offPairs + 1] <<  8; RT_FALL_THRU();
     752                    case 1: cClustersInRun |= (uint16_t)pbPairs[offPairs + 0] <<  0; RT_FALL_THRU();
     753                }
     754                offPairs += cbRunField;
     755                AssertBreakStmt(cClustersInRun <= cMaxClustersInRun,
     756                                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     757                                                             "Bad MFT record %#RX64: Extent #%#x for attribute (@%#x): too many clusters %#RX64, max %#RX64",
     758                                                             idxMft, iExtent, offAttrib, cClustersInRun, cMaxClustersInRun));
     759                cMaxClustersInRun          -= cClustersInRun;
     760                paExtents[iExtent].cbExtent = cClustersInRun << cClusterShift;
     761                cbData                     += cClustersInRun << cClusterShift;
     762
     763                if (cbLcnField)
     764                {
     765                    unsigned offVncDelta = cbLcnField;
     766                    int64_t  cLncDelta   = (int8_t)pbPairs[--offVncDelta + offPairs];
     767                    while (offVncDelta-- > 0)
     768                        cLncDelta = (cLncDelta << 8) | pbPairs[offVncDelta + offPairs];
     769                    offPairs += cbLcnField;
     770
     771                    iLcn += cLncDelta;
     772                    if (iLcn >= 0)
     773                    {
     774                        paExtents[iExtent].off = (uint64_t)iLcn << cClusterShift;
     775                        AssertBreakStmt((paExtents[iExtent].off >> cClusterShift) == (uint64_t)iLcn,
     776                                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     777                                                                     "Bad MFT record %#RX64: Extent #%#x for attribute (@%#x): iLcn %RX64 overflows when shifted by %u",
     778                                                                     idxMft, iExtent, offAttrib, iLcn, cClusterShift));
     779                    }
     780                    else
     781                        paExtents[iExtent].off = UINT64_MAX;
     782                }
     783                else
     784                    paExtents[iExtent].off = UINT64_MAX;
     785                Log3(("   paExtent[%#04x]: %#018RX64 LB %#010RX64\n", iExtent, paExtents[iExtent].off, paExtents[iExtent].cbExtent));
     786            }
     787
     788            /* Commit if everything went fine? */
     789            if (RT_SUCCESS(rc))
     790            {
     791                pExtents->cbData    = cbData;
     792                pExtents->cExtents  = cExtents;
     793                pExtents->paExtents = paExtents;
     794            }
     795            else
     796            {
     797                RTMemFree(paExtents);
     798                return rc;
     799            }
     800        }
     801    }
     802    return VINF_SUCCESS;
     803}
     804
     805
     806static int rtFsNtfsVol_ParseMft(PRTFSNTFSVOL pThis, PRTFSNTFSMFTREC pRec, PRTERRINFO pErrInfo)
     807{
     808    AssertReturn(!pRec->pCore, VERR_INTERNAL_ERROR_4);
     809
     810    /*
     811     * Check that it is a file record and that its base MFT record number is zero.
     812     * Caller should do the base record resolving.
     813     */
     814    PNTFSRECFILE pFileRec = pRec->pFileRec;
     815    if (pFileRec->Hdr.uMagic != NTFSREC_MAGIC_FILE)
     816        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     817                                       "Bad MFT record %#RX64: Not a FILE entry (%.4Rhxs)",
     818                                       pRec->TreeNode.Key, &pFileRec->Hdr);
     819    if (pFileRec->BaseMftRec.u64 != 0)
     820        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     821                                       "Bad MFT record %#RX64: Not a base record (%#RX64, sqn %#x)",
     822                                       pRec->TreeNode.Key, NTFSMFTREF_GET_IDX(&pFileRec->BaseMftRec),
     823                                       NTFSMFTREF_GET_SEQ(&pFileRec->BaseMftRec) );
     824
     825     /*
     826      * Create a core node (1 reference, returned even on error).
     827      */
     828    PRTFSNTFSCORE pCore = (PRTFSNTFSCORE)RTMemAllocZ(sizeof(*pCore));
     829    AssertReturn(pCore, VERR_NO_MEMORY);
     830
     831    pCore->cRefs    = 1;
     832    pCore->pVol     = pThis;
     833    RTListInit(&pCore->AttribHead);
     834    pCore->pMftRec  = pRec;
     835    rtFsNtfsMftRec_Retain(pRec);
     836    pRec->pCore     = pCore;
     837
     838    /*
     839     * Parse attributes.
     840     * We process any attribute list afterwards, skipping attributes in this MFT record.
     841     */
     842    PRTFSNTFSATTR       pAttrList = NULL;
     843    uint8_t * const     pbRec     = pRec->pbRec;
     844    uint32_t            offRec    = pFileRec->offFirstAttrib;
     845    uint32_t const      cbRecUsed = RT_MIN(pThis->cbMftRecord, pFileRec->cbRecUsed);
     846    while (offRec + NTFSATTRIBHDR_SIZE_RESIDENT <= cbRecUsed)
     847    {
     848        PNTFSATTRIBHDR  pAttrHdr  = (PNTFSATTRIBHDR)&pbRec[offRec];
     849        uint32_t const  cbAttrib  = RT_LE2H_U32(pAttrHdr->cbAttrib);
     850        uint32_t const  cbMin     = !pAttrHdr->fNonResident                   ? NTFSATTRIBHDR_SIZE_RESIDENT
     851                                  : !pAttrHdr->u.NonRes.uCompressionUnit == 0 ? NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED
     852                                  :                                             NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED;
     853        if (cbAttrib < cbMin)
     854            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     855                                           "Bad MFT record %#RX64: Attribute (@%#x) is too small (%#x, cbMin=%#x)",
     856                                           pRec->TreeNode.Key, offRec, cbAttrib, cbMin);
     857        if (offRec + cbAttrib > cbRecUsed)
     858            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     859                                           "Bad MFT record %#RX64: Attribute (@%#x) is too long (%#x, cbRecUsed=%#x)",
     860                                           pRec->TreeNode.Key, offRec, cbAttrib, cbRecUsed);
     861        PRTFSNTFSATTR pAttrib = (PRTFSNTFSATTR)RTMemAllocZ(sizeof(*pAttrib));
     862        AssertReturn(pAttrib, VERR_NO_MEMORY);
     863        pAttrib->pAttrHdr           = pAttrHdr;
     864        pAttrib->pCore              = pCore;
     865        //pAttrib->Extents.cExtents   = 0;
     866        //pAttrib->Extents.paExtents  = NULL;
     867        //pAttrib->pSubRecHead        = NULL;
     868        if (pAttrHdr->fNonResident)
     869        {
     870            int rc = rtFsNtfsAttr_ParseExtents(pAttrib, &pAttrib->Extents, pThis->cClusterShift, 0 /*iVncFirst*/,
     871                                               pErrInfo, pRec->TreeNode.Key, offRec);
     872            if (RT_FAILURE(rc))
     873            {
     874                RTMemFree(pAttrib);
     875                return rc;
     876            }
     877        }
     878        RTListAppend(&pCore->AttribHead, &pAttrib->ListEntry);
     879
     880        if (pAttrHdr->uAttrType == NTFS_AT_ATTRIBUTE_LIST)
     881            pAttrList = pAttrib;
     882
     883        /* Advance. */
     884        offRec += cbAttrib;
     885    }
     886
     887    /*
     888     * Process any attribute list.
     889     */
     890    if (pAttrList)
     891    {
     892        /** @todo    */
     893    }
     894
     895    return VINF_SUCCESS;
     896}
     897
     898
     899/**
     900 * Destroys a core structure.
     901 *
     902 * @returns 0
     903 * @param   pThis               The core structure.
     904 */
     905static uint32_t rtFsNtfsCore_Destroy(PRTFSNTFSCORE pThis)
     906{
     907    /*
     908     * Free attributes.
     909     */
     910    PRTFSNTFSATTR pCurAttr;
     911    PRTFSNTFSATTR pNextAttr;
     912    RTListForEachSafe(&pThis->AttribHead, pCurAttr, pNextAttr, RTFSNTFSATTR, ListEntry)
     913    {
     914        PRTFSNTFSATTRSUBREC pSub = pCurAttr->pSubRecHead;
     915        while (pSub)
     916        {
     917            pCurAttr->pSubRecHead = pSub->pNext;
     918            RTMemFree(pSub->Extents.paExtents);
     919            pSub->Extents.paExtents = NULL;
     920            pSub->pAttrHdr          = NULL;
     921            pSub->pNext             = NULL;
     922            RTMemFree(pSub);
     923
     924            pSub = pCurAttr->pSubRecHead;
     925        }
     926
     927        pCurAttr->pCore    = NULL;
     928        pCurAttr->pAttrHdr = NULL;
     929        RTMemFree(pCurAttr->Extents.paExtents);
     930        pCurAttr->Extents.paExtents = NULL;
     931    }
     932
     933    /*
     934     * Release the MFT chain.
     935     */
     936    PRTFSNTFSMFTREC pMftRec = pThis->pMftRec;
     937    while (pMftRec)
     938    {
     939        pThis->pMftRec = pMftRec->pNext;
     940        Assert(pMftRec->pCore == pThis);
     941        pMftRec->pNext = NULL;
     942        pMftRec->pCore = NULL;
     943        rtFsNtfsMftRec_Release(pMftRec, pThis->pVol);
     944
     945        pMftRec = pThis->pMftRec;
     946    }
     947
     948    RTMemFree(pThis);
     949
     950    return 0;
     951}
     952
     953
     954/**
     955 * Releases a refernece to a core structure, maybe destroying it.
     956 *
     957 * @returns New reference count.
     958 * @param   pThis               The core structure.
     959 */
     960static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis)
     961{
     962    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     963    Assert(cRefs < 128);
     964    if (cRefs != 0)
     965        return cRefs;
     966    return rtFsNtfsCore_Destroy(pThis);
     967}
     968
     969
     970/**
     971 * Retains a refernece to a core structure.
     972 *
     973 * @returns New reference count.
     974 * @param   pThis               The core structure.
     975 */
     976static uint32_t rtFsNtfsCore_Retain(PRTFSNTFSCORE pThis)
     977{
     978    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     979    Assert(cRefs < 128);
     980    return cRefs;
     981}
     982
     983
     984/**
     985 * Finds an unnamed attribute.
     986 *
     987 * @returns Pointer to the attribute structure if found, NULL if not.
     988 * @param   pThis               The core object structure to search.
     989 * @param   uAttrType           The attribute type to find.
     990 */
     991static PRTFSNTFSATTR rtFsNtfsCore_FindUnnamedAttribute(PRTFSNTFSCORE pThis, uint32_t uAttrType)
     992{
     993    PRTFSNTFSATTR pCurAttr;
     994    RTListForEach(&pThis->AttribHead, pCurAttr, RTFSNTFSATTR, ListEntry)
     995    {
     996        PNTFSATTRIBHDR pAttrHdr = pCurAttr->pAttrHdr;
     997        if (   pAttrHdr->uAttrType == uAttrType
     998            && pAttrHdr->cwcName == 0)
     999            return pCurAttr;
     1000    }
     1001    return NULL;
     1002}
     1003
     1004
     1005
    5031006/**
    5041007 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
     
    5641067};
    5651068
     1069
     1070
    5661071static int rtFsNtfsVolLoadMft(PRTFSNTFSVOL pThis, void *pvBuf, size_t cbBuf, PRTERRINFO pErrInfo)
    5671072{
     
    5711076     *        rtFsNtfsVol_QueryRangeState. */
    5721077
    573     PRTFSNTFSMFTREC pRec = rtFsNtfsMftRec_New(pThis, 0);
     1078    /*
     1079     * Bootstrap the MFT data stream.
     1080     */
     1081    PRTFSNTFSMFTREC pRec = rtFsNtfsMftVol_New(pThis, 0);
    5741082    AssertReturn(pRec, VERR_NO_MEMORY);
    575     pThis->pMft = pRec;
    576 
    577     int rc = RTVfsFileReadAt(pThis->hVfsBacking, pThis->uLcnMft << pThis->cClusterShift, pRec->pbRec, pThis->cbMftRecord, NULL);
    578     if (RT_FAILURE(rc))
    579         return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading MFT record #0");
     1083
     1084#if 0 //def LOG_ENABLED
     1085    for (uint32_t i = 0; i < 64; i++)
     1086    {
     1087        RTVfsFileReadAt(pThis->hVfsBacking, (pThis->uLcnMft << pThis->cClusterShift) + i * pThis->cbMftRecord,
     1088                        pRec->pbRec, pThis->cbMftRecord, NULL);
     1089        pRec->TreeNode.Key = i;
     1090        Log(("\n"));
     1091        rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);
     1092    }
     1093    pRec->TreeNode.Key = 0;
     1094#endif
     1095
     1096    pRec->offDisk = pThis->uLcnMft << pThis->cClusterShift;
     1097    int rc = RTVfsFileReadAt(pThis->hVfsBacking, pRec->offDisk, pRec->pbRec, pThis->cbMftRecord, NULL);
     1098    if (RT_SUCCESS(rc))
     1099    {
    5801100#ifdef LOG_ENABLED
    581     rtfsNtfsMftRec_Log(pRec);
     1101        rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord);
    5821102#endif
    583 
    584     //Log(("MFT#0:\n%.*Rhxd\n", pThis->cbMftRecord, pRec->pbRec));
    585 
    586     return VINF_SUCCESS;
     1103        rc = rtFsNtfsVol_ParseMft(pThis, pRec, pErrInfo);
     1104        if (RT_SUCCESS(rc))
     1105        {
     1106            pThis->pMftData = rtFsNtfsCore_FindUnnamedAttribute(pRec->pCore, NTFS_AT_DATA);
     1107            if (pThis->pMftData)
     1108            {
     1109                /** @todo sanity check the attribute. */
     1110                rtFsNtfsMftRec_Release(pRec, pThis);
     1111                return rc;
     1112            }
     1113            rc = RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed DATA attribute!");
     1114        }
     1115        if (pRec->pCore)
     1116            rtFsNtfsCore_Release(pRec->pCore);
     1117        rtFsNtfsMftRec_Release(pRec, pThis);
     1118    }
     1119    else
     1120        rc = RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading MFT record #0");
     1121    return rc;
    5871122}
    5881123
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