VirtualBox

Changeset 69902 in vbox


Ignore:
Timestamp:
Dec 1, 2017 5:58:28 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119378
Message:

IPRT/ntfsvfs.h: Working on reading the root dir. Did some cleanups.

Location:
trunk
Files:
2 edited

Legend:

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

    r69885 r69902  
    202202#define NTFS_AT_SECURITY_DESCRIPTOR         RT_H2LE_U32_C(UINT32_C(0x00000050))
    203203#define NTFS_AT_VOLUME_NAME                 RT_H2LE_U32_C(UINT32_C(0x00000060))
     204/** NTFSATVOLUMEINFO */
    204205#define NTFS_AT_VOLUME_INFORMATION          RT_H2LE_U32_C(UINT32_C(0x00000070))
    205206#define NTFS_AT_DATA                        RT_H2LE_U32_C(UINT32_C(0x00000080))
     207/** NTFSATINDEXROOT */
    206208#define NTFS_AT_INDEX_ROOT                  RT_H2LE_U32_C(UINT32_C(0x00000090))
    207209#define NTFS_AT_INDEX_ALLOCATION            RT_H2LE_U32_C(UINT32_C(0x000000a0))
     
    218220/** @name NTFS_AF_XXX - Attribute flags.
    219221 * @{ */
    220 #define NTFS_AF_COMPR_FMT_NONE              UINT16_C(0x0000)
    221 #define NTFS_AF_COMPR_FMT_LZNT1             UINT16_C(0x0001)    /**< See RtlCompressBuffer / COMPRESSION_FORMAT_LZNT1. */
    222 #define NTFS_AF_COMPR_FMT_XPRESS            UINT16_C(0x0002)    /**< See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */
    223 #define NTFS_AF_COMPR_FMT_XPRESS_HUFF       UINT16_C(0x0003)    /**< See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */
    224 #define NTFS_AF_COMPR_FMT_MASK              UINT16_C(0x00ff)
    225 #define NTFS_AF_ENCRYPTED                   UINT16_C(0x4000)
    226 #define NTFS_AF_SPARSE                      UINT16_C(0x8000)
     222#define NTFS_AF_COMPR_FMT_NONE              RT_H2LE_U16_C(UINT16_C(0x0000))
     223/** See RtlCompressBuffer / COMPRESSION_FORMAT_LZNT1. */
     224#define NTFS_AF_COMPR_FMT_LZNT1             RT_H2LE_U16_C(UINT16_C(0x0001))
     225/** See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */
     226#define NTFS_AF_COMPR_FMT_XPRESS            RT_H2LE_U16_C(UINT16_C(0x0002))
     227/** See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */
     228#define NTFS_AF_COMPR_FMT_XPRESS_HUFF       RT_H2LE_U16_C(UINT16_C(0x0003))
     229#define NTFS_AF_COMPR_FMT_MASK              RT_H2LE_U16_C(UINT16_C(0x00ff))
     230#define NTFS_AF_ENCRYPTED                   RT_H2LE_U16_C(UINT16_C(0x4000))
     231#define NTFS_AF_SPARSE                      RT_H2LE_U16_C(UINT16_C(0x8000))
    227232/** @} */
    228233
     
    294299             * @note Only set in the first attribute record (iVcnFirst == 0). */
    295300            int64_t         cbData;
    296             /** 0x38: The length of the initialized data (rounded to cluster).
     301            /** 0x38: The length of the initialized data.  (Not necessarily
     302             *  rounded up to cluster size.)
    297303             * @note Only set in the first attribute record (iVcnFirst == 0). */
    298304            int64_t         cbInitialized;
     
    322328/** @} */
    323329
     330/** Get the pointer to the embedded name from an attribute.
     331 * @note  ASSUMES the caller check that there is a name.   */
     332#define NTFSATTRIBHDR_GET_NAME(a_pAttrHdr)          ( (PRTUTF16)((uintptr_t)(a_pAttrHdr) + (a_pAttrHdr)->offName) )
     333
     334
     335/** @name NTFS_RES_AF_XXX
     336 *  @{ */
     337/** Attribute is referenced in an index. */
     338#define NTFS_RES_AF_INDEXED                         UINT8_C(0x01)
     339/** @} */
    324340
    325341/**
     
    487503/** @} */
    488504
     505
     506/**
     507 * NTFS volume information (NTFS_AT_VOLUME_INFORMATION).
     508 *
     509 * This is found in the special NTFS_MFT_IDX_VOLUME file.
     510 */
     511typedef struct NTFSATVOLUMEINFO
     512{
     513    /** 0x00: Reserved bytes. */
     514    uint8_t         abReserved[8];
     515    /** 0x08: Major NTFS version number.   */
     516    uint8_t         uMajorVersion;
     517    /** 0x09: Minor NTFS version number.   */
     518    uint8_t         uMinorVersion;
     519    /** 0x0a: Volume flags (NTFS_VOLUME_F_XXX)  */
     520    uint16_t        fFlags;
     521} NTFSATVOLUMEINFO;
     522AssertCompileSize(NTFSATVOLUMEINFO, 12);
     523/** Pointer to NTFS volume information. */
     524typedef NTFSATVOLUMEINFO *PNTFSATVOLUMEINFO;
     525/** Pointer to const NTFS volume information. */
     526typedef NTFSATVOLUMEINFO const *PCNTFSATVOLUMEINFO;
     527
     528/** @name NTFS_VOLUME_F_XXX
     529 *  @{ */
     530#define NTFS_VOLUME_F_DIRTY                 RT_H2LE_U16_C(0x0001) /**< Volume is dirty. */
     531#define NTFS_VOLUME_F_RESIZE_LOG_FILE       RT_H2LE_U16_C(0x0002) /**< */
     532#define NTFS_VOLUME_F_UPGRADE_ON_MOUNT      RT_H2LE_U16_C(0x0004) /**< */
     533#define NTFS_VOLUME_F_MOUNTED_ON_NT4        RT_H2LE_U16_C(0x0008) /**< */
     534#define NTFS_VOLUME_F_DELETE_USN_UNDERWAY   RT_H2LE_U16_C(0x0010) /**< */
     535#define NTFS_VOLUME_F_REPAIR_OBJECT_ID      RT_H2LE_U16_C(0x0020) /**< */
     536#define NTFS_VOLUME_F_CHKDSK_UNDERWAY       RT_H2LE_U16_C(0x4000) /**< */
     537#define NTFS_VOLUME_F_MODIFIED_BY_CHKDSK    RT_H2LE_U16_C(0x8000) /**< */
     538
     539#define NTFS_VOLUME_F_KNOWN_MASK            RT_H2LE_U16_C(0xc03f)
     540#define NTFS_VOLUME_F_MOUNT_READONLY_MASK   RT_H2LE_U16_C(0xc027)
     541/** @} */
     542
     543
     544/** The attribute name used by the index attributes on NTFS directories,
     545 *  ASCII stirng variant. */
     546#define NTFS_DIR_ATTRIBUTE_NAME             "$I30"
     547
     548/**
     549 * NTFS index header.
     550 *
     551 * This is used by NTFSATINDEXROOT and NTFSATINDEXALLOC.
     552 */
     553typedef struct NTFSINDEXHEADER
     554{
     555    /** 0x00: Offset of the first entry relative to this header. */
     556    uint32_t        offFirstEntry;
     557    /** 0x04: Size of the index in bytes, including this header.  */
     558    uint32_t        cbIndex;
     559    /** 0x08: Number of bytes allocated for the index (including this header). */
     560    uint32_t        cbAllocated;
     561    /** 0x0c: Flags (NTFSINDEXHEADER_F_XXX).   */
     562    uint8_t         fFlags;
     563    /** 0x0d: Reserved bytes. */
     564    uint8_t         abReserved[3];
     565} NTFSINDEXHEADER;
     566AssertCompileSize(NTFSINDEXHEADER, 16);
     567/** Pointer to a NTFS index header. */
     568typedef NTFSINDEXHEADER *PNTFSINDEXHEADER;
     569/** Pointer to a const NTFS index header. */
     570typedef NTFSINDEXHEADER const *PCNTFSINDEXHEADER;
     571
     572/** Index root only: Small enough to fit inside the index root attrib.  */
     573#define NTFSINDEXHEADER_F_ROOT_SMALL        UINT8_C(0x00)
     574/** Index root only: Too large to fit inside the index root attrib and/or an
     575 *  index allocation attribute is present. */
     576#define NTFSINDEXHEADER_F_ROOT_LARGE        UINT8_C(0x01)
     577
     578
     579/**
     580 * NTFS index root (NTFS_AT_INDEX_ROOT).
     581 *
     582 * This is a generic index structure, but is most prominently used for
     583 * implementating directories.
     584 */
     585typedef struct NTFSATINDEXROOT
     586{
     587    /** 0x00: The index type (NTFSATINDEXROOT_TYPE_XXX). */
     588    uint32_t        uType;
     589    /** 0x04: The sorting rules to use (NTFS_COLLATION_XXX). */
     590    uint32_t        uCollationRules;
     591    /** 0x08: Index buffer size (in bytes). */
     592    uint32_t        cbIndexBuffer;
     593    /** 0x0c: Number of clusters allocated for each index buffer if
     594     * cbIndexBuffer is larger than a cluster, otherwise log2(cbIndexBuffer)?  */
     595    uint8_t         cClustersPerBuffer;
     596    /** 0x0d: Reserved padding or something. */
     597    uint8_t         abReserved[3];
     598    /** 0x10: Index header detailing the entries that follows. */
     599    NTFSINDEXHEADER Hdr;
     600    /* NTFSINDEXENTRYHDR array typically follows */
     601} NTFSATINDEXROOT;
     602AssertCompileSize(NTFSATINDEXROOT, 32);
     603/** Pointer to a NTFS index root. */
     604typedef NTFSATINDEXROOT *PNTFSATINDEXROOT;
     605/** Pointer to a const NTFS index root. */
     606typedef NTFSATINDEXROOT const *PCNTFSATINDEXROOT;
     607
     608/** @name NTFSATINDEXROOT_TYPE_XXX
     609 * @{ */
     610/** View index. */
     611#define NTFSATINDEXROOT_TYPE_VIEW           RT_H2LE_U32_C(UINT32_C(0x00000000))
     612/** Directory index, NTFSATFILENAME follows NTFSINDEXENTRY. */
     613#define NTFSATINDEXROOT_TYPE_DIRECTORY      RT_H2LE_U32_C(UINT32_C(0x00000030))
     614/** @} */
     615
     616/** @name NTFS_COLLATION_XXX - index sorting rules
     617 * @{ */
     618/** Little endian binary compare (or plain byte compare if you like). */
     619#define NTFS_COLLATION_BINARY               RT_H2LE_U32_C(UINT32_C(0x00000000))
     620/** Same as NTFS_COLLATION_UNICODE_STRING. */
     621#define NTFS_COLLATION_FILENAME             RT_H2LE_U32_C(UINT32_C(0x00000001))
     622/** Compare the uppercased unicode characters. */
     623#define NTFS_COLLATION_UNICODE_STRING       RT_H2LE_U32_C(UINT32_C(0x00000002))
     624
     625/** Single little endian 32-bit unsigned integer value as sort key. */
     626#define NTFS_COLLATION_UINT32               RT_H2LE_U32_C(UINT32_C(0x00000010))
     627/** Little endian SID value as sort key. */
     628#define NTFS_COLLATION_SID                  RT_H2LE_U32_C(UINT32_C(0x00000011))
     629/** Two little endian 32-bit unsigned integer values used as sorting key. */
     630#define NTFS_COLLATION_UINT32_PAIR          RT_H2LE_U32_C(UINT32_C(0x00000012))
     631/** Sequence of little endian 32-bit unsigned integer values used as sorting key. */
     632#define NTFS_COLLATION_UINT32_SEQ           RT_H2LE_U32_C(UINT32_C(0x00000013))
     633
     634/** @} */
     635
     636
     637/**
     638 * NTFS index entry header.
     639 */
     640typedef struct NTFSINDEXENTRYHDR
     641{
     642    union
     643    {
     644        /** 0x00: Non-View: Reference to the MFT record being indexed here.
     645         * This is invalid if NTFSINDEX_EF_LAST is set.  */
     646        NTFSMFTREF      FileMftRec;
     647        /** 0x00: View   */
     648        struct
     649        {
     650            /** 0x00: Offset to the data relative to this header. */
     651            uint16_t    offData;
     652            /** 0x02: Size of data at offData. */
     653            uint16_t    cbData;
     654            /** 0x04: Reserved.   */
     655            uint32_t    uReserved;
     656        } View;
     657    } u;
     658
     659    /** 0x08: Size of this entry, 8-byte aligned. */
     660    uint16_t        cbEntry;
     661    /** 0x0a: Key length (unaligned). */
     662    uint16_t        cbKey;
     663    /** 0x0c: Entry flags, NTFSINDEX_EF_XXX. */
     664    uint16_t        fFlags;
     665    /** 0x0d: Entry flags, NTFSINDEX_EF_XXX. */
     666    uint16_t        uReserved;
     667} NTFSINDEXENTRYHDR;
     668AssertCompileSize(NTFSINDEXENTRYHDR, 16);
     669/** Pointer to a NTFS index entry header. */
     670typedef NTFSINDEXENTRYHDR *PNTFSINDEXENTRYHDR;
     671/** Pointer to a const NTFS index entry header. */
     672typedef NTFSINDEXENTRYHDR const *PCNTFSINDEXENTRYHDR;
     673
     674/** @name  NTFSINDEX_EF_XXX - NTFSINDEXENTRYHDR::fFlags
     675 * @{ */
     676/** Indicates an internal node, as opposed to a leaf node. */
     677#define NTFSINDEX_EF_NODE           RT_H2LE_U16_C(UINT16_C(0x0001))
     678/** Last entry in a block, may point to the next node. */
     679#define NTFSINDEX_EF_LAST           RT_H2LE_U16_C(UINT16_C(0x0002))
     680/** @}  */
     681
    489682/** @} */
    490683
  • trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp

    r69889 r69902  
    5050/** The maximum bitmap cache size. */
    5151#define RTFSNTFS_MAX_BITMAP_CACHE           _64K
     52
     53/** Makes a combined NTFS version value.
     54 * @see RTFSNTFSVOL::uNtfsVersion  */
     55#define RTFSNTFS_MAKE_VERSION(a_uMajor, a_uMinor)   RT_MAKE_U16(a_uMinor, a_uMajor)
    5256
    5357
     
    160164     * This is needed to validate header relative offsets. */
    161165    uint32_t            offAttrHdrInMftRec;
     166    /** Number of resident bytes available (can be smaller than cbValue).
     167     *  Set to zero for non-resident attributes. */
     168    uint32_t            cbResident;
     169    /** The (uncompressed) attribute size.  */
     170    uint64_t            cbValue;
    162171    /** Disk space allocation if non-resident. */
    163172    RTFSNTFSEXTENTS     Extents;
     
    185194} RTFSNTFSCORE;
    186195
     196/**
     197 * Pointer to a shared NTFS directory object.
     198 */
     199typedef struct RTFSNTFSDIRSHRD
     200{
     201    /** Reference counter.   */
     202    uint32_t volatile   cRefs;
     203
     204    /** Pointer to the core object for the directory (referenced). */
     205    PRTFSNTFSCORE       pCore;
     206    /** Pointer to the index root attribute. */
     207    PRTFSNTFSATTR       pIndexRoot;
     208
     209    /** Pointer to the index allocation attribute, if present.
     210     * This and the bitmap may be absent if the whole directory fits into the
     211     * root index. */
     212    PRTFSNTFSATTR       pIndexAlloc;
     213    /** Pointer to the index allocation bitmap attribute, if present. */
     214    PRTFSNTFSATTR       pIndexBitmap;
     215
     216} RTFSNTFSDIRSHRD;
     217/** Pointer to a shared NTFS directory object. */
     218typedef RTFSNTFSDIRSHRD *PRTFSNTFSDIRSHRD;
     219
    187220
    188221/**
     
    207240    uint32_t        fNtfsFlags;
    208241
     242    /** The (logical) sector size. */
     243    uint32_t        cbSector;
     244
    209245    /** The (logical) cluster size. */
    210246    uint32_t        cbCluster;
    211     /** The (logical) sector size. */
    212     uint32_t        cbSector;
    213 
     247    /** Max cluster count value that won't overflow a signed 64-bit when
     248     * converted to bytes.  Inclusive. */
     249    uint64_t        iMaxVirtualCluster;
    214250    /** The shift count for converting between bytes and clusters. */
    215251    uint8_t         cClusterShift;
     252
    216253    /** Explicit padding. */
    217     uint8_t         abReserved[7];
     254    uint8_t         abReserved[3];
     255    /** The NTFS version of the volume (RTFSNTFS_MAKE_VERSION). */
     256    uint16_t        uNtfsVersion;
     257    /** The NTFS_VOLUME_F_XXX. */
     258    uint16_t        fVolumeFlags;
    218259
    219260    /** The logical cluster number of the MFT. */
     
    233274    PRTFSNTFSATTR   pMftData;
    234275
     276    /** The root directory. */
     277    PRTFSNTFSDIRSHRD pRootDir;
    235278
    236279    /** @name Allocation bitmap and cache.
     
    254297    /** Root of the MFT record tree (RTFSNTFSMFTREC). */
    255298    AVLU64TREE      MftRoot;
     299
    256300} RTFSNTFSVOL;
    257301
     
    915959    {
    916960        PNTFSATTRIBHDR  pAttrHdr  = (PNTFSATTRIBHDR)&pbRec[offRec];
     961
     962        /*
     963         * Validate the attribute data.
     964         */
    917965        uint32_t const  cbAttrib  = RT_LE2H_U32(pAttrHdr->cbAttrib);
    918966        uint32_t const  cbMin     = !pAttrHdr->fNonResident                  ? NTFSATTRIBHDR_SIZE_RESIDENT
     
    927975                                           "Bad MFT record %#RX64: Attribute (@%#x) is too long (%#x, cbRecUsed=%#x)",
    928976                                           pRec->TreeNode.Key, offRec, cbAttrib, cbRecUsed);
     977        if (cbAttrib & 0x7)
     978            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     979                                           "Bad MFT record %#RX64: Attribute (@%#x) size is misaligned: %#x",
     980                                           pRec->TreeNode.Key, offRec, cbAttrib);
     981        if (pAttrHdr->fNonResident)
     982        {
     983            int64_t const iVcnFirst = RT_LE2H_U64(pAttrHdr->u.NonRes.iVcnFirst);
     984            int64_t const iVcnLast  = RT_LE2H_U64(pAttrHdr->u.NonRes.iVcnLast);
     985            if (iVcnFirst > iVcnLast)
     986                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     987                                               "Bad MFT record %#RX64: Attribute (@%#x): iVcnFirst (%#RX64) is higher than iVcnLast (%#RX64)",
     988                                               pRec->TreeNode.Key, offRec, iVcnFirst, iVcnLast);
     989            if (iVcnFirst < 0)
     990                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     991                                               "Bad MFT record %#RX64: Attribute (@%#x): iVcnFirst (%#RX64) is negative",
     992                                               pRec->TreeNode.Key, offRec, iVcnFirst);
     993            if ((uint64_t)iVcnLast > pThis->iMaxVirtualCluster)
     994                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     995                                               "Bad MFT record %#RX64: Attribute (@%#x): iVcnLast (%#RX64) is too high, max %RX64 (shift %#x)",
     996                                               pRec->TreeNode.Key, offRec, iVcnLast, pThis->cClusterShift, pThis->iMaxVirtualCluster);
     997            uint16_t const offMappingPairs = RT_LE2H_U16(pAttrHdr->u.NonRes.offMappingPairs);
     998            if (   (offMappingPairs != 0 && offMappingPairs < cbMin)
     999                || offMappingPairs > cbAttrib)
     1000                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1001                                               "Bad MFT record %#RX64: Attribute (@%#x): offMappingPairs (%#x) is out of bounds (cbAttrib=%#x, cbMin=%#x)",
     1002                                               pRec->TreeNode.Key, offRec, offMappingPairs, cbAttrib, cbMin);
     1003            if (pAttrHdr->u.NonRes.uCompressionUnit > 16)
     1004                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1005                                               "Bad MFT record %#RX64: Attribute (@%#x): uCompressionUnit (%#x) is too high",
     1006                                               pRec->TreeNode.Key, offRec, pAttrHdr->u.NonRes.uCompressionUnit);
     1007
     1008            int64_t const cbAllocated = RT_LE2H_U64(pAttrHdr->u.NonRes.cbAllocated);
     1009            if (cbAllocated < 0)
     1010                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1011                                               "Bad MFT record %#RX64: Attribute (@%#x): cbAllocated (%#RX64) is negative",
     1012                                               pRec->TreeNode.Key, offRec, cbAllocated, pThis->cbCluster);
     1013            if ((uint64_t)cbAllocated & (pThis->cbCluster - 1))
     1014                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1015                                               "Bad MFT record %#RX64: Attribute (@%#x): cbAllocated (%#RX64) isn't cluster aligned (cbCluster=%#x)",
     1016                                               pRec->TreeNode.Key, offRec, cbAllocated, pThis->cbCluster);
     1017
     1018            int64_t const cbData = RT_LE2H_U64(pAttrHdr->u.NonRes.cbData);
     1019            if (cbData < 0)
     1020                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1021                                               "Bad MFT record %#RX64: Attribute (@%#x): cbData (%#RX64) is negative",
     1022                                               pRec->TreeNode.Key, offRec, cbData, pThis->cbCluster);
     1023
     1024            int64_t const cbInitialized = RT_LE2H_U64(pAttrHdr->u.NonRes.cbInitialized);
     1025            if (cbInitialized < 0)
     1026                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1027                                               "Bad MFT record %#RX64: Attribute (@%#x): cbInitialized (%#RX64) is negative",
     1028                                               pRec->TreeNode.Key, offRec, cbInitialized, pThis->cbCluster);
     1029            if (cbMin >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED)
     1030            {
     1031                int64_t const cbCompressed = RT_LE2H_U64(pAttrHdr->u.NonRes.cbCompressed);
     1032                if (cbAllocated < 0)
     1033                    return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1034                                                   "Bad MFT record %#RX64: Attribute (@%#x): cbCompressed (%#RX64) is negative",
     1035                                                   pRec->TreeNode.Key, offRec, cbCompressed, pThis->cbCluster);
     1036            }
     1037        }
     1038        else
     1039        {
     1040            uint16_t const offValue = RT_LE2H_U32(pAttrHdr->u.Res.offValue);
     1041            if (   offValue > cbAttrib
     1042                || offValue < NTFSATTRIBHDR_SIZE_RESIDENT)
     1043                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1044                                               "Bad MFT record %#RX64: Attribute (@%#x): offValue (%#RX16) is out of bounds (cbAttrib=%#RX32, cbValue=%#RX32)",
     1045                                               pRec->TreeNode.Key, offRec, offValue, cbAttrib, RT_LE2H_U32(pAttrHdr->u.Res.cbValue));
     1046            if ((pAttrHdr->fFlags & NTFS_AF_COMPR_FMT_MASK) != NTFS_AF_COMPR_FMT_NONE)
     1047                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1048                                               "Bad MFT record %#RX64: Attribute (@%#x): fFlags (%#RX16) indicate compression of a resident attribute",
     1049                                               pRec->TreeNode.Key, offRec, RT_LE2H_U16(pAttrHdr->fFlags));
     1050        }
     1051
     1052        if (pAttrHdr->cwcName != 0)
     1053        {
     1054            uint16_t offName = RT_LE2H_U16(pAttrHdr->offName);
     1055            if (   offName < cbMin
     1056                || offName >= cbAttrib)
     1057                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1058                                               "Bad MFT record %#RX64: Attribute (@%#x): offName (%#RX16) is out of bounds (cbAttrib=%#RX32, cbMin=%#RX32)",
     1059                                               pRec->TreeNode.Key, offRec, offName, cbAttrib, cbMin);
     1060            if (offName + pAttrHdr->cwcName * sizeof(RTUTF16) > cbAttrib)
     1061                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1062                                               "Bad MFT record %#RX64: Attribute (@%#x): offName (%#RX16) + cwcName (%#x) is out of bounds (cbAttrib=%#RX32)",
     1063                                               pRec->TreeNode.Key, offRec, offName, pAttrHdr->cwcName, cbAttrib);
     1064        }
     1065
     1066        /*
     1067         * Allocate and initialize a new attribute.
     1068         */
    9291069        PRTFSNTFSATTR pAttrib = (PRTFSNTFSATTR)RTMemAllocZ(sizeof(*pAttrib));
    9301070        AssertReturn(pAttrib, VERR_NO_MEMORY);
     
    9321072        pAttrib->offAttrHdrInMftRec = offRec;
    9331073        pAttrib->pCore              = pCore;
     1074        //pAttrib->cbResident         = 0;
     1075        //pAttrib->cbValue            = 0;
    9341076        //pAttrib->Extents.cExtents   = 0;
    9351077        //pAttrib->Extents.paExtents  = NULL;
     
    9371079        if (pAttrHdr->fNonResident)
    9381080        {
     1081            pAttrib->cbValue        = RT_LE2H_U64(pAttrHdr->u.NonRes.cbData);
    9391082            int rc = rtFsNtfsAttr_ParseExtents(pAttrib, &pAttrib->Extents, pThis->cClusterShift, 0 /*iVncFirst*/,
    9401083                                               pThis->cbVolume, pErrInfo, pRec->TreeNode.Key, offRec);
     
    9451088            }
    9461089        }
     1090        else
     1091        {
     1092            pAttrib->cbValue        = RT_LE2H_U32(pAttrHdr->u.Res.cbValue);
     1093            if (   (uint32_t)pAttrib->cbValue > 0
     1094                && RT_LE2H_U16(pAttrHdr->u.Res.offValue) < cbAttrib)
     1095            {
     1096                pAttrib->cbResident = cbAttrib - RT_LE2H_U16(pAttrHdr->u.Res.offValue);
     1097                if (pAttrib->cbResident > (uint32_t)pAttrib->cbValue)
     1098                    pAttrib->cbResident = (uint32_t)pAttrib->cbValue;
     1099            }
     1100        }
     1101
    9471102        RTListAppend(&pCore->AttribHead, &pAttrib->ListEntry);
    9481103
     
    12801435
    12811436/**
     1437 * Finds a named attribute, case insensitive ASCII variant.
     1438 *
     1439 * @returns Pointer to the attribute structure if found, NULL if not.
     1440 * @param   pThis               The core object structure to search.
     1441 * @param   uAttrType           The attribute type to find.
     1442 * @param   pszAttrib           The attribute name, predefined 7-bit ASCII name.
     1443 * @param   cchAttrib           The length of the attribute.
     1444 */
     1445static PRTFSNTFSATTR rtFsNtfsCore_FindNamedAttributeAscii(PRTFSNTFSCORE pThis, uint32_t uAttrType,
     1446                                                          const char *pszAttrib, size_t cchAttrib)
     1447{
     1448    Assert(cchAttrib > 0);
     1449    PRTFSNTFSATTR pCurAttr;
     1450    RTListForEach(&pThis->AttribHead, pCurAttr, RTFSNTFSATTR, ListEntry)
     1451    {
     1452        PNTFSATTRIBHDR pAttrHdr = pCurAttr->pAttrHdr;
     1453        if (   pAttrHdr->uAttrType == uAttrType
     1454            && pAttrHdr->cwcName == cchAttrib
     1455            && RTUtf16NICmpAscii(NTFSATTRIBHDR_GET_NAME(pAttrHdr), pszAttrib, cchAttrib) == 0)
     1456            return pCurAttr;
     1457    }
     1458    return NULL;
     1459}
     1460
     1461
     1462
     1463/*
     1464 *
     1465 * NTFS directory code.
     1466 * NTFS directory code.
     1467 * NTFS directory code.
     1468 *
     1469 */
     1470
     1471
     1472static int rtFsNtfsVol_NewSharedDirFromCore(PRTFSNTFSVOL pThis, PRTFSNTFSCORE pCore, PRTFSNTFSDIRSHRD *ppSharedDir,
     1473                                            PRTERRINFO pErrInfo, const char *pszWhat)
     1474{
     1475    *ppSharedDir = NULL;
     1476
     1477    /*
     1478     * Look for the index root and do some quick checks of it first.
     1479     */
     1480    PRTFSNTFSATTR pRootAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
     1481                                                                      NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ROOT);
     1482    if (!pRootAttr)
     1483        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: Found no INDEX_ROOT attribute named $I30", pszWhat);
     1484    if (pRootAttr->pAttrHdr->fNonResident)
     1485        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: INDEX_ROOT is is not resident", pszWhat);
     1486
     1487
     1488#if 1 /* later */
     1489    NOREF(pThis);
     1490#else
     1491    /*
     1492     *
     1493     */
     1494    PRTFSNTFSATTR pAllocAttr  = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
     1495                                                                      NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ALLOCATION);
     1496    PRTFSNTFSATTR pBitmapAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
     1497                                                                      NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_BITMAP);
     1498#endif
     1499    return VINF_SUCCESS;
     1500}
     1501
     1502
     1503/*
     1504 *
     1505 * Volume level code.
     1506 * Volume level code.
     1507 * Volume level code.
     1508 *
     1509 */
     1510
     1511
     1512/**
    12821513 * Slow path for querying the allocation state of a cluster.
    12831514 *
     
    15381769
    15391770/**
     1771 * Loads, validates and setups the '.' (NTFS_MFT_IDX_ROOT) MFT entry.
     1772 *
     1773 * @returns IPRT status code
     1774 * @param   pThis               The NTFS volume instance.  Will set pawcUpcase.
     1775 * @param   pErrInfo            Where to return additional error info.
     1776 */
     1777static int rtFsNtfsVolLoadRootDir(PRTFSNTFSVOL pThis, PRTERRINFO pErrInfo)
     1778{
     1779    /*
     1780     * Load it and do some checks.
     1781     */
     1782    PRTFSNTFSCORE pCore;
     1783    int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_ROOT, &pCore, pErrInfo);
     1784    if (RT_SUCCESS(rc))
     1785    {
     1786        PRTFSNTFSATTR pFilenameAttr = rtFsNtfsCore_FindUnnamedAttribute(pCore, NTFS_AT_FILENAME);
     1787        if (!pFilenameAttr)
     1788            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir: has no FILENAME attribute!");
     1789        else if (pFilenameAttr->pAttrHdr->fNonResident)
     1790            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir:  FILENAME attribute is non-resident!");
     1791        else if (pFilenameAttr->pAttrHdr->u.Res.cbValue < RT_UOFFSETOF(NTFSATFILENAME, wszFilename[1]))
     1792            rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1793                                         "RootDir:  FILENAME attribute value size is too small: %#x",
     1794                                         pFilenameAttr->pAttrHdr->u.Res.cbValue);
     1795        else
     1796        {
     1797            PNTFSATFILENAME pFilename = (PNTFSATFILENAME)(  (uint8_t *)pFilenameAttr->pAttrHdr
     1798                                                          + pFilenameAttr->pAttrHdr->u.Res.offValue);
     1799            if (   pFilename->cwcFilename != 1
     1800                || (   RTUtf16NICmpAscii(pFilename->wszFilename, ".", 1) != 0
     1801                    && RTUtf16NICmpAscii(pFilename->wszFilename, "$", 1) != 0))
     1802                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     1803                                             "RootDir: FILENAME is not '.' nor '$: '%.*ls'",
     1804                                             pFilename->cwcFilename, pFilename->wszFilename);
     1805            else
     1806            {
     1807                PRTFSNTFSATTR pIndexRoot   = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
     1808                                                                                  NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ROOT);
     1809                PRTFSNTFSATTR pIndexAlloc  = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
     1810                                                                                  NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_INDEX_ALLOCATION);
     1811                PRTFSNTFSATTR pIndexBitmap = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_FILENAME,
     1812                                                                                  NTFS_DIR_ATTRIBUTE_NAME, NTFS_AT_BITMAP);
     1813                if (!pIndexRoot)
     1814                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir: Found no INDEX_ROOT attribute named $I30");
     1815                else if (!pIndexAlloc && pIndexBitmap)
     1816                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir: Found no INDEX_ALLOCATION attribute named $I30");
     1817                else if (!pIndexBitmap && pIndexAlloc)
     1818                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "RootDir: Found no BITMAP attribute named $I30");
     1819                if (RT_SUCCESS(rc) && pIndexAlloc)
     1820                    rc = rtFsNtfsVolCheckBitmap(pThis, pIndexAlloc, "RootDir", pErrInfo);
     1821                if (RT_SUCCESS(rc) && pIndexBitmap)
     1822                    rc = rtFsNtfsVolCheckBitmap(pThis, pIndexBitmap, "RootDir/bitmap", pErrInfo);
     1823                if (RT_SUCCESS(rc))
     1824                {
     1825                    /*
     1826                     * Load it as a normal directory.
     1827                     */
     1828                    PRTFSNTFSDIRSHRD pSharedDir;
     1829                    rc = rtFsNtfsVol_NewSharedDirFromCore(pThis, pCore, &pSharedDir, pErrInfo, "RootDir");
     1830                    if (RT_SUCCESS(rc))
     1831                    {
     1832                        rtFsNtfsCore_Release(pCore);
     1833                        pThis->pRootDir = pSharedDir;
     1834                        return VINF_SUCCESS;
     1835                    }
     1836                }
     1837            }
     1838        }
     1839        rtFsNtfsCore_Release(pCore);
     1840    }
     1841    else
     1842        rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "Root dir: Error reading MFT record");
     1843    return rc;
     1844}
     1845
     1846
     1847/**
    15401848 * Loads, validates and setups the '$UpCase' (NTFS_MFT_IDX_UP_CASE) MFT entry.
    15411849 *
     
    15611869            uint32_t const cbMax = _128K;
    15621870            if (!pDataAttr->pAttrHdr->fNonResident)
    1563                 rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$UpCasea unnamed DATA attribute is resident!");
     1871                rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$UpCase: unnamed DATA attribute is resident!");
    15641872            else if (   (uint64_t)RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbAllocated) < cbMin
    15651873                     || (uint64_t)RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbAllocated) > cbMax)
    15661874                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1567                                              "$UpCase unnamed DATA attribute allocated size is out of range: %#RX64, expected at least %#RX32 and no more than %#RX32",
     1875                                             "$UpCase: unnamed DATA attribute allocated size is out of range: %#RX64, expected at least %#RX32 and no more than %#RX32",
    15681876                                             RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbAllocated), cbMin, cbMax);
    15691877            else if (   (uint64_t)RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbData) < cbMin
     
    15721880                     || ((uint64_t)RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbData) & 1) )
    15731881                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1574                                              "$UpCase unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX32 and no more than %#RX64",
     1882                                             "$UpCase: unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX32 and no more than %#RX64",
    15751883                                             RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbData), cbMin,
    15761884                                             RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbAllocated) );
     
    15801888                     || ((uint64_t)RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbInitialized) & 1) )
    15811889                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1582                                              "$UpCase unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX32 and no more than %#RX64",
     1890                                             "$UpCase: unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX32 and no more than %#RX64",
    15831891                                             RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbInitialized), cbMin,
    15841892                                             RT_LE2H_U64(pDataAttr->pAttrHdr->u.NonRes.cbAllocated) );
    15851893            else if (pDataAttr->pAttrHdr->u.NonRes.uCompressionUnit != 0)
    15861894                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1587                                              "$UpCase unnamed DATA attribute is compressed: %#x",
     1895                                             "$UpCase: unnamed DATA attribute is compressed: %#x",
    15881896                                             pDataAttr->pAttrHdr->u.NonRes.uCompressionUnit);
    15891897            else
     
    15961904                else if (pFilenameAttr->pAttrHdr->u.Res.cbValue < RT_UOFFSETOF(NTFSATFILENAME, wszFilename[7]))
    15971905                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1598                                                  "$UpCase FILENAME attribute value size is too small: %#x",
     1906                                                 "$UpCase: FILENAME attribute value size is too small: %#x",
    15991907                                                 pFilenameAttr->pAttrHdr->u.Res.cbValue);
    16001908                else
     
    16051913                        || RTUtf16NICmpAscii(pFilename->wszFilename, "$UpCase", 7) != 0)
    16061914                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1607                                                      "$UpCase FILENAME isn't '$UpCase': '%.*ls'",
     1915                                                     "$UpCase: FILENAME isn't '$UpCase': '%.*ls'",
    16081916                                                     pFilename->cwcFilename, pFilename->wszFilename);
    16091917                    else
     
    16511959        }
    16521960        else
    1653             rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed DATA attribute!");
     1961            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$UpCase: has no unnamed DATA attribute!");
    16541962        rtFsNtfsCore_Release(pCore);
    16551963    }
    16561964    else
    1657         rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "Error reading $UpCase MFT record");
     1965        rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "$UpCase: Error reading the MFT record");
    16581966    return rc;
    16591967}
     
    16911999                     || (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) > cbMaxBitmap)
    16922000                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1693                                              "MFT record #6 unnamed DATA attribute allocated size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
     2001                                             "$Bitmap: unnamed DATA attribute allocated size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
    16942002                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated), cbMinBitmap, cbMaxBitmap);
    16952003            else if (   (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData) < cbMinBitmap
     
    16972005                         > (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData))
    16982006                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1699                                              "MFT record #6 unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
     2007                                             "$Bitmap: unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
    17002008                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbData), cbMinBitmap,
    17012009                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) );
     
    17042012                         > (uint64_t)RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated))
    17052013                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1706                                              "MFT record #6 unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
     2014                                             "$Bitmap: unnamed DATA attribute initialized size is out of range: %#RX64, expected at least %#RX64 and no more than %#RX64",
    17072015                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbInitialized), cbMinBitmap,
    17082016                                             RT_LE2H_U64(pMftBitmap->pAttrHdr->u.NonRes.cbAllocated) );
    17092017            else if (pMftBitmap->pAttrHdr->u.NonRes.uCompressionUnit != 0)
    17102018                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1711                                              "MFT record #6 unnamed DATA attribute is compressed: %#x",
     2019                                             "$Bitmap: unnamed DATA attribute is compressed: %#x",
    17122020                                             pMftBitmap->pAttrHdr->u.NonRes.uCompressionUnit);
    17132021            else if (pMftBitmap->Extents.cExtents != 1) /* paranoia for now */
    17142022                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1715                                              "MFT record #6 unnamed DATA attribute is expected to have a single extent: %u extents",
     2023                                             "$Bitmap: unnamed DATA attribute is expected to have a single extent: %u extents",
    17162024                                             pMftBitmap->Extents.cExtents);
    17172025            else if (pMftBitmap->Extents.paExtents[0].off == UINT64_MAX)
     
    17262034                else if (pFilenameAttr->pAttrHdr->u.Res.cbValue < RT_UOFFSETOF(NTFSATFILENAME, wszFilename[7]))
    17272035                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1728                                                  "MFT record #6 FILENAME attribute value size is too small: %#x",
     2036                                                 "$Bitmap FILENAME attribute value size is too small: %#x",
    17292037                                                 pFilenameAttr->pAttrHdr->u.Res.cbValue);
    17302038                else
     
    17352043                        || RTUtf16NICmpAscii(pFilename->wszFilename, "$Bitmap", 7) != 0)
    17362044                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    1737                                                      "MFT record #6 FILENAME isn't '$Bitmap': '%.*ls'",
     2045                                                     "$Bitmap: FILENAME isn't '$Bitmap': '%.*ls'",
    17382046                                                     pFilename->cwcFilename, pFilename->wszFilename);
    17392047                    else
     
    17742082        }
    17752083        else
    1776             rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "MFT record #0 has no unnamed DATA attribute!");
     2084            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$Bitmap: has no unnamed DATA attribute!");
    17772085        rtFsNtfsCore_Release(pCore);
    17782086    }
    17792087    else
    1780         rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "Error reading MFT record #6");
     2088        rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "$Bitmap: Error MFT record");
     2089    return rc;
     2090}
     2091
     2092
     2093/**
     2094 * Loads, validates and setups the '$Volume' (NTFS_MFT_IDX_VOLUME) MFT entry.
     2095 *
     2096 * @returns IPRT status code
     2097 * @param   pThis               The NTFS volume instance.  Will set uNtfsVersion
     2098 *                              and fVolumeFlags.
     2099 * @param   pErrInfo            Where to return additional error info.
     2100 */
     2101static int rtFsNtfsVolLoadVolumeInfo(PRTFSNTFSVOL pThis, PRTERRINFO pErrInfo)
     2102{
     2103    PRTFSNTFSCORE pCore;
     2104    int rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFS_MFT_IDX_VOLUME, &pCore, pErrInfo);
     2105    if (RT_SUCCESS(rc))
     2106    {
     2107        PRTFSNTFSATTR pVolInfoAttr = rtFsNtfsCore_FindUnnamedAttribute(pCore, NTFS_AT_VOLUME_INFORMATION);
     2108        if (pVolInfoAttr)
     2109        {
     2110            /*
     2111             * Validate the '$Volume' MFT record.
     2112             */
     2113            if (pVolInfoAttr->pAttrHdr->fNonResident)
     2114                rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$Volume unnamed VOLUME_INFORMATION attribute is not resident!");
     2115            else if (   pVolInfoAttr->cbResident != sizeof(NTFSATVOLUMEINFO)
     2116                     || pVolInfoAttr->cbValue    != sizeof(NTFSATVOLUMEINFO))
     2117                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2118                                             "$Volume VOLUME_INFORMATION attribute has the wrong size: cbValue=%#RX64, cbResident=%#RX32, expected %#x\n",
     2119                                             pVolInfoAttr->cbValue, pVolInfoAttr->cbResident, sizeof(NTFSATVOLUMEINFO));
     2120            else
     2121            {
     2122                PRTFSNTFSATTR pFilenameAttr = rtFsNtfsCore_FindUnnamedAttribute(pCore, NTFS_AT_FILENAME);
     2123                if (!pFilenameAttr)
     2124                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$Volume has no FILENAME attribute!");
     2125                else if (pFilenameAttr->pAttrHdr->fNonResident)
     2126                    rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "$Volume FILENAME attribute is non-resident!");
     2127                else if (pFilenameAttr->pAttrHdr->u.Res.cbValue < RT_UOFFSETOF(NTFSATFILENAME, wszFilename[7]))
     2128                    rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2129                                                 "$Volume FILENAME attribute value size is too small: %#x",
     2130                                                 pFilenameAttr->pAttrHdr->u.Res.cbValue);
     2131                else
     2132                {
     2133                    PNTFSATFILENAME pFilename = (PNTFSATFILENAME)(  (uint8_t *)pFilenameAttr->pAttrHdr
     2134                                                                  + pFilenameAttr->pAttrHdr->u.Res.offValue);
     2135                    if (   pFilename->cwcFilename != 7
     2136                        || RTUtf16NICmpAscii(pFilename->wszFilename, "$Volume", 7) != 0)
     2137                        rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2138                                                     "$Volume FILENAME isn't '$Volume': '%.*ls'",
     2139                                                     pFilename->cwcFilename, pFilename->wszFilename);
     2140                    else
     2141                    {
     2142                        /*
     2143                         * Look at the information.
     2144                         */
     2145                        PCNTFSATVOLUMEINFO pVolInfo;
     2146                        pVolInfo = (PCNTFSATVOLUMEINFO)((uint8_t *)pVolInfoAttr->pAttrHdr + pVolInfoAttr->pAttrHdr->u.Res.offValue);
     2147                        pThis->uNtfsVersion = RTFSNTFS_MAKE_VERSION(pVolInfo->uMajorVersion, pVolInfo->uMinorVersion);
     2148                        pThis->fVolumeFlags = RT_LE2H_U16(pVolInfo->fFlags);
     2149                        Log(("NTFS: Version %u.%u, flags=%#x\n", pVolInfo->uMajorVersion, pVolInfo->uMinorVersion, pThis->fVolumeFlags));
     2150
     2151                        /* We're done, no need for special success return here though. */
     2152                    }
     2153                }
     2154            }
     2155        }
     2156        else
     2157            rc = RTERRINFO_LOG_REL_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2158                                       "MFT record $Volume has no unnamed VOLUME_INFORMATION attribute!");
     2159        rtFsNtfsCore_Release(pCore);
     2160    }
     2161    else
     2162        rc = RTERRINFO_LOG_REL_SET(pErrInfo, rc, "Error reading $Volume MFT record");
    17812163    return rc;
    17822164}
     
    19582340    pThis->cClusterShift = ASMBitFirstSetU32(pThis->cbCluster) - 1;
    19592341    Log2(("NTFS BPB: cClusterPerSector=%#x => %#x bytes, %u shift\n", cClusterPerSector, pThis->cbCluster, pThis->cClusterShift));
     2342    pThis->iMaxVirtualCluster = (uint64_t)INT64_MAX >> pThis->cClusterShift;
     2343    Log2(("NTFS BPB: iMaxVirtualCluster=%#RX64\n", pThis->iMaxVirtualCluster));
    19602344
    19612345    /* NTFS BPB: cSectors. */
     
    20742458                    rc = rtFsNtfsVolLoadMft(pThis, pErrInfo);
    20752459                if (RT_SUCCESS(rc))
     2460                    rc = rtFsNtfsVolLoadVolumeInfo(pThis, pErrInfo);
     2461                if (RT_SUCCESS(rc))
    20762462                    rc = rtFsNtfsVolLoadBitmap(pThis, pErrInfo);
    20772463                if (RT_SUCCESS(rc))
    20782464                    rc = rtFsNtfsVolLoadUpCase(pThis, pErrInfo);
     2465                if (RT_SUCCESS(rc))
     2466                    rc = rtFsNtfsVolLoadRootDir(pThis, pErrInfo);
    20792467                RTMemTmpFree(pvBuf);
    20802468                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