VirtualBox

Changeset 69861 in vbox


Ignore:
Timestamp:
Nov 28, 2017 7:01:35 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119307
Message:

iprt/formats/ntfs: updates

Location:
trunk
Files:
5 edited

Legend:

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

    r69849 r69861  
    4040
    4141
    42 /** @} */
    43 
     42/** @name NTFS_MFT_IDX_XXX - Predefined MFT indexes.
     43 * @{ */
     44#define NTFS_MFT_IDX_MFT            0   /**< The MFT itself. */
     45#define NTFS_MFT_IDX_MFT_MIRROR     1   /**< Mirror MFT (partial?). */
     46#define NTFS_MFT_IDX_LOG_FILE       2   /**< Journalling log. */
     47#define NTFS_MFT_IDX_VOLUME         3   /**< Volume attributes. */
     48#define NTFS_MFT_IDX_ATTRIB_DEF     4   /**< Attribute definitions. */
     49#define NTFS_MFT_IDX_ROOT           5   /**< The root directory. */
     50#define NTFS_MFT_IDX_BITMAP         6   /**< Allocation bitmap. */
     51#define NTFS_MFT_IDX_BOOT           7   /**< The boot sector. */
     52#define NTFS_MFT_IDX_BAD_CLUSTER    8   /**< Bad cluster table. */
     53#define NTFS_MFT_IDX_SECURITY       9   /**< Shared security descriptors (w2k and later). */
     54#define NTFS_MFT_IDX_UP_CASE        10  /**< Unicode upper case table. */
     55#define NTFS_MFT_IDX_EXTEND         11  /**< Directory containing further system files. */
     56#define NTFS_MFT_IDX_FIRST_USER     16  /**< The first user file. */
     57/** @} */
     58
     59/**
     60 * NTFS MFT record reference.
     61 */
     62typedef union NTFSMFTREF
     63{
     64    /** unsigned 64-bit view. */
     65    uint64_t        u64;
     66    /** unsigned 32-bit view. */
     67    uint32_t        au32[2];
     68    /** unsigned 16-bit view. */
     69    uint16_t        au16[4];
     70
     71    /** Structured view. */
     72    struct
     73    {
     74        /** Index of the master file table record. */
     75        uint64_t        idxMft : 48;
     76        /** MFT record reuse sequence number (for catching dangling references). */
     77        uint64_t        uRecReuseSeqNo : 16;
     78    } RT_UNION_NM(s);
     79} NTFSMFTREF;
     80AssertCompileSize(NTFSMFTREF, 8);
     81/** Pointer to a NTFS MFT record reference. */
     82typedef NTFSMFTREF *PNTFSMFTREF;
     83/** Pointer to a const NTFS MFT record reference. */
     84typedef NTFSMFTREF const *PCNTFSMFTREF;
     85
     86/** @name NTFSMFTREF_GET_IDX
     87 * Gets the MFT index number from a MFT reference. */
     88/** @name NTFSMFTREF_GET_SEQ
     89 * Gets the MFT reuse sequence number from a MFT reference. */
     90/** @name NTFSMFTREF_SET_IDX
     91 * Sets the MFT index number of a MFT reference. */
     92/** @name NTFSMFTREF_SET_SEQ
     93 * Sets the MFT reuse sequence number of a MFT reference. */
     94/** @name NTFSMFTREF_SET
     95 * Sets the values of a MFT reference. */
     96#ifdef RT_LITTLE_ENDIAN
     97# define NTFSMFTREF_GET_IDX(a_pMftRef)              ((a_pMftRef)->RT_UNION_NM(s.)idxMft)
     98# define NTFSMFTREF_GET_SEQ(a_pMftRef)              ((a_pMftRef)->RT_UNION_NM(s.)uRecReuseSeqNo)
     99# define NTFSMFTREF_SET_SEQ(a_pMftRef, a_uValue)    do { (a_pMftRef)->RT_UNION_NM(s.)uRecReuseSeqNo = (a_uValue); } while (0)
     100# define NTFSMFTREF_SET_IDX(a_pMftRef, a_uValue)    do { (a_pMftRef)->RT_UNION_NM(s.)idxMft         = (a_uValue); } while (0)
     101# define NTFSMFTREF_SET(a_pMftRef, a_idx, a_uSeq)  \
     102    do { \
     103        (a_pMftRef)->RT_UNION_NM(s.)idxMft         = (a_idx); \
     104        (a_pMftRef)->RT_UNION_NM(s.)uRecReuseSeqNo = (a_uSeq); \
     105    } while (0)
     106#else
     107# define NTFSMFTREF_GET_IDX(a_pMftRef)              (RT_LE2H_U64((a_pMftRef)->u64) & UINT64_C(0x0000ffffffffffff))
     108# define NTFSMFTREF_GET_SEQ(a_pMftRef)              RT_LE2H_U16((uint16_t)(a_pMftRef)->u64)
     109# define NTFSMFTREF_SET_SEQ(a_pMftRef, a_uValue)    do { (a_pMftRef)->au16[3] = RT_H2LE_U16(a_uValue); } while (0)
     110# define NTFSMFTREF_SET_IDX(a_pMftRef, a_uValue)  \
     111    do { \
     112        (a_pMftRef)->au32[0] = RT_H2LE_U32((uint32_t)(a_uValue)); \
     113        (a_pMftRef)->au16[2] = RT_H2LE_U16((uint16_t)((a_uValue) >> 32)); \
     114    } while (0)
     115# define NTFSMFTREF_SET(a_pMftRef, a_idx, a_uSeq)  \
     116    do { \
     117        (a_pMftRef)->au32[0] = RT_H2LE_U32((uint32_t)(a_idx)); \
     118        (a_pMftRef)->au16[2] = RT_H2LE_U16((uint16_t)((a_idx) >> 32)); \
     119        (a_pMftRef)->au16[3] = RT_H2LE_U16((uint16_t)(a_uSeq)); \
     120    } while (0)
    44121#endif
    45122
    46123
     124/**
     125 * NTFS record header.
     126 */
     127typedef struct NTFSRECHDR
     128{
     129    /** Magic number (usually ASCII). */
     130    uint32_t        uMagic;
     131    /** Offset of the update sequence array from the start of the record. */
     132    uint16_t        offUpdateSeqArray;
     133    /** Number of entries in the update sequence array. (uint16_t sized entries) */
     134    uint16_t        cUpdateSeqEntries;
     135} NTFSRECHDR;
     136AssertCompileSize(NTFSRECHDR, 8);
     137/** Pointer to a NTFS record header. */
     138typedef NTFSRECHDR *PNTFSRECHDR;
     139/** Pointer to a const NTFS record header. */
     140typedef NTFSRECHDR const *PCNTFSRECHDR;
     141
     142
     143/**
     144 * NTFS file record (in the MFT).
     145 */
     146typedef struct NTFSRECFILE
     147{
     148    /** 0x00: Header with NTFSREC_MAGIC_FILE. */
     149    NTFSRECHDR          Hdr;
     150    /** 0x08: Log file sequence number. */
     151    uint64_t            uLsn;
     152    /** 0x10: MFT record reuse sequence number (for dangling MFT references). */
     153    uint16_t            uRecReuseSeqNo;
     154    /** 0x12: Number of hard links. */
     155    uint16_t            cLinks;
     156    /** 0x14: Offset of the first attribute (relative to start of record). */
     157    uint16_t            offFirstAttrib;
     158    /** 0x16: Record flags (NTFSRECFILE_F_XXX). */
     159    uint16_t            fFlags;
     160    /** 0x18: Number of byte in use in this MFT record. */
     161    uint32_t            cbRecUsed;
     162    /** 0x1c: The MFT record size. */
     163    uint32_t            cbRecSize;
     164    /** 0x20: Reference to the base MFT record. */
     165    NTFSMFTREF          BaseMftRec;
     166    /** 0x28: Next attribute instance number. */
     167    uint16_t            idNextAttrib;
     168    /** 0x2a: Padding if NTFS 3.1+, update sequence array if older. */
     169    uint16_t            uPaddingOrUsa;
     170    /** 0x2c: MFT index of this record. */
     171    uint32_t            idxMftSelf;
     172} NTFSRECFILE;
     173AssertCompileSize(NTFSRECFILE, 0x30);
     174/** Pointer to a NTFS file record. */
     175typedef NTFSRECFILE *PNTFSRECFILE;
     176/** Pointer to a const NTFS file record. */
     177typedef NTFSRECFILE const *PCNTFSRECFILE;
     178
     179
     180/** NTFS 'FILE' record magic value. */
     181#define NTFSREC_MAGIC_FILE      RT_H2LE_U32_C(UINT32_C(0x454c4946))
     182
     183/** @name NTFSRECFILE_F_XXX - NTFSRECFILE::fFlags.
     184 * @{ */
     185/** MFT record is in use. */
     186#define NTFSRECFILE_F_IN_USE        RT_H2LE_U16_C(UINT16_C(0x0001))
     187/** Directory record. */
     188#define NTFSRECFILE_F_DIRECTORY     RT_H2LE_U16_C(UINT16_C(0x0002))
     189/** @} */
     190
     191
     192/** @name NTFS_AT_XXX - Attribute types
     193 * @{ */
     194#define NTFS_AT_UNUSED                      RT_H2LE_U32_C(UINT32_C(0x00000000))
     195/** NTFSATSTDINFO */
     196#define NTFS_AT_STANDARD_INFORMATION        RT_H2LE_U32_C(UINT32_C(0x00000010))
     197#define NTFS_AT_ATTRIBUTE_LIST              RT_H2LE_U32_C(UINT32_C(0x00000020))
     198/** PCNTFSATFILENAME */
     199#define NTFS_AT_FILENAME                    RT_H2LE_U32_C(UINT32_C(0x00000030))
     200#define NTFS_AT_OBJECT_ID                   RT_H2LE_U32_C(UINT32_C(0x00000040))
     201#define NTFS_AT_SECURITY_DESCRIPTOR         RT_H2LE_U32_C(UINT32_C(0x00000050))
     202#define NTFS_AT_VOLUME_NAME                 RT_H2LE_U32_C(UINT32_C(0x00000060))
     203#define NTFS_AT_VOLUME_INFORMATION          RT_H2LE_U32_C(UINT32_C(0x00000070))
     204#define NTFS_AT_DATA                        RT_H2LE_U32_C(UINT32_C(0x00000080))
     205#define NTFS_AT_INDEX_ROOT                  RT_H2LE_U32_C(UINT32_C(0x00000090))
     206#define NTFS_AT_INDEX_ALLOCATION            RT_H2LE_U32_C(UINT32_C(0x000000a0))
     207#define NTFS_AT_BITMAP                      RT_H2LE_U32_C(UINT32_C(0x000000b0))
     208#define NTFS_AT_REPARSE_POINT               RT_H2LE_U32_C(UINT32_C(0x000000c0))
     209#define NTFS_AT_EA_INFORMATION              RT_H2LE_U32_C(UINT32_C(0x000000d0))
     210#define NTFS_AT_EA                          RT_H2LE_U32_C(UINT32_C(0x000000e0))
     211#define NTFS_AT_PROPERTY_SET                RT_H2LE_U32_C(UINT32_C(0x000000f0))
     212#define NTFS_AT_LOGGED_UTILITY_STREAM       RT_H2LE_U32_C(UINT32_C(0x00000100))
     213#define NTFS_AT_FIRST_USER_DEFINED          RT_H2LE_U32_C(UINT32_C(0x00001000))
     214#define NTFS_AT_END                         RT_H2LE_U32_C(UINT32_C(0xffffffff))
     215/** @} */
     216
     217/** @name NTFS_AF_XXX - Attribute flags.
     218 * @{ */
     219#define NTFS_AF_COMPR_FMT_NONE              UINT16_C(0x0000)
     220#define NTFS_AF_COMPR_FMT_LZNT1             UINT16_C(0x0001)    /**< See RtlCompressBuffer / COMPRESSION_FORMAT_LZNT1. */
     221#define NTFS_AF_COMPR_FMT_XPRESS            UINT16_C(0x0002)    /**< See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */
     222#define NTFS_AF_COMPR_FMT_XPRESS_HUFF       UINT16_C(0x0003)    /**< See RtlCompressBuffer / COMPRESSION_FORMAT_XPRESS_HUFF. */
     223#define NTFS_AF_COMPR_FMT_MASK              UINT16_C(0x00ff)
     224#define NTFS_AF_ENCRYPTED                   UINT16_C(0x4000)
     225#define NTFS_AF_SPARSE                      UINT16_C(0x8000)
     226/** @} */
     227
     228/**
     229 * NTFS attribute header.
     230 *
     231 * This has three forms:
     232 *      - Resident
     233 *      - Non-resident, no compression
     234 *      - Non-resident, compressed.
     235 *
     236 * Each form translates to a different header size.
     237 */
     238typedef struct NTFSATTRIBHDR
     239{
     240    /** 0x00: Attribute type (NTFS_AT_XXX). */
     241    uint32_t                uAttrType;
     242    /** 0x04: Length of this attribute (resident part). */
     243    uint32_t                cbAttrib;
     244    /** 0x08: Set (1) if non-resident attribute, 0 if resident. */
     245    uint8_t                 fNonResident;
     246    /** 0x09: Attribute name length (can be zero). */
     247    uint8_t                 cwcName;
     248    /** 0x0a: Offset of the name string (relative to the start of this header). */
     249    uint16_t                offName;
     250    /** 0x0c: NTFS_AF_XXX. */
     251    uint16_t                fFlags;
     252    /** 0x0e: Attribute instance number.  Unique within the MFT record. */
     253    uint16_t                idAttrib;
     254    /** 0x10: Data depending on the fNonResident member value. */
     255    union
     256    {
     257        /** Resident attributes. */
     258        struct
     259        {
     260            /** 0x10: Attribute value length. */
     261            uint32_t        cbValue;
     262            /** 0x14: Offset of the value (relative to the start of this header). */
     263            uint16_t        offValue;
     264            /** 0x16: NTFS_RES_AF_XXX. */
     265            uint8_t         fFlags;
     266            /** 0x17: Reserved. */
     267            uint8_t         bReserved;
     268        } Res;
     269
     270        /** Non-resident attributes. */
     271        struct
     272        {
     273            /** 0x10: The first virtual cluster containing data. */
     274            int64_t         iVcnFirst;
     275            /** 0x18: The last virtual cluster containing data (inclusive). */
     276            int64_t         iVcnLast;
     277            /** 0x20: Offset of the mapping pair program.  This program gives us a mapping
     278             * between VNC and LCN for the attribute value. */
     279            uint16_t        offMappingPairs;
     280            /** 0x22: Power of two compression unit size in clusters (cbCluster << uCompessionUnit).
     281             * Zero means uncompressed.  */
     282            uint8_t         uCompressionUnit;
     283            /** 0x23: Reserved */
     284            uint8_t         abReserved[5];
     285            /** 0x28: Allocated size. */
     286            int64_t         cbAllocated;
     287            /** 0x30: Initialized size. */
     288            int64_t         cbInitialized;
     289            /** 0x38: Compressed size if compressed, otherwise absent. */
     290            int64_t         cbCompressed;
     291        } NonRes;
     292    } RT_UNION_NM(u);
     293} NTFSATTRIBHDR;
     294AssertCompileSize(NTFSATTRIBHDR, 0x40);
     295AssertCompileMemberOffset(NTFSATTRIBHDR, RT_UNION_NM(u.) Res, 0x10);
     296AssertCompileMemberOffset(NTFSATTRIBHDR, RT_UNION_NM(u.) Res.bReserved, 0x17);
     297AssertCompileMemberOffset(NTFSATTRIBHDR, RT_UNION_NM(u.) NonRes, 0x10);
     298AssertCompileMemberOffset(NTFSATTRIBHDR, RT_UNION_NM(u.) NonRes.cbCompressed, 0x38);
     299/** Pointer to a NTFS attribute header. */
     300typedef NTFSATTRIBHDR *PNTFSATTRIBHDR;
     301/** Pointer to a const NTFS attribute header. */
     302typedef NTFSATTRIBHDR const *PCNTFSATTRIBHDR;
     303
     304/** @name NTFSATTRIBHDR_SIZE_XXX - Attribute header sizes.
     305 * @{ */
     306/** Attribute header size for resident values. */
     307#define NTFSATTRIBHDR_SIZE_RESIDENT                 (0x18)
     308/** Attribute header size for uncompressed non-resident values. */
     309#define NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED      (0x38)
     310/** Attribute header size for compressed non-resident values. */
     311#define NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED        (0x40)
     312/** @} */
     313
     314/**
     315 * NTFS standard file info attribute (NTFS_AT_STANDARD_INFORMATION).
     316 */
     317typedef struct NTFSATSTDINFO
     318{
     319    /** 0x00: Creation timestamp. */
     320    int64_t             iCreationTime;
     321    /** 0x08: Last data modification timestamp. */
     322    int64_t             iLastDataModTime;
     323    /** 0x10: Last MFT record modification timestamp. */
     324    int64_t             iLastMftModTime;
     325    /** 0x18: Last access timestamp. */
     326    int64_t             iLastAccessTime;
     327    /** 0x20: File attributes. */
     328    uint32_t            fFileAttribs;
     329    /** 0x24: Maximum number of file versions allowed.
     330     * @note NTFS 3.x, padding in 1.2  */
     331    uint32_t            cMaxFileVersions;
     332    /** 0x28: Current file version number.
     333     * @note NTFS 3.x, padding in 1.2  */
     334    uint32_t            uFileVersion;
     335    /** 0x2c: Class ID (whatever that is).
     336     * @note NTFS 3.x, padding in 1.2  */
     337    uint32_t            idClass;
     338    /** 0x30: Owner ID.
     339     * Translated via $Q index in NTFS_MFT_IDX_EXTENDED/$Quota.
     340     * @note NTFS 3.x, not present in 1.2  */
     341    uint32_t            idOwner;
     342    /** 0x34: Security ID. Translated via $SII index and $SDS data stream in
     343     *  NTFS_MFT_IDX_SECURITY.
     344     * @note NTFS 3.x, not present in 1.2  */
     345    uint32_t            idSecurity;
     346    /** 0x38: Total quota charged for this file.
     347     * @note NTFS 3.x, not present in 1.2  */
     348    uint64_t            cbQuotaChared;
     349    /** 0x40: Last update sequence number, index into $UsnJrnl.
     350     * @note NTFS 3.x, not present in 1.2  */
     351    uint64_t            idxUpdateSequence;
     352} NTFSATSTDINFO;
     353AssertCompileSize(NTFSATSTDINFO, 0x48);
     354/** Pointer to NTFS standard file info. */
     355typedef NTFSATSTDINFO *PNTFSATSTDINFO;
     356/** Pointer to const NTFS standard file info. */
     357typedef NTFSATSTDINFO const *PCNTFSATSTDINFO;
     358
     359/** The size of NTFSATSTDINFO in NTFS v1.2 and earlier. */
     360#define NTFSATSTDINFO_SIZE_NTFS_V12     (0x30)
     361
     362/** @name NTFS_FA_XXX - NTFS file attributes.
     363 * @{ */
     364#define NTFS_FA_READONLY                            UINT32_C(0x00000001)
     365#define NTFS_FA_HIDDEN                              UINT32_C(0x00000002)
     366#define NTFS_FA_SYSTEM                              UINT32_C(0x00000004)
     367#define NTFS_FA_DIRECTORY                           UINT32_C(0x00000010)
     368#define NTFS_FA_ARCHIVE                             UINT32_C(0x00000020)
     369#define NTFS_FA_DEVICE                              UINT32_C(0x00000040)
     370#define NTFS_FA_NORMAL                              UINT32_C(0x00000080)
     371#define NTFS_FA_TEMPORARY                           UINT32_C(0x00000100)
     372#define NTFS_FA_SPARSE_FILE                         UINT32_C(0x00000200)
     373#define NTFS_FA_REPARSE_POINT                       UINT32_C(0x00000400)
     374#define NTFS_FA_COMPRESSED                          UINT32_C(0x00000800)
     375#define NTFS_FA_OFFLINE                             UINT32_C(0x00001000)
     376#define NTFS_FA_NOT_CONTENT_INDEXED                 UINT32_C(0x00002000)
     377#define NTFS_FA_ENCRYPTED                           UINT32_C(0x00004000)
     378#define NTFS_FA_VALID_FLAGS                         UINT32_C(0x00007fb7)
     379#define NTFS_FA_VALID_SET_FLAGS                     UINT32_C(0x000031a7)
     380#define NTFS_FA_DUP_FILE_NAME_INDEX_PRESENT         UINT32_C(0x10000000) /**< ?? */
     381#define NTFS_FA_DUP_VIEW_INDEX_PRESENT              UINT32_C(0x20000000) /**< ?? */
     382/** @} */
     383
     384
     385
     386/**
     387 * NTFS filename attribute (NTFS_AT_FILENAME).
     388 */
     389typedef struct NTFSATFILENAME
     390{
     391    /** 0x00: The parent directory MFT record. */
     392    NTFSMFTREF          ParentDirMftRec;
     393    /** 0x08: Creation timestamp. */
     394    int64_t             iCreationTime;
     395    /** 0x10: Last data modification timestamp. */
     396    int64_t             iLastDataModTime;
     397    /** 0x18: Last MFT record modification timestamp. */
     398    int64_t             iLastMftModTime;
     399    /** 0x20: Last access timestamp. */
     400    int64_t             iLastAccessTime;
     401    /** 0x28: Allocated disk space for the unnamed data attribute. */
     402    int64_t             cbAllocated;
     403    /** 0x30: Actual size of unnamed data attribute. */
     404    int64_t             cbData;
     405    /** 0x38: File attributes. */
     406    uint32_t            fFileAttribs;
     407    union
     408    {
     409        /** 0x3c: Packed EA length. */
     410        uint16_t        cbPackedEas;
     411        /** 0x3c: Reparse tag, if no EAs. */
     412        uint32_t        uReparseTag;
     413    };
     414    /** 0x40: Filename length in unicode chars. */
     415    uint8_t             cwcFilename;
     416    /** 0x41: Filename type (NTFS_FILENAME_T_XXX). */
     417    uint8_t             fFilenameType;
     418    /** 0x42: The filename. */
     419    RTUTF16             wszFilename[RT_FLEXIBLE_ARRAY];
     420} NTFSATFILENAME;
     421AssertCompileMemberOffset(NTFSATFILENAME, cbData, 0x30);
     422AssertCompileMemberOffset(NTFSATFILENAME, cbPackedEas, 0x3c);
     423AssertCompileMemberOffset(NTFSATFILENAME, uReparseTag, 0x3c);
     424AssertCompileMemberOffset(NTFSATFILENAME, wszFilename, 0x42);
     425/** Pointer to a NTFS filename attribute. */
     426typedef NTFSATFILENAME *PNTFSATFILENAME;
     427/** Pointer to a const NTFS filename attribute. */
     428typedef NTFSATFILENAME const *PCNTFSATFILENAME;
     429
     430/** @name NTFS_FILENAME_T_XXX - filename types
     431 * @{ */
     432#define NTFS_FILENAME_T_POSIX           0
     433#define NTFS_FILENAME_T_WINDOWS         1
     434#define NTFS_FILENAME_T_DOS             2
     435#define NTFS_FILENAME_T_WINDOWS_AND_DSO 3
     436/** @} */
     437
     438/** @} */
     439
     440#endif
     441
  • trunk/src/VBox/Runtime/common/fs/ext2vfs.cpp

    r69845 r69861  
    238238{
    239239    AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
    240     AssertReturn(!(fMntFlags & RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
     240    AssertReturn(!(fMntFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
    241241    AssertReturn(!fExtFlags, VERR_INVALID_FLAGS);
    242242
  • trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp

    r69849 r69861  
    3333
    3434#include <iprt/asm.h>
     35#include <iprt/avl.h>
    3536#include <iprt/assert.h>
    3637#include <iprt/file.h>
     
    4647*   Structures and Typedefs                                                                                                      *
    4748*********************************************************************************************************************************/
     49/** Pointer to the instance data for a NTFS volume. */
     50typedef struct RTFSNTFSVOL *PRTFSNTFSVOL;
     51/** Pointer to a NTFS MFT record. */
     52typedef struct RTFSNTFSMFTREC *PRTFSNTFSMFTREC;
     53
     54/**
     55 * NTFS MFT record.
     56 */
     57typedef struct RTFSNTFSMFTREC
     58{
     59    /** MFT record number as key. */
     60    AVLU64NODECORE      Core;
     61    /** Pointer to the next MFT record if chained. */
     62    PRTFSNTFSMFTREC     pNext;
     63    /** Pointer back to the volume. */
     64    PRTFSNTFSVOL        pVol;
     65    /** The disk offset of this MFT entry. */
     66    uint64_t            offDisk;
     67    union
     68    {
     69        /** Generic pointer. */
     70        uint8_t        *pbRec;
     71        /** Pointer to the file record. */
     72        PNTFSRECFILE    pFileRec;
     73    } RT_UNION_NM(u);
     74
     75    /** Reference counter. */
     76    uint32_t volatile   cRefs;
     77
     78    // ....
     79} RTFSNTFSMFTREC;
    4880
    4981/**
     
    91123    uint64_t        uSerialNo;
    92124
     125    /** Pointer to the MFT record for the MFT. */
     126    PRTFSNTFSMFTREC pMft;
     127
     128    /** Root of the MFT record tree (RTFSNTFSMFTREC). */
     129    AVLU64TREE      MftRoot;
    93130} RTFSNTFSVOL;
    94 /** Pointer to the instance data for a NTFS volume. */
    95 typedef RTFSNTFSVOL *PRTFSNTFSVOL;
     131
     132
     133static PRTFSNTFSMFTREC rtFsNtfsMftRec_New(PRTFSNTFSVOL pVol, uint64_t idMft)
     134{
     135    PRTFSNTFSMFTREC pRec = (PRTFSNTFSMFTREC)RTMemAllocZ(sizeof(*pRec));
     136    if (pRec)
     137    {
     138        pRec->pbRec = (uint8_t *)RTMemAllocZ(pVol->cbMftRecord);
     139        if (pRec->pbRec)
     140        {
     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;
     147        }
     148    }
     149    return NULL;
     150}
     151
     152
     153static uint32_t rtFsNtfsMftRec_Destroy(PRTFSNTFSMFTREC pThis)
     154{
     155    RTMemFree(pThis->pbRec);
     156    pThis->pbRec = NULL;
     157
     158    PAVLU64NODECORE pRemoved = RTAvlU64Remove(&pThis->pVol->MftRoot, pThis->Core.Key);
     159    Assert(pRemoved == &pThis->Core); NOREF(pRemoved);
     160
     161    pThis->pVol = NULL;
     162    RTMemFree(pThis);
     163
     164    return 0;
     165}
     166
     167
     168static uint32_t rtFsNtfsMftRec_Retain(PRTFSNTFSMFTREC pThis)
     169{
     170    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     171    Assert(cRefs < 64);
     172    return cRefs;
     173}
     174
     175
     176static uint32_t rtFsNtfsMftRec_Release(PRTFSNTFSMFTREC pThis)
     177{
     178    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     179    Assert(cRefs < 64);
     180    if (cRefs != 0)
     181        return cRefs;
     182    return rtFsNtfsMftRec_Destroy(pThis);
     183}
     184
     185
     186#ifdef LOG_ENABLED
     187/**
     188 * Logs the MFT record
     189 *
     190 * @param   pRec        The MFT record to log.
     191 */
     192static void rtfsNtfsMftRec_Log(PRTFSNTFSMFTREC pRec)
     193{
     194    if (LogIs2Enabled())
     195    {
     196        PCNTFSRECFILE  pFileRec = pRec->pFileRec;
     197        Log2(("NTFS: MFT #%#RX64 at %#RX64\n", pRec->Core.Key, pRec->offDisk));
     198        if (pFileRec->Hdr.uMagic == NTFSREC_MAGIC_FILE)
     199        {
     200            size_t const          cbRec = pRec->pVol->cbMftRecord;
     201            uint8_t const * const pbRec = pRec->pbRec;
     202
     203            Log2(("NTFS: FILE record: \n"));
     204            Log2(("NTFS:   UpdateSeqArray  %#x L %#x\n", RT_LE2H_U16(pFileRec->Hdr.offUpdateSeqArray), RT_LE2H_U16(pFileRec->Hdr.cUpdateSeqEntries) ));
     205            Log2(("NTFS:   uLsn            %#RX64\n", RT_LE2H_U64(pFileRec->uLsn)));
     206            Log2(("NTFS:   uRecReuseSeqNo  %#RX16\n", RT_LE2H_U16(pFileRec->uRecReuseSeqNo)));
     207            Log2(("NTFS:   cLinks          %#RX16\n", RT_LE2H_U16(pFileRec->cLinks)));
     208            Log2(("NTFS:   offFirstAttrib  %#RX16\n", RT_LE2H_U16(pFileRec->offFirstAttrib)));
     209            Log2(("NTFS:   fFlags          %#RX16%s%s\n", RT_LE2H_U16(pFileRec->fFlags),
     210                  RT_LE2H_U16(pFileRec->fFlags) & NTFSRECFILE_F_IN_USE    ? " in-use"    : "",
     211                  RT_LE2H_U16(pFileRec->fFlags) & NTFSRECFILE_F_DIRECTORY ? " directory" : ""));
     212            Log2(("NTFS:   cbRecUsed       %#RX32\n", RT_LE2H_U32(pFileRec->cbRecUsed)));
     213            Log2(("NTFS:   BaseMftRec      %#RX64, sqn %#x\n",
     214                  NTFSMFTREF_GET_IDX(&pFileRec->BaseMftRec), NTFSMFTREF_GET_SEQ(&pFileRec->BaseMftRec)));
     215            Log2(("NTFS:   idNextAttrib    %#RX16\n", RT_LE2H_U16(pFileRec->idNextAttrib)));
     216            if (   RT_LE2H_U16(pFileRec->offFirstAttrib)         >= sizeof(*pFileRec)
     217                && (   RT_LE2H_U16(pFileRec->Hdr.offUpdateSeqArray) >= sizeof(*pFileRec)
     218                    || pFileRec->Hdr.offUpdateSeqArray == 0))
     219            {
     220                Log2(("NTFS:   uPaddingOrUsa   %#RX16\n", pFileRec->uPaddingOrUsa));
     221                Log2(("NTFS:   idxMftSelf      %#RX32\n", RT_LE2H_U32(pFileRec->idxMftSelf)));
     222            }
     223
     224            uint32_t offRec = pFileRec->offFirstAttrib;
     225            size_t   cbRecUsed = RT_MIN(cbRec, pFileRec->cbRecUsed);
     226            while (offRec + NTFSATTRIBHDR_SIZE_RESIDENT <= cbRecUsed)
     227            {
     228                PCNTFSATTRIBHDR pHdr     = (PCNTFSATTRIBHDR)&pbRec[offRec];
     229                uint32_t const  cbAttrib = RT_LE2H_U32(pHdr->cbAttrib);
     230                Log2(("NTFS:   @%#05x: Attrib record: %#x LB %#x, instance #%#x, fFlags=%#RX16, %s\n", offRec,
     231                      RT_LE2H_U32(pHdr->uAttrType), cbAttrib, RT_LE2H_U16(pHdr->idAttrib), RT_LE2H_U16(pHdr->fFlags),
     232                      pHdr->fNonResident == 0 ? "resident" : pHdr->fNonResident == 1 ? "non-resident" : "bad-resident-flag"));
     233                if (pHdr->offName && pHdr->cwcName)
     234                {
     235                    if (offRec + RT_LE2H_U16(pHdr->offName) + pHdr->cwcName * sizeof(RTUTF16) <= cbRec)
     236                        Log2(("NTFS:     Name %.*ls\n", pHdr->cwcName,&pbRec[offRec + RT_LE2H_U16(pHdr->offName)]));
     237                    else
     238                        Log2(("NTFS:     Name <!out of bounds!> %#x L %#x\n", RT_LE2H_U16(pHdr->offName), pHdr->cwcName));
     239                }
     240                switch (pHdr->uAttrType)
     241                {
     242                    case NTFS_AT_UNUSED:                    Log2(("NTFS:     Type: UNUSED\n")); break;
     243                    case NTFS_AT_STANDARD_INFORMATION:      Log2(("NTFS:     Type: STANDARD_INFORMATION\n")); break;
     244                    case NTFS_AT_ATTRIBUTE_LIST:            Log2(("NTFS:     Type: ATTRIBUTE_LIST\n")); break;
     245                    case NTFS_AT_FILENAME:                  Log2(("NTFS:     Type: FILENAME\n")); break;
     246                    case NTFS_AT_OBJECT_ID:                 Log2(("NTFS:     Type: OBJECT_ID\n")); break;
     247                    case NTFS_AT_SECURITY_DESCRIPTOR:       Log2(("NTFS:     Type: SECURITY_DESCRIPTOR\n")); break;
     248                    case NTFS_AT_VOLUME_NAME:               Log2(("NTFS:     Type: VOLUME_NAME\n")); break;
     249                    case NTFS_AT_VOLUME_INFORMATION:        Log2(("NTFS:     Type: VOLUME_INFORMATION\n")); break;
     250                    case NTFS_AT_DATA:                      Log2(("NTFS:     Type: DATA\n")); break;
     251                    case NTFS_AT_INDEX_ROOT:                Log2(("NTFS:     Type: INDEX_ROOT\n")); break;
     252                    case NTFS_AT_INDEX_ALLOCATION:          Log2(("NTFS:     Type: INDEX_ALLOCATION\n")); break;
     253                    case NTFS_AT_BITMAP:                    Log2(("NTFS:     Type: BITMAP\n")); break;
     254                    case NTFS_AT_REPARSE_POINT:             Log2(("NTFS:     Type: REPARSE_POINT\n")); break;
     255                    case NTFS_AT_EA_INFORMATION:            Log2(("NTFS:     Type: EA_INFORMATION\n")); break;
     256                    case NTFS_AT_EA:                        Log2(("NTFS:     Type: EA\n")); break;
     257                    case NTFS_AT_PROPERTY_SET:              Log2(("NTFS:     Type: PROPERTY_SET\n")); break;
     258                    case NTFS_AT_LOGGED_UTILITY_STREAM:     Log2(("NTFS:     Type: LOGGED_UTILITY_STREAM\n")); break;
     259                    default:
     260                        if (RT_LE2H_U32(pHdr->uAttrType) >= RT_LE2H_U32_C(NTFS_AT_FIRST_USER_DEFINED))
     261                            Log2(("NTFS:     Type: unknown user defined - %#x!\n", RT_LE2H_U32(pHdr->uAttrType)));
     262                        else
     263                            Log2(("NTFS:     Type: unknown - %#x!\n", RT_LE2H_U32(pHdr->uAttrType)));
     264                        break;
     265                }
     266
     267                size_t const cbMaxAttrib = cbRec - offRec;
     268                if (!pHdr->fNonResident)
     269                {
     270                    uint16_t const offValue = RT_LE2H_U16(pHdr->Res.offValue);
     271                    uint32_t const cbValue  = RT_LE2H_U32(pHdr->Res.cbValue);
     272                    Log2(("NTFS:     Value: %#x LB %#x, fFlags=%#x bReserved=%#x\n",
     273                          offValue, cbValue, pHdr->Res.fFlags, pHdr->Res.bReserved));
     274                    if (   offValue < cbMaxAttrib
     275                        && cbValue  < cbMaxAttrib
     276                        && offValue + cbValue <= cbMaxAttrib)
     277                    {
     278                        uint8_t const *pbValue = &pbRec[offRec + offValue];
     279                        RTTIMESPEC     Spec;
     280                        char           sz[80];
     281                        switch (pHdr->uAttrType)
     282                        {
     283                            case NTFS_AT_STANDARD_INFORMATION:
     284                            {
     285                                PCNTFSATSTDINFO pInfo = (PCNTFSATSTDINFO)pbValue;
     286                                if (cbValue >= NTFSATSTDINFO_SIZE_NTFS_V12)
     287                                {
     288                                    Log2(("NTFS:     iCreationTime      %#RX64 %s\n", RT_LE2H_U64(pInfo->iCreationTime),
     289                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iCreationTime)), sz, sizeof(sz)) ));
     290                                    Log2(("NTFS:     iLastDataModTime   %#RX64 %s\n", RT_LE2H_U64(pInfo->iLastDataModTime),
     291                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iLastDataModTime)), sz, sizeof(sz)) ));
     292                                    Log2(("NTFS:     iLastMftModTime    %#RX64 %s\n", RT_LE2H_U64(pInfo->iLastMftModTime),
     293                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iLastMftModTime)), sz, sizeof(sz)) ));
     294                                    Log2(("NTFS:     iLastAccessTime    %#RX64 %s\n", RT_LE2H_U64(pInfo->iLastAccessTime),
     295                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iLastAccessTime)), sz, sizeof(sz)) ));
     296                                    Log2(("NTFS:     fFileAttribs       %#RX32\n", RT_LE2H_U32(pInfo->fFileAttribs) ));
     297                                    Log2(("NTFS:     cMaxFileVersions   %#RX32\n", RT_LE2H_U32(pInfo->cMaxFileVersions) ));
     298                                    Log2(("NTFS:     uFileVersion       %#RX32\n", RT_LE2H_U32(pInfo->uFileVersion) ));
     299                                }
     300                                else
     301                                    Log2(("NTFS:     Error! cbValue=%#x is smaller than expected (%#x) for NTFSATSTDINFO!\n",
     302                                          cbValue, NTFSATSTDINFO_SIZE_NTFS_V12));
     303                                if (cbValue >= sizeof(*pInfo))
     304                                {
     305                                    Log2(("NTFS:     idClass            %#RX32\n", RT_LE2H_U32(pInfo->idClass) ));
     306                                    Log2(("NTFS:     idOwner            %#RX32\n", RT_LE2H_U32(pInfo->idOwner) ));
     307                                    Log2(("NTFS:     idSecurity         %#RX32\n", RT_LE2H_U32(pInfo->idSecurity) ));
     308                                    Log2(("NTFS:     cbQuotaChared      %#RX64\n", RT_LE2H_U64(pInfo->cbQuotaChared) ));
     309                                    Log2(("NTFS:     idxUpdateSequence  %#RX64\n", RT_LE2H_U64(pInfo->idxUpdateSequence) ));
     310                                }
     311                                if (cbValue > sizeof(*pInfo))
     312                                    Log2(("NTFS:     Undefined data: %.*Rhxs\n", cbValue - sizeof(*pInfo), &pbValue[sizeof(*pInfo)]));
     313                                break;
     314                            }
     315
     316                            //case NTFS_AT_ATTRIBUTE_LIST:
     317
     318                            case NTFS_AT_FILENAME:
     319                            {
     320                                PCNTFSATFILENAME pInfo = (PCNTFSATFILENAME)pbValue;
     321                                if (cbValue >= RT_OFFSETOF(NTFSATFILENAME, wszFilename))
     322                                {
     323                                    Log2(("NTFS:     ParentDirMftRec    %#RX64, sqn %#x\n",
     324                                          NTFSMFTREF_GET_IDX(&pInfo->ParentDirMftRec), NTFSMFTREF_GET_SEQ(&pInfo->ParentDirMftRec) ));
     325                                    Log2(("NTFS:     iCreationTime      %#RX64 %s\n", RT_LE2H_U64(pInfo->iCreationTime),
     326                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iCreationTime)), sz, sizeof(sz)) ));
     327                                    Log2(("NTFS:     iLastDataModTime   %#RX64 %s\n", RT_LE2H_U64(pInfo->iLastDataModTime),
     328                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iLastDataModTime)), sz, sizeof(sz)) ));
     329                                    Log2(("NTFS:     iLastMftModTime    %#RX64 %s\n", RT_LE2H_U64(pInfo->iLastMftModTime),
     330                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iLastMftModTime)), sz, sizeof(sz)) ));
     331                                    Log2(("NTFS:     iLastAccessTime    %#RX64 %s\n", RT_LE2H_U64(pInfo->iLastAccessTime),
     332                                          RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pInfo->iLastAccessTime)), sz, sizeof(sz)) ));
     333                                    Log2(("NTFS:     cbAllocated        %#RX64 (%Rhcb)\n",
     334                                          RT_LE2H_U64(pInfo->cbAllocated), RT_LE2H_U64(pInfo->cbAllocated)));
     335                                    Log2(("NTFS:     cbData             %#RX64 (%Rhcb)\n",
     336                                          RT_LE2H_U64(pInfo->cbData), RT_LE2H_U64(pInfo->cbData)));
     337                                    Log2(("NTFS:     fFileAttribs       %#RX32\n", RT_LE2H_U32(pInfo->fFileAttribs) ));
     338                                    if (RT_LE2H_U32(pInfo->fFileAttribs) & NTFS_FA_REPARSE_POINT)
     339                                        Log2(("NTFS:     uReparseTag        %#RX32\n", RT_LE2H_U32(pInfo->uReparseTag) ));
     340                                    else
     341                                        Log2(("NTFS:     cbPackedEas        %#RX16\n", RT_LE2H_U16(pInfo->cbPackedEas) ));
     342                                    Log2(("NTFS:     cwcFilename        %#x\n", pInfo->cwcFilename));
     343                                    Log2(("NTFS:     fFilenameType      %#x\n", pInfo->fFilenameType));
     344                                    if (cbValue >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename))
     345                                        Log2(("NTFS:     wszFilename       '%.*ls'\n", pInfo->cwcFilename, pInfo->wszFilename ));
     346                                    else
     347                                        Log2(("NTFS:     Error! Truncated filename!!\n"));
     348                                }
     349                                else
     350                                    Log2(("NTFS:     Error! cbValue=%#x is smaller than expected (%#x) for NTFSATFILENAME!\n",
     351                                          cbValue, RT_OFFSETOF(NTFSATFILENAME, wszFilename) ));
     352                                break;
     353                            }
     354
     355                            //case NTFS_AT_OBJECT_ID:
     356                            //case NTFS_AT_SECURITY_DESCRIPTOR:
     357                            //case NTFS_AT_VOLUME_NAME:
     358                            //case NTFS_AT_VOLUME_INFORMATION:
     359                            //case NTFS_AT_DATA:
     360                            //case NTFS_AT_INDEX_ROOT:
     361                            //case NTFS_AT_INDEX_ALLOCATION:
     362                            //case NTFS_AT_BITMAP:
     363                            //case NTFS_AT_REPARSE_POINT:
     364                            //case NTFS_AT_EA_INFORMATION:
     365                            //case NTFS_AT_EA:
     366                            //case NTFS_AT_PROPERTY_SET:
     367                            //case NTFS_AT_LOGGED_UTILITY_STREAM:
     368
     369                            default:
     370                                if (cbValue <= 24)
     371                                    Log2(("NTFS:     %.*Rhxs\n", cbValue, pbValue));
     372                                else
     373                                    Log2(("%.*Rhxd\n", cbValue, pbValue));
     374                                break;
     375                        }
     376
     377                    }
     378                    else
     379                        Log2(("NTFS:     !Value is out of bounds!\n"));
     380                }
     381                else if (RT_MAX(cbAttrib, NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED) <= cbMaxAttrib)
     382                {
     383                    Log2(("NTFS:     VNC range          %#RX64 .. %#RX64 (%#RX64 clusters)\n",
     384                          RT_LE2H_U64(pHdr->NonRes.iVcnFirst), RT_LE2H_U64(pHdr->NonRes.iVcnLast),
     385                          RT_LE2H_U64(pHdr->NonRes.iVcnLast) - RT_LE2H_U64(pHdr->NonRes.iVcnFirst) + 1));
     386                    Log2(("NTFS:     cbAllocated        %#RX64 (%Rhcb)\n",
     387                          RT_LE2H_U64(pHdr->NonRes.cbAllocated), RT_LE2H_U64(pHdr->NonRes.cbAllocated)));
     388                    Log2(("NTFS:     cbInitialized      %#RX64 (%Rhcb)\n",
     389                          RT_LE2H_U64(pHdr->NonRes.cbInitialized), RT_LE2H_U64(pHdr->NonRes.cbInitialized)));
     390                    uint16_t const offMappingPairs = RT_LE2H_U16(pHdr->NonRes.offMappingPairs);
     391                    Log2(("NTFS:     offMappingPairs    %#RX16\n", offMappingPairs));
     392                    if (   pHdr->NonRes.abReserved[0] || pHdr->NonRes.abReserved[1]
     393                        || pHdr->NonRes.abReserved[2] || pHdr->NonRes.abReserved[3] || pHdr->NonRes.abReserved[4] )
     394                        Log2(("NTFS:     abReserved         %.7Rhxs\n", pHdr->NonRes.abReserved));
     395                    if (pHdr->NonRes.uCompressionUnit != 0)
     396                        Log2(("NTFS:     Compression unit   2^%u clusters\n", pHdr->NonRes.uCompressionUnit));
     397
     398                    if (   NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED <= cbMaxAttrib
     399                        && NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED <= cbAttrib
     400                        && (   offMappingPairs >= NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED
     401                            || offMappingPairs <  NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED))
     402                        Log2(("NTFS:     cbCompressed       %#RX64 (%Rhcb)\n",
     403                              RT_LE2H_U64(pHdr->NonRes.cbCompressed), RT_LE2H_U64(pHdr->NonRes.cbCompressed)));
     404                    else if (pHdr->NonRes.uCompressionUnit != 0 && pHdr->NonRes.uCompressionUnit != 64)
     405                        Log2(("NTFS:     !Error! Compressed attrib fields are out of bound!\n"));
     406
     407                    if (   offMappingPairs < cbAttrib
     408                        && offMappingPairs >= NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED)
     409                    {
     410                        uint8_t const *pbPairs    = &pbRec[offRec + offMappingPairs];
     411                        uint32_t const cbMaxPairs = cbAttrib - offMappingPairs;
     412                        int64_t iVnc = pHdr->NonRes.iVcnFirst;
     413                        Log2(("NTFS:     Mapping Pairs: %.*Rhxsd\n", cbMaxPairs, pbPairs));
     414                        if (!iVnc && !*pbPairs)
     415                            Log2(("NTFS:         [0]: Empty\n", cbMaxPairs, pbPairs));
     416                        else
     417                        {
     418                            if (iVnc != 0)
     419                                Log2(("NTFS:         [0]: VCN=%#012RX64 L %#012RX64 - not mapped\n", 0, iVnc));
     420                            int64_t  iLnc     = 0;
     421                            uint32_t iPair    = 0;
     422                            uint32_t offPairs = 0;
     423                            while (offPairs < cbMaxPairs)
     424                            {
     425                                /* First byte: 4-bit length of each of the pair values */
     426                                uint8_t const bLengths = pbPairs[offPairs];
     427                                if (!bLengths)
     428                                    break;
     429                                uint8_t const cbRun    = (bLengths & 0x0f) + (bLengths >> 4);
     430                                if (offPairs + cbRun > cbMaxPairs)
     431                                {
     432                                    Log2(("NTFS:         [%d]: run overrun! cbRun=%#x bLengths=%#x offPairs=%#x cbMaxPairs=%#x\n",
     433                                          iPair, cbRun, bLengths, offPairs, cbMaxPairs));
     434                                    break;
     435                                }
     436
     437                                /* Value 1: Number of (virtual) clusters in this run. */
     438                                int64_t cClustersInRun;
     439                                uint8_t cbNum = (bLengths & 0xf);
     440                                if (cbNum)
     441                                {
     442                                    int8_t const *pbNum = (int8_t const *)&pbPairs[offPairs + cbNum]; /* last byte */
     443                                    cClustersInRun = *pbNum--;
     444                                    while (cbNum-- > 1)
     445                                        cClustersInRun = (cClustersInRun << 8) + *pbNum--;
     446                                }
     447                                else
     448                                    cClustersInRun = -1;
     449
     450                                /* Value 2: The logical cluster delta to get to the first cluster in the run. */
     451                                cbNum = bLengths >> 4;
     452                                if (cbNum)
     453                                {
     454                                    int8_t const *pbNum  = (int8_t const *)&pbPairs[offPairs + cbNum + (bLengths & 0xf)]; /* last byte */
     455                                    int64_t cLcnDelta = *pbNum--;
     456                                    while (cbNum-- > 1)
     457                                        cLcnDelta = (cLcnDelta << 8) + *pbNum--;
     458                                    iLnc += cLcnDelta;
     459                                    Log2(("NTFS:         [%d]: VNC=%#012RX64 L %#012RX64 => LNC=%#012RX64\n",
     460                                          iPair, iVnc, cClustersInRun, iLnc));
     461                                }
     462                                else
     463                                    Log2(("NTFS:         [%d]: VNC=%#012RX64 L %#012RX64 => HOLE\n",
     464                                          iPair, iVnc, cClustersInRun));
     465
     466                                /* Advance. */
     467                                iVnc     += cClustersInRun;
     468                                offPairs += 1 + cbRun;
     469                                iPair++;
     470                            }
     471                        }
     472                    }
     473                    else if (   cbAttrib != NTFSATTRIBHDR_SIZE_NONRES_COMPRESSED
     474                             && cbAttrib != NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED)
     475                    {
     476                        Log2(("NTFS:     Warning! Odd non-resident attribute size: %#x!\n", cbAttrib));
     477                        if (cbAttrib >= NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED)
     478                            Log2(("NTFS:     @%05x: %.*Rhxs!\n", offRec + NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED,
     479                                  cbAttrib - NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED,
     480                                  &pbRec[offRec + NTFSATTRIBHDR_SIZE_NONRES_UNCOMPRESSED]));
     481                    }
     482                }
     483                else
     484                    Log2(("NTFS:     !Attrib header is out of bound!\n"));
     485
     486                /* Advance. */
     487                offRec += RT_MAX(cbAttrib, NTFSATTRIBHDR_SIZE_RESIDENT);
     488            }
     489
     490            /* Anything left? */
     491            if (offRec < cbRecUsed)
     492                Log2(("NTFS:   @%#05x: Tail: %.*Rhxs\n", offRec, cbRecUsed - offRec, &pbRec[offRec]));
     493        }
     494        else
     495            Log2(("NTFS:   Unknown record type: %.4Rhxs\n", pFileRec));
     496    }
     497}
     498#endif /* LOG_ENABLED */
    96499
    97500
     
    165568    /** @todo read MFT, find bitmap allocation, implement
    166569     *        rtFsNtfsVol_QueryRangeState. */
     570
     571    PRTFSNTFSMFTREC pRec = rtFsNtfsMftRec_New(pThis, 0);
     572    AssertReturn(pRec, VERR_NO_MEMORY);
     573    pThis->pMft = pRec;
     574
     575    int rc = RTVfsFileReadAt(pThis->hVfsBacking, pThis->uLcnMft << pThis->cClusterShift, pRec->pbRec, pThis->cbMftRecord, NULL);
     576    if (RT_FAILURE(rc))
     577        return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading MFT record #0");
     578#ifdef LOG_ENABLED
     579    rtfsNtfsMftRec_Log(pRec);
     580#endif
     581
     582    //Log(("MFT#0:\n%.*Rhxd\n", pThis->cbMftRecord, pRec->pbRec));
     583
    167584    return VINF_SUCCESS;
    168585}
     
    189606     */
    190607    PFATBOOTSECTOR pBootSector = (PFATBOOTSECTOR)pvBuf;
    191     int rc = RTVfsFileRead(pThis->hVfsBacking, pBootSector, sizeof(*pBootSector), NULL);
     608    int rc = RTVfsFileReadAt(pThis->hVfsBacking, 0, pBootSector, sizeof(*pBootSector), NULL);
    192609    if (RT_FAILURE(rc))
    193610        return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading boot sector");
     
    287704        pThis->cbMftRecord = UINT32_C(1) << -pBootSector->Bpb.Ntfs.cClustersPerMftRecord;
    288705    Log2(("NTFS BPB: cbMftRecord=%#x\n", pThis->cbMftRecord));
     706    if (   pThis->cbMftRecord > _32K
     707        || pThis->cbMftRecord < 256)
     708        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
     709                                   "Unsupported NTFS MFT record size: %#x", pThis->cbMftRecord);
    289710
    290711    /* NTFS BPB: Index block size */
     
    319740{
    320741    AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
    321     AssertReturn(!(fMntFlags & RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
     742    AssertReturn(!(fMntFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
    322743    AssertReturn(!fNtfsFlags, VERR_INVALID_FLAGS);
    323744
     
    476897RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainNtfsVolReg, rtVfsChainNtfsVolReg);
    477898
    478 
  • trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp

    r69844 r69861  
    30083008    if (RT_SUCCESS(rc))
    30093009    {
    3010         if (pPath->cComponents > 0)
     3010        /*
     3011         * Tranverse the path, resolving the parent node.
     3012         * We'll do the symbolic link checking here with help of pfnOpen.
     3013         */
     3014        RTVFSDIRINTERNAL *pVfsParentDir;
     3015        rc = rtVfsDirTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
     3016        if (RT_SUCCESS(rc))
    30113017        {
    3012             RTVFSDIRINTERNAL *pVfsParentDir;
    3013             rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
    3014             if (RT_SUCCESS(rc))
     3018            /*
     3019             * Do the opening.  Loop if we need to follow symbolic links.
     3020             */
     3021            uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING;
     3022            for (uint32_t cLoops = 1;; cLoops++)
    30153023            {
    3016                 /*
    3017                  * Call the query method on the parent directory.
    3018                  */
    3019                 /** @todo symlink race condition here :/ */
     3024                /* If we end with a directory slash, adjust open flags. */
     3025                if (pPath->fDirSlash)
     3026                {
     3027                    fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
     3028                    if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
     3029                        fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
     3030                }
     3031                if (fObjFlags & RTPATH_F_FOLLOW_LINK)
     3032                    fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
     3033
     3034                /* Do the querying.  If pfnQueryEntryInfo is available, we use it first,
     3035                   falling back on pfnOpen in case of symbolic links that needs following. */
    30203036                const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
    3021                 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
    3022                 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
    3023                 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
    3024 
    3025                 RTVfsDirRelease(pVfsParentDir);
     3037                if (pVfsParentDir->pOps->pfnQueryEntryInfo)
     3038                {
     3039                    RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
     3040                    rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
     3041                    RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
     3042                    if (RT_FAILURE(rc))
     3043                        break;
     3044                    if (   !RTFS_IS_SYMLINK(pObjInfo->Attr.fMode)
     3045                        || !(fFlags & RTPATH_F_FOLLOW_LINK))
     3046                    {
     3047                        if (   (fObjFlags & RTVFSOBJ_F_OPEN_MASK) != RTVFSOBJ_F_OPEN_ANY
     3048                            && RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
     3049                            rc = VERR_NOT_A_DIRECTORY;
     3050                        break;
     3051                    }
     3052                }
     3053
     3054                RTVFSOBJ hVfsObj;
     3055                RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
     3056                rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName,
     3057                                                  RTFILE_O_ACCESS_ATTR_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
     3058                                                  fObjFlags, &hVfsObj);
     3059                RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
     3060                if (RT_FAILURE(rc))
     3061                    break;
     3062
     3063                /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
     3064                if (   !(fObjFlags & RTPATH_F_FOLLOW_LINK)
     3065                    || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
     3066                {
     3067                    rc = RTVfsObjQueryInfo(hVfsObj, pObjInfo, enmAddAttr);
     3068                    RTVfsObjRelease(hVfsObj);
     3069                    break;
     3070                }
     3071
     3072                /* Follow symbolic link. */
     3073                if (cLoops < RTVFS_MAX_LINKS)
     3074                    rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
     3075                else
     3076                    rc = VERR_TOO_MANY_SYMLINKS;
     3077                RTVfsObjRelease(hVfsObj);
     3078                if (RT_FAILURE(rc))
     3079                    break;
    30263080            }
    3027             else
    3028                 rc = VERR_INVALID_PARAMETER;
    3029         }
    3030         /*
    3031          * The path boils down to '.' so just query the directory.
    3032          */
    3033         else
    3034         {
    3035             RTVfsLockAcquireRead(pThis->Base.hLock);
    3036             rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
    3037             RTVfsLockReleaseRead(pThis->Base.hLock);
     3081
     3082            RTVfsDirRelease(pVfsParentDir);
    30383083        }
    30393084        RTVfsParsePathFree(pPath);
  • trunk/src/VBox/Runtime/common/vfs/vfsmount.cpp

    r69853 r69861  
    3535#include <iprt/assert.h>
    3636#include <iprt/err.h>
     37#include <iprt/file.h>
    3738#include <iprt/fsvfs.h>
    3839#include <iprt/mem.h>
    3940#include <iprt/log.h>
    4041#include <iprt/string.h>
     42#include <iprt/vfslowlevel.h>
    4143
    4244#include <iprt/formats/fat.h>
     
    422424
    423425    if (rtVfsMountIsNtfs(&pBuf->Bootsector))
    424         return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "NTFS not yet supported");
     426        return RTFsNtfsVolOpen(hVfsFileIn, fFlags, 0 /*fNtfsFlags*/, phVfs, pErrInfo);
    425427
    426428    if (rtVfsMountIsHpfs(&pBuf->Bootsector, hVfsFileIn, pBuf2))
     
    462464}
    463465
     466
     467/**
     468 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
     469 */
     470static DECLCALLBACK(int) rtVfsChainMountVol_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
     471                                                     PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
     472{
     473    RT_NOREF(pProviderReg);
     474
     475    /*
     476     * Basic checks.
     477     */
     478    if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
     479        return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
     480    if (   pElement->enmType != RTVFSOBJTYPE_VFS
     481        && pElement->enmType != RTVFSOBJTYPE_DIR)
     482        return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
     483    if (pElement->cArgs > 1)
     484        return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
     485
     486    /*
     487     * Parse the flag if present, save in pElement->uProvider.
     488     */
     489    bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
     490    if (pElement->cArgs > 0)
     491    {
     492        const char *psz = pElement->paArgs[0].psz;
     493        if (*psz)
     494        {
     495            if (!strcmp(psz, "ro"))
     496                fReadOnly = true;
     497            else if (!strcmp(psz, "rw"))
     498                fReadOnly = false;
     499            else
     500            {
     501                *poffError = pElement->paArgs[0].offSpec;
     502                return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
     503            }
     504        }
     505    }
     506
     507    pElement->uProvider = fReadOnly ? RTVFSMNT_F_READ_ONLY : 0;
     508    return VINF_SUCCESS;
     509}
     510
     511
     512/**
     513 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
     514 */
     515static DECLCALLBACK(int) rtVfsChainMountVol_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
     516                                                        PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
     517                                                        PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
     518{
     519    RT_NOREF(pProviderReg, pSpec, poffError);
     520
     521    int         rc;
     522    RTVFSFILE   hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
     523    if (hVfsFileIn != NIL_RTVFSFILE)
     524    {
     525        RTVFS hVfs;
     526        rc = RTVfsMountVol(hVfsFileIn, (uint32_t)pElement->uProvider, &hVfs, pErrInfo);
     527        RTVfsFileRelease(hVfsFileIn);
     528        if (RT_SUCCESS(rc))
     529        {
     530            *phVfsObj = RTVfsObjFromVfs(hVfs);
     531            RTVfsRelease(hVfs);
     532            if (*phVfsObj != NIL_RTVFSOBJ)
     533                return VINF_SUCCESS;
     534            rc = VERR_VFS_CHAIN_CAST_FAILED;
     535        }
     536    }
     537    else
     538        rc = VERR_VFS_CHAIN_CAST_FAILED;
     539    return rc;
     540}
     541
     542
     543/**
     544 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
     545 */
     546static DECLCALLBACK(bool) rtVfsChainMountVol_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
     547                                                             PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
     548                                                             PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
     549{
     550    RT_NOREF(pProviderReg, pSpec, pReuseSpec);
     551    if (   pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
     552        || !pReuseElement->paArgs[0].uProvider)
     553        return true;
     554    return false;
     555}
     556
     557
     558/** VFS chain element 'file'. */
     559static RTVFSCHAINELEMENTREG g_rtVfsChainMountVolReg =
     560{
     561    /* uVersion = */            RTVFSCHAINELEMENTREG_VERSION,
     562    /* fReserved = */           0,
     563    /* pszName = */             "mount",
     564    /* ListEntry = */           { NULL, NULL },
     565    /* pszHelp = */             "Open a file system, requires a file object on the left side.\n"
     566                                "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
     567    /* pfnValidate = */         rtVfsChainMountVol_Validate,
     568    /* pfnInstantiate = */      rtVfsChainMountVol_Instantiate,
     569    /* pfnCanReuseElement = */  rtVfsChainMountVol_CanReuseElement,
     570    /* uEndMarker = */          RTVFSCHAINELEMENTREG_VERSION
     571};
     572
     573RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainMountVolReg, rtVfsChainMountVolReg);
     574
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette