VirtualBox

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


Ignore:
Timestamp:
Dec 1, 2017 5:58:28 PM (7 years ago)
Author:
vboxsync
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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