Changeset 69924 in vbox
- Timestamp:
- Dec 4, 2017 9:12:01 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/formats/ntfs.h
r69910 r69924 85 85 86 86 /** @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. */ 88 88 /** @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. */ 90 90 /** @name NTFSMFTREF_SET_IDX 91 91 * Sets the MFT index number of a MFT reference. */ … … 120 120 } while (0) 121 121 #endif 122 /** Check that the reference is zero. */ 123 #define NTFSMFTREF_IS_ZERO(a_pMftRef) ((a_pMftRef)->u64 == 0) 122 124 123 125 … … 437 439 #define NTFSATSTDINFO_SIZE_NTFS_V12 (0x30) 438 440 439 /** @name NTFS_FA_XXX - NTFS file attributes .441 /** @name NTFS_FA_XXX - NTFS file attributes (host endian). 440 442 * @{ */ 441 443 #define NTFS_FA_READONLY UINT32_C(0x00000001) … … 480 482 /** 0x30: Actual size of unnamed data attribute. */ 481 483 int64_t cbData; 482 /** 0x38: File attributes . */484 /** 0x38: File attributes (NTFS_FA_XXX). */ 483 485 uint32_t fFileAttribs; 484 486 union … … 588 590 #define NTFSINDEXHDR_F_INTERNAL UINT8_C(0x01) 589 591 /** @} */ 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)) ) 590 596 591 597 -
trunk/src/VBox/Runtime/common/fs/isovfs.cpp
r69844 r69924 2210 2210 * 2211 2211 * @returns IPRT status code. 2212 * @param pThis The FATvolume instance.2212 * @param pThis The ISO volume instance. 2213 2213 * @param pParentDir The parent directory (shared part). 2214 2214 * @param pDirRec The directory record. … … 2281 2281 * 2282 2282 * @returns IPRT status code. 2283 * @param pThis The FATvolume instance.2283 * @param pThis The ISO volume instance. 2284 2284 * @param pParentDir The parent directory (shared part). 2285 2285 * @param pFid The file ID descriptor. (Points to parent directory … … 2910 2910 2911 2911 /* 2912 * Special cases '.' and '. '2912 * Special cases '.' and '..' 2913 2913 */ 2914 2914 if (pszEntry[0] == '.') … … 3484 3484 3485 3485 /** 3486 * FATfile operations.3486 * ISO file operations. 3487 3487 */ 3488 3488 static const RTVFSDIROPS g_rtFsIsoDirOps = … … 3638 3638 * 3639 3639 * @returns IPRT status code. 3640 * @param pThis The FATvolume instance.3640 * @param pThis The ISO volume instance. 3641 3641 * @param pParentDir The parent directory. This is NULL for the root 3642 3642 * directory. … … 3785 3785 * 3786 3786 * @returns IPRT status code. 3787 * @param pThis The FATvolume instance.3787 * @param pThis The ISO volume instance. 3788 3788 * @param pParentDir The parent directory. This is NULL for the root 3789 3789 * directory. … … 3849 3849 * 3850 3850 * @returns IPRT status code. 3851 * @param pThis The FATvolume instance.3851 * @param pThis The ISO volume instance. 3852 3852 * @param pShared Referenced pointer to the shared structure. The 3853 3853 * reference is always CONSUMED. … … 3885 3885 * 3886 3886 * @returns IPRT status code. 3887 * @param pThis The FATvolume instance.3887 * @param pThis The ISO volume instance. 3888 3888 * @param pParentDir The parent directory. This is NULL for the root 3889 3889 * directory. … … 3918 3918 * 3919 3919 * @returns IPRT status code. 3920 * @param pThis The FATvolume instance.3920 * @param pThis The ISO volume instance. 3921 3921 * @param pParentDir The parent directory. 3922 3922 * @param pFid The file ID descriptor for the directory. … … 5657 5657 * @param pThis The ISO VFS instance to initialize. 5658 5658 * @param hVfsSelf The ISO VFS handle (no reference consumed). 5659 * @param hVfsBacking The file backing the alleged FATfile system.5659 * @param hVfsBacking The file backing the alleged ISO file system. 5660 5660 * Reference is consumed (via rtFsIsoVol_Close). 5661 5661 * @param fFlags Flags, RTFSISO9660_F_XXX. … … 5925 5925 5926 5926 /* 5927 * Create a new FATVFS 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. 5928 5928 */ 5929 5929 RTVFS hVfs = NIL_RTVFS; -
trunk/src/VBox/Runtime/common/fs/ntfsvfs.cpp
r69913 r69924 48 48 * Defined Constants And Macros * 49 49 *********************************************************************************************************************************/ 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 52 58 53 59 /** Makes a combined NTFS version value. … … 65 71 /** Poitner to a NTFS core object record. */ 66 72 typedef struct RTFSNTFSCORE *PRTFSNTFSCORE; 73 /** Pointer to an index node. */ 74 typedef struct RTFSNTFSIDXNODE *PRTFSNTFSIDXNODE; 75 /** Pointer to a shared NTFS directory object. */ 76 typedef struct RTFSNTFSDIRSHRD *PRTFSNTFSDIRSHRD; 77 /** Pointer to a shared NTFS file object. */ 78 typedef struct RTFSNTFSFILESHRD *PRTFSNTFSFILESHRD; 67 79 68 80 … … 173 185 /** Pointer to any subrecords containing further allocation extents. */ 174 186 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; 175 196 } RTFSNTFSATTR; 176 197 /** Pointer to a attribute structure. */ … … 194 215 } RTFSNTFSCORE; 195 216 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 */ 221 typedef 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. */ 238 typedef RTFSNTFSIDXNODEINFO *PRTFSNTFSIDXNODEINFO; 239 /** Pointer to const index node lookup info. */ 240 typedef 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 */ 248 typedef 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 */ 268 typedef struct RTFSNTFSIDXROOTINFO 269 { 270 /** Pointer to the index root attribute value. */ 271 PCNTFSATINDEXROOT pRoot; 209 272 /** Pointer to the index allocation attribute, if present. 210 273 * This and the bitmap may be absent if the whole directory fits into the 211 274 * 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. */ 289 typedef RTFSNTFSIDXROOTINFO *PRTFSNTFSIDXROOTINFO; 290 /** Pointer to a const index root structure. */ 291 typedef RTFSNTFSIDXROOTINFO const *PCRTFSNTFSIDXROOTINFO; 292 293 /** 294 * Pointer to a shared NTFS directory object. 295 */ 296 typedef struct RTFSNTFSDIRSHRD 297 { 298 /** Reference counter. */ 299 uint32_t volatile cRefs; 300 /** Index root information. */ 301 RTFSNTFSIDXROOTINFO RootInfo; 216 302 } RTFSNTFSDIRSHRD; 217 /** Pointer to a shared NTFS directory object. */ 218 typedef RTFSNTFSDIRSHRD *PRTFSNTFSDIRSHRD; 303 304 /** 305 * Index stack entry for index enumeration. 306 */ 307 typedef 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. */ 315 typedef RTFSNTFSIDXSTACKENTRY *PRTFSNTFSIDXSTACKENTRY; 316 317 318 /** 319 * Open directory instance. 320 */ 321 typedef 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. */ 335 typedef RTFSNTFSDIR *PRTFSNTFSDIR; 219 336 220 337 … … 225 342 { 226 343 /** Handle to itself. */ 227 RTVFS hVfsSelf;344 RTVFS hVfsSelf; 228 345 /** The file, partition, or whatever backing the NTFS volume. */ 229 RTVFSFILE hVfsBacking;346 RTVFSFILE hVfsBacking; 230 347 /** The size of the backing thingy. */ 231 uint64_t cbBacking;348 uint64_t cbBacking; 232 349 /** The formatted size of the volume. */ 233 uint64_t cbVolume;350 uint64_t cbVolume; 234 351 /** cbVolume expressed as a cluster count. */ 235 uint64_t cClusters;352 uint64_t cClusters; 236 353 237 354 /** RTVFSMNT_F_XXX. */ 238 uint32_t fMntFlags;355 uint32_t fMntFlags; 239 356 /** RTFSNTVFS_F_XXX (currently none defined). */ 240 uint32_t fNtfsFlags;357 uint32_t fNtfsFlags; 241 358 242 359 /** The (logical) sector size. */ 243 uint32_t cbSector;360 uint32_t cbSector; 244 361 245 362 /** The (logical) cluster size. */ 246 uint32_t cbCluster;363 uint32_t cbCluster; 247 364 /** Max cluster count value that won't overflow a signed 64-bit when 248 365 * converted to bytes. Inclusive. */ 249 uint64_t iMaxVirtualCluster;366 uint64_t iMaxVirtualCluster; 250 367 /** The shift count for converting between bytes and clusters. */ 251 uint8_t cClusterShift;368 uint8_t cClusterShift; 252 369 253 370 /** Explicit padding. */ 254 uint8_t abReserved[3];371 uint8_t abReserved[3]; 255 372 /** The NTFS version of the volume (RTFSNTFS_MAKE_VERSION). */ 256 uint16_t uNtfsVersion;373 uint16_t uNtfsVersion; 257 374 /** The NTFS_VOLUME_F_XXX. */ 258 uint16_t fVolumeFlags;375 uint16_t fVolumeFlags; 259 376 260 377 /** The logical cluster number of the MFT. */ 261 uint64_t uLcnMft;378 uint64_t uLcnMft; 262 379 /** The logical cluster number of the mirror MFT. */ 263 uint64_t uLcnMftMirror;380 uint64_t uLcnMftMirror; 264 381 265 382 /** The MFT record size. */ 266 uint32_t cbMftRecord;383 uint32_t cbMftRecord; 267 384 /** The default index (B-tree) node size. */ 268 uint32_t cbDefaultIndexNode;385 uint32_t cbDefaultIndexNode; 269 386 270 387 /** The volume serial number. */ 271 uint64_t uSerialNo;388 uint64_t uSerialNo; 272 389 273 390 /** The '$Mft' data attribute. */ 274 PRTFSNTFSATTR pMftData; 275 276 /** The root directory. */ 277 PRTFSNTFSDIRSHRD pRootDir; 391 PRTFSNTFSATTR pMftData; 278 392 279 393 /** @name Allocation bitmap and cache. 280 394 * @{ */ 281 395 /** The '$Bitmap' data attribute. */ 282 PRTFSNTFSATTR pMftBitmap;396 PRTFSNTFSATTR pMftBitmap; 283 397 /** The first cluster currently loaded into the bitmap cache . */ 284 uint64_t iFirstBitmapCluster;398 uint64_t iFirstBitmapCluster; 285 399 /** The number of clusters currently loaded into the bitmap cache */ 286 uint32_t cBitmapClusters;400 uint32_t cBitmapClusters; 287 401 /** The size of the pvBitmap allocation. */ 288 uint32_t cbBitmapAlloc;402 uint32_t cbBitmapAlloc; 289 403 /** Allocation bitmap cache buffer. */ 290 void *pvBitmap;404 void *pvBitmap; 291 405 /** @} */ 292 406 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; 293 430 /** 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 /** @} */ 299 434 300 435 } RTFSNTFSVOL; … … 306 441 *********************************************************************************************************************************/ 307 442 static uint32_t rtFsNtfsCore_Release(PRTFSNTFSCORE pThis); 443 static uint32_t rtFsNtfsCore_Retain(PRTFSNTFSCORE pThis); 308 444 #ifdef LOG_ENABLED 309 445 static void rtFsNtfsVol_LogIndexRoot(PCNTFSATINDEXROOT pIdxRoot, uint32_t cbIdxRoot); 310 446 #endif 447 static int rtFsNtfsVol_NewDirFromShared(PRTFSNTFSVOL pThis, PRTFSNTFSDIRSHRD pSharedDir, PRTVFSDIR phVfsDir); 448 static uint32_t rtFsNtfsDirShrd_Retain(PRTFSNTFSDIRSHRD pThis); 449 static uint32_t rtFsNtfsIdxNode_Release(PRTFSNTFSIDXNODE pNode); 450 static uint32_t rtFsNtfsIdxNode_Retain(PRTFSNTFSIDXNODE pNode); 311 451 312 452 … … 567 707 Log2(("NTFS: cwcFilename %#x\n", pInfo->cwcFilename)); 568 708 Log2(("NTFS: fFilenameType %#x\n", pInfo->fFilenameType)); 569 if ( cbValue >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename))709 if (RT_UOFFSETOF(NTFSATFILENAME, wszFilename[pInfo->cwcFilename]) <= cbValue) 570 710 Log2(("NTFS: wszFilename '%.*ls'\n", pInfo->cwcFilename, pInfo->wszFilename )); 571 711 else … … 1132 1272 1133 1273 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 */ 1283 static 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 1134 1326 static int rtFsNtfsAttr_Read(PRTFSNTFSATTR pAttr, uint64_t off, void *pvBuf, size_t cbToRead) 1135 1327 { … … 1411 1603 1412 1604 /** 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 */ 1619 static 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 /** 1413 1681 * Destroys a core structure. 1414 1682 * … … 1485 1753 1486 1754 1487 #if 0 /* currently unused */1488 1755 /** 1489 1756 * Retains a refernece to a core structure. … … 1498 1765 return cRefs; 1499 1766 } 1500 #endif1501 1767 1502 1768 … … 1629 1895 Log2(("NTFS: Subnode=%#RX64\n", RT_LE2H_U64(NTFSIDXENTRYHDR_GET_SUBNODE(pEntryHdr)) )); 1630 1896 1631 if ( RT_LE2H_U16(pEntryHdr->cbKey) >= sizeof(NTFSATFILENAME)1897 if ( RT_LE2H_U16(pEntryHdr->cbKey) >= RT_UOFFSETOF(NTFSATFILENAME, wszFilename) 1632 1898 && uIdxType == NTFSATINDEXROOT_TYPE_DIR) 1633 1899 { 1634 1900 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")); 1636 1926 } 1637 1927 … … 1712 2002 1713 2003 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 */ 2015 static 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 */ 1714 2141 static int rtFsNtfsVol_NewSharedDirFromCore(PRTFSNTFSVOL pThis, PRTFSNTFSCORE pCore, PRTFSNTFSDIRSHRD *ppSharedDir, 1715 2142 PRTERRINFO pErrInfo, const char *pszWhat) … … 1718 2145 1719 2146 /* 1720 * Look for the index root and do some quick checks of it first.2147 * Look for the index root and validate it. 1721 2148 */ 1722 2149 PRTFSNTFSATTR pRootAttr = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ROOT, … … 1734 2161 rtFsNtfsVol_LogIndexRoot(pIdxRoot, pRootAttr->cbResident); 1735 2162 #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 1744 2183 /* 1745 * 2184 * Check for the node data stream and related allocation bitmap. 1746 2185 */ 1747 2186 PRTFSNTFSATTR pIndexAlloc = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_INDEX_ALLOCATION, … … 1749 2188 PRTFSNTFSATTR pIndexBitmap = rtFsNtfsCore_FindNamedAttributeAscii(pCore, NTFS_AT_BITMAP, 1750 2189 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 */ 2259 static 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 */ 2306 static 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 */ 2323 static 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); 1751 2383 #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 */ 2421 static 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 */ 2438 static 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 */ 2452 static 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 */ 2468 static 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 */ 2491 static 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 */ 2526 static 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 */ 2670 static 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 */ 2694 static 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 */ 2713 static 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 */ 2738 static 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 */ 2760 static 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 */ 2785 static 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 1752 2805 return VINF_SUCCESS; 1753 2806 } 2807 2808 2809 /** 2810 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo} 2811 */ 2812 static 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 */ 2825 static 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 */ 2836 static 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 */ 2848 static 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 */ 2859 static 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 */ 3013 static 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 */ 3024 static 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 */ 3035 static 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 */ 3047 static 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 */ 3058 static 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 */ 3069 static 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 */ 3089 static 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 */ 3105 static 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 */ 3150 static 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 1754 3167 1755 3168 … … 1783 3196 * Try cache the whole bitmap if it's not too large. 1784 3197 */ 1785 if ( cbWholeBitmap <= RTFSNTFS_MAX_ BITMAP_CACHE3198 if ( cbWholeBitmap <= RTFSNTFS_MAX_WHOLE_BITMAP_CACHE 1786 3199 && cbWholeBitmap >= RT_ALIGN_64(pThis->cClusters >> 3, 8)) 1787 3200 { … … 1896 3309 static DECLCALLBACK(int) rtFsNtfsVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir) 1897 3310 { 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; 1900 3316 } 1901 3317 … … 2718 4134 pThis->fMntFlags = fMntFlags; 2719 4135 pThis->fNtfsFlags = fNtfsFlags; 4136 RTListInit(&pThis->IdxNodeUnusedHead); 2720 4137 2721 4138 rc = RTVfsFileGetSize(pThis->hVfsBacking, &pThis->cbBacking);
Note:
See TracChangeset
for help on using the changeset viewer.