Changeset 69873 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Nov 29, 2017 10:38:53 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp
r69868 r69873 45 45 46 46 /********************************************************************************************************************************* 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 /********************************************************************************************************************************* 47 55 * Structures and Typedefs * 48 56 *********************************************************************************************************************************/ … … 51 59 /** Pointer to a NTFS MFT record. */ 52 60 typedef struct RTFSNTFSMFTREC *PRTFSNTFSMFTREC; 61 /** Poitner to a NTFS core object record. */ 62 typedef struct RTFSNTFSCORE *PRTFSNTFSCORE; 63 64 65 /** 66 * NTFS disk allocation extent (internal representation). 67 */ 68 typedef 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. */ 77 typedef RTFSNTFSEXTENT *PRTFSNTFSEXTENT; 78 /** Pointer to a const NTFS 9660 extent. */ 79 typedef RTFSNTFSEXTENT const *PCRTFSNTFSEXTENT; 80 81 /** 82 * An array of zero or more extents. 83 */ 84 typedef 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. */ 94 typedef RTFSNTFSEXTENTS *PRTFSNTFSEXTENTS; 95 /** Pointer to a const extent array. */ 96 typedef RTFSNTFSEXTENTS const *PCRTFSNTFSEXTENTS; 97 53 98 54 99 /** 55 100 * NTFS MFT record. 101 * 102 * These are kept in a tree to , so 56 103 */ 57 104 typedef struct RTFSNTFSMFTREC 58 105 { 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. */ 62 109 PRTFSNTFSMFTREC pNext; 63 /** Pointer back to the volume. */64 PRTFSNTFSVOL pVol;65 /** The disk offset of this MFT entry. */66 uint64_t offDisk;67 110 union 68 111 { 69 /** Generic pointer. */112 /** Generic record pointer. RTFSNTFSVOL::cbMftRecord in size. */ 70 113 uint8_t *pbRec; 71 114 /** Pointer to the file record. */ 72 115 PNTFSRECFILE pFileRec; 73 116 } 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; 75 120 /** Reference counter. */ 76 121 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; 79 126 } RTFSNTFSMFTREC; 127 128 129 /** Pointer to a attribute subrecord structure. */ 130 typedef 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 */ 138 typedef 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 */ 152 typedef 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. */ 167 typedef RTFSNTFSATTR *PRTFSNTFSATTR; 168 169 170 /** 171 * NTFS file system object, shared part. 172 */ 173 typedef 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 80 186 81 187 /** … … 123 229 uint64_t uSerialNo; 124 230 125 /** Pointer to the MFT record for the MFT. */126 PRTFSNTFS MFTREC pMft;231 /** The MFT data attribute. */ 232 PRTFSNTFSATTR pMftData; 127 233 128 234 /** Root of the MFT record tree (RTFSNTFSMFTREC). */ … … 131 237 132 238 133 static PRTFSNTFSMFTREC rtFsNtfsMft Rec_New(PRTFSNTFSVOL pVol, uint64_t idMft)239 static PRTFSNTFSMFTREC rtFsNtfsMftVol_New(PRTFSNTFSVOL pVol, uint64_t idMft) 134 240 { 135 241 PRTFSNTFSMFTREC pRec = (PRTFSNTFSMFTREC)RTMemAllocZ(sizeof(*pRec)); … … 139 245 if (pRec->pbRec) 140 246 { 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); 147 254 } 148 255 } … … 151 258 152 259 153 #if 0 /* currently unused */ 154 static uint32_t rtFsNtfsMftRec_Destroy(PRTFSNTFSMFTREC pThis) 260 static uint32_t rtFsNtfsMftRec_Destroy(PRTFSNTFSMFTREC pThis, PRTFSNTFSVOL pVol) 155 261 { 156 262 RTMemFree(pThis->pbRec); 157 263 pThis->pbRec = NULL; 158 264 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 163 268 RTMemFree(pThis); 164 269 … … 174 279 } 175 280 176 177 static uint32_t rtFsNtfsMftRec_Release(PRTFSNTFSMFTREC pThis) 281 static uint32_t rtFsNtfsMftRec_Release(PRTFSNTFSMFTREC pThis, PRTFSNTFSVOL pVol) 178 282 { 179 283 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); … … 181 285 if (cRefs != 0) 182 286 return cRefs; 183 return rtFsNtfsMftRec_Destroy(pThis); 184 } 185 #endif 287 return rtFsNtfsMftRec_Destroy(pThis, pVol); 288 } 186 289 187 290 … … 190 293 * Logs the MFT record 191 294 * 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 */ 298 static void rtfsNtfsMftRec_Log(PRTFSNTFSMFTREC pRec, uint32_t cbMftRecord) 195 299 { 196 300 if (LogIs2Enabled()) 197 301 { 198 302 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)); 200 304 if (pFileRec->Hdr.uMagic == NTFSREC_MAGIC_FILE) 201 305 { 202 size_t const cbRec = pRec->pVol->cbMftRecord;306 size_t const cbRec = cbMftRecord; 203 307 uint8_t const * const pbRec = pRec->pbRec; 204 308 … … 316 420 } 317 421 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 } 319 449 320 450 case NTFS_AT_FILENAME: … … 442 572 if (cbNum) 443 573 { 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--; 446 576 while (cbNum-- > 1) 447 577 cClustersInRun = (cClustersInRun << 8) + *pbNum--; … … 454 584 if (cbNum) 455 585 { 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--; 458 588 while (cbNum-- > 1) 459 589 cLcnDelta = (cLcnDelta << 8) + *pbNum--; … … 501 631 502 632 633 static 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 806 static 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 */ 905 static 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 */ 960 static 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 */ 976 static 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 */ 991 static 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 503 1006 /** 504 1007 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose} … … 564 1067 }; 565 1068 1069 1070 566 1071 static int rtFsNtfsVolLoadMft(PRTFSNTFSVOL pThis, void *pvBuf, size_t cbBuf, PRTERRINFO pErrInfo) 567 1072 { … … 571 1076 * rtFsNtfsVol_QueryRangeState. */ 572 1077 573 PRTFSNTFSMFTREC pRec = rtFsNtfsMftRec_New(pThis, 0); 1078 /* 1079 * Bootstrap the MFT data stream. 1080 */ 1081 PRTFSNTFSMFTREC pRec = rtFsNtfsMftVol_New(pThis, 0); 574 1082 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 { 580 1100 #ifdef LOG_ENABLED 581 rtfsNtfsMftRec_Log(pRec);1101 rtfsNtfsMftRec_Log(pRec, pThis->cbMftRecord); 582 1102 #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; 587 1122 } 588 1123
Note:
See TracChangeset
for help on using the changeset viewer.