VirtualBox

Changeset 69924 in vbox


Ignore:
Timestamp:
Dec 4, 2017 9:12:01 PM (7 years ago)
Author:
vboxsync
Message:

iprt/ntfsvfs.cpp: working on the directory access (readonly) bits

Location:
trunk
Files:
3 edited

Legend:

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

    r69910 r69924  
    8585
    8686/** @name NTFSMFTREF_GET_IDX
    87  * Gets the MFT index number from a MFT reference. */
     87 * Gets the MFT index number (host endian) from a MFT reference. */
    8888/** @name NTFSMFTREF_GET_SEQ
    89  * Gets the MFT reuse sequence number from a MFT reference. */
     89 * Gets the MFT reuse sequence number (host endian) from a MFT reference. */
    9090/** @name NTFSMFTREF_SET_IDX
    9191 * Sets the MFT index number of a MFT reference. */
     
    120120    } while (0)
    121121#endif
     122/** Check that the reference is zero. */
     123#define NTFSMFTREF_IS_ZERO(a_pMftRef)               ((a_pMftRef)->u64 == 0)
    122124
    123125
     
    437439#define NTFSATSTDINFO_SIZE_NTFS_V12     (0x30)
    438440
    439 /** @name NTFS_FA_XXX - NTFS file attributes.
     441/** @name NTFS_FA_XXX - NTFS file attributes (host endian).
    440442 * @{ */
    441443#define NTFS_FA_READONLY                            UINT32_C(0x00000001)
     
    480482    /** 0x30: Actual size of unnamed data attribute. */
    481483    int64_t             cbData;
    482     /** 0x38: File attributes. */
     484    /** 0x38: File attributes (NTFS_FA_XXX). */
    483485    uint32_t            fFileAttribs;
    484486    union
     
    588590#define NTFSINDEXHDR_F_INTERNAL        UINT8_C(0x01)
    589591/** @} */
     592
     593/** Gets the pointer to the first entry header for an index.  */
     594#define NTFSINDEXHDR_GET_FIRST_ENTRY(a_pIndexHdr) \
     595    ( (PNTFSIDXENTRYHDR)((uint8_t *)(a_pIndexHdr) + RT_LE2H_U32((a_pIndexHdr)->offFirstEntry)) )
    590596
    591597
  • trunk/src/VBox/Runtime/common/fs/isovfs.cpp

    r69844 r69924  
    22102210 *
    22112211 * @returns IPRT status code.
    2212  * @param   pThis           The FAT volume instance.
     2212 * @param   pThis           The ISO volume instance.
    22132213 * @param   pParentDir      The parent directory (shared part).
    22142214 * @param   pDirRec         The directory record.
     
    22812281 *
    22822282 * @returns IPRT status code.
    2283  * @param   pThis           The FAT volume instance.
     2283 * @param   pThis           The ISO volume instance.
    22842284 * @param   pParentDir      The parent directory (shared part).
    22852285 * @param   pFid            The file ID descriptor.  (Points to parent directory
     
    29102910
    29112911    /*
    2912      * Special cases '.' and '.'
     2912     * Special cases '.' and '..'
    29132913     */
    29142914    if (pszEntry[0] == '.')
     
    34843484
    34853485/**
    3486  * FAT file operations.
     3486 * ISO file operations.
    34873487 */
    34883488static const RTVFSDIROPS g_rtFsIsoDirOps =
     
    36383638 *
    36393639 * @returns IPRT status code.
    3640  * @param   pThis           The FAT volume instance.
     3640 * @param   pThis           The ISO volume instance.
    36413641 * @param   pParentDir      The parent directory.  This is NULL for the root
    36423642 *                          directory.
     
    37853785 *
    37863786 * @returns IPRT status code.
    3787  * @param   pThis           The FAT volume instance.
     3787 * @param   pThis           The ISO volume instance.
    37883788 * @param   pParentDir      The parent directory.  This is NULL for the root
    37893789 *                          directory.
     
    38493849 *
    38503850 * @returns IPRT status code.
    3851  * @param   pThis           The FAT volume instance.
     3851 * @param   pThis           The ISO volume instance.
    38523852 * @param   pShared         Referenced pointer to the shared structure.  The
    38533853 *                          reference is always CONSUMED.
     
    38853885 *
    38863886 * @returns IPRT status code.
    3887  * @param   pThis           The FAT volume instance.
     3887 * @param   pThis           The ISO volume instance.
    38883888 * @param   pParentDir      The parent directory.  This is NULL for the root
    38893889 *                          directory.
     
    39183918 *
    39193919 * @returns IPRT status code.
    3920  * @param   pThis           The FAT volume instance.
     3920 * @param   pThis           The ISO volume instance.
    39213921 * @param   pParentDir      The parent directory.
    39223922 * @param   pFid            The file ID descriptor for the directory.
     
    56575657 * @param   pThis           The ISO VFS instance to initialize.
    56585658 * @param   hVfsSelf        The ISO VFS handle (no reference consumed).
    5659  * @param   hVfsBacking     The file backing the alleged FAT file system.
     5659 * @param   hVfsBacking     The file backing the alleged ISO file system.
    56605660 *                          Reference is consumed (via rtFsIsoVol_Close).
    56615661 * @param   fFlags          Flags, RTFSISO9660_F_XXX.
     
    59255925
    59265926    /*
    5927      * Create a new FAT VFS instance and try initialize it using the given input file.
     5927     * Create a new ISO VFS instance and try initialize it using the given input file.
    59285928     */
    59295929    RTVFS hVfs   = NIL_RTVFS;
  • trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp

    r69913 r69924  
    4848*   Defined Constants And Macros                                                                                                 *
    4949*********************************************************************************************************************************/
    50 /** The maximum bitmap cache size. */
    51 #define RTFSNTFS_MAX_BITMAP_CACHE           _64K
     50/** The maximum bitmap size to try cache in its entirity (in bytes).  */
     51#define RTFSNTFS_MAX_WHOLE_BITMAP_CACHE     _64K
     52/** The maximum node cache size (in bytes).    */
     53#if ARCH_BITS >= 64
     54# define RTFSNTFS_MAX_NODE_CACHE_SIZE        _1M
     55#else
     56# define RTFSNTFS_MAX_NODE_CACHE_SIZE        _256K
     57#endif
    5258
    5359/** Makes a combined NTFS version value.
     
    6571/** Poitner to a NTFS core object record.   */
    6672typedef struct RTFSNTFSCORE *PRTFSNTFSCORE;
     73/** Pointer to an index node. */
     74typedef struct RTFSNTFSIDXNODE *PRTFSNTFSIDXNODE;
     75/** Pointer to a shared NTFS directory object. */
     76typedef struct RTFSNTFSDIRSHRD *PRTFSNTFSDIRSHRD;
     77/** Pointer to a shared NTFS file object. */
     78typedef struct RTFSNTFSFILESHRD *PRTFSNTFSFILESHRD;
    6779
    6880
     
    173185    /** Pointer to any subrecords containing further allocation extents. */
    174186    PRTFSNTFSATTRSUBREC pSubRecHead;
     187    /** Pointer to the VFS object for this attribute.
     188     * This is a weak reference since it's the VFS object that is referencing us. */
     189    union
     190    {
     191        /** Pointer to a shared directory (NTFS_AT_DIRECTORY). */
     192        PRTFSNTFSDIRSHRD    pSharedDir;
     193        /** Pointer to a shared file (NTFS_AT_DATA). */
     194        PRTFSNTFSFILESHRD   pSharedFile;
     195    } uObj;
    175196} RTFSNTFSATTR;
    176197/** Pointer to a attribute structure. */
     
    194215} RTFSNTFSCORE;
    195216
    196 /**
    197  * Pointer to a shared NTFS directory object.
    198  */
    199 typedef 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 
     217
     218/**
     219 * Node lookup information for facilitating binary searching of node.
     220 */
     221typedef struct RTFSNTFSIDXNODEINFO
     222{
     223    /** The index header. */
     224    PCNTFSINDEXHDR      pIndexHdr;
     225    /** Number of entries. */
     226    uint32_t            cEntries;
     227    /** Set if internal node. */
     228    bool                fInternal;
     229    /** Array with pointers to the entries. */
     230    PCNTFSIDXENTRYHDR  *papEntries;
     231    /** Pointer to the index node this info is for, NULL if root node.
     232     * This is for reducing the enumeration stack entry size. */
     233    PRTFSNTFSIDXNODE    pNode;
     234    /** Pointer to the NTFS volume instace. */
     235    PRTFSNTFSVOL        pVol;
     236} RTFSNTFSIDXNODEINFO;
     237/** Pointer to index node lookup info. */
     238typedef RTFSNTFSIDXNODEINFO *PRTFSNTFSIDXNODEINFO;
     239/** Pointer to const index node lookup info. */
     240typedef RTFSNTFSIDXNODEINFO const *PCRTFSNTFSIDXNODEINFO;
     241
     242/**
     243 * Index node, cached.
     244 *
     245 * These are cached to avoid reading, validating and parsing things each time a
     246 * subnode is accessed.
     247 */
     248typedef struct RTFSNTFSIDXNODE
     249{
     250    /** Entry in RTFSNTFSVOL::IdxNodeCahceRoot, key is disk byte offset. */
     251    AVLU64NODECORE          TreeNode;
     252    /** List entry on the unused list.  Gets removed from it when cRefs is
     253     * increase to one, and added when it reaches zero. */
     254    RTLISTNODE              UnusedListEntry;
     255    /** Reference counter. */
     256    uint32_t volatile       cRefs;
     257    /** The estimated memory cost of this node. */
     258    uint32_t                cbCost;
     259    /** Pointer to the node data. */
     260    PNTFSATINDEXALLOC       pNode;
     261    /** Node info. */
     262    RTFSNTFSIDXNODEINFO     NodeInfo;
     263} RTFSNTFSIDXNODE;
     264
     265/**
     266 * Common index root structure.
     267 */
     268typedef struct RTFSNTFSIDXROOTINFO
     269{
     270    /** Pointer to the index root attribute value. */
     271    PCNTFSATINDEXROOT       pRoot;
    209272    /** Pointer to the index allocation attribute, if present.
    210273     * This and the bitmap may be absent if the whole directory fits into the
    211274     * root index. */
    212     PRTFSNTFSATTR       pIndexAlloc;
    213     /** Pointer to the index allocation bitmap attribute, if present. */
    214     PRTFSNTFSATTR       pIndexBitmap;
    215 
     275    PRTFSNTFSATTR           pAlloc;
     276    /** End of the node addresses range (exclusive). */
     277    uint64_t                uEndNodeAddresses;
     278    /** Node address misalignement mask. */
     279    uint32_t                fNodeAddressMisalign;
     280    /** The byte shift count for node addresses. */
     281    uint8_t                 cNodeAddressByteShift;
     282    /** Node info for the root. */
     283    RTFSNTFSIDXNODEINFO     NodeInfo;
     284    /** Pointer to the index root attribute.  We reference the core thru this and
     285     *  use it to zero RTFSNTFSATTR::uObj::pSharedDir on destruction. */
     286    PRTFSNTFSATTR           pRootAttr;
     287} RTFSNTFSIDXROOTINFO;
     288/** Pointer to an index root structure. */
     289typedef RTFSNTFSIDXROOTINFO *PRTFSNTFSIDXROOTINFO;
     290/** Pointer to a const index root structure. */
     291typedef RTFSNTFSIDXROOTINFO const *PCRTFSNTFSIDXROOTINFO;
     292
     293/**
     294 * Pointer to a shared NTFS directory object.
     295 */
     296typedef struct RTFSNTFSDIRSHRD
     297{
     298    /** Reference counter.   */
     299    uint32_t volatile       cRefs;
     300    /** Index root information. */
     301    RTFSNTFSIDXROOTINFO     RootInfo;
    216302} RTFSNTFSDIRSHRD;
    217 /** Pointer to a shared NTFS directory object. */
    218 typedef RTFSNTFSDIRSHRD *PRTFSNTFSDIRSHRD;
     303
     304/**
     305 * Index stack entry for index enumeration.
     306 */
     307typedef struct RTFSNTFSIDXSTACKENTRY
     308{
     309    /** The next entry to process in this stack entry. */
     310    uint32_t                iNext;
     311    /** Pointer to the node info for this entry. */
     312    PRTFSNTFSIDXNODEINFO    pNodeInfo;
     313} RTFSNTFSIDXSTACKENTRY;
     314/** Pointer to an index enumeration stack entry. */
     315typedef RTFSNTFSIDXSTACKENTRY *PRTFSNTFSIDXSTACKENTRY;
     316
     317
     318/**
     319 * Open directory instance.
     320 */
     321typedef struct RTFSNTFSDIR
     322{
     323    /** Pointer to the shared directory instance (referenced). */
     324    PRTFSNTFSDIRSHRD        pShared;
     325    /** Set if we've reached the end of the directory enumeration. */
     326    bool                    fNoMoreFiles;
     327    /** The enumeration stack size. */
     328    uint32_t                cEnumStackEntries;
     329    /** The allocated enumeration stack depth.    */
     330    uint32_t                cEnumStackMaxDepth;
     331    /** The numeration stack.  Allocated as needed. */
     332    PRTFSNTFSIDXSTACKENTRY  paEnumStack;
     333} RTFSNTFSDIR;
     334/** Pointer to an open directory instance. */
     335typedef RTFSNTFSDIR *PRTFSNTFSDIR;
    219336
    220337
     
    225342{
    226343    /** Handle to itself. */
    227     RTVFS           hVfsSelf;
     344    RTVFS               hVfsSelf;
    228345    /** The file, partition, or whatever backing the NTFS volume. */
    229     RTVFSFILE       hVfsBacking;
     346    RTVFSFILE           hVfsBacking;
    230347    /** The size of the backing thingy. */
    231     uint64_t        cbBacking;
     348    uint64_t            cbBacking;
    232349    /** The formatted size of the volume. */
    233     uint64_t        cbVolume;
     350    uint64_t            cbVolume;
    234351    /** cbVolume expressed as a cluster count. */
    235     uint64_t        cClusters;
     352    uint64_t            cClusters;
    236353
    237354    /** RTVFSMNT_F_XXX. */
    238     uint32_t        fMntFlags;
     355    uint32_t            fMntFlags;
    239356    /** RTFSNTVFS_F_XXX (currently none defined). */
    240     uint32_t        fNtfsFlags;
     357    uint32_t            fNtfsFlags;
    241358
    242359    /** The (logical) sector size. */
    243     uint32_t        cbSector;
     360    uint32_t            cbSector;
    244361
    245362    /** The (logical) cluster size. */
    246     uint32_t        cbCluster;
     363    uint32_t            cbCluster;
    247364    /** Max cluster count value that won't overflow a signed 64-bit when
    248365     * converted to bytes.  Inclusive. */
    249     uint64_t        iMaxVirtualCluster;
     366    uint64_t            iMaxVirtualCluster;
    250367    /** The shift count for converting between bytes and clusters. */
    251     uint8_t         cClusterShift;
     368    uint8_t             cClusterShift;
    252369
    253370    /** Explicit padding. */
    254     uint8_t         abReserved[3];
     371    uint8_t             abReserved[3];
    255372    /** The NTFS version of the volume (RTFSNTFS_MAKE_VERSION). */
    256     uint16_t        uNtfsVersion;
     373    uint16_t            uNtfsVersion;
    257374    /** The NTFS_VOLUME_F_XXX. */
    258     uint16_t        fVolumeFlags;
     375    uint16_t            fVolumeFlags;
    259376
    260377    /** The logical cluster number of the MFT. */
    261     uint64_t        uLcnMft;
     378    uint64_t            uLcnMft;
    262379    /** The logical cluster number of the mirror MFT. */
    263     uint64_t        uLcnMftMirror;
     380    uint64_t            uLcnMftMirror;
    264381
    265382    /** The MFT record size. */
    266     uint32_t        cbMftRecord;
     383    uint32_t            cbMftRecord;
    267384    /** The default index (B-tree) node size. */
    268     uint32_t        cbDefaultIndexNode;
     385    uint32_t            cbDefaultIndexNode;
    269386
    270387    /** The volume serial number. */
    271     uint64_t        uSerialNo;
     388    uint64_t            uSerialNo;
    272389
    273390    /** The '$Mft' data attribute. */
    274     PRTFSNTFSATTR   pMftData;
    275 
    276     /** The root directory. */
    277     PRTFSNTFSDIRSHRD pRootDir;
     391    PRTFSNTFSATTR       pMftData;
    278392
    279393    /** @name Allocation bitmap and cache.
    280394     * @{ */
    281395    /** The '$Bitmap' data attribute. */
    282     PRTFSNTFSATTR   pMftBitmap;
     396    PRTFSNTFSATTR       pMftBitmap;
    283397    /** The first cluster currently loaded into the bitmap cache . */
    284     uint64_t        iFirstBitmapCluster;
     398    uint64_t            iFirstBitmapCluster;
    285399    /** The number of clusters currently loaded into the bitmap cache */
    286     uint32_t        cBitmapClusters;
     400    uint32_t            cBitmapClusters;
    287401    /** The size of the pvBitmap allocation. */
    288     uint32_t        cbBitmapAlloc;
     402    uint32_t            cbBitmapAlloc;
    289403    /** Allocation bitmap cache buffer. */
    290     void           *pvBitmap;
     404    void               *pvBitmap;
    291405    /** @} */
    292406
     407    /** Root of the MFT record tree (RTFSNTFSMFTREC). */
     408    AVLU64TREE          MftRoot;
     409
     410    /** @name Directory/index related.
     411     * @{ */
     412    /** Tree of index nodes, index by disk byte offset. (RTFSNTFSIDXNODE) */
     413    AVLU64TREE          IdxNodeCacheRoot;
     414    /** List of currently unreferenced index nodes. (RTFSNTFSIDXNODE)
     415     * Most recently used nodes are found at the end of the list.  Nodes are added
     416     * when their reference counter reaches zero.  They are removed when it
     417     * increases to one again.
     418     *
     419     * The nodes are still in the index node cache tree (IdxNodeCacheRoot), but
     420     * we'll trim this from the end when we reach a certain size. */
     421    RTLISTANCHOR        IdxNodeUnusedHead;
     422    /** Number of unreferenced index nodes. */
     423    uint32_t            cUnusedIdxNodes;
     424    /** Number of cached index nodes. */
     425    uint32_t            cIdxNodes;
     426    /** Total index node memory cost. */
     427    size_t              cbIdxNodes;
     428    /** The root directory. */
     429    PRTFSNTFSDIRSHRD    pRootDir;
    293430    /** Lower to uppercase conversion table for this filesystem.
    294      * This always has 64K valid entries.  */
    295     PRTUTF16        pawcUpcase;
    296 
    297     /** Root of the MFT record tree (RTFSNTFSMFTREC). */
    298     AVLU64TREE      MftRoot;
     431     * This always has 64K valid entries. */
     432    PRTUTF16            pawcUpcase;
     433    /** @} */
    299434
    300435} RTFSNTFSVOL;
     
    306441*********************************************************************************************************************************/
    307442static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis);
     443static uint32_t rtFsNtfsCore_Retain(PRTFSNTFSCORE pThis);
    308444#ifdef LOG_ENABLED
    309445static void     rtFsNtfsVol_LogIndexRoot(PCNTFSATINDEXROOT pIdxRoot, uint32_t cbIdxRoot);
    310446#endif
     447static int      rtFsNtfsVol_NewDirFromShared(PRTFSNTFSVOL pThis, PRTFSNTFSDIRSHRD pSharedDir, PRTVFSDIR phVfsDir);
     448static uint32_t rtFsNtfsDirShrd_Retain(PRTFSNTFSDIRSHRD pThis);
     449static uint32_t rtFsNtfsIdxNode_Release(PRTFSNTFSIDXNODE pNode);
     450static uint32_t rtFsNtfsIdxNode_Retain(PRTFSNTFSIDXNODE pNode);
    311451
    312452
     
    567707                                    Log2(("NTFS:     cwcFilename        %#x\n", pInfo->cwcFilename));
    568708                                    Log2(("NTFS:     fFilenameType      %#x\n", pInfo->fFilenameType));
    569                                     if (cbValue >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename))
     709                                    if (RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pInfo->cwcFilename]) <= cbValue)
    570710                                        Log2(("NTFS:     wszFilename       '%.*ls'\n", pInfo->cwcFilename, pInfo->wszFilename ));
    571711                                    else
     
    11321272
    11331273
     1274/**
     1275 * Translates a attribute value offset to a disk offset.
     1276 *
     1277 * @returns Disk offset, UINT64_MAX if not translatable for some reason.
     1278 * @param   pAttr           The
     1279 * @param   off             The offset to translate.
     1280 * @param   pcbValid        Where to return the run length at the return offset.
     1281 *                          Optional.
     1282 */
     1283static uint64_t rtFsNtfsAttr_OffsetToDisk(PRTFSNTFSATTR pAttr, uint64_t off, uint64_t *pcbValid)
     1284{
     1285    /*
     1286     * Searching the extend list is a tad complicated since it starts in one
     1287     * structure and continues in a different one.  But whatever.
     1288     */
     1289    PRTFSNTFSEXTENTS    pTable   = &pAttr->Extents;
     1290    PRTFSNTFSATTRSUBREC pCurSub  = NULL;
     1291    for (;;)
     1292    {
     1293        if (off < pTable->cbData)
     1294        {
     1295            uint32_t iExtent  = 0;
     1296            while (   iExtent < pTable->cExtents
     1297                   && off >= pTable->paExtents[iExtent].cbExtent)
     1298            {
     1299                off -= pTable->paExtents[iExtent].cbExtent;
     1300                iExtent++;
     1301            }
     1302            AssertReturn(iExtent < pTable->cExtents, UINT64_MAX);
     1303            if (pcbValid)
     1304                *pcbValid = pTable->paExtents[iExtent].cbExtent - off;
     1305            return pTable->paExtents[iExtent].off != UINT64_MAX ? pTable->paExtents[iExtent].off + off : UINT64_MAX;
     1306        }
     1307
     1308        /* Next table. */
     1309        off -= pTable->cbData;
     1310        if (!pCurSub)
     1311            pCurSub = pAttr->pSubRecHead;
     1312        else
     1313            pCurSub = pCurSub->pNext;
     1314        if (!pCurSub)
     1315        {
     1316            if (pcbValid)
     1317                *pcbValid = 0;
     1318            return UINT64_MAX;
     1319        }
     1320        pTable = &pCurSub->Extents;
     1321    }
     1322    /* not reached */
     1323}
     1324
     1325
    11341326static int rtFsNtfsAttr_Read(PRTFSNTFSATTR pAttr, uint64_t off, void *pvBuf, size_t cbToRead)
    11351327{
     
    14111603
    14121604/**
     1605 * Queries the core object struct for the given MFT record reference.
     1606 *
     1607 * Does caching.
     1608 *
     1609 * @returns IPRT status code.
     1610 * @param   pThis           The NTFS volume instance.
     1611 * @param   pMftRef         The MFT reference to get the corresponding core
     1612 *                          for.
     1613 * @param   fRelaxedUsa     Relaxed update sequence checking. Won't fail if
     1614 *                          checks doesn't work or not present.
     1615 * @param   ppCore          Where to return the referenced core object
     1616 *                          structure.
     1617 * @param   pErrInfo        Where to return error details.  Optional.
     1618 */
     1619static int rtFsNtfsVol_QueryCoreForMftRef(PRTFSNTFSVOL pThis, PCNTFSMFTREF pMftRef , bool fRelaxedUsa,
     1620                                          PRTFSNTFSCORE *ppCore, PRTERRINFO pErrInfo)
     1621{
     1622    *ppCore = NULL;
     1623    Assert(pThis->pMftData);
     1624
     1625    int rc;
     1626    PRTFSNTFSMFTREC pMftRec = (PRTFSNTFSMFTREC)RTAvlU64Get(&pThis->MftRoot, NTFSMFTREF_GET_IDX(pMftRef));
     1627    if (pMftRec)
     1628    {
     1629        /*
     1630         * Cache hit.  Check that the resure sequence number matches.
     1631         * To be slightly paranoid, also check that it's a base MFT record and that it has been parsed already.
     1632         */
     1633        if (RT_LE2H_U16(pMftRec->pFileRec->uRecReuseSeqNo) == NTFSMFTREF_GET_SEQ(pMftRef))
     1634        {
     1635            if (   NTFSMFTREF_IS_ZERO(&pMftRec->pFileRec->BaseMftRec)
     1636                && pMftRec->pCore)
     1637            {
     1638                rtFsNtfsCore_Retain(pMftRec->pCore);
     1639                *ppCore = pMftRec->pCore;
     1640                rc = VINF_SUCCESS;
     1641            }
     1642            else
     1643                AssertLogRelMsgFailedStmt(("pCore=%p; BaseMftRec=%#RX64 sqn %#x\n", pMftRec->pCore,
     1644                                           NTFSMFTREF_GET_IDX(&pMftRec->pFileRec->BaseMftRec),
     1645                                           NTFSMFTREF_GET_SEQ(&pMftRec->pFileRec->BaseMftRec)),
     1646                                           rc = VERR_INTERNAL_ERROR_3 );
     1647        }
     1648        else
     1649            rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_OFFSET,
     1650                                         "Stale parent directory MFT reference: %#RX64 sqn %#x - current sqn %#x",
     1651                                         NTFSMFTREF_GET_IDX(pMftRef), NTFSMFTREF_GET_SEQ(pMftRef),
     1652                                         RT_LE2H_U16(pMftRec->pFileRec->uRecReuseSeqNo) );
     1653    }
     1654    else
     1655    {
     1656        /*
     1657         * Load new and check that the reuse sequence number match.
     1658         */
     1659        rc = rtFsNtfsVol_NewCoreForMftIdx(pThis, NTFSMFTREF_GET_IDX(pMftRef), fRelaxedUsa, ppCore, pErrInfo);
     1660        if (RT_SUCCESS(rc))
     1661        {
     1662            PRTFSNTFSCORE pCore = *ppCore;
     1663            if (RT_LE2H_U16(pCore->pMftRec->pFileRec->uRecReuseSeqNo) == NTFSMFTREF_GET_SEQ(pMftRef))
     1664                rc = VINF_SUCCESS;
     1665            else
     1666            {
     1667                rtFsNtfsCore_Release(pCore);
     1668                *ppCore = NULL;
     1669                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_OFFSET,
     1670                                             "Stale parent directory MFT reference: %#RX64 sqn %#x - current sqn %#x",
     1671                                             NTFSMFTREF_GET_IDX(pMftRef), NTFSMFTREF_GET_SEQ(pMftRef),
     1672                                             RT_LE2H_U16(pCore->pMftRec->pFileRec->uRecReuseSeqNo) );
     1673            }
     1674        }
     1675    }
     1676    return rc;
     1677}
     1678
     1679
     1680/**
    14131681 * Destroys a core structure.
    14141682 *
     
    14851753
    14861754
    1487 #if 0 /* currently unused */
    14881755/**
    14891756 * Retains a refernece to a core structure.
     
    14981765    return cRefs;
    14991766}
    1500 #endif
    15011767
    15021768
     
    16291895            Log2(("NTFS:             Subnode=%#RX64\n", RT_LE2H_U64(NTFSIDXENTRYHDR_GET_SUBNODE(pEntryHdr)) ));
    16301896
    1631         if (   RT_LE2H_U16(pEntryHdr->cbKey) >= sizeof(NTFSATFILENAME)
     1897        if (   RT_LE2H_U16(pEntryHdr->cbKey) >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename)
    16321898            && uIdxType == NTFSATINDEXROOT_TYPE_DIR)
    16331899        {
    16341900            PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)(pEntryHdr + 1);
    1635             Log2(("NTFS:             Filename=%.*ls\n", pFilename->cwcFilename, pFilename->wszFilename));
     1901            RTTIMESPEC       Spec;
     1902            char             sz[80];
     1903            Log2(("NTFS:             iCreationTime      %#RX64 %s\n", RT_LE2H_U64(pFilename->iCreationTime),
     1904                  RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pFilename->iCreationTime)), sz, sizeof(sz)) ));
     1905            Log2(("NTFS:             iLastDataModTime   %#RX64 %s\n", RT_LE2H_U64(pFilename->iLastDataModTime),
     1906                  RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pFilename->iLastDataModTime)), sz, sizeof(sz)) ));
     1907            Log2(("NTFS:             iLastMftModTime    %#RX64 %s\n", RT_LE2H_U64(pFilename->iLastMftModTime),
     1908                  RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pFilename->iLastMftModTime)), sz, sizeof(sz)) ));
     1909            Log2(("NTFS:             iLastAccessTime    %#RX64 %s\n", RT_LE2H_U64(pFilename->iLastAccessTime),
     1910                  RTTimeSpecToString(RTTimeSpecSetNtTime(&Spec, RT_LE2H_U64(pFilename->iLastAccessTime)), sz, sizeof(sz)) ));
     1911            Log2(("NTFS:             cbAllocated        %#RX64 (%Rhcb)\n",
     1912                  RT_LE2H_U64(pFilename->cbAllocated), RT_LE2H_U64(pFilename->cbAllocated)));
     1913            Log2(("NTFS:             cbData             %#RX64 (%Rhcb)\n",
     1914                  RT_LE2H_U64(pFilename->cbData), RT_LE2H_U64(pFilename->cbData)));
     1915            Log2(("NTFS:             fFileAttribs       %#RX32\n", RT_LE2H_U32(pFilename->fFileAttribs) ));
     1916            if (RT_LE2H_U32(pFilename->fFileAttribs) & NTFS_FA_REPARSE_POINT)
     1917                Log2(("NTFS:             uReparseTag        %#RX32\n", RT_LE2H_U32(pFilename->u.uReparseTag) ));
     1918            else
     1919                Log2(("NTFS:             cbPackedEas        %#RX16\n", RT_LE2H_U16(pFilename->u.cbPackedEas) ));
     1920            Log2(("NTFS:             cwcFilename        %#x\n", pFilename->cwcFilename));
     1921            Log2(("NTFS:             fFilenameType      %#x\n", pFilename->fFilenameType));
     1922            if (RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]) <= RT_LE2H_U16(pEntryHdr->cbKey))
     1923                Log2(("NTFS:             wszFilename       '%.*ls'\n", pFilename->cwcFilename, pFilename->wszFilename ));
     1924            else
     1925                Log2(("NTFS:             Error! Truncated filename!!\n"));
    16361926        }
    16371927
     
    17122002
    17132003
     2004/**
     2005 * Validates an index header.
     2006 *
     2007 * @returns IPRT status code.
     2008 * @param   pRootInfo           Pointer to the index root info.
     2009 * @param   pNodeInfo           Pointer to the node info structure to load.
     2010 * @param   pIndexHdr           Pointer to the index header.
     2011 * @param   cbIndex             Size of the index.
     2012 * @param   pErrInfo            Where to return extra error info.
     2013 * @param   pszWhat             Error prefix.
     2014 */
     2015static int rtFsNtfsVol_LoadIndexNodeInfo(PCRTFSNTFSIDXROOTINFO pRootInfo, PRTFSNTFSIDXNODEINFO pNodeInfo, PCNTFSINDEXHDR pIndexHdr,
     2016                                         uint32_t cbIndex, PRTERRINFO pErrInfo, const char *pszWhat)
     2017{
     2018    uint32_t const cbMinIndex = sizeof(*pIndexHdr) + sizeof(NTFSIDXENTRYHDR);
     2019    if (cbIndex < cbMinIndex)
     2020        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2021                                       "%s: Not enough room for the index header and one entry header! cbIndex=%#x (cbMinIndex=%#x)",
     2022                                       pszWhat, cbIndex, cbMinIndex);
     2023    uint32_t const cbAllocated = RT_LE2H_U32(pIndexHdr->cbAllocated);
     2024    if (   cbAllocated > cbIndex
     2025        || cbAllocated < cbMinIndex
     2026        || (cbAllocated & 7) )
     2027        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2028                                       "%s: Bogus index allocation size: %#x (min %#x, max %#x, 8 byte aligned)",
     2029                                       pszWhat, cbAllocated, cbMinIndex, cbIndex);
     2030    uint32_t const cbUsed = RT_LE2H_U32(pIndexHdr->cbUsed);
     2031    if (   cbUsed > cbAllocated
     2032        || cbUsed < cbMinIndex
     2033        || (cbUsed & 7) )
     2034        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2035                                       "%s: Bogus index used size: %#x (min %#x, max %#x, 8 byte aligned)",
     2036                                       pszWhat, cbUsed, cbMinIndex, cbAllocated);
     2037    uint32_t const offFirstEntry = RT_LE2H_U32(pIndexHdr->offFirstEntry);
     2038    if (   offFirstEntry < sizeof(*pIndexHdr)
     2039        || offFirstEntry >= cbUsed - sizeof(NTFSIDXENTRYHDR)
     2040        || (offFirstEntry & 7) )
     2041        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2042                                       "%s: Bogus first entry offset: %#x (min %#x, max %#x, 8 byte aligned)",
     2043                                       pszWhat, offFirstEntry, sizeof(*pIndexHdr), cbUsed - sizeof(NTFSIDXENTRYHDR));
     2044
     2045    /*
     2046     * The index entries.
     2047     */
     2048    uint32_t const uType = pRootInfo->pRoot->uType;
     2049    uint32_t offEntry = offFirstEntry;
     2050    uint32_t iEntry = 0;
     2051    for (;;)
     2052    {
     2053        if (offEntry + sizeof(NTFSIDXENTRYHDR) > cbUsed)
     2054            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2055                                           "%s: Entry #%u is out of bound: offset %#x (cbUsed=%#x)",
     2056                                           pszWhat, iEntry, offEntry, cbUsed);
     2057        PCNTFSIDXENTRYHDR pEntryHdr     = (PCNTFSIDXENTRYHDR)((uint8_t const *)pIndexHdr + offEntry);
     2058        uint16_t const    cbEntry       = RT_LE2H_U16(pEntryHdr->cbEntry);
     2059        uint32_t const    cbSubnodeAddr = (pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_INTERNAL ? sizeof(int64_t) : 0);
     2060        uint32_t const    cbMinEntry    = sizeof(*pEntryHdr) + cbSubnodeAddr;
     2061        if (   cbEntry < cbMinEntry
     2062            || offEntry + cbEntry > cbUsed
     2063            || (cbEntry & 7) )
     2064            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2065                                           "%s: Entry #%u has a bogus size: %#x (min %#x, max %#x, 8 byte aligned)",
     2066                                           pszWhat, iEntry, cbEntry, cbMinEntry, cbUsed - offEntry);
     2067
     2068        uint32_t const cbMaxKey = cbEntry - sizeof(*pEntryHdr) - cbSubnodeAddr;
     2069        uint32_t const cbMinKey = (pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_END) ? 0
     2070                                : uType == NTFSATINDEXROOT_TYPE_DIR ? RT_UOFFSETOF(NTFSATFILENAME, wszFilename) : 0;
     2071        uint16_t const cbKey    = RT_LE2H_U16(pEntryHdr->cbKey);
     2072        if (   cbKey < cbMinKey
     2073            || cbKey > cbMaxKey)
     2074            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2075                                           "%s: Entry #%u has a bogus key size: %#x (min %#x, max %#x)",
     2076                                           pszWhat, iEntry, cbKey, cbMinKey, cbMaxKey);
     2077        if (   !(pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_END)
     2078            && uType == NTFSATINDEXROOT_TYPE_DIR)
     2079        {
     2080            PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)(pEntryHdr + 1);
     2081            if (RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]) > cbKey)
     2082                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2083                                               "%s: Entry #%u filename is out of bounds: cwcFilename=%#x -> %#x key, max %#x",
     2084                                               pszWhat, iEntry, pFilename->cwcFilename,
     2085                                               RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pFilename->cwcFilename]), cbKey);
     2086        }
     2087
     2088        if (pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_INTERNAL)
     2089        {
     2090            int64_t iSubnode = NTFSIDXENTRYHDR_GET_SUBNODE(pEntryHdr);
     2091            if (   (uint64_t)iSubnode >= pRootInfo->uEndNodeAddresses
     2092                || (iSubnode & pRootInfo->fNodeAddressMisalign) )
     2093                return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2094                                               "%s: Entry #%u has bogus subnode address: %#RX64 (max %#RX64, misalign %#x)",
     2095                                               pszWhat, iEntry, iSubnode, pRootInfo->uEndNodeAddresses,
     2096                                               pRootInfo->fNodeAddressMisalign);
     2097        }
     2098
     2099        /* Advance. */
     2100        offEntry += cbEntry;
     2101        iEntry++;
     2102        if (pEntryHdr->fFlags & NTFSIDXENTRYHDR_F_END)
     2103            break;
     2104    }
     2105
     2106    /*
     2107     * Popuplate the node info structure.
     2108     */
     2109    pNodeInfo->pIndexHdr  = pIndexHdr;
     2110    pNodeInfo->fInternal  = RT_BOOL(pIndexHdr->fFlags & NTFSINDEXHDR_F_INTERNAL);
     2111    if (pNodeInfo != &pRootInfo->NodeInfo)
     2112        pNodeInfo->pVol   = pRootInfo->NodeInfo.pVol;
     2113    pNodeInfo->cEntries   = iEntry;
     2114    pNodeInfo->papEntries = (PCNTFSIDXENTRYHDR *)RTMemAlloc(iEntry * sizeof(pNodeInfo->papEntries[0]));
     2115    if (pNodeInfo->papEntries)
     2116    {
     2117        PCNTFSIDXENTRYHDR pEntryHdr = NTFSINDEXHDR_GET_FIRST_ENTRY(pIndexHdr);
     2118        for (iEntry = 0; iEntry < pNodeInfo->cEntries; iEntry++)
     2119        {
     2120            pNodeInfo->papEntries[iEntry] = pEntryHdr;
     2121            pEntryHdr = NTFSIDXENTRYHDR_GET_NEXT(pEntryHdr);
     2122        }
     2123        return VINF_SUCCESS;
     2124    }
     2125    return VERR_NO_MEMORY;
     2126}
     2127
     2128
     2129/**
     2130 * Creates a shared directory structure given a MFT core.
     2131 *
     2132 * @returns IPRT status code.
     2133 * @param   pThis       The NTFS volume instance.
     2134 * @param   pCore       The MFT core structure that's allegedly a directory.
     2135 *                      (No reference consumed of course.)
     2136 * @param   ppSharedDir Where to return the pointer to the new shared directory
     2137 *                      structure on success. (Referenced.)
     2138 * @param   pErrInfo    Where to return additions error info.  Optional.
     2139 * @param   pszWhat     Context prefix for error reporting and logging.
     2140 */
    17142141static int rtFsNtfsVol_NewSharedDirFromCore(PRTFSNTFSVOL pThis, PRTFSNTFSCORE pCore, PRTFSNTFSDIRSHRD *ppSharedDir,
    17152142                                            PRTERRINFO pErrInfo, const char *pszWhat)
     
    17182145
    17192146    /*
    1720      * Look for the index root and do some quick checks of it first.
     2147     * Look for the index root and validate it.
    17212148     */
    17222149    PRTFSNTFSATTR pRootAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ROOT,
     
    17342161    rtFsNtfsVol_LogIndexRoot(pIdxRoot, pRootAttr->cbResident);
    17352162#endif
    1736     NOREF(pIdxRoot);
    1737 //    if (pIdxRoot->uType)
    1738 //    {
    1739 //    }
    1740 
    1741 #if 1 /* later */
    1742     NOREF(pThis);
    1743 #else
     2163    if (pIdxRoot->uType != NTFSATINDEXROOT_TYPE_DIR)
     2164        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2165                                       "%s: Wrong INDEX_ROOT type for a directory: %#x, expected %#x",
     2166                                       pszWhat, RT_LE2H_U32(pIdxRoot->uType), RT_LE2H_U32_C(NTFSATINDEXROOT_TYPE_DIR));
     2167    if (pIdxRoot->uCollationRules != NTFS_COLLATION_FILENAME)
     2168        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2169                                       "%s: Wrong collation rules for a directory: %#x, expected %#x",
     2170                                       pszWhat, RT_LE2H_U32(pIdxRoot->uCollationRules), RT_LE2H_U32_C(NTFS_COLLATION_FILENAME));
     2171    uint32_t cbIndexNode = RT_LE2H_U32(pIdxRoot->cbIndexNode);
     2172    if (cbIndexNode < 512 || cbIndexNode > _64K || !RT_IS_POWER_OF_TWO(cbIndexNode))
     2173        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2174                                       "%s: Bogus index node size: %#x (expected power of two between 512 and 64KB)",
     2175                                       pszWhat, cbIndexNode);
     2176    unsigned const cNodeAddressShift = cbIndexNode >= pThis->cbCluster ? pThis->cClusterShift : 9;
     2177    if (((uint32_t)pIdxRoot->cAddressesPerIndexNode << cNodeAddressShift) != cbIndexNode)
     2178        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2179                                       "%s: Bogus addresses per index node value: %#x (cbIndexNode=%#x cNodeAddressShift=%#x)",
     2180                                       pszWhat, pIdxRoot->cAddressesPerIndexNode, cbIndexNode, cNodeAddressShift);
     2181    AssertReturn(pRootAttr->uObj.pSharedDir == NULL, VERR_INTERNAL_ERROR_3);
     2182
    17442183    /*
    1745      *
     2184     * Check for the node data stream and related allocation bitmap.
    17462185     */
    17472186    PRTFSNTFSATTR pIndexAlloc  = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ALLOCATION,
     
    17492188    PRTFSNTFSATTR pIndexBitmap = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_BITMAP,
    17502189                                                                      RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME));
     2190    if (pIndexAlloc && !pIndexBitmap)
     2191        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2192                                       "%s: INDEX_ALLOCATION attribute without BITMAP", pszWhat);
     2193    if (!pIndexAlloc && pIndexBitmap)
     2194        return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2195                                       "%s: BITMAP attribute without INDEX_ALLOCATION", pszWhat);
     2196    uint64_t uNodeAddressEnd = 0;
     2197    if (pIndexAlloc)
     2198    {
     2199        if (!pIndexAlloc->pAttrHdr->fNonResident)
     2200            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "%s: INDEX_ALLOCATION is resident", pszWhat);
     2201        if (pIndexAlloc->cbValue & (cbIndexNode - 1))
     2202            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2203                                           "%s: INDEX_ALLOCATION size isn't aligned on node boundrary: %#RX64, cbIndexNode=%#x",
     2204                                           pszWhat, pIndexAlloc->cbValue, cbIndexNode);
     2205        uint64_t const cNodes = pIndexAlloc->cbValue / cbIndexNode;
     2206        if (pIndexBitmap->cbValue != (RT_ALIGN_64(cNodes, 64) >> 3))
     2207            return RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
     2208                                           "%s: BITMAP size does not match INDEX_ALLOCATION: %#RX64, expected %#RX64 (cbIndexNode=%#x, cNodes=%#RX64)",
     2209                                           pszWhat, pIndexBitmap->cbValue, RT_ALIGN_64(cNodes, 64) >> 3, cbIndexNode, cNodes);
     2210        uNodeAddressEnd = cNodes * pIdxRoot->cAddressesPerIndexNode;
     2211    }
     2212
     2213    /*
     2214     * Create a directory instance.
     2215     */
     2216    PRTFSNTFSDIRSHRD pNewDir = (PRTFSNTFSDIRSHRD)RTMemAllocZ(sizeof(*pNewDir));
     2217    if (!pNewDir)
     2218        return VERR_NO_MEMORY;
     2219
     2220    pNewDir->cRefs = 1;
     2221    rtFsNtfsCore_Retain(pCore);
     2222    pNewDir->RootInfo.pRootAttr             = pRootAttr;
     2223    pNewDir->RootInfo.pRoot                 = pIdxRoot;
     2224    pNewDir->RootInfo.pAlloc                = pIndexAlloc;
     2225    pNewDir->RootInfo.uEndNodeAddresses     = uNodeAddressEnd;
     2226    pNewDir->RootInfo.cNodeAddressByteShift = cNodeAddressShift;
     2227    pNewDir->RootInfo.fNodeAddressMisalign  = pIdxRoot->cAddressesPerIndexNode - 1;
     2228    pNewDir->RootInfo.NodeInfo.pVol         = pThis;
     2229
     2230    /*
     2231     * Finally validate the index header and entries.
     2232     */
     2233    int rc = rtFsNtfsVol_LoadIndexNodeInfo(&pNewDir->RootInfo, &pNewDir->RootInfo.NodeInfo, &pIdxRoot->Hdr,
     2234                                           pRootAttr->cbResident - RT_UOFFSETOF(NTFSATINDEXROOT, Hdr), pErrInfo, pszWhat);
     2235    if (RT_SUCCESS(rc))
     2236    {
     2237        *ppSharedDir = pNewDir;
     2238        pRootAttr->uObj.pSharedDir = pNewDir;
     2239        return VINF_SUCCESS;
     2240    }
     2241    RTMemFree(pNewDir);
     2242    rtFsNtfsCore_Release(pCore);
     2243    return rc;
     2244}
     2245
     2246
     2247/**
     2248 * Gets a shared directory structure given an MFT record reference, creating a
     2249 * new one if necessary.
     2250 *
     2251 * @returns IPRT status code.
     2252 * @param   pThis               The NTFS volume instance.
     2253 * @param   pDirMftRef          The MFT record reference to follow.
     2254 * @param   ppSharedDir         Where to return the shared directory structure
     2255 *                              (referenced).
     2256 * @param   pErrInfo            Where to return error details. Optional.
     2257 * @param   pszWhat             Error/log prefix.
     2258 */
     2259static int rtFsNtfsVol_QueryOrCreateSharedDirByMftRef(PRTFSNTFSVOL pThis, PCNTFSMFTREF pDirMftRef,
     2260                                                      PRTFSNTFSDIRSHRD *ppSharedDir, PRTERRINFO pErrInfo, const char *pszWhat)
     2261{
     2262    /*
     2263     * Get the core structure for the MFT record and check that it's a directory we've got.
     2264     */
     2265    PRTFSNTFSCORE pCore;
     2266    int rc = rtFsNtfsVol_QueryCoreForMftRef(pThis, pDirMftRef, false /*fRelaxedUsa*/, &pCore, pErrInfo);
     2267    if (RT_SUCCESS(rc))
     2268    {
     2269        if (pCore->pMftRec->pFileRec->fFlags & NTFSRECFILE_F_DIRECTORY)
     2270        {
     2271            /*
     2272             * Locate the $I30 root index attribute as we associate the
     2273             * pointer to the shared directory pointer with it.
     2274             */
     2275            PRTFSNTFSATTR pRootAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ROOT,
     2276                                                                           RT_STR_TUPLE(NTFS_DIR_ATTRIBUTE_NAME));
     2277            if (pRootAttr)
     2278            {
     2279                if (!pRootAttr->uObj.pSharedDir)
     2280                    rc = rtFsNtfsVol_NewSharedDirFromCore(pThis, pCore, ppSharedDir, pErrInfo, pszWhat);
     2281                else
     2282                {
     2283                    Assert(pRootAttr->uObj.pSharedDir->RootInfo.pRootAttr->pCore == pCore);
     2284                    rtFsNtfsDirShrd_Retain(pRootAttr->uObj.pSharedDir);
     2285                    *ppSharedDir = pRootAttr->uObj.pSharedDir;
     2286                }
     2287            }
     2288            else
     2289                rc = RTERRINFO_LOG_REL_SET_F(pErrInfo, VERR_NOT_A_DIRECTORY,
     2290                                             "%s: Found INDEX_ROOT attribute named $I30, even though NTFSRECFILE_F_DIRECTORY is set",
     2291                                             pszWhat);
     2292        }
     2293        else
     2294            rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_NOT_A_DIRECTORY, "%s: fFlags=%#x", pszWhat, pCore->pMftRec->pFileRec->fFlags);
     2295        rtFsNtfsCore_Release(pCore);
     2296    }
     2297    return rc;
     2298}
     2299
     2300
     2301/**
     2302 * Frees resource kept by an index node info structure.
     2303 *
     2304 * @param   pNodeInfo           The index node info structure to delelte.
     2305 */
     2306static void rtFsNtfsIdxNodeInfo_Delete(PRTFSNTFSIDXNODEINFO pNodeInfo)
     2307{
     2308    RTMemFree(pNodeInfo->papEntries);
     2309    pNodeInfo->papEntries = NULL;
     2310    pNodeInfo->pNode = NULL;
     2311    pNodeInfo->pVol  = NULL;
     2312}
     2313
     2314
     2315/**
     2316 * Gets or loads the specified subnode.
     2317 *
     2318 * @returns IPRT status code.
     2319 * @param   pRootInfo   The index root info.
     2320 * @param   iNode       The address of the node being queried.
     2321 * @param   ppNode      Where to return the referenced pointer to the node.
     2322 */
     2323static int rtFsNtfsIdxRootInfo_QueryNode(PRTFSNTFSIDXROOTINFO pRootInfo, int64_t iNode, PRTFSNTFSIDXNODE *ppNode)
     2324{
     2325    /*
     2326     * A bit of paranoia.  These has been checked already when loading, but it
     2327     * usually doesn't hurt too much to be careful.
     2328     */
     2329    AssertReturn(!(iNode & pRootInfo->fNodeAddressMisalign), VERR_VFS_BOGUS_OFFSET);
     2330    AssertReturn((uint64_t)iNode < pRootInfo->uEndNodeAddresses, VERR_VFS_BOGUS_OFFSET);
     2331    AssertReturn(pRootInfo->pAlloc, VERR_VFS_BOGUS_OFFSET);
     2332
     2333    /*
     2334     * First translate the node address to a disk byte offset and check the index node cache.
     2335     */
     2336    uint64_t offNode = iNode << pRootInfo->cNodeAddressByteShift;
     2337    uint64_t offNodeOnDisk = rtFsNtfsAttr_OffsetToDisk(pRootInfo->pAlloc, offNode, NULL);
     2338    PRTFSNTFSIDXNODE pNode = (PRTFSNTFSIDXNODE)RTAvlU64Get(&pRootInfo->NodeInfo.pVol->IdxNodeCacheRoot, offNodeOnDisk);
     2339    if (pNode)
     2340    {
     2341        rtFsNtfsIdxNode_Retain(pNode);
     2342        *ppNode = pNode;
     2343        return VINF_SUCCESS;
     2344    }
     2345
     2346    /*
     2347     * Need to create a load a new node.
     2348     */
     2349    pNode = (PRTFSNTFSIDXNODE)RTMemAllocZ(sizeof(*pNode));
     2350    AssertReturn(pNode, VERR_NO_MEMORY);
     2351
     2352    pNode->TreeNode.Key  = offNodeOnDisk;
     2353    uint32_t cbIndexNode = RT_LE2H_U32(pRootInfo->pRoot->cbIndexNode);
     2354    pNode->cbCost        = sizeof(*pNode) + cbIndexNode;
     2355    pNode->cRefs         = 1;
     2356    pNode->pNode         = (PNTFSATINDEXALLOC)RTMemAllocZ(cbIndexNode);
     2357    int rc;
     2358    if (pNode->pNode)
     2359    {
     2360        rc = rtFsNtfsAttr_Read(pRootInfo->pAlloc, offNode, pNode->pNode, cbIndexNode);
     2361        if (RT_SUCCESS(rc))
     2362        {
     2363            rc = VERR_VFS_BOGUS_FORMAT;
     2364            if (pNode->pNode->RecHdr.uMagic != NTFSREC_MAGIC_INDEX_ALLOC)
     2365                LogRel(("rtFsNtfsIdxRootInfo_QueryNode(iNode=%#x): Invalid node magic %#x\n",
     2366                        iNode, RT_LE2H_U32(pNode->pNode->RecHdr.uMagic) ));
     2367            else if ((int64_t)RT_LE2H_U64(pNode->pNode->iSelfAddress) != iNode)
     2368                LogRel(("rtFsNtfsIdxRootInfo_QueryNode(iNode=%#x): Wrong iSelfAddress: %#x\n",
     2369                        iNode, RT_LE2H_U64(pNode->pNode->iSelfAddress) ));
     2370            else
     2371            {
     2372                rc = rtFsNtfsRec_DoMultiSectorFixups(&pNode->pNode->RecHdr, cbIndexNode, false /*fRelaxedUsa*/, NULL /*pErrInfo*/);
     2373                if (RT_SUCCESS(rc))
     2374                {
     2375                    /*
     2376                     * Validate/parse it
     2377                     */
     2378#ifdef LOG_ENABLED
     2379                    rtFsNtfsVol_LogIndexHdrAndEntries(&pNode->pNode->Hdr,
     2380                                                      cbIndexNode - RT_UOFFSETOF(NTFSATINDEXALLOC, Hdr),
     2381                                                      RT_UOFFSETOF(NTFSATINDEXALLOC, Hdr), "index node",
     2382                                                      pRootInfo->pRoot->uType);
    17512383#endif
     2384                    rc = rtFsNtfsVol_LoadIndexNodeInfo(pRootInfo, &pNode->NodeInfo, &pNode->pNode->Hdr,
     2385                                                       cbIndexNode - RT_UOFFSETOF(NTFSATINDEXALLOC, Hdr),
     2386                                                       NULL /*pErrInfo*/, "index node");
     2387                    if (RT_SUCCESS(rc))
     2388                    {
     2389                        pNode->cbCost += pNode->NodeInfo.cEntries * sizeof(pNode->NodeInfo.papEntries[0]);
     2390
     2391                        /*
     2392                         * Insert it into the cache.
     2393                         */
     2394                        bool fInsertOkay = RTAvlU64Insert(&pRootInfo->NodeInfo.pVol->IdxNodeCacheRoot, &pNode->TreeNode);
     2395                        Assert(fInsertOkay);
     2396                        if (fInsertOkay)
     2397                        {
     2398                            *ppNode = pNode;
     2399                            return VINF_SUCCESS;
     2400                        }
     2401                    }
     2402                }
     2403            }
     2404        }
     2405
     2406        RTMemFree(pNode->pNode);
     2407        pNode->pNode = NULL;
     2408    }
     2409    else
     2410        rc = VERR_NO_MEMORY;
     2411    RTMemFree(pNode);
     2412    return rc;
     2413}
     2414
     2415
     2416/**
     2417 * Frees resource kept by an index root info structure.
     2418 *
     2419 * @param   pRootInfo           The index root info structure to delete.
     2420 */
     2421static void rtFsNtfsIdxRootInfo_Delete(PRTFSNTFSIDXROOTINFO pRootInfo)
     2422{
     2423    rtFsNtfsIdxNodeInfo_Delete(&pRootInfo->NodeInfo);
     2424    pRootInfo->pRootAttr->uObj.pSharedDir = NULL;
     2425    rtFsNtfsCore_Release(pRootInfo->pRootAttr->pCore);
     2426    pRootInfo->pRootAttr = NULL;
     2427    pRootInfo->pAlloc    = NULL;
     2428    pRootInfo->pRoot     = NULL;
     2429}
     2430
     2431
     2432/**
     2433 * Destroys a shared directory structure when the reference count reached zero.
     2434 *
     2435 * @returns zero
     2436 * @param   pThis               The shared directory structure to destroy.
     2437 */
     2438static uint32_t rtFsNtfsDirShrd_Destroy(PRTFSNTFSDIRSHRD pThis)
     2439{
     2440    rtFsNtfsIdxRootInfo_Delete(&pThis->RootInfo);
     2441    RTMemFree(pThis);
     2442    return 0;
     2443}
     2444
     2445
     2446/**
     2447 * Releases a references to a shared directory structure.
     2448 *
     2449 * @returns New reference count.
     2450 * @param   pThis               The shared directory structure.
     2451 */
     2452static uint32_t rtFsNtfsDirShrd_Release(PRTFSNTFSDIRSHRD pThis)
     2453{
     2454    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     2455    Assert(cRefs < 128);
     2456    if (cRefs > 0)
     2457        return cRefs;
     2458    return rtFsNtfsDirShrd_Destroy(pThis);
     2459}
     2460
     2461
     2462/**
     2463 * Retains a references to a shared directory structure.
     2464 *
     2465 * @returns New reference count.
     2466 * @param   pThis               The shared directory structure.
     2467 */
     2468static uint32_t rtFsNtfsDirShrd_Retain(PRTFSNTFSDIRSHRD pThis)
     2469{
     2470    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     2471    Assert(cRefs > 1);
     2472    Assert(cRefs < 128);
     2473    return cRefs;
     2474}
     2475
     2476
     2477/**
     2478 * Compares the two filenames in an case insentivie manner.
     2479 *
     2480 * @retval  -1 if the first filename comes first
     2481 * @retval  0 if equal
     2482 * @retval  1 if the second filename comes first.
     2483 *
     2484 * @param   pwszUpper1      The first filename, this has been uppercase already.
     2485 * @param   cwcUpper1       The length of the first filename.
     2486 * @param   pawcFilename2   The second filename to compare it with.  Not zero
     2487 *                          terminated.
     2488 * @param   cwcFilename2    The length of the second filename.
     2489 * @param   pawcUpcase      The uppercase table. 64K entries.
     2490 */
     2491static int rtFsNtfsIdxComp_Filename(PCRTUTF16 pwszUpper1, uint8_t cwcUpper1, PCRTUTF16 pawcFilename2, uint8_t cwcFilename2,
     2492                                    PCRTUTF16 const pawcUpcase)
     2493{
     2494    while (cwcUpper1 > 0 && cwcFilename2 > 0)
     2495    {
     2496        RTUTF16 uc1 = *pwszUpper1++;
     2497        RTUTF16 uc2 = *pawcFilename2++;
     2498        if (   uc1 != uc2
     2499            && uc1 != pawcUpcase[uc2])
     2500            return uc1 < uc2 ? -1 : 1;
     2501
     2502        /* Decrement the lengths and loop. */
     2503        cwcUpper1--;
     2504        cwcFilename2--;
     2505    }
     2506
     2507    if (!cwcUpper1)
     2508        return cwcFilename2 ? -1 : 0;
     2509    return cwcFilename2 ? 1 : 0;
     2510}
     2511
     2512
     2513/**
     2514 * Look up a name in the directory.
     2515 *
     2516 * @returns IPRT status code.
     2517 * @param   pShared     The shared directory structure.
     2518 * @param   pszEntry    The name to lookup.
     2519 * @param   ppFilename  Where to return the pointer to the filename structure.
     2520 * @param   ppEntryHdr  Where to return the poitner to the entry header
     2521 *                      structure.
     2522 * @param   ppNode      Where to return the pointer to the node the filename
     2523 *                      structure resides in.  This must be released.  It will
     2524 *                      be set to NULL if the name was found in the root node.
     2525 */
     2526static int rtFsNtfsDirShrd_Lookup(PRTFSNTFSDIRSHRD pShared, const char *pszEntry,
     2527                                  PCNTFSATFILENAME *ppFilename, PCNTFSIDXENTRYHDR *ppEntryHdr, PRTFSNTFSIDXNODE *ppNode)
     2528{
     2529    PRTFSNTFSVOL    pVol = pShared->RootInfo.NodeInfo.pVol;
     2530
     2531    *ppFilename = NULL;
     2532    *ppEntryHdr = NULL;
     2533    *ppNode     = NULL;
     2534    /** @todo do streams (split on ':') */
     2535
     2536    /*
     2537     * Convert the filename to UTF16 and uppercase.
     2538     */
     2539    PCRTUTF16 const pawcUpcase = pVol->pawcUpcase;
     2540    RTUTF16         wszFilename[256+4];
     2541    PRTUTF16        pwszDst = wszFilename;
     2542    PRTUTF16        pwszEnd = &wszFilename[255];
     2543    const char     *pszSrc = pszEntry;
     2544    for (;;)
     2545    {
     2546        RTUNICP uc;
     2547        int rc = RTStrGetCpEx(&pszSrc, &uc);
     2548        if (RT_SUCCESS(rc))
     2549        {
     2550            if (uc != 0)
     2551            {
     2552                if (uc < _64K)
     2553                    uc = pawcUpcase[uc];
     2554                pwszDst = RTUtf16PutCp(pwszDst, uc);
     2555                if ((uintptr_t)pwszDst <= (uintptr_t)pwszEnd)
     2556                { /* likely */ }
     2557                else
     2558                {
     2559                    Log(("rtFsNtfsDirShrd_Lookup: Filename too long '%s'\n", pszEntry));
     2560                    return VERR_FILENAME_TOO_LONG;
     2561                }
     2562            }
     2563            else
     2564            {
     2565                *pwszDst = '\0';
     2566                break;
     2567            }
     2568        }
     2569        else
     2570        {
     2571            Log(("rtFsNtfsDirShrd_Lookup: Invalid UTF-8 encoding (%Rrc): %.*Rhxs\n", rc, strlen(pszEntry), pszEntry));
     2572            return rc;
     2573        }
     2574    }
     2575    uint8_t const cwcFilename = (uint8_t)(pwszDst - wszFilename);
     2576
     2577    /*
     2578     * Do the tree traversal.
     2579     */
     2580    PRTFSNTFSIDXROOTINFO pRootInfo = &pShared->RootInfo;
     2581    PRTFSNTFSIDXNODEINFO pNodeInfo = &pRootInfo->NodeInfo;
     2582    PRTFSNTFSIDXNODE     pNode     = NULL;
     2583    for (;;)
     2584    {
     2585        /*
     2586         * Search it.
     2587         */
     2588        PCNTFSIDXENTRYHDR  *papEntries = pNodeInfo->papEntries;
     2589        uint32_t            iEnd       = pNodeInfo->cEntries;
     2590        AssertReturn(iEnd > 0, VERR_INTERNAL_ERROR_3);
     2591
     2592        /* Exclude the end node from the serach as it doesn't have any key. */
     2593        if (papEntries[iEnd - 1]->fFlags & NTFSIDXENTRYHDR_F_END)
     2594            iEnd--;
     2595
     2596        uint32_t iEntry;
     2597        if (1 /*iEnd < 8*/ )
     2598        {
     2599            if (iEnd > 0)
     2600            {
     2601                for (iEntry = 0; iEntry < iEnd; iEntry++)
     2602                {
     2603                    PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)(papEntries[iEntry] + 1);
     2604                    int iDiff = rtFsNtfsIdxComp_Filename(wszFilename, cwcFilename, pFilename->wszFilename,
     2605                                                         pFilename->cwcFilename, pawcUpcase);
     2606                    if (iDiff > 0)
     2607                    { /* likely */ }
     2608                    else if (iDiff == 0)
     2609                    {
     2610                        *ppNode     = pNode;
     2611                        *ppEntryHdr = papEntries[iEntry];
     2612                        *ppFilename = pFilename;
     2613                        LogFlow(("rtFsNtfsDirShrd_Lookup(%s): Found it!\n", pszEntry));
     2614                        return VINF_SUCCESS;
     2615                    }
     2616                    else
     2617                    {
     2618                        rtFsNtfsIdxNode_Release(pNode);
     2619                        LogFlow(("rtFsNtfsDirShrd_Lookup(%s): Not found!\n", pszEntry));
     2620                        return VERR_FILE_NOT_FOUND;
     2621                    }
     2622                }
     2623            }
     2624            else
     2625                iEntry = iEnd;
     2626        }
     2627        /* else: implement binary search */
     2628
     2629        /*
     2630         * Decend thru node iEntry.
     2631         *
     2632         * We could be bold and ASSUME that there is always an END node, but we're
     2633         * playing safe for now.
     2634         */
     2635        if (iEnd < pNodeInfo->cEntries)
     2636        {
     2637            PCNTFSIDXENTRYHDR pEntry = papEntries[iEntry];
     2638            if (pEntry->fFlags & NTFSIDXENTRYHDR_F_INTERNAL)
     2639            {
     2640                int64_t iSubnode = NTFSIDXENTRYHDR_GET_SUBNODE(pEntry);
     2641                rtFsNtfsIdxNode_Release(pNode);
     2642                int rc = rtFsNtfsIdxRootInfo_QueryNode(pRootInfo, iSubnode, &pNode);
     2643                if (RT_SUCCESS(rc))
     2644                {
     2645                    pNodeInfo = &pNode->NodeInfo;
     2646                    continue;
     2647                }
     2648                LogFlow(("rtFsNtfsDirShrd_Lookup(%s): rtFsNtfsIdxRootInfo_QueryNode(%#RX64) error %Rrc!\n",
     2649                         pszEntry, iSubnode, rc));
     2650                return rc;
     2651            }
     2652        }
     2653        rtFsNtfsIdxNode_Release(pNode);
     2654        LogFlow(("rtFsNtfsDirShrd_Lookup(%s): Not found! (#2)\n", pszEntry));
     2655        return VERR_FILE_NOT_FOUND;
     2656    }
     2657
     2658    /* not reached */
     2659}
     2660
     2661
     2662/**
     2663 * Destroys an index node.
     2664 *
     2665 * This will remove it from the cache tree, however the caller must make sure
     2666 * its not in the reuse list any more.
     2667 *
     2668 * @param   pNode               The node to destroy.
     2669 */
     2670static void rtFsNtfsIdxNode_Destroy(PRTFSNTFSIDXNODE pNode)
     2671{
     2672    PRTFSNTFSVOL pVol = pNode->NodeInfo.pVol;
     2673
     2674    /* Remove it from the volume node cache. */
     2675    PAVLU64NODECORE pAssertRemove = RTAvlU64Remove(&pVol->IdxNodeCacheRoot, pNode->TreeNode.Key);
     2676    Assert(pAssertRemove == &pNode->TreeNode); NOREF(pAssertRemove);
     2677    pVol->cIdxNodes--;
     2678    pVol->cbIdxNodes -= pNode->cbCost;
     2679
     2680    /* Destroy it. */
     2681    rtFsNtfsIdxNodeInfo_Delete(&pNode->NodeInfo);
     2682    RTMemFree(pNode->pNode);
     2683    pNode->pNode = NULL;
     2684    RTMemFree(pNode);
     2685}
     2686
     2687
     2688/**
     2689 * Trims the index node cache.
     2690 *
     2691 * @param   pThis               The NTFS volume instance which index node cache
     2692 *                              needs trimming.
     2693 */
     2694static void rtFsNtfsIdxVol_TrimIndexNodeCache(PRTFSNTFSVOL pThis)
     2695{
     2696    while (   pThis->cbIdxNodes > RTFSNTFS_MAX_NODE_CACHE_SIZE
     2697           && pThis->cUnusedIdxNodes)
     2698    {
     2699        PRTFSNTFSIDXNODE pNode = RTListRemoveFirst(&pThis->IdxNodeUnusedHead, RTFSNTFSIDXNODE, UnusedListEntry);
     2700        pThis->cUnusedIdxNodes--;
     2701        rtFsNtfsIdxNode_Destroy(pNode);
     2702    }
     2703}
     2704
     2705
     2706/**
     2707 * Index node reference reached zero, put it in the unused list and trim the
     2708 * cache.
     2709 *
     2710 * @returns zero
     2711 * @param   pNode               The index node.
     2712 */
     2713static uint32_t rtFsNtfsIdxNode_MaybeDestroy(PRTFSNTFSIDXNODE pNode)
     2714{
     2715    PRTFSNTFSVOL pVol = pNode->NodeInfo.pVol;
     2716    if (pVol)
     2717    {
     2718        RTListAppend(&pVol->IdxNodeUnusedHead, &pNode->UnusedListEntry);
     2719        pVol->cUnusedIdxNodes++;
     2720        if (pVol->cbIdxNodes > RTFSNTFS_MAX_NODE_CACHE_SIZE)
     2721            rtFsNtfsIdxVol_TrimIndexNodeCache(pVol);
     2722        rtFsNtfsIdxVol_TrimIndexNodeCache(pVol);
     2723        return 0;
     2724    }
     2725    /* not sure if this is needed yet... */
     2726    rtFsNtfsIdxNodeInfo_Delete(&pNode->NodeInfo);
     2727    RTMemFree(pNode);
     2728    return 0;
     2729}
     2730
     2731
     2732/**
     2733 * Releases a reference to an index node.
     2734 *
     2735 * @returns New reference count.
     2736 * @param   pNode               The index node to release.  NULL is ignored.
     2737 */
     2738static uint32_t rtFsNtfsIdxNode_Release(PRTFSNTFSIDXNODE pNode)
     2739{
     2740    if (pNode)
     2741    {
     2742        uint32_t cRefs = ASMAtomicDecU32(&pNode->cRefs);
     2743        Assert(cRefs < 128);
     2744        if (cRefs > 0)
     2745            return cRefs;
     2746        return rtFsNtfsIdxNode_MaybeDestroy(pNode);
     2747    }
     2748    return 0;
     2749}
     2750
     2751
     2752/**
     2753 * Retains a reference to an index node.
     2754 *
     2755 * This will remove it from the unused list if necessary.
     2756 *
     2757 * @returns New reference count.
     2758 * @param   pNode               The index to reference.
     2759 */
     2760static uint32_t rtFsNtfsIdxNode_Retain(PRTFSNTFSIDXNODE pNode)
     2761{
     2762    uint32_t cRefs = ASMAtomicIncU32(&pNode->cRefs);
     2763    if (cRefs == 1)
     2764    {
     2765        RTListNodeRemove(&pNode->UnusedListEntry);
     2766        pNode->NodeInfo.pVol->cUnusedIdxNodes--;
     2767    }
     2768    return cRefs;
     2769}
     2770
     2771
     2772
     2773
     2774/*
     2775 *
     2776 * Directory instance methods
     2777 * Directory instance methods
     2778 * Directory instance methods
     2779 *
     2780 */
     2781
     2782/**
     2783 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
     2784 */
     2785static DECLCALLBACK(int) rtFsNtfsDir_Close(void *pvThis)
     2786{
     2787    PRTFSNTFSDIR pThis = (PRTFSNTFSDIR)pvThis;
     2788    LogFlow(("rtFsNtfsDir_Close(%p/%p)\n", pThis, pThis->pShared));
     2789
     2790    PRTFSNTFSDIRSHRD pShared = pThis->pShared;
     2791    pThis->pShared = NULL;
     2792    if (pShared)
     2793        rtFsNtfsDirShrd_Release(pShared);
     2794
     2795    while (pThis->cEnumStackEntries > 0)
     2796    {
     2797        PRTFSNTFSIDXSTACKENTRY pEntry = &pThis->paEnumStack[--pThis->cEnumStackEntries];
     2798        rtFsNtfsIdxNode_Release(pEntry->pNodeInfo->pNode);
     2799        pEntry->pNodeInfo = NULL;
     2800    }
     2801    RTMemFree(pThis->paEnumStack);
     2802    pThis->paEnumStack = NULL;
     2803    pThis->cEnumStackMaxDepth = 0;
     2804
    17522805    return VINF_SUCCESS;
    17532806}
     2807
     2808
     2809/**
     2810 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
     2811 */
     2812static DECLCALLBACK(int) rtFsNtfsDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
     2813{
     2814    Log(("rtFsNtfsDir_QueryInfo\n"));
     2815    //PRTFSNTFSDIR pThis = (PRTFSNTFSDIR)pvThis;
     2816    //return rtFsNtfsCore_QueryInfo(&pThis->pShared->Core, pObjInfo, enmAddAttr);
     2817    NOREF(pvThis); NOREF(pObjInfo); NOREF(enmAddAttr);
     2818    return VERR_NOT_IMPLEMENTED;
     2819}
     2820
     2821
     2822/**
     2823 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
     2824 */
     2825static DECLCALLBACK(int) rtFsNtfsDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
     2826{
     2827    Log(("rtFsNtfsDir_SetMode\n"));
     2828    RT_NOREF(pvThis, fMode, fMask);
     2829    return VERR_WRITE_PROTECT;
     2830}
     2831
     2832
     2833/**
     2834 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
     2835 */
     2836static DECLCALLBACK(int) rtFsNtfsDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
     2837                                                 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
     2838{
     2839    Log(("rtFsNtfsDir_SetTimes\n"));
     2840    RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
     2841    return VERR_WRITE_PROTECT;
     2842}
     2843
     2844
     2845/**
     2846 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
     2847 */
     2848static DECLCALLBACK(int) rtFsNtfsDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
     2849{
     2850    Log(("rtFsNtfsDir_SetOwner\n"));
     2851    RT_NOREF(pvThis, uid, gid);
     2852    return VERR_WRITE_PROTECT;
     2853}
     2854
     2855
     2856/**
     2857 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
     2858 */
     2859static DECLCALLBACK(int) rtFsNtfsDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen,
     2860                                          uint32_t fFlags, PRTVFSOBJ phVfsObj)
     2861{
     2862    LogFlow(("rtFsNtfsDir_Open: pszEntry='%s' fOpen=%#RX64 fFlags=%#x\n", pszEntry, fOpen, fFlags));
     2863    PRTFSNTFSDIR        pThis   = (PRTFSNTFSDIR)pvThis;
     2864    PRTFSNTFSDIRSHRD    pShared = pThis->pShared;
     2865    PRTFSNTFSVOL        pVol    = pShared->RootInfo.NodeInfo.pVol;
     2866    int rc;
     2867
     2868    /*
     2869     * We cannot create or replace anything, just open stuff.
     2870     */
     2871    if (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
     2872        || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE)
     2873    { /* likely */ }
     2874    else
     2875        return VERR_WRITE_PROTECT;
     2876
     2877    /*
     2878     * Special cases '.' and '..'
     2879     */
     2880    if (   pszEntry[0] == '.'
     2881        && (   pszEntry[1] == '\0'
     2882            || (   pszEntry[1] == '.'
     2883                && pszEntry[2] == '\0')))
     2884    {
     2885        if (!(fFlags & RTVFSOBJ_F_OPEN_DIRECTORY))
     2886            return VERR_IS_A_DIRECTORY;
     2887
     2888        PRTFSNTFSDIRSHRD pSharedToOpen;
     2889        if (   pszEntry[1] == '\0'
     2890            || pVol->pRootDir == pShared)
     2891        {
     2892            pSharedToOpen = pShared;
     2893            rtFsNtfsDirShrd_Retain(pSharedToOpen);
     2894            rc = VINF_SUCCESS;
     2895        }
     2896        else
     2897        {
     2898            /* Find a parent mft reference */
     2899            pSharedToOpen = NULL;
     2900            rc = VERR_VFS_BOGUS_FORMAT;
     2901            PRTFSNTFSCORE pCore = pShared->RootInfo.pRootAttr->pCore;
     2902            PRTFSNTFSATTR pCurAttr;
     2903            RTListForEach(&pCore->AttribHead, pCurAttr, RTFSNTFSATTR, ListEntry)
     2904            {
     2905                if (   pCurAttr->pAttrHdr->uAttrType == NTFS_AT_FILENAME
     2906                    && pCurAttr->cbResident >= sizeof(NTFSATFILENAME))
     2907                {
     2908                    PCNTFSATFILENAME pFilename = (PCNTFSATFILENAME)NTFSATTRIBHDR_GET_RES_VALUE_PTR(pCurAttr->pAttrHdr);
     2909                    rc = rtFsNtfsVol_QueryOrCreateSharedDirByMftRef(pVol, &pFilename->ParentDirMftRec,
     2910                                                                    &pSharedToOpen, NULL /*pErrInfo*/, "..");
     2911                    break;
     2912                }
     2913            }
     2914        }
     2915        if (RT_SUCCESS(rc))
     2916        {
     2917            RTVFSDIR hVfsDir;
     2918            rc = rtFsNtfsVol_NewDirFromShared(pVol, pSharedToOpen, &hVfsDir);
     2919            rtFsNtfsDirShrd_Release(pSharedToOpen);
     2920            if (RT_SUCCESS(rc))
     2921            {
     2922                *phVfsObj = RTVfsObjFromDir(hVfsDir);
     2923                RTVfsDirRelease(hVfsDir);
     2924                AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
     2925            }
     2926        }
     2927        LogFlow(("rtFsNtfsDir_Open(%s): returns %Rrc\n", pszEntry, rc));
     2928        return rc;
     2929    }
     2930
     2931    /*
     2932     * Lookup the index entry.
     2933     */
     2934    PRTFSNTFSIDXNODE  pNode;
     2935    PCNTFSIDXENTRYHDR pEntryHdr;
     2936    PCNTFSATFILENAME  pFilename;
     2937    rc = rtFsNtfsDirShrd_Lookup(pShared, pszEntry, &pFilename, &pEntryHdr, &pNode);
     2938    if (RT_SUCCESS(rc))
     2939    {
     2940        uint32_t fFileAttribs = RT_LE2H_U32(pFilename->fFileAttribs);
     2941        switch (fFileAttribs & (NTFS_FA_DIRECTORY | NTFS_FA_REPARSE_POINT))
     2942        {
     2943            /*
     2944             * File.
     2945             */
     2946            case 0:
     2947                if (fFlags & RTVFSOBJ_F_OPEN_FILE)
     2948                {
     2949                    //RTVFSFILE hVfsFile;
     2950                    //rc = rtFsIsoFile_New9660(pVol, pShared, pDirRec, cDirRecs,
     2951                    //                         offDirRec, fOpen, uVersion, &hVfsFile);
     2952                    //if (RT_SUCCESS(rc))
     2953                    //{
     2954                    //    *phVfsObj = RTVfsObjFromFile(hVfsFile);
     2955                    //    RTVfsFileRelease(hVfsFile);
     2956                    //    AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
     2957                    //}
     2958                    rc = VERR_NOT_IMPLEMENTED;
     2959                }
     2960                else
     2961                    rc = VERR_IS_A_FILE;
     2962                break;
     2963
     2964            /*
     2965             * Directory
     2966             */
     2967            case NTFS_FA_DIRECTORY:
     2968                if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
     2969                {
     2970                    PRTFSNTFSDIRSHRD pSharedToOpen;
     2971                    rc = rtFsNtfsVol_QueryOrCreateSharedDirByMftRef(pVol, &pEntryHdr->u.FileMftRec,
     2972                                                                    &pSharedToOpen, NULL, pszEntry);
     2973                    if (RT_SUCCESS(rc))
     2974                    {
     2975                        RTVFSDIR hVfsDir;
     2976                        rc = rtFsNtfsVol_NewDirFromShared(pVol, pSharedToOpen, &hVfsDir);
     2977                        rtFsNtfsDirShrd_Release(pSharedToOpen);
     2978                        if (RT_SUCCESS(rc))
     2979                        {
     2980                            *phVfsObj = RTVfsObjFromDir(hVfsDir);
     2981                            RTVfsDirRelease(hVfsDir);
     2982                            AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
     2983                        }
     2984                    }
     2985                }
     2986                else
     2987                    rc = VERR_IS_A_DIRECTORY;
     2988                break;
     2989
     2990            /*
     2991             * Possible symbolic links.
     2992             */
     2993            case NTFS_FA_REPARSE_POINT:
     2994            case NTFS_FA_DIRECTORY | NTFS_FA_REPARSE_POINT:
     2995                rc = VERR_NOT_IMPLEMENTED;
     2996                break;
     2997
     2998            default:
     2999                rc = VERR_IPE_NOT_REACHED_DEFAULT_CASE;
     3000                break;
     3001        }
     3002        rtFsNtfsIdxNode_Release(pNode);
     3003    }
     3004
     3005    LogFlow(("rtFsNtfsDir_Open(%s): returns %Rrc\n", pszEntry, rc));
     3006    return rc;
     3007}
     3008
     3009
     3010/**
     3011 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
     3012 */
     3013static DECLCALLBACK(int) rtFsNtfsDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
     3014{
     3015    RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
     3016    Log(("rtFsNtfsDir_CreateDir\n"));
     3017    return VERR_WRITE_PROTECT;
     3018}
     3019
     3020
     3021/**
     3022 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
     3023 */
     3024static DECLCALLBACK(int) rtFsNtfsDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
     3025{
     3026    RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
     3027    Log(("rtFsNtfsDir_OpenSymlink\n"));
     3028    return VERR_NOT_SUPPORTED;
     3029}
     3030
     3031
     3032/**
     3033 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
     3034 */
     3035static DECLCALLBACK(int) rtFsNtfsDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
     3036                                                  RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
     3037{
     3038    RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
     3039    Log(("rtFsNtfsDir_CreateSymlink\n"));
     3040    return VERR_WRITE_PROTECT;
     3041}
     3042
     3043
     3044/**
     3045 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
     3046 */
     3047static DECLCALLBACK(int) rtFsNtfsDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
     3048{
     3049    RT_NOREF(pvThis, pszEntry, fType);
     3050    Log(("rtFsNtfsDir_UnlinkEntry\n"));
     3051    return VERR_WRITE_PROTECT;
     3052}
     3053
     3054
     3055/**
     3056 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
     3057 */
     3058static DECLCALLBACK(int) rtFsNtfsDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
     3059{
     3060    RT_NOREF(pvThis, pszEntry, fType, pszNewName);
     3061    Log(("rtFsNtfsDir_RenameEntry\n"));
     3062    return VERR_WRITE_PROTECT;
     3063}
     3064
     3065
     3066/**
     3067 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
     3068 */
     3069static DECLCALLBACK(int) rtFsNtfsDir_RewindDir(void *pvThis)
     3070{
     3071    PRTFSNTFSDIR pThis = (PRTFSNTFSDIR)pvThis;
     3072    LogFlow(("rtFsNtfsDir_RewindDir\n"));
     3073
     3074    while (pThis->cEnumStackEntries > 0)
     3075    {
     3076        PRTFSNTFSIDXSTACKENTRY pEntry = &pThis->paEnumStack[--pThis->cEnumStackEntries];
     3077        rtFsNtfsIdxNode_Release(pEntry->pNodeInfo->pNode);
     3078        pEntry->pNodeInfo = NULL;
     3079    }
     3080    pThis->fNoMoreFiles = false;
     3081
     3082    return VINF_SUCCESS;
     3083}
     3084
     3085
     3086/**
     3087 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
     3088 */
     3089static DECLCALLBACK(int) rtFsNtfsDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
     3090                                            RTFSOBJATTRADD enmAddAttr)
     3091{
     3092    PRTFSNTFSDIR    pThis   = (PRTFSNTFSDIR)pvThis;
     3093    if (pThis->fNoMoreFiles)
     3094        return VERR_NO_MORE_FILES;
     3095    Log(("rtFsNtfsDir_ReadDir\n"));
     3096    //PRTFSNTFSDIRSHRD pShared = pThis->pShared;
     3097    NOREF(pvThis); NOREF(pDirEntry); NOREF(pcbDirEntry); NOREF(enmAddAttr);
     3098    return VERR_NOT_IMPLEMENTED;
     3099}
     3100
     3101
     3102/**
     3103 * NTFS file operations.
     3104 */
     3105static const RTVFSDIROPS g_rtFsNtfsDirOps =
     3106{
     3107    { /* Obj */
     3108        RTVFSOBJOPS_VERSION,
     3109        RTVFSOBJTYPE_DIR,
     3110        "NTFS Dir",
     3111        rtFsNtfsDir_Close,
     3112        rtFsNtfsDir_QueryInfo,
     3113        RTVFSOBJOPS_VERSION
     3114    },
     3115    RTVFSDIROPS_VERSION,
     3116    0,
     3117    { /* ObjSet */
     3118        RTVFSOBJSETOPS_VERSION,
     3119        RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
     3120        rtFsNtfsDir_SetMode,
     3121        rtFsNtfsDir_SetTimes,
     3122        rtFsNtfsDir_SetOwner,
     3123        RTVFSOBJSETOPS_VERSION
     3124    },
     3125    rtFsNtfsDir_Open,
     3126    NULL /* pfnFollowAbsoluteSymlink */,
     3127    NULL /* pfnOpenFile */,
     3128    NULL /* pfnOpenDir */,
     3129    rtFsNtfsDir_CreateDir,
     3130    rtFsNtfsDir_OpenSymlink,
     3131    rtFsNtfsDir_CreateSymlink,
     3132    NULL /* pfnQueryEntryInfo */,
     3133    rtFsNtfsDir_UnlinkEntry,
     3134    rtFsNtfsDir_RenameEntry,
     3135    rtFsNtfsDir_RewindDir,
     3136    rtFsNtfsDir_ReadDir,
     3137    RTVFSDIROPS_VERSION,
     3138};
     3139
     3140
     3141/**
     3142 * Creates a new directory instance given a shared directory structure.
     3143 *
     3144 * @returns IPRT status code.
     3145 * @param   pThis               The NTFS volume instance.
     3146 * @param   pSharedDir          The shared directory structure to create a new
     3147 *                              handle to.
     3148 * @param   phVfsDir            Where to return the directory handle.
     3149 */
     3150static int rtFsNtfsVol_NewDirFromShared(PRTFSNTFSVOL pThis, PRTFSNTFSDIRSHRD pSharedDir, PRTVFSDIR phVfsDir)
     3151{
     3152    PRTFSNTFSDIR pNewDir;
     3153    int rc = RTVfsNewDir(&g_rtFsNtfsDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf, NIL_RTVFSLOCK,
     3154                         phVfsDir, (void **)&pNewDir);
     3155    if (RT_SUCCESS(rc))
     3156    {
     3157        rtFsNtfsDirShrd_Retain(pSharedDir);
     3158        pNewDir->pShared            = pSharedDir;
     3159        pNewDir->cEnumStackEntries  = 0;
     3160        pNewDir->cEnumStackMaxDepth = 0;
     3161        pNewDir->paEnumStack        = NULL;
     3162        return VINF_SUCCESS;
     3163    }
     3164    return rc;
     3165}
     3166
    17543167
    17553168
     
    17833196             * Try cache the whole bitmap if it's not too large.
    17843197             */
    1785             if (   cbWholeBitmap <= RTFSNTFS_MAX_BITMAP_CACHE
     3198            if (   cbWholeBitmap <= RTFSNTFS_MAX_WHOLE_BITMAP_CACHE
    17863199                && cbWholeBitmap >= RT_ALIGN_64(pThis->cClusters >> 3, 8))
    17873200            {
     
    18963309static DECLCALLBACK(int) rtFsNtfsVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
    18973310{
    1898     NOREF(pvThis); NOREF(phVfsDir);
    1899     return VERR_NOT_IMPLEMENTED;
     3311    PRTFSNTFSVOL pThis = (PRTFSNTFSVOL)pvThis;
     3312    AssertReturn(pThis->pRootDir, VERR_INTERNAL_ERROR_4);
     3313    int rc = rtFsNtfsVol_NewDirFromShared(pThis, pThis->pRootDir, phVfsDir);
     3314    LogFlow(("rtFsNtfsVol_OpenRoot: returns %Rrc\n", rc));
     3315    return rc;
    19003316}
    19013317
     
    27184134        pThis->fMntFlags      = fMntFlags;
    27194135        pThis->fNtfsFlags     = fNtfsFlags;
     4136        RTListInit(&pThis->IdxNodeUnusedHead);
    27204137
    27214138        rc = RTVfsFileGetSize(pThis->hVfsBacking, &pThis->cbBacking);
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