Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

9215 lines
251 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. StrucSup.c
  5. Abstract:
  6. This module implements the Ntfs in-memory data structure manipulation
  7. routines
  8. Author:
  9. Gary Kimura [GaryKi] 21-May-1991
  10. Tom Miller [TomM] 9-Sep-1991
  11. Revision History:
  12. --*/
  13. #include "NtfsProc.h"
  14. #include "lockorder.h"
  15. //
  16. // Temporarily reference our local attribute definitions
  17. //
  18. extern ATTRIBUTE_DEFINITION_COLUMNS NtfsAttributeDefinitions[];
  19. //
  20. // The Bug check file id for this module
  21. //
  22. #define BugCheckFileId (NTFS_BUG_CHECK_STRUCSUP)
  23. //
  24. // The debug trace level
  25. //
  26. #define Dbg (DEBUG_TRACE_STRUCSUP)
  27. //
  28. // Define a tag for general pool allocations from this module
  29. //
  30. #undef MODULE_POOL_TAG
  31. #define MODULE_POOL_TAG ('sFtN')
  32. //
  33. // Define a structure to use when renaming or moving Lcb's so that
  34. // all the allocation for new filenames will succeed before munging names.
  35. // This new allocation can be for the filename attribute in an Lcb or the
  36. // filename in a Ccb.
  37. //
  38. typedef struct _NEW_FILENAME {
  39. //
  40. // Ntfs structure which needs the allocation.
  41. //
  42. PVOID Structure;
  43. PVOID NewAllocation;
  44. } NEW_FILENAME;
  45. typedef NEW_FILENAME *PNEW_FILENAME;
  46. //
  47. // Local support routines
  48. //
  49. VOID
  50. NtfsCheckScbForCache (
  51. IN OUT PSCB Scb
  52. );
  53. BOOLEAN
  54. NtfsRemoveScb (
  55. IN PIRP_CONTEXT IrpContext,
  56. IN PSCB Scb,
  57. IN BOOLEAN CheckForAttributeTable
  58. );
  59. BOOLEAN
  60. NtfsPrepareFcbForRemoval (
  61. IN PIRP_CONTEXT IrpContext,
  62. IN PFCB Fcb,
  63. IN PSCB StartingScb OPTIONAL,
  64. IN BOOLEAN CheckForAttributeTable
  65. );
  66. VOID
  67. NtfsTeardownFromLcb (
  68. IN PIRP_CONTEXT IrpContext,
  69. IN PVCB Vcb,
  70. IN PFCB StartingFcb,
  71. IN PLCB StartingLcb,
  72. IN BOOLEAN CheckForAttributeTable,
  73. IN ULONG AcquireFlags,
  74. OUT PBOOLEAN RemovedStartingLcb,
  75. OUT PBOOLEAN RemovedStartingFcb
  76. );
  77. VOID
  78. NtfsReserveCcbNamesInLcb (
  79. IN PIRP_CONTEXT IrpContext,
  80. IN PLCB Lcb,
  81. IN PULONG ParentNameLength OPTIONAL,
  82. IN ULONG LastComponentNameLength
  83. );
  84. VOID
  85. NtfsClearRecursiveLcb (
  86. IN PLCB Lcb
  87. );
  88. //
  89. // The following local routines are for manipulating the Fcb Table.
  90. // The first three are generic table calls backs.
  91. //
  92. RTL_GENERIC_COMPARE_RESULTS
  93. NtfsFcbTableCompare (
  94. IN PRTL_GENERIC_TABLE FcbTable,
  95. IN PVOID FirstStruct,
  96. IN PVOID SecondStruct
  97. );
  98. //
  99. // VOID
  100. // NtfsInsertFcbTableEntry (
  101. // IN PIRP_CONTEXT IrpContext,
  102. // IN PVCB Vcb,
  103. // IN PFCB Fcb,
  104. // IN FILE_REFERENCE FileReference
  105. // );
  106. //
  107. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  108. #define NtfsInsertFcbTableEntry(IC,V,F,FR) { \
  109. FCB_TABLE_ELEMENT _Key; \
  110. PFCB_TABLE_ELEMENT _NewKey; \
  111. _Key.FileReference = (FR); \
  112. _Key.Fcb = (F); \
  113. _NewKey = RtlInsertElementGenericTable( &(V)->FcbTable, \
  114. &_Key, \
  115. sizeof(FCB_TABLE_ELEMENT), \
  116. NULL ); \
  117. ASSERT( _NewKey->Fcb == _Key.Fcb ); \
  118. }
  119. #else
  120. #define NtfsInsertFcbTableEntry(IC,V,F,FR) { \
  121. FCB_TABLE_ELEMENT _Key; \
  122. _Key.FileReference = (FR); \
  123. _Key.Fcb = (F); \
  124. (VOID) RtlInsertElementGenericTable( &(V)->FcbTable, \
  125. &_Key, \
  126. sizeof(FCB_TABLE_ELEMENT), \
  127. NULL ); \
  128. }
  129. #endif
  130. //
  131. // VOID
  132. // NtfsInsertFcbTableEntryFull (
  133. // IN PIRP_CONTEXT IrpContext,
  134. // IN PVCB Vcb,
  135. // IN PFCB Fcb,
  136. // IN FILE_REFERENCE FileReference,
  137. // IN PVOID NodeOrParent,
  138. // IN ULONG SearchResult
  139. // );
  140. //
  141. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  142. #define NtfsInsertFcbTableEntryFull(IC,V,F,FR,N,SR) { \
  143. FCB_TABLE_ELEMENT _Key; \
  144. PFCB_TABLE_ELEMENT _NewKey; \
  145. _Key.FileReference = (FR); \
  146. _Key.Fcb = (F); \
  147. _NewKey = RtlInsertElementGenericTableFull( &(V)->FcbTable, \
  148. &_Key, \
  149. sizeof(FCB_TABLE_ELEMENT), \
  150. NULL, \
  151. (N), \
  152. (SR) \
  153. ); \
  154. ASSERT( _NewKey->Fcb == _Key.Fcb ); \
  155. }
  156. #else
  157. #define NtfsInsertFcbTableEntryFull(IC,V,F,FR,N,SR) { \
  158. FCB_TABLE_ELEMENT _Key; \
  159. _Key.FileReference = (FR); \
  160. _Key.Fcb = (F); \
  161. (VOID) RtlInsertElementGenericTableFull( &(V)->FcbTable, \
  162. &_Key, \
  163. sizeof(FCB_TABLE_ELEMENT), \
  164. NULL, \
  165. (N), \
  166. (SR) \
  167. ); \
  168. }
  169. #endif
  170. #ifdef ALLOC_PRAGMA
  171. #pragma alloc_text(PAGE, NtfsAllocateCompressionSync)
  172. #pragma alloc_text(PAGE, NtfsBuildNormalizedName)
  173. #pragma alloc_text(PAGE, NtfsBuildRelativeName)
  174. #pragma alloc_text(PAGE, NtfsCheckScbForCache)
  175. #pragma alloc_text(PAGE, NtfsClearRecursiveLcb)
  176. #pragma alloc_text(PAGE, NtfsCombineLcbs)
  177. #pragma alloc_text(PAGE, NtfsCreateCcb)
  178. #pragma alloc_text(PAGE, NtfsCreateFcb)
  179. #pragma alloc_text(PAGE, NtfsCreateFileLock)
  180. #pragma alloc_text(PAGE, NtfsCreateLcb)
  181. #pragma alloc_text(PAGE, NtfsCreatePrerestartScb)
  182. #pragma alloc_text(PAGE, NtfsCreateRootFcb)
  183. #pragma alloc_text(PAGE, NtfsCreateScb)
  184. #pragma alloc_text(PAGE, NtfsDeallocateCompressionSync)
  185. #pragma alloc_text(PAGE, NtfsDeleteCcb)
  186. #pragma alloc_text(PAGE, NtfsDeleteFcb)
  187. #pragma alloc_text(PAGE, NtfsDeleteLcb)
  188. #pragma alloc_text(PAGE, NtfsDeleteNormalizedName)
  189. #pragma alloc_text(PAGE, NtfsDeleteScb)
  190. #pragma alloc_text(PAGE, NtfsDeleteVcb)
  191. #pragma alloc_text(PAGE, NtfsFcbTableCompare)
  192. #pragma alloc_text(PAGE, NtfsGetDeallocatedClusters)
  193. #pragma alloc_text(PAGE, NtfsGetNextFcbTableEntry)
  194. #pragma alloc_text(PAGE, NtfsGetNextScb)
  195. #pragma alloc_text(PAGE, NtfsInitializeVcb)
  196. #pragma alloc_text(PAGE, NtfsLookupLcbByFlags)
  197. #pragma alloc_text(PAGE, NtfsMoveLcb)
  198. #pragma alloc_text(PAGE, NtfsPostToNewLengthQueue)
  199. #pragma alloc_text(PAGE, NtfsProcessNewLengthQueue)
  200. #pragma alloc_text(PAGE, NtfsRemoveScb)
  201. #pragma alloc_text(PAGE, NtfsRenameLcb)
  202. #pragma alloc_text(PAGE, NtfsReserveCcbNamesInLcb)
  203. #pragma alloc_text(PAGE, NtfsTeardownStructures)
  204. #pragma alloc_text(PAGE, NtfsTestStatusProc)
  205. #pragma alloc_text(PAGE, NtfsUpdateNormalizedName)
  206. #pragma alloc_text(PAGE, NtfsUpdateScbSnapshots)
  207. #pragma alloc_text(PAGE, NtfsWalkUpTree)
  208. #endif
  209. VOID
  210. NtfsInitializeVcb (
  211. IN PIRP_CONTEXT IrpContext,
  212. IN OUT PVCB Vcb,
  213. IN PDEVICE_OBJECT TargetDeviceObject,
  214. IN PVPB Vpb
  215. )
  216. /*++
  217. Routine Description:
  218. This routine initializes and inserts a new Vcb record into the in-memory
  219. data structure. The Vcb record "hangs" off the end of the Volume device
  220. object and must be allocated by our caller.
  221. Arguments:
  222. Vcb - Supplies the address of the Vcb record being initialized.
  223. TargetDeviceObject - Supplies the address of the target device object to
  224. associate with the Vcb record.
  225. Vpb - Supplies the address of the Vpb to associate with the Vcb record.
  226. Return Value:
  227. None.
  228. --*/
  229. {
  230. ULONG i;
  231. ULONG NumberProcessors;
  232. ASSERT_IRP_CONTEXT( IrpContext );
  233. PAGED_CODE();
  234. DebugTrace( +1, Dbg, ("NtfsInitializeVcb, Vcb = %08lx\n", Vcb) );
  235. //
  236. // First zero out the Vcb
  237. //
  238. RtlZeroMemory( Vcb, sizeof(VCB) );
  239. //
  240. // Set the node type code and size
  241. //
  242. Vcb->NodeTypeCode = NTFS_NTC_VCB;
  243. Vcb->NodeByteSize = sizeof(VCB);
  244. //
  245. // Set the following Vcb flags before putting the Vcb in the
  246. // Vcb queue. This will lock out checkpoints until the
  247. // volume is mounted.
  248. //
  249. SetFlag( Vcb->CheckpointFlags,
  250. VCB_CHECKPOINT_IN_PROGRESS |
  251. VCB_LAST_CHECKPOINT_CLEAN);
  252. //
  253. // Insert this vcb record into the vcb queue off of the global data
  254. // record
  255. //
  256. InsertTailList( &NtfsData.VcbQueue, &Vcb->VcbLinks );
  257. //
  258. // Set the target device object and vpb fields
  259. //
  260. ObReferenceObject( TargetDeviceObject );
  261. Vcb->TargetDeviceObject = TargetDeviceObject;
  262. Vcb->Vpb = Vpb;
  263. //
  264. // Set the state and condition fields. The removable media flag
  265. // is set based on the real device's characteristics.
  266. //
  267. if (FlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
  268. SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA );
  269. }
  270. SetFlag( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED );
  271. //
  272. // Initialized the ModifiedOpenFilesListhead and the delete notify queue.
  273. //
  274. InitializeListHead( &Vcb->NotifyUsnDeleteIrps );
  275. InitializeListHead( &Vcb->ModifiedOpenFiles );
  276. InitializeListHead( &Vcb->TimeOutListA );
  277. InitializeListHead( &Vcb->TimeOutListB );
  278. Vcb->CurrentTimeOutFiles = &Vcb->TimeOutListA;
  279. Vcb->AgedTimeOutFiles = &Vcb->TimeOutListB;
  280. //
  281. // Initialize list of OpenAttribute structures.
  282. //
  283. InitializeListHead( &Vcb->OpenAttributeData );
  284. //
  285. // Initialize list of deallocated clusters
  286. //
  287. InitializeListHead( &Vcb->DeallocatedClusterListHead );
  288. //
  289. // Initialize the synchronization objects in the Vcb.
  290. //
  291. ExInitializeResourceLite( &Vcb->Resource );
  292. ExInitializeResourceLite( &Vcb->MftFlushResource );
  293. ExInitializeFastMutex( &Vcb->FcbTableMutex );
  294. ExInitializeFastMutex( &Vcb->FcbSecurityMutex );
  295. ExInitializeFastMutex( &Vcb->ReservedClustersMutex );
  296. ExInitializeFastMutex( &Vcb->HashTableMutex );
  297. ExInitializeFastMutex( &Vcb->CheckpointMutex );
  298. KeInitializeEvent( &Vcb->CheckpointNotifyEvent, NotificationEvent, TRUE );
  299. //
  300. // Initialize the Fcb Table
  301. //
  302. RtlInitializeGenericTable( &Vcb->FcbTable,
  303. NtfsFcbTableCompare,
  304. NtfsAllocateFcbTableEntry,
  305. NtfsFreeFcbTableEntry,
  306. NULL );
  307. //
  308. // Initialize the property tunneling structure
  309. //
  310. FsRtlInitializeTunnelCache(&Vcb->Tunnel);
  311. #ifdef BENL_DBG
  312. InitializeListHead( &(Vcb->RestartRedoHead) );
  313. InitializeListHead( &(Vcb->RestartUndoHead) );
  314. #endif
  315. //
  316. // Possible calls that might fail begins here
  317. //
  318. //
  319. // Initialize the list head and mutex for the dir notify Irps.
  320. // Also the rename resource.
  321. //
  322. InitializeListHead( &Vcb->DirNotifyList );
  323. InitializeListHead( &Vcb->ViewIndexNotifyList );
  324. FsRtlNotifyInitializeSync( &Vcb->NotifySync );
  325. //
  326. // Allocate and initialize struct array for performance data. This
  327. // attempt to allocate could raise STATUS_INSUFFICIENT_RESOURCES.
  328. //
  329. NumberProcessors = KeNumberProcessors;
  330. Vcb->Statistics = NtfsAllocatePool( NonPagedPool,
  331. sizeof(FILE_SYSTEM_STATISTICS) * NumberProcessors );
  332. RtlZeroMemory( Vcb->Statistics, sizeof(FILE_SYSTEM_STATISTICS) * NumberProcessors );
  333. for (i = 0; i < NumberProcessors; i += 1) {
  334. Vcb->Statistics[i].Common.FileSystemType = FILESYSTEM_STATISTICS_TYPE_NTFS;
  335. Vcb->Statistics[i].Common.Version = 1;
  336. Vcb->Statistics[i].Common.SizeOfCompleteStructure =
  337. sizeof(FILE_SYSTEM_STATISTICS);
  338. }
  339. //
  340. // Initialize the cached runs.
  341. //
  342. NtfsInitializeCachedRuns( &Vcb->CachedRuns );
  343. //
  344. // Initialize the hash table.
  345. //
  346. NtfsInitializeHashTable( &Vcb->HashTable );
  347. //
  348. // Allocate a spare Vpb for the dismount case.
  349. //
  350. Vcb->SpareVpb = NtfsAllocatePoolWithTag( NonPagedPool, sizeof( VPB ), 'VftN' );
  351. //
  352. // Capture the current change count in the device we talk to.
  353. //
  354. if (FlagOn( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA )) {
  355. ULONG ChangeCount = 0;
  356. NtfsDeviceIoControlAsync( IrpContext,
  357. Vcb->TargetDeviceObject,
  358. IOCTL_DISK_CHECK_VERIFY,
  359. (PVOID) &ChangeCount,
  360. sizeof( ChangeCount ));
  361. //
  362. // Ignore any error for now. We will see it later if there is
  363. // one.
  364. //
  365. Vcb->DeviceChangeCount = ChangeCount;
  366. }
  367. //
  368. // Set the dirty page table hint to its initial value
  369. //
  370. Vcb->DirtyPageTableSizeHint = INITIAL_DIRTY_TABLE_HINT;
  371. //
  372. // Initialize the recently deallocated cluster mcbs and put the 1st one on the list.
  373. //
  374. FsRtlInitializeLargeMcb( &Vcb->DeallocatedClusters1.Mcb, PagedPool );
  375. FsRtlInitializeLargeMcb( &Vcb->DeallocatedClusters2.Mcb, PagedPool );
  376. Vcb->DeallocatedClusters1.Lsn.QuadPart = 0;
  377. InsertHeadList( &Vcb->DeallocatedClusterListHead, &Vcb->DeallocatedClusters1.Link );
  378. //
  379. // And return to our caller
  380. //
  381. DebugTrace( -1, Dbg, ("NtfsInitializeVcb -> VOID\n") );
  382. return;
  383. }
  384. BOOLEAN
  385. NtfsDeleteVcb (
  386. IN PIRP_CONTEXT IrpContext,
  387. IN OUT PVCB *Vcb
  388. )
  389. /*++
  390. Routine Description:
  391. This routine removes the Vcb record from Ntfs's in-memory data
  392. structures.
  393. Arguments:
  394. Vcb - Supplies the Vcb to be removed
  395. Return Value:
  396. BOOLEAN - TRUE if the Vcb was deleted, FALSE otherwise.
  397. --*/
  398. {
  399. PVOLUME_DEVICE_OBJECT VolDo;
  400. BOOLEAN AcquiredFcb;
  401. PSCB Scb;
  402. PFCB Fcb;
  403. BOOLEAN VcbDeleted = FALSE;
  404. ASSERT_IRP_CONTEXT( IrpContext );
  405. ASSERT_VCB( *Vcb );
  406. ASSERTMSG("Cannot delete Vcb ", !FlagOn((*Vcb)->VcbState, VCB_STATE_VOLUME_MOUNTED));
  407. PAGED_CODE();
  408. DebugTrace( +1, Dbg, ("NtfsDeleteVcb, *Vcb = %08lx\n", *Vcb) );
  409. //
  410. // Remember the volume device object.
  411. //
  412. VolDo = CONTAINING_RECORD( *Vcb, VOLUME_DEVICE_OBJECT, Vcb );
  413. //
  414. // Make sure that we can really delete the vcb
  415. //
  416. ASSERT( (*Vcb)->CloseCount == 0 );
  417. NtOfsPurgeSecurityCache( *Vcb );
  418. //
  419. // If the Vcb log file object is present then we need to
  420. // dereference it and uninitialize it through the cache.
  421. //
  422. if (((*Vcb)->LogFileObject != NULL) &&
  423. !FlagOn( (*Vcb)->CheckpointFlags, VCB_DEREFERENCED_LOG_FILE )) {
  424. CcUninitializeCacheMap( (*Vcb)->LogFileObject,
  425. &Li0,
  426. NULL );
  427. //
  428. // Set a flag indicating that we are dereferencing the LogFileObject.
  429. //
  430. SetFlag( (*Vcb)->CheckpointFlags, VCB_DEREFERENCED_LOG_FILE );
  431. ObDereferenceObject( (*Vcb)->LogFileObject );
  432. }
  433. //
  434. // Only proceed if the log file object went away. In the typical case the
  435. // close will come in through a recursive call from the ObDereference call
  436. // above.
  437. //
  438. if ((*Vcb)->LogFileObject == NULL) {
  439. //
  440. // If the OnDiskOat is not the same as the embedded table then
  441. // free the OnDisk table.
  442. //
  443. if (((*Vcb)->OnDiskOat != NULL) &&
  444. ((*Vcb)->OnDiskOat != &(*Vcb)->OpenAttributeTable)) {
  445. NtfsFreeRestartTable( (*Vcb)->OnDiskOat );
  446. NtfsFreePool( (*Vcb)->OnDiskOat );
  447. (*Vcb)->OnDiskOat = NULL;
  448. }
  449. //
  450. // Uninitialize the Mcb's for the deallocated cluster Mcb's.
  451. //
  452. if ((*Vcb)->DeallocatedClusters1.Link.Flink == NULL) {
  453. FsRtlUninitializeLargeMcb( &(*Vcb)->DeallocatedClusters1.Mcb );
  454. }
  455. if ((*Vcb)->DeallocatedClusters2.Link.Flink == NULL) {
  456. FsRtlUninitializeLargeMcb( &(*Vcb)->DeallocatedClusters2.Mcb );
  457. }
  458. while (!IsListEmpty(&(*Vcb)->DeallocatedClusterListHead )) {
  459. PDEALLOCATED_CLUSTERS Clusters;
  460. Clusters = (PDEALLOCATED_CLUSTERS) RemoveHeadList( &(*Vcb)->DeallocatedClusterListHead );
  461. FsRtlUninitializeLargeMcb( &Clusters->Mcb );
  462. if ((Clusters != &((*Vcb)->DeallocatedClusters2)) &&
  463. (Clusters != &((*Vcb)->DeallocatedClusters1))) {
  464. NtfsFreePool( Clusters );
  465. }
  466. }
  467. //
  468. // Clean up the Root Lcb if present.
  469. //
  470. if ((*Vcb)->RootLcb != NULL) {
  471. //
  472. // Cleanup the Lcb so the DeleteLcb routine won't look at any
  473. // other structures.
  474. //
  475. InitializeListHead( &(*Vcb)->RootLcb->ScbLinks );
  476. InitializeListHead( &(*Vcb)->RootLcb->FcbLinks );
  477. ClearFlag( (*Vcb)->RootLcb->LcbState,
  478. LCB_STATE_EXACT_CASE_IN_TREE | LCB_STATE_IGNORE_CASE_IN_TREE );
  479. NtfsDeleteLcb( IrpContext, &(*Vcb)->RootLcb );
  480. (*Vcb)->RootLcb = NULL;
  481. }
  482. //
  483. // Make sure the Fcb table is completely emptied. It is possible that an occasional Fcb
  484. // (along with its Scb) will not be deleted when the file object closes come in.
  485. //
  486. while (TRUE) {
  487. PVOID RestartKey;
  488. //
  489. // Always reinitialize the search so we get the first element in the tree.
  490. //
  491. RestartKey = NULL;
  492. NtfsAcquireFcbTable( IrpContext, *Vcb );
  493. Fcb = NtfsGetNextFcbTableEntry( *Vcb, &RestartKey );
  494. NtfsReleaseFcbTable( IrpContext, *Vcb );
  495. if (Fcb == NULL) { break; }
  496. while ((Scb = NtfsGetNextChildScb( Fcb, NULL )) != NULL) {
  497. NtfsDeleteScb( IrpContext, &Scb );
  498. }
  499. NtfsAcquireFcbTable( IrpContext, *Vcb );
  500. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcb );
  501. }
  502. //
  503. // Free the upcase table and attribute definitions. The upcase
  504. // table only gets freed if it is not the global table.
  505. //
  506. if (((*Vcb)->UpcaseTable != NULL) && ((*Vcb)->UpcaseTable != NtfsData.UpcaseTable)) {
  507. NtfsFreePool( (*Vcb)->UpcaseTable );
  508. }
  509. (*Vcb)->UpcaseTable = NULL;
  510. if (((*Vcb)->AttributeDefinitions != NULL) &&
  511. ((*Vcb)->AttributeDefinitions != NtfsAttributeDefinitions)) {
  512. NtfsFreePool( (*Vcb)->AttributeDefinitions );
  513. (*Vcb)->AttributeDefinitions = NULL;
  514. }
  515. //
  516. // Free the device name string if present.
  517. //
  518. if ((*Vcb)->DeviceName.Buffer != NULL) {
  519. NtfsFreePool( (*Vcb)->DeviceName.Buffer );
  520. (*Vcb)->DeviceName.Buffer = NULL;
  521. }
  522. FsRtlNotifyUninitializeSync( &(*Vcb)->NotifySync );
  523. //
  524. // We will free the structure allocated for the Lfs handle.
  525. //
  526. LfsDeleteLogHandle( (*Vcb)->LogHandle );
  527. (*Vcb)->LogHandle = NULL;
  528. //
  529. // Delete the vcb resource and also free the restart tables
  530. //
  531. //
  532. // Empty the list of OpenAttribute Data.
  533. //
  534. NtfsFreeAllOpenAttributeData( *Vcb );
  535. NtfsFreeRestartTable( &(*Vcb)->OpenAttributeTable );
  536. NtfsFreeRestartTable( &(*Vcb)->TransactionTable );
  537. //
  538. // The Vpb in the Vcb may be a temporary Vpb and we should free it here.
  539. //
  540. if (FlagOn( (*Vcb)->VcbState, VCB_STATE_TEMP_VPB )) {
  541. NtfsFreePool( (*Vcb)->Vpb );
  542. (*Vcb)->Vpb = NULL;
  543. }
  544. //
  545. // Uninitialize the hash table.
  546. //
  547. NtfsUninitializeHashTable( &(*Vcb)->HashTable );
  548. ExDeleteResourceLite( &(*Vcb)->Resource );
  549. ExDeleteResourceLite( &(*Vcb)->MftFlushResource );
  550. //
  551. // Delete the space used to store performance counters.
  552. //
  553. if ((*Vcb)->Statistics != NULL) {
  554. NtfsFreePool( (*Vcb)->Statistics );
  555. (*Vcb)->Statistics = NULL;
  556. }
  557. //
  558. // Tear down the file property tunneling structure
  559. //
  560. FsRtlDeleteTunnelCache(&(*Vcb)->Tunnel);
  561. #ifdef NTFS_CHECK_BITMAP
  562. if ((*Vcb)->BitmapCopy != NULL) {
  563. ULONG Count = 0;
  564. while (Count < (*Vcb)->BitmapPages) {
  565. if (((*Vcb)->BitmapCopy + Count)->Buffer != NULL) {
  566. NtfsFreePool( ((*Vcb)->BitmapCopy + Count)->Buffer );
  567. }
  568. Count += 1;
  569. }
  570. NtfsFreePool( (*Vcb)->BitmapCopy );
  571. (*Vcb)->BitmapCopy = NULL;
  572. }
  573. #endif
  574. //
  575. // Drop the reference on the target device object
  576. //
  577. ObDereferenceObject( (*Vcb)->TargetDeviceObject );
  578. //
  579. // Check that the Usn queues are empty.
  580. //
  581. ASSERT( IsListEmpty( &(*Vcb)->NotifyUsnDeleteIrps ));
  582. ASSERT( IsListEmpty( &(*Vcb)->ModifiedOpenFiles ));
  583. ASSERT( IsListEmpty( &(*Vcb)->TimeOutListA ));
  584. ASSERT( IsListEmpty( &(*Vcb)->TimeOutListB ));
  585. //
  586. // Unnitialize the cached runs.
  587. //
  588. NtfsUninitializeCachedRuns( &(*Vcb)->CachedRuns );
  589. //
  590. // Free any spare Vpb we might have stored in the Vcb.
  591. //
  592. if ((*Vcb)->SpareVpb != NULL) {
  593. NtfsFreePool( (*Vcb)->SpareVpb );
  594. (*Vcb)->SpareVpb = NULL;
  595. }
  596. //
  597. // Return the Vcb (i.e., the VolumeDeviceObject) to pool and null out
  598. // the input pointer to be safe
  599. //
  600. IoDeleteDevice( (PDEVICE_OBJECT)VolDo );
  601. *Vcb = NULL;
  602. VcbDeleted = TRUE;
  603. }
  604. //
  605. // And return to our caller
  606. //
  607. DebugTrace( -1, Dbg, ("NtfsDeleteVcb -> VOID\n") );
  608. return VcbDeleted;
  609. }
  610. PFCB
  611. NtfsCreateRootFcb (
  612. IN PIRP_CONTEXT IrpContext,
  613. IN PVCB Vcb
  614. )
  615. /*++
  616. Routine Description:
  617. This routine allocates, initializes, and inserts a new root FCB record
  618. into the in memory data structure. It also creates the necessary Root LCB
  619. record and inserts the root name into the prefix table.
  620. Arguments:
  621. Vcb - Supplies the Vcb to associate with the new root Fcb and Lcb
  622. Return Value:
  623. PFCB - returns pointer to the newly allocated root FCB.
  624. --*/
  625. {
  626. PFCB RootFcb;
  627. PLCB RootLcb;
  628. //
  629. // The following variables are only used for abnormal termination
  630. //
  631. PVOID UnwindStorage = NULL;
  632. PERESOURCE UnwindResource = NULL;
  633. PFAST_MUTEX UnwindFastMutex = NULL;
  634. PAGED_CODE();
  635. ASSERT_IRP_CONTEXT( IrpContext );
  636. ASSERT_VCB( Vcb );
  637. DebugTrace( +1, Dbg, ("NtfsCreateRootFcb, Vcb = %08lx\n", Vcb) );
  638. try {
  639. //
  640. // Allocate a new fcb and zero it out. We use Fcb locally so we
  641. // don't have to continually go through the Vcb
  642. //
  643. RootFcb =
  644. UnwindStorage = (PFCB)ExAllocateFromPagedLookasideList( &NtfsFcbIndexLookasideList );
  645. RtlZeroMemory( RootFcb, sizeof(FCB_INDEX) );
  646. //
  647. // Set the proper node type code and byte size
  648. //
  649. RootFcb->NodeTypeCode = NTFS_NTC_FCB;
  650. RootFcb->NodeByteSize = sizeof(FCB);
  651. SetFlag( RootFcb->FcbState, FCB_STATE_COMPOUND_INDEX );
  652. //
  653. // Initialize the Lcb queue and point back to our Vcb.
  654. //
  655. InitializeListHead( &RootFcb->LcbQueue );
  656. RootFcb->Vcb = Vcb;
  657. //
  658. // File Reference
  659. //
  660. NtfsSetSegmentNumber( &RootFcb->FileReference,
  661. 0,
  662. ROOT_FILE_NAME_INDEX_NUMBER );
  663. RootFcb->FileReference.SequenceNumber = ROOT_FILE_NAME_INDEX_NUMBER;
  664. //
  665. // Initialize the Scb
  666. //
  667. InitializeListHead( &RootFcb->ScbQueue );
  668. //
  669. // Allocate and initialize the resource variable
  670. //
  671. UnwindResource = RootFcb->Resource = NtfsAllocateEresource();
  672. //
  673. // Allocate and initialize the Fcb fast mutex.
  674. //
  675. UnwindFastMutex =
  676. RootFcb->FcbMutex = NtfsAllocatePool( NonPagedPool, sizeof( FAST_MUTEX ));
  677. ExInitializeFastMutex( UnwindFastMutex );
  678. //
  679. // Insert this new fcb into the fcb table
  680. //
  681. NtfsInsertFcbTableEntry( IrpContext, Vcb, RootFcb, RootFcb->FileReference );
  682. SetFlag( RootFcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  683. //
  684. // Now insert this new root fcb into it proper position in the graph with a
  685. // root lcb. First allocate an initialize the root lcb and then build the
  686. // lcb/scb graph.
  687. //
  688. {
  689. //
  690. // Use the root Lcb within the Fcb.
  691. //
  692. RootLcb = Vcb->RootLcb = (PLCB) &((PFCB_INDEX) RootFcb)->Lcb;
  693. RootLcb->NodeTypeCode = NTFS_NTC_LCB;
  694. RootLcb->NodeByteSize = sizeof(LCB);
  695. //
  696. // Insert the root lcb into the Root Fcb's queue
  697. //
  698. InsertTailList( &RootFcb->LcbQueue, &RootLcb->FcbLinks );
  699. RootLcb->Fcb = RootFcb;
  700. //
  701. // Use the embedded file name attribute.
  702. //
  703. RootLcb->FileNameAttr = (PFILE_NAME) &RootLcb->ParentDirectory;
  704. RootLcb->FileNameAttr->ParentDirectory = RootFcb->FileReference;
  705. RootLcb->FileNameAttr->FileNameLength = 1;
  706. RootLcb->FileNameAttr->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
  707. RootLcb->ExactCaseLink.LinkName.Buffer = (PWCHAR) &RootLcb->FileNameAttr->FileName;
  708. RootLcb->IgnoreCaseLink.LinkName.Buffer = Add2Ptr( RootLcb->FileNameAttr,
  709. NtfsFileNameSizeFromLength( 2 ));
  710. RootLcb->ExactCaseLink.LinkName.MaximumLength =
  711. RootLcb->ExactCaseLink.LinkName.Length =
  712. RootLcb->IgnoreCaseLink.LinkName.MaximumLength =
  713. RootLcb->IgnoreCaseLink.LinkName.Length = 2;
  714. RootLcb->ExactCaseLink.LinkName.Buffer[0] =
  715. RootLcb->IgnoreCaseLink.LinkName.Buffer[0] = L'\\';
  716. SetFlag( RootLcb->FileNameAttr->Flags, FILE_NAME_NTFS | FILE_NAME_DOS );
  717. //
  718. // Initialize both the ccb.
  719. //
  720. InitializeListHead( &RootLcb->CcbQueue );
  721. }
  722. } finally {
  723. DebugUnwind( NtfsCreateRootFcb );
  724. if (AbnormalTermination()) {
  725. if (UnwindResource) { NtfsFreeEresource( UnwindResource ); }
  726. if (UnwindStorage) { NtfsFreePool( UnwindStorage ); }
  727. if (UnwindFastMutex) { NtfsFreePool( UnwindFastMutex ); }
  728. }
  729. }
  730. DebugTrace( -1, Dbg, ("NtfsCreateRootFcb -> %8lx\n", RootFcb) );
  731. return RootFcb;
  732. }
  733. PFCB
  734. NtfsCreateFcb (
  735. IN PIRP_CONTEXT IrpContext,
  736. IN PVCB Vcb,
  737. IN FILE_REFERENCE FileReference,
  738. IN BOOLEAN IsPagingFile,
  739. IN BOOLEAN LargeFcb,
  740. OUT PBOOLEAN ReturnedExistingFcb OPTIONAL
  741. )
  742. /*++
  743. Routine Description:
  744. This routine allocates and initializes a new Fcb record. The record
  745. is not placed within the Fcb/Scb graph but is only inserted in the
  746. FcbTable.
  747. Arguments:
  748. Vcb - Supplies the Vcb to associate the new FCB under.
  749. FileReference - Supplies the file reference to use to identify the
  750. Fcb with. We will search the Fcb table for any preexisting
  751. Fcb's with the same file reference number.
  752. IsPagingFile - Indicates if we are creating an FCB for a paging file
  753. or some other type of file.
  754. LargeFcb - Indicates if we should use the larger of the compound Fcb's.
  755. ReturnedExistingFcb - Optionally indicates to the caller if the
  756. returned Fcb already existed
  757. Return Value:
  758. PFCB - Returns a pointer to the newly allocated FCB
  759. --*/
  760. {
  761. FCB_TABLE_ELEMENT Key;
  762. PFCB_TABLE_ELEMENT Entry;
  763. PFCB Fcb;
  764. PVOID NodeOrParent;
  765. TABLE_SEARCH_RESULT SearchResult;
  766. BOOLEAN LocalReturnedExistingFcb;
  767. BOOLEAN DeletedOldFcb = FALSE;
  768. //
  769. // The following variables are only used for abnormal termination
  770. //
  771. PVOID UnwindStorage = NULL;
  772. PERESOURCE UnwindResource = NULL;
  773. PFAST_MUTEX UnwindFastMutex = NULL;
  774. PAGED_CODE();
  775. ASSERT_IRP_CONTEXT( IrpContext );
  776. ASSERT_VCB( Vcb );
  777. ASSERT_SHARED_RESOURCE( &Vcb->Resource );
  778. DebugTrace( +1, Dbg, ("NtfsCreateFcb\n") );
  779. if (!ARGUMENT_PRESENT(ReturnedExistingFcb)) { ReturnedExistingFcb = &LocalReturnedExistingFcb; }
  780. //
  781. // First search the FcbTable for a matching fcb
  782. //
  783. Key.FileReference = FileReference;
  784. Fcb = NULL;
  785. if ((Entry = RtlLookupElementGenericTableFull( &Vcb->FcbTable, &Key, &NodeOrParent, &SearchResult )) != NULL) {
  786. Fcb = Entry->Fcb;
  787. //
  788. // It's possible that this Fcb has been deleted but in truncating and
  789. // growing the Mft we are reusing some of the file references.
  790. // If this file has been deleted but the Fcb is waiting around for
  791. // closes, we will remove it from the Fcb table and create a new Fcb
  792. // below.
  793. //
  794. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED )) {
  795. //
  796. // Remove it from the Fcb table and remember to create an
  797. // Fcb below.
  798. //
  799. NtfsDeleteFcbTableEntry( Fcb->Vcb,
  800. Fcb->FileReference );
  801. ClearFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  802. DeletedOldFcb = TRUE;
  803. Fcb = NULL;
  804. } else {
  805. *ReturnedExistingFcb = TRUE;
  806. }
  807. }
  808. //
  809. // Now check if we have an Fcb.
  810. //
  811. if (Fcb == NULL) {
  812. *ReturnedExistingFcb = FALSE;
  813. try {
  814. //
  815. // Allocate a new FCB and zero it out.
  816. //
  817. if (IsPagingFile ||
  818. NtfsSegmentNumber( &FileReference ) <= MASTER_FILE_TABLE2_NUMBER ||
  819. NtfsSegmentNumber( &FileReference ) == BAD_CLUSTER_FILE_NUMBER ||
  820. NtfsSegmentNumber( &FileReference ) == BIT_MAP_FILE_NUMBER) {
  821. Fcb = UnwindStorage = NtfsAllocatePoolWithTag( NonPagedPool,
  822. sizeof(FCB),
  823. 'fftN' );
  824. RtlZeroMemory( Fcb, sizeof(FCB) );
  825. if (IsPagingFile) {
  826. //
  827. // We can't have the pagingfile on a readonly volume.
  828. //
  829. if (NtfsIsVolumeReadOnly( Vcb )) {
  830. NtfsFreePool( Fcb );
  831. leave;
  832. }
  833. SetFlag( Fcb->FcbState, FCB_STATE_PAGING_FILE );
  834. //
  835. // We don't want to dismount this volume now that
  836. // we have a pagefile open on it.
  837. //
  838. SetFlag( Vcb->VcbState, VCB_STATE_DISALLOW_DISMOUNT );
  839. }
  840. SetFlag( Fcb->FcbState, FCB_STATE_NONPAGED );
  841. } else {
  842. if (LargeFcb) {
  843. Fcb = UnwindStorage =
  844. (PFCB)ExAllocateFromPagedLookasideList( &NtfsFcbIndexLookasideList );
  845. RtlZeroMemory( Fcb, sizeof( FCB_INDEX ));
  846. SetFlag( Fcb->FcbState, FCB_STATE_COMPOUND_INDEX );
  847. } else {
  848. Fcb = UnwindStorage =
  849. (PFCB)ExAllocateFromPagedLookasideList( &NtfsFcbDataLookasideList );
  850. RtlZeroMemory( Fcb, sizeof( FCB_DATA ));
  851. SetFlag( Fcb->FcbState, FCB_STATE_COMPOUND_DATA );
  852. }
  853. }
  854. //
  855. // Set the proper node type code and byte size
  856. //
  857. Fcb->NodeTypeCode = NTFS_NTC_FCB;
  858. Fcb->NodeByteSize = sizeof(FCB);
  859. //
  860. // Initialize the Lcb queue and point back to our Vcb, and indicate
  861. // that we are a directory
  862. //
  863. InitializeListHead( &Fcb->LcbQueue );
  864. Fcb->Vcb = Vcb;
  865. //
  866. // File Reference
  867. //
  868. Fcb->FileReference = FileReference;
  869. //
  870. // Initialize the Scb
  871. //
  872. InitializeListHead( &Fcb->ScbQueue );
  873. //
  874. // Allocate and initialize the resource variable
  875. //
  876. UnwindResource = Fcb->Resource = NtfsAllocateEresource();
  877. //
  878. // Allocate and initialize fast mutex for the Fcb.
  879. //
  880. UnwindFastMutex = Fcb->FcbMutex = NtfsAllocatePool( NonPagedPool, sizeof( FAST_MUTEX ));
  881. ExInitializeFastMutex( UnwindFastMutex );
  882. //
  883. // Insert this new fcb into the fcb table. We have to use the basic
  884. // version of this function when we deleted an old fcb because the "smarter" one
  885. // will just return back the old entry rather than researching
  886. //
  887. if (DeletedOldFcb) {
  888. NtfsInsertFcbTableEntry( IrpContext, Vcb, Fcb, FileReference );
  889. } else {
  890. NtfsInsertFcbTableEntryFull( IrpContext, Vcb, Fcb, FileReference, NodeOrParent, SearchResult );
  891. }
  892. SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  893. //
  894. // Set the flag to indicate if this is a system file.
  895. //
  896. if (NtfsSegmentNumber( &FileReference ) < FIRST_USER_FILE_NUMBER) {
  897. SetFlag( Fcb->FcbState, FCB_STATE_SYSTEM_FILE );
  898. }
  899. } finally {
  900. DebugUnwind( NtfsCreateFcb );
  901. if (AbnormalTermination()) {
  902. if (UnwindFastMutex) { NtfsFreePool( UnwindFastMutex ); }
  903. if (UnwindResource) { NtfsFreeEresource( UnwindResource ); }
  904. if (UnwindStorage) { NtfsFreePool( UnwindStorage ); }
  905. }
  906. }
  907. }
  908. DebugTrace( -1, Dbg, ("NtfsCreateFcb -> %08lx\n", Fcb) );
  909. return Fcb;
  910. }
  911. VOID
  912. NtfsDeleteFcb (
  913. IN PIRP_CONTEXT IrpContext,
  914. IN OUT PFCB *Fcb,
  915. OUT PBOOLEAN AcquiredFcbTable
  916. )
  917. /*++
  918. Routine Description:
  919. This routine deallocates and removes an FCB record from all Ntfs's in-memory
  920. data structures. It assumes that it does not have anything Scb children nor
  921. does it have any lcb edges going into it at the time of the call.
  922. Arguments:
  923. Fcb - Supplies the FCB to be removed
  924. AcquiredFcbTable - Set to FALSE when this routine releases the
  925. FcbTable.
  926. Return Value:
  927. None
  928. --*/
  929. {
  930. PAGED_CODE();
  931. ASSERT_IRP_CONTEXT( IrpContext );
  932. ASSERT_FCB( *Fcb );
  933. ASSERT( IsListEmpty(&(*Fcb)->ScbQueue) );
  934. ASSERT( (NodeType(*Fcb) == NTFS_NTC_FCB) );
  935. DebugTrace( +1, Dbg, ("NtfsDeleteFcb, *Fcb = %08lx\n", *Fcb) );
  936. //
  937. // First free any possible Scb snapshots.
  938. //
  939. NtfsFreeSnapshotsForFcb( IrpContext, *Fcb );
  940. //
  941. // This Fcb may be in the ExclusiveFcb list of the IrpContext.
  942. // If it is (The Flink is not NULL), we remove it.
  943. // And release the global resource.
  944. //
  945. if ((*Fcb)->ExclusiveFcbLinks.Flink != NULL) {
  946. RemoveEntryList( &(*Fcb)->ExclusiveFcbLinks );
  947. }
  948. //
  949. // Clear the IrpContext field for any request which may own the paging
  950. // IO resource for this Fcb.
  951. //
  952. if (IrpContext->CleanupStructure == *Fcb) {
  953. IrpContext->CleanupStructure = NULL;
  954. } else if (IrpContext->TopLevelIrpContext->CleanupStructure == *Fcb) {
  955. IrpContext->TopLevelIrpContext->CleanupStructure = NULL;
  956. }
  957. //
  958. // Either we own the FCB or nobody should own it. The extra acquire
  959. // here does not matter since we will free the resource below.
  960. //
  961. ASSERT( NtfsAcquireResourceExclusive( IrpContext, (*Fcb), FALSE ));
  962. ASSERT( ExGetSharedWaiterCount( (*Fcb)->Resource ) == 0 );
  963. ASSERT( ExGetExclusiveWaiterCount( (*Fcb)->Resource) == 0 );
  964. #ifdef NTFSDBG
  965. //
  966. // Lock order package needs to know this resource is gone
  967. //
  968. if (IrpContext->Vcb && FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  969. NtfsChangeResourceOrderState( IrpContext, NtfsIdentifyFcb( IrpContext->Vcb, *Fcb ), TRUE, FALSE );
  970. }
  971. #endif
  972. //
  973. // Deallocate the resources protecting the Fcb
  974. //
  975. NtfsFreeEresource( (*Fcb)->Resource );
  976. if ( (*Fcb)->PagingIoResource != NULL ) {
  977. if (IrpContext->CleanupStructure == *Fcb) {
  978. IrpContext->CleanupStructure = NULL;
  979. }
  980. NtfsFreeEresource( (*Fcb)->PagingIoResource );
  981. }
  982. //
  983. // Deallocate the fast mutex.
  984. //
  985. if ((*Fcb)->FcbMutex != NULL) {
  986. NtfsFreePool( (*Fcb)->FcbMutex );
  987. }
  988. //
  989. // Remove the fcb from the fcb table if present.
  990. //
  991. if (FlagOn( (*Fcb)->FcbState, FCB_STATE_IN_FCB_TABLE )) {
  992. NtfsDeleteFcbTableEntry( (*Fcb)->Vcb, (*Fcb)->FileReference );
  993. ClearFlag( (*Fcb)->FcbState, FCB_STATE_IN_FCB_TABLE );
  994. }
  995. NtfsReleaseFcbTable( IrpContext, (*Fcb)->Vcb );
  996. *AcquiredFcbTable = FALSE;
  997. //
  998. // Dereference and possibly deallocate the security descriptor if present.
  999. //
  1000. if ((*Fcb)->SharedSecurity != NULL) {
  1001. NtfsAcquireFcbSecurity( (*Fcb)->Vcb );
  1002. RemoveReferenceSharedSecurityUnsafe( &(*Fcb)->SharedSecurity );
  1003. NtfsReleaseFcbSecurity( (*Fcb)->Vcb );
  1004. }
  1005. //
  1006. // Release the quota control block.
  1007. //
  1008. if (NtfsPerformQuotaOperation( *Fcb )) {
  1009. NtfsDereferenceQuotaControlBlock( (*Fcb)->Vcb, &(*Fcb)->QuotaControl );
  1010. }
  1011. //
  1012. // Delete the UsnRecord if one exists.
  1013. //
  1014. if ((*Fcb)->FcbUsnRecord != NULL) {
  1015. PUSN_FCB ThisUsn, LastUsn;
  1016. //
  1017. // See if the Fcb is in one of the Usn blocks.
  1018. //
  1019. ThisUsn = &IrpContext->Usn;
  1020. do {
  1021. if (ThisUsn->CurrentUsnFcb == (*Fcb)) {
  1022. //
  1023. // Cleanup the UsnFcb in the IrpContext. It's possible that
  1024. // we might want to reuse the UsnFcb later in this request.
  1025. //
  1026. if (ThisUsn != &IrpContext->Usn) {
  1027. LastUsn->NextUsnFcb = ThisUsn->NextUsnFcb;
  1028. NtfsFreePool( ThisUsn );
  1029. } else {
  1030. ThisUsn->CurrentUsnFcb = NULL;
  1031. ThisUsn->NewReasons = 0;
  1032. ThisUsn->RemovedSourceInfo = 0;
  1033. ThisUsn->UsnFcbFlags = 0;
  1034. }
  1035. break;
  1036. }
  1037. if (ThisUsn->NextUsnFcb == NULL) { break; }
  1038. LastUsn = ThisUsn;
  1039. ThisUsn = ThisUsn->NextUsnFcb;
  1040. } while (TRUE);
  1041. //
  1042. // Remove the Fcb from the list in the Usn journal.
  1043. //
  1044. if ((*Fcb)->FcbUsnRecord->ModifiedOpenFilesLinks.Flink != NULL) {
  1045. NtfsLockFcb( IrpContext, (*Fcb)->Vcb->UsnJournal->Fcb );
  1046. RemoveEntryList( &(*Fcb)->FcbUsnRecord->ModifiedOpenFilesLinks );
  1047. if ((*Fcb)->FcbUsnRecord->TimeOutLinks.Flink != NULL) {
  1048. RemoveEntryList( &(*Fcb)->FcbUsnRecord->TimeOutLinks );
  1049. }
  1050. NtfsUnlockFcb( IrpContext, (*Fcb)->Vcb->UsnJournal->Fcb );
  1051. }
  1052. NtfsFreePool( (*Fcb)->FcbUsnRecord );
  1053. }
  1054. //
  1055. // Let our top-level caller know the Fcb was deleted.
  1056. //
  1057. if ((*Fcb)->FcbContext != NULL) {
  1058. (*Fcb)->FcbContext->FcbDeleted = TRUE;
  1059. }
  1060. //
  1061. // Deallocate the Fcb itself
  1062. //
  1063. if (FlagOn( (*Fcb)->FcbState, FCB_STATE_NONPAGED )) {
  1064. NtfsFreePool( *Fcb );
  1065. } else {
  1066. if (FlagOn( (*Fcb)->FcbState, FCB_STATE_COMPOUND_INDEX )) {
  1067. ExFreeToPagedLookasideList( &NtfsFcbIndexLookasideList, *Fcb );
  1068. } else {
  1069. ExFreeToPagedLookasideList( &NtfsFcbDataLookasideList, *Fcb );
  1070. }
  1071. }
  1072. //
  1073. // Zero out the input pointer
  1074. //
  1075. *Fcb = NULL;
  1076. //
  1077. // And return to our caller
  1078. //
  1079. DebugTrace( -1, Dbg, ("NtfsDeleteFcb -> VOID\n") );
  1080. return;
  1081. }
  1082. PFCB
  1083. NtfsGetNextFcbTableEntry (
  1084. IN PVCB Vcb,
  1085. IN PVOID *RestartKey
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This routine will enumerate through all of the fcb's for the given
  1090. vcb
  1091. Arguments:
  1092. Vcb - Supplies the Vcb used in this operation
  1093. RestartKey - This value is used by the table package to maintain
  1094. its position in the enumeration. It is initialized to NULL
  1095. for the first search.
  1096. Return Value:
  1097. PFCB - A pointer to the next fcb or NULL if the enumeration is
  1098. completed
  1099. --*/
  1100. {
  1101. PFCB Fcb;
  1102. PAGED_CODE();
  1103. Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey );
  1104. if (Fcb != NULL) {
  1105. Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb;
  1106. }
  1107. return Fcb;
  1108. }
  1109. PSCB
  1110. NtfsCreateScb (
  1111. IN PIRP_CONTEXT IrpContext,
  1112. IN PFCB Fcb,
  1113. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  1114. IN PCUNICODE_STRING AttributeName,
  1115. IN BOOLEAN ReturnExistingOnly,
  1116. OUT PBOOLEAN ReturnedExistingScb OPTIONAL
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. This routine allocates, initializes, and inserts a new Scb record into
  1121. the in memory data structures, provided one does not already exist
  1122. with the identical attribute record.
  1123. Arguments:
  1124. Fcb - Supplies the Fcb to associate the new SCB under.
  1125. AttributeTypeCode - Supplies the attribute type code for the new Scb
  1126. AttributeName - Supplies the attribute name for the new Scb, with
  1127. AttributeName->Length == 0 if there is no name.
  1128. ReturnExistingOnly - If specified as TRUE then only an existing Scb
  1129. will be returned. If no matching Scb exists then NULL is returned.
  1130. ReturnedExistingScb - Indicates if this procedure found an existing
  1131. Scb with the identical attribute record (variable is set to TRUE)
  1132. or if this procedure needed to create a new Scb (variable is set to
  1133. FALSE).
  1134. Return Value:
  1135. PSCB - Returns a pointer to the newly allocated SCB or NULL if there is
  1136. no Scb and ReturnExistingOnly is TRUE.
  1137. --*/
  1138. {
  1139. PSCB Scb;
  1140. NODE_TYPE_CODE NodeTypeCode;
  1141. NODE_BYTE_SIZE NodeByteSize;
  1142. BOOLEAN LocalReturnedExistingScb;
  1143. BOOLEAN PagingIoResource;
  1144. BOOLEAN ModifiedNoWrite;
  1145. #if (defined(NTFS_RWCMP_TRACE) || defined(SYSCACHE) || defined(NTFS_RWC_DEBUG) || defined(SYSCACHE_DEBUG))
  1146. BOOLEAN SyscacheFile = FALSE;
  1147. #endif
  1148. //
  1149. // The following variables are only used for abnormal termination
  1150. //
  1151. PVOID UnwindStorage[4];
  1152. POPLOCK UnwindOplock;
  1153. PNTFS_MCB UnwindMcb;
  1154. PLARGE_MCB UnwindAddedClustersMcb;
  1155. PLARGE_MCB UnwindRemovedClustersMcb;
  1156. BOOLEAN UnwindFromQueue;
  1157. BOOLEAN Nonpaged;
  1158. PAGED_CODE();
  1159. ASSERT_IRP_CONTEXT( IrpContext );
  1160. ASSERT_FCB( Fcb );
  1161. ASSERT( AttributeTypeCode >= $STANDARD_INFORMATION );
  1162. DebugTrace( +1, Dbg, ("NtfsCreateScb\n") );
  1163. if (!ARGUMENT_PRESENT(ReturnedExistingScb)) { ReturnedExistingScb = &LocalReturnedExistingScb; }
  1164. //
  1165. // Search the scb queue of the fcb looking for a matching
  1166. // attribute type code and attribute name
  1167. //
  1168. NtfsLockFcb( IrpContext, Fcb );
  1169. Scb = NULL;
  1170. while ((Scb = NtfsGetNextChildScb( Fcb, Scb )) != NULL) {
  1171. ASSERT_SCB( Scb );
  1172. //
  1173. // For every scb already in the fcb's queue check for a matching
  1174. // type code and name. If we find a match we return from this
  1175. // procedure right away.
  1176. //
  1177. if ((AttributeTypeCode == Scb->AttributeTypeCode) &&
  1178. !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED) &&
  1179. NtfsAreNamesEqual( IrpContext->Vcb->UpcaseTable,
  1180. &Scb->AttributeName,
  1181. (PUNICODE_STRING) AttributeName,
  1182. FALSE )) {
  1183. NtfsUnlockFcb( IrpContext, Fcb );
  1184. *ReturnedExistingScb = TRUE;
  1185. if (NtfsIsExclusiveScb(Scb)) {
  1186. NtfsSnapshotScb( IrpContext, Scb );
  1187. }
  1188. DebugTrace( -1, Dbg, ("NtfsCreateScb -> %08lx\n", Scb) );
  1189. return Scb;
  1190. }
  1191. }
  1192. //
  1193. // If the user only wanted an existing Scb then return NULL.
  1194. //
  1195. if (ReturnExistingOnly) {
  1196. NtfsUnlockFcb( IrpContext, Fcb );
  1197. DebugTrace( -1, Dbg, ("NtfsCreateScb -> %08lx\n", NULL) );
  1198. return NULL;
  1199. }
  1200. //
  1201. // We didn't find it so we are not going to be returning an existing Scb
  1202. // Initialize local variables for later cleanup.
  1203. //
  1204. PagingIoResource = FALSE;
  1205. ModifiedNoWrite = TRUE;
  1206. UnwindOplock = NULL;
  1207. UnwindMcb = NULL;
  1208. UnwindAddedClustersMcb = NULL;
  1209. UnwindRemovedClustersMcb = NULL;
  1210. UnwindFromQueue = FALSE;
  1211. Nonpaged = FALSE;
  1212. UnwindStorage[0] = NULL;
  1213. UnwindStorage[1] = NULL;
  1214. UnwindStorage[2] = NULL;
  1215. UnwindStorage[3] = NULL;
  1216. *ReturnedExistingScb = FALSE;
  1217. try {
  1218. //
  1219. // Decide the node type and size of the Scb. Also decide if it will be
  1220. // allocated from paged or non-paged pool.
  1221. //
  1222. if (AttributeTypeCode == $INDEX_ALLOCATION) {
  1223. if (NtfsSegmentNumber( &Fcb->FileReference ) == ROOT_FILE_NAME_INDEX_NUMBER) {
  1224. NodeTypeCode = NTFS_NTC_SCB_ROOT_INDEX;
  1225. } else {
  1226. NodeTypeCode = NTFS_NTC_SCB_INDEX;
  1227. }
  1228. NodeByteSize = SIZEOF_SCB_INDEX;
  1229. } else if ((NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) &&
  1230. (AttributeTypeCode == $DATA)) {
  1231. NodeTypeCode = NTFS_NTC_SCB_MFT;
  1232. NodeByteSize = SIZEOF_SCB_MFT;
  1233. } else {
  1234. NodeTypeCode = NTFS_NTC_SCB_DATA;
  1235. NodeByteSize = SIZEOF_SCB_DATA;
  1236. //
  1237. // If this is a user data stream then remember that we need
  1238. // a paging IO resource. Test for the cases where we DONT want
  1239. // to mark this stream as MODIFIED_NO_WRITE.
  1240. //
  1241. // If we need a paging IO resource the file must be a data stream.
  1242. //
  1243. if ((AttributeTypeCode == $DATA) ||
  1244. (AttributeTypeCode >= $FIRST_USER_DEFINED_ATTRIBUTE)) {
  1245. //
  1246. // For Data streams in the Root File or non-system files we need
  1247. // a paging IO resource and don't want to mark the file as
  1248. // MODIFIED_NO_WRITE.
  1249. //
  1250. //
  1251. // We should never reach this point for either the volume bitmap or
  1252. // volume dasd files.
  1253. //
  1254. ASSERT( (NtfsSegmentNumber( &Fcb->FileReference ) != VOLUME_DASD_NUMBER) &&
  1255. (NtfsSegmentNumber( &Fcb->FileReference ) != BIT_MAP_FILE_NUMBER) );
  1256. if (!FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  1257. //
  1258. // Make sure that all files in the reserved area are marked as system except
  1259. // the root index.
  1260. //
  1261. ASSERT( (NtfsSegmentNumber( &Fcb->FileReference ) >= FIRST_USER_FILE_NUMBER) ||
  1262. (NtfsSegmentNumber( &Fcb->FileReference ) == ROOT_FILE_NAME_INDEX_NUMBER) );
  1263. ModifiedNoWrite = FALSE;
  1264. PagingIoResource = TRUE;
  1265. }
  1266. }
  1267. }
  1268. //
  1269. // The scb will come from non-paged if the Fcb is non-paged or
  1270. // it is an attribute list.
  1271. //
  1272. if (FlagOn( Fcb->FcbState, FCB_STATE_NONPAGED ) || (AttributeTypeCode == $ATTRIBUTE_LIST)) {
  1273. Scb = UnwindStorage[0] = NtfsAllocatePoolWithTag( NonPagedPool, NodeByteSize, 'nftN' );
  1274. Nonpaged = TRUE;
  1275. } else if (AttributeTypeCode == $INDEX_ALLOCATION) {
  1276. //
  1277. // If the Fcb is an INDEX Fcb and the Scb is unused, then
  1278. // use that. Otherwise allocate from the lookaside list.
  1279. //
  1280. if (FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_INDEX ) &&
  1281. (SafeNodeType( &((PFCB_INDEX) Fcb)->Scb ) == 0)) {
  1282. Scb = (PSCB) &((PFCB_INDEX) Fcb)->Scb;
  1283. } else {
  1284. Scb = UnwindStorage[0] = (PSCB)NtfsAllocatePoolWithTag( PagedPool, SIZEOF_SCB_INDEX, 'SftN' );
  1285. }
  1286. #ifdef SYSCACHE_DEBUG
  1287. if (((IrpContext->OriginatingIrp != NULL) &&
  1288. (FsRtlIsSyscacheFile( IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->FileObject )))) {
  1289. KdPrint( ("NTFS: Found syscache dir: fo:0x%x scb:0x%x filref: 0x%x\n",
  1290. IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject,
  1291. Scb,
  1292. NtfsUnsafeSegmentNumber( &Fcb->FileReference )) );
  1293. SyscacheFile = TRUE;
  1294. }
  1295. #endif
  1296. } else {
  1297. //
  1298. // We can use the Scb field in the Fcb in all cases if it is
  1299. // unused. We will only use it for a data stream since
  1300. // it will have the longest life.
  1301. //
  1302. ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_INDEX ) ||
  1303. FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_DATA ));
  1304. if ((AttributeTypeCode == $DATA) &&
  1305. (SafeNodeType( &((PFCB_INDEX) Fcb)->Scb ) == 0)) {
  1306. Scb = (PSCB) &((PFCB_INDEX) Fcb)->Scb;
  1307. } else {
  1308. Scb = UnwindStorage[0] = (PSCB)ExAllocateFromPagedLookasideList( &NtfsScbDataLookasideList );
  1309. }
  1310. #ifdef SYSCACHE_DEBUG
  1311. if (((IrpContext->OriginatingIrp != NULL) &&
  1312. (FsRtlIsSyscacheFile( IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->FileObject )))) {
  1313. KdPrint( ("NTFS: Found syscache file: fo:0x%x scb:0x%x filref: 0x%x\n",
  1314. IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject,
  1315. Scb,
  1316. NtfsUnsafeSegmentNumber( &Fcb->FileReference )) );
  1317. SyscacheFile = TRUE;
  1318. }
  1319. if (!IsListEmpty( &Fcb->LcbQueue )) {
  1320. PLCB Lcb = (PLCB) CONTAINING_RECORD( Fcb->LcbQueue.Flink, LCB, FcbLinks.Flink );
  1321. while (TRUE) {
  1322. if ((Lcb->Scb != NULL) &&
  1323. (FlagOn( Lcb->Scb->ScbPersist, SCB_PERSIST_SYSCACHE_DIR ))) {
  1324. SyscacheFile = TRUE;
  1325. KdPrint( ("NTFS: Found syscache file in dir: fo:0x%x scb:0x%x filref: 0x%x\n",
  1326. IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject,
  1327. Scb,
  1328. NtfsUnsafeSegmentNumber( &Fcb->FileReference )) );
  1329. }
  1330. if (Lcb->FcbLinks.Flink != &Fcb->LcbQueue) {
  1331. Lcb = (PLCB)CONTAINING_RECORD( Lcb->FcbLinks.Flink, LCB, FcbLinks.Flink );
  1332. } else {
  1333. break;
  1334. }
  1335. }
  1336. }
  1337. #endif
  1338. #if (defined(NTFS_RWCMP_TRACE) || defined(SYSCACHE) || defined(NTFS_RWC_DEBUG))
  1339. if (( IrpContext->OriginatingIrp != NULL)
  1340. (FsRtlIsSyscacheFile(IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject))) {
  1341. SyscacheFile = TRUE;
  1342. }
  1343. #endif
  1344. }
  1345. //
  1346. // Store the Scb address and zero it out.
  1347. //
  1348. RtlZeroMemory( Scb, NodeByteSize );
  1349. #if (defined(NTFS_RWCMP_TRACE) || defined(SYSCACHE) || defined(NTFS_RWC_DEBUG))
  1350. if (SyscacheFile) {
  1351. SetFlag( Scb->ScbState, SCB_STATE_SYSCACHE_FILE );
  1352. }
  1353. #endif
  1354. //
  1355. // Set the proper node type code and byte size
  1356. //
  1357. Scb->Header.NodeTypeCode = NodeTypeCode;
  1358. Scb->Header.NodeByteSize = NodeByteSize;
  1359. //
  1360. // Set a back pointer to the resource we will be using
  1361. //
  1362. Scb->Header.Resource = Fcb->Resource;
  1363. //
  1364. // Decide if we will be using the PagingIoResource
  1365. //
  1366. if (PagingIoResource) {
  1367. PERESOURCE NewResource;
  1368. //
  1369. // Initialize it in the Fcb if it is not already there, and
  1370. // setup the pointer and flag in the Scb.
  1371. //
  1372. if (Fcb->PagingIoResource == NULL) {
  1373. //
  1374. // If this is a superseding open and our caller wants
  1375. // to acquire the paging io resource, then do it now.
  1376. // We could be in a state where there was no paging
  1377. // IO resource when we acquired the Fcb but will need
  1378. // it if this transaction needs to be unwound.
  1379. //
  1380. NewResource = NtfsAllocateEresource();
  1381. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) &&
  1382. (IrpContext->MajorFunction == IRP_MJ_CREATE) &&
  1383. (IrpContext->OriginatingIrp != NULL) &&
  1384. (IrpContext->CleanupStructure == NULL)) {
  1385. ExAcquireResourceExclusiveLite( NewResource, TRUE );
  1386. IrpContext->CleanupStructure = Fcb;
  1387. }
  1388. Fcb->PagingIoResource = NewResource;
  1389. }
  1390. Scb->Header.PagingIoResource = Fcb->PagingIoResource;
  1391. }
  1392. //
  1393. // Insert this Scb into our parents scb queue, and point back to
  1394. // our parent fcb and vcb. Put this entry at the head of the list.
  1395. // Any Scb on the delayed close queue goes to the end of the list.
  1396. //
  1397. InsertHeadList( &Fcb->ScbQueue, &Scb->FcbLinks );
  1398. UnwindFromQueue = TRUE;
  1399. Scb->Fcb = Fcb;
  1400. Scb->Vcb = Fcb->Vcb;
  1401. //
  1402. // If the attribute name exists then allocate a buffer for the
  1403. // attribute name and iniitalize it.
  1404. //
  1405. if (AttributeName->Length != 0) {
  1406. //
  1407. // The typical case is the $I30 string. If this matches then
  1408. // point to a common string.
  1409. //
  1410. if ((AttributeName->Length == NtfsFileNameIndex.Length) &&
  1411. (RtlEqualMemory( AttributeName->Buffer,
  1412. NtfsFileNameIndex.Buffer,
  1413. AttributeName->Length ) )) {
  1414. Scb->AttributeName = NtfsFileNameIndex;
  1415. } else {
  1416. Scb->AttributeName.Length = AttributeName->Length;
  1417. Scb->AttributeName.MaximumLength = (USHORT)(AttributeName->Length + sizeof( WCHAR ));
  1418. Scb->AttributeName.Buffer = UnwindStorage[1] =
  1419. NtfsAllocatePool(PagedPool, AttributeName->Length + sizeof( WCHAR ));
  1420. RtlCopyMemory( Scb->AttributeName.Buffer, AttributeName->Buffer, AttributeName->Length );
  1421. Scb->AttributeName.Buffer[AttributeName->Length / sizeof( WCHAR )] = L'\0';
  1422. }
  1423. }
  1424. //
  1425. // Set the attribute Type Code
  1426. //
  1427. Scb->AttributeTypeCode = AttributeTypeCode;
  1428. if (NtfsIsTypeCodeSubjectToQuota( AttributeTypeCode )){
  1429. SetFlag( Scb->ScbState, SCB_STATE_SUBJECT_TO_QUOTA );
  1430. }
  1431. //
  1432. // If this is an Mft Scb then initialize the cluster Mcb's.
  1433. //
  1434. if (NodeTypeCode == NTFS_NTC_SCB_MFT) {
  1435. FsRtlInitializeLargeMcb( &Scb->ScbType.Mft.AddedClusters, NonPagedPool );
  1436. UnwindAddedClustersMcb = &Scb->ScbType.Mft.AddedClusters;
  1437. FsRtlInitializeLargeMcb( &Scb->ScbType.Mft.RemovedClusters, NonPagedPool );
  1438. UnwindRemovedClustersMcb = &Scb->ScbType.Mft.RemovedClusters;
  1439. }
  1440. //
  1441. // Get the mutex for the Scb. We may be able to use the one in the Fcb.
  1442. // We can if the Scb is paged.
  1443. //
  1444. if (Nonpaged) {
  1445. SetFlag( Scb->ScbState, SCB_STATE_NONPAGED );
  1446. UnwindStorage[3] =
  1447. Scb->Header.FastMutex = NtfsAllocatePool( NonPagedPool, sizeof( FAST_MUTEX ));
  1448. ExInitializeFastMutex( Scb->Header.FastMutex );
  1449. } else {
  1450. Scb->Header.FastMutex = Fcb->FcbMutex;
  1451. }
  1452. //
  1453. // Initialize the FCB advanced header. Note that the mutex
  1454. // has already been setup (just above) so we don't re-setitup
  1455. // here. We will not support filter contexts for paging files
  1456. //
  1457. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  1458. FsRtlSetupAdvancedHeader( &Scb->Header, NULL );
  1459. } else {
  1460. SetFlag( Scb->Header.Flags, FSRTL_FLAG_ADVANCED_HEADER );
  1461. }
  1462. //
  1463. // Allocate the Nonpaged portion of the Scb.
  1464. //
  1465. Scb->NonpagedScb =
  1466. UnwindStorage[2] = (PSCB_NONPAGED)ExAllocateFromNPagedLookasideList( &NtfsScbNonpagedLookasideList );
  1467. RtlZeroMemory( Scb->NonpagedScb, sizeof( SCB_NONPAGED ));
  1468. Scb->NonpagedScb->NodeTypeCode = NTFS_NTC_SCB_NONPAGED;
  1469. Scb->NonpagedScb->NodeByteSize = sizeof( SCB_NONPAGED );
  1470. Scb->NonpagedScb->Vcb = Scb->Vcb;
  1471. //
  1472. // Fill in the advanced fields
  1473. //
  1474. Scb->Header.PendingEofAdvances = &Scb->EofListHead;
  1475. InitializeListHead( &Scb->EofListHead );
  1476. NtfsInitializeNtfsMcb( &Scb->Mcb,
  1477. &Scb->Header,
  1478. &Scb->McbStructs,
  1479. FlagOn( Scb->ScbState, SCB_STATE_NONPAGED )
  1480. ? NonPagedPool : PagedPool);
  1481. UnwindMcb = &Scb->Mcb;
  1482. InitializeListHead( &Scb->CcbQueue );
  1483. //
  1484. // Do that data stream specific initialization.
  1485. //
  1486. if (NodeTypeCode == NTFS_NTC_SCB_DATA) {
  1487. FsRtlInitializeOplock( &Scb->ScbType.Data.Oplock );
  1488. UnwindOplock = &Scb->ScbType.Data.Oplock;
  1489. InitializeListHead( &Scb->ScbType.Data.WaitForNewLength );
  1490. InitializeListHead( &Scb->ScbType.Data.CompressionSyncList );
  1491. //
  1492. // Set a flag if this is the Usn Journal.
  1493. //
  1494. if (!PagingIoResource &&
  1495. (*((PLONGLONG) &Fcb->Vcb->UsnJournalReference) == *((PLONGLONG) &Fcb->FileReference)) &&
  1496. (AttributeName->Length == JournalStreamName.Length) &&
  1497. RtlEqualMemory( AttributeName->Buffer,
  1498. JournalStreamName.Buffer,
  1499. JournalStreamName.Length )) {
  1500. SetFlag( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL );
  1501. }
  1502. #ifdef SYSCACHE_DEBUG
  1503. if (SyscacheFile)
  1504. {
  1505. Scb->LogSetNumber = InterlockedIncrement( &NtfsCurrentSyscacheLogSet ) % NUM_SC_LOGSETS;
  1506. NtfsSyscacheLogSet[Scb->LogSetNumber].Scb = Scb;
  1507. NtfsSyscacheLogSet[Scb->LogSetNumber].SegmentNumberUnsafe =
  1508. NtfsUnsafeSegmentNumber( &Fcb->FileReference );
  1509. if (NtfsSyscacheLogSet[Scb->LogSetNumber].SyscacheLog == NULL) {
  1510. NtfsSyscacheLogSet[Scb->LogSetNumber].SyscacheLog = NtfsAllocatePoolWithTagNoRaise( NonPagedPool, sizeof(SYSCACHE_LOG) * NUM_SC_EVENTS, ' neB' );
  1511. }
  1512. Scb->SyscacheLog = NtfsSyscacheLogSet[Scb->LogSetNumber].SyscacheLog;
  1513. Scb->SyscacheLogEntryCount = NUM_SC_EVENTS;
  1514. Scb->CurrentSyscacheLogEntry = -1;
  1515. //
  1516. // Degrade gracefully if no memory
  1517. //
  1518. if (!Scb->SyscacheLog)
  1519. {
  1520. Scb->SyscacheLogEntryCount = 0;
  1521. } else
  1522. {
  1523. memset( Scb->SyscacheLog, 0x61626162, sizeof( SYSCACHE_LOG ) * NUM_SC_EVENTS );
  1524. }
  1525. }
  1526. #endif
  1527. #ifdef SYSCACHE
  1528. InitializeListHead( &Scb->ScbType.Data.SyscacheEventList );
  1529. #endif
  1530. } else {
  1531. //
  1532. // There is a deallocated queue for indexes and the Mft.
  1533. //
  1534. InitializeListHead( &Scb->ScbType.Index.RecentlyDeallocatedQueue );
  1535. //
  1536. // Initialize index-specific fields.
  1537. //
  1538. if (AttributeTypeCode == $INDEX_ALLOCATION) {
  1539. InitializeListHead( &Scb->ScbType.Index.LcbQueue );
  1540. }
  1541. #ifdef SYSCACHE_DEBUG
  1542. if (SyscacheFile) {
  1543. SetFlag( Scb->ScbPersist, SCB_PERSIST_SYSCACHE_DIR );
  1544. }
  1545. #endif
  1546. }
  1547. //
  1548. // If this Scb should be marked as containing Lsn's or
  1549. // Update Sequence Arrays, do so now.
  1550. //
  1551. NtfsCheckScbForCache( Scb );
  1552. //
  1553. // We shouldn't make this call during restart.
  1554. //
  1555. ASSERT( !FlagOn( Scb->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ));
  1556. //
  1557. // Set the flag indicating that we want the Mapped Page Writer out of this file.
  1558. //
  1559. if (ModifiedNoWrite) {
  1560. SetFlag( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE );
  1561. }
  1562. //
  1563. // Let's make sure we caught all of the interesting cases.
  1564. //
  1565. ASSERT( ModifiedNoWrite ?
  1566. (((Scb->AttributeTypeCode != $DATA) ||
  1567. FlagOn( Scb->ScbState, SCB_STATE_USA_PRESENT ) ||
  1568. FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE ))) :
  1569. (((Scb->AttributeTypeCode == $DATA) &&
  1570. !FlagOn( Scb->ScbState, SCB_STATE_USA_PRESENT ) &&
  1571. !FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE ))) );
  1572. //
  1573. // Decide whether this is a view index and set
  1574. // the appropriate scb state bit accordingly.
  1575. //
  1576. if (FlagOn( Fcb->Info.FileAttributes, DUP_VIEW_INDEX_PRESENT ) &&
  1577. (Scb->AttributeTypeCode == $INDEX_ALLOCATION) &&
  1578. (Scb->AttributeName.Buffer != NtfsFileNameIndex.Buffer)) {
  1579. SetFlag( Scb->ScbState, SCB_STATE_VIEW_INDEX );
  1580. }
  1581. } finally {
  1582. DebugUnwind( NtfsCreateScb );
  1583. NtfsUnlockFcb( IrpContext, Fcb );
  1584. if (AbnormalTermination()) {
  1585. if (UnwindFromQueue) { RemoveEntryList( &Scb->FcbLinks ); }
  1586. if (UnwindMcb != NULL) { NtfsUninitializeNtfsMcb( UnwindMcb ); }
  1587. if (UnwindAddedClustersMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindAddedClustersMcb ); }
  1588. if (UnwindRemovedClustersMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindRemovedClustersMcb ); }
  1589. if (UnwindOplock != NULL) { FsRtlUninitializeOplock( UnwindOplock ); }
  1590. if (UnwindStorage[0]) { NtfsFreePool( UnwindStorage[0] );
  1591. } else if (Scb != NULL) { Scb->Header.NodeTypeCode = 0; }
  1592. if (UnwindStorage[1]) { NtfsFreePool( UnwindStorage[1] ); }
  1593. if (UnwindStorage[2]) { NtfsFreePool( UnwindStorage[2] ); }
  1594. if (UnwindStorage[3]) { NtfsFreePool( UnwindStorage[3] ); }
  1595. }
  1596. }
  1597. DebugTrace( -1, Dbg, ("NtfsCreateScb -> %08lx\n", Scb) );
  1598. #ifdef SYSCACHE_DEBUG
  1599. ASSERT( SyscacheFile || (Scb->SyscacheLogEntryCount == 0 && Scb->SyscacheLog == 0 ));
  1600. #endif
  1601. return Scb;
  1602. }
  1603. PSCB
  1604. NtfsCreatePrerestartScb (
  1605. IN PIRP_CONTEXT IrpContext,
  1606. IN PVCB Vcb,
  1607. IN PFILE_REFERENCE FileReference,
  1608. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  1609. IN PUNICODE_STRING AttributeName OPTIONAL,
  1610. IN ULONG BytesPerIndexBuffer
  1611. )
  1612. /*++
  1613. Routine Description:
  1614. This routine allocates, initializes, and inserts a new Scb record into
  1615. the in memory data structures, provided one does not already exist
  1616. with the identical attribute record. It does this on the FcbTable
  1617. off of the Vcb. If necessary this routine will also create the fcb
  1618. if one does not already exist for the indicated file reference.
  1619. Arguments:
  1620. Vcb - Supplies the Vcb to associate the new SCB under.
  1621. FileReference - Supplies the file reference for the new SCB this is
  1622. used to identify/create a new lookaside Fcb.
  1623. AttributeTypeCode - Supplies the attribute type code for the new SCB
  1624. AttributeName - Supplies the optional attribute name of the SCB
  1625. BytesPerIndexBuffer - For index Scbs, this must specify the bytes per
  1626. index buffer.
  1627. Return Value:
  1628. PSCB - Returns a pointer to the newly allocated SCB
  1629. --*/
  1630. {
  1631. PSCB Scb;
  1632. PFCB Fcb;
  1633. NODE_TYPE_CODE NodeTypeCode;
  1634. NODE_BYTE_SIZE NodeByteSize;
  1635. PAGED_CODE();
  1636. ASSERT_IRP_CONTEXT( IrpContext );
  1637. ASSERT_VCB( Vcb );
  1638. ASSERT( AttributeTypeCode >= $STANDARD_INFORMATION );
  1639. DebugTrace( +1, Dbg, ("NtfsCreatePrerestartScb\n") );
  1640. //
  1641. // Use a try-finally to release the Fcb table.
  1642. //
  1643. NtfsAcquireFcbTable( IrpContext, Vcb );
  1644. try {
  1645. //
  1646. // First make sure we have an Fcb of the proper file reference
  1647. // and indicate that it is from prerestart
  1648. //
  1649. Fcb = NtfsCreateFcb( IrpContext,
  1650. Vcb,
  1651. *FileReference,
  1652. FALSE,
  1653. TRUE,
  1654. NULL );
  1655. } finally {
  1656. NtfsReleaseFcbTable( IrpContext, Vcb );
  1657. }
  1658. //
  1659. // Search the child scbs of this fcb for a matching Scb (based on
  1660. // attribute type code and attribute name) if one is not found then
  1661. // we'll create a new scb. When we exit the following loop if the
  1662. // scb pointer to not null then we've found a preexisting scb.
  1663. //
  1664. Scb = NULL;
  1665. while ((Scb = NtfsGetNextChildScb(Fcb, Scb)) != NULL) {
  1666. ASSERT_SCB( Scb );
  1667. //
  1668. // The the attribute type codes match and if supplied the name also
  1669. // matches then we got our scb
  1670. //
  1671. if (Scb->AttributeTypeCode == AttributeTypeCode) {
  1672. if (!ARGUMENT_PRESENT( AttributeName )) {
  1673. if (Scb->AttributeName.Length == 0) {
  1674. break;
  1675. }
  1676. } else if (AttributeName->Length == 0
  1677. && Scb->AttributeName.Length == 0) {
  1678. break;
  1679. } else if (NtfsAreNamesEqual( IrpContext->Vcb->UpcaseTable,
  1680. AttributeName,
  1681. &Scb->AttributeName,
  1682. FALSE )) { // Ignore Case
  1683. break;
  1684. }
  1685. }
  1686. }
  1687. //
  1688. // If scb now null then we need to create a minimal scb. We always allocate
  1689. // these out of non-paged pool.
  1690. //
  1691. if (Scb == NULL) {
  1692. BOOLEAN ShareScb = FALSE;
  1693. //
  1694. // Allocate new scb and zero it out and set the node type code and byte size.
  1695. //
  1696. if (AttributeTypeCode == $INDEX_ALLOCATION) {
  1697. if (NtfsSegmentNumber( FileReference ) == ROOT_FILE_NAME_INDEX_NUMBER) {
  1698. NodeTypeCode = NTFS_NTC_SCB_ROOT_INDEX;
  1699. } else {
  1700. NodeTypeCode = NTFS_NTC_SCB_INDEX;
  1701. }
  1702. NodeByteSize = SIZEOF_SCB_INDEX;
  1703. } else if (NtfsSegmentNumber( FileReference ) <= MASTER_FILE_TABLE2_NUMBER
  1704. && (AttributeTypeCode == $DATA)) {
  1705. NodeTypeCode = NTFS_NTC_SCB_MFT;
  1706. NodeByteSize = SIZEOF_SCB_MFT;
  1707. } else {
  1708. NodeTypeCode = NTFS_NTC_SCB_DATA;
  1709. NodeByteSize = SIZEOF_SCB_DATA;
  1710. }
  1711. Scb = NtfsAllocatePoolWithTag( NonPagedPool, NodeByteSize, 'tftN' );
  1712. RtlZeroMemory( Scb, NodeByteSize );
  1713. //
  1714. // Fill in the node type code and size.
  1715. //
  1716. Scb->Header.NodeTypeCode = NodeTypeCode;
  1717. Scb->Header.NodeByteSize = NodeByteSize;
  1718. //
  1719. // Show that all of the Scb's are from nonpaged pool.
  1720. //
  1721. SetFlag( Scb->ScbState, SCB_STATE_NONPAGED );
  1722. //
  1723. // Initialize all of the fields that don't require allocations
  1724. // first. We want to make sure we don't leave the Scb in
  1725. // a state that could cause a crash during Scb teardown.
  1726. //
  1727. //
  1728. // Set a back pointer to the resource we will be using
  1729. //
  1730. Scb->Header.Resource = Fcb->Resource;
  1731. //
  1732. // Insert this scb into our parents scb queue and point back to our
  1733. // parent fcb and vcb. Put this entry at the head of the list.
  1734. // Any Scb on the delayed close queue goes to the end of the list.
  1735. //
  1736. InsertHeadList( &Fcb->ScbQueue, &Scb->FcbLinks );
  1737. Scb->Fcb = Fcb;
  1738. Scb->Vcb = Vcb;
  1739. InitializeListHead( &Scb->CcbQueue );
  1740. //
  1741. // Set the attribute type code recently deallocated information structures.
  1742. //
  1743. Scb->AttributeTypeCode = AttributeTypeCode;
  1744. //
  1745. // Fill in the advanced fields
  1746. //
  1747. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  1748. FsRtlSetupAdvancedHeader( &Scb->Header, NULL );
  1749. } else {
  1750. SetFlag( Scb->Header.Flags, FSRTL_FLAG_ADVANCED_HEADER );
  1751. }
  1752. Scb->Header.PendingEofAdvances = &Scb->EofListHead;
  1753. InitializeListHead( &Scb->EofListHead );
  1754. //
  1755. // Do that data stream specific initialization.
  1756. //
  1757. if (NodeTypeCode == NTFS_NTC_SCB_DATA) {
  1758. FsRtlInitializeOplock( &Scb->ScbType.Data.Oplock );
  1759. InitializeListHead( &Scb->ScbType.Data.WaitForNewLength );
  1760. InitializeListHead( &Scb->ScbType.Data.CompressionSyncList );
  1761. //
  1762. // Set a flag if this is the Usn Journal.
  1763. //
  1764. if (ARGUMENT_PRESENT( AttributeName ) &&
  1765. (*((PLONGLONG) &Vcb->UsnJournalReference) == *((PLONGLONG) &Fcb->FileReference)) &&
  1766. (AttributeName->Length == JournalStreamName.Length) &&
  1767. RtlEqualMemory( AttributeName->Buffer,
  1768. JournalStreamName.Buffer,
  1769. JournalStreamName.Length )) {
  1770. SetFlag( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL );
  1771. }
  1772. #ifdef SYSCACHE
  1773. InitializeListHead( &Scb->ScbType.Data.SyscacheEventList );
  1774. #endif
  1775. } else {
  1776. //
  1777. // There is a deallocated queue for indexes and the Mft.
  1778. //
  1779. InitializeListHead( &Scb->ScbType.Index.RecentlyDeallocatedQueue );
  1780. //
  1781. // Initialize index-specific fields.
  1782. //
  1783. if (AttributeTypeCode == $INDEX_ALLOCATION) {
  1784. Scb->ScbType.Index.BytesPerIndexBuffer = BytesPerIndexBuffer;
  1785. InitializeListHead( &Scb->ScbType.Index.LcbQueue );
  1786. }
  1787. }
  1788. //
  1789. // If this is an Mft Scb then initialize the cluster Mcb's.
  1790. //
  1791. if (NodeTypeCode == NTFS_NTC_SCB_MFT) {
  1792. FsRtlInitializeLargeMcb( &Scb->ScbType.Mft.AddedClusters, NonPagedPool );
  1793. FsRtlInitializeLargeMcb( &Scb->ScbType.Mft.RemovedClusters, NonPagedPool );
  1794. }
  1795. Scb->NonpagedScb = (PSCB_NONPAGED)ExAllocateFromNPagedLookasideList( &NtfsScbNonpagedLookasideList );
  1796. RtlZeroMemory( Scb->NonpagedScb, sizeof( SCB_NONPAGED ));
  1797. Scb->NonpagedScb->NodeTypeCode = NTFS_NTC_SCB_NONPAGED;
  1798. Scb->NonpagedScb->NodeByteSize = sizeof( SCB_NONPAGED );
  1799. Scb->NonpagedScb->Vcb = Vcb;
  1800. //
  1801. // Allocate and insert the mutext into the advanced header. This is
  1802. // done now (instead of up with the call to FsRtlSetupAdvancedHeader)
  1803. // to guarentee the existing order during initilization.
  1804. //
  1805. Scb->Header.FastMutex = NtfsAllocatePool( NonPagedPool, sizeof( FAST_MUTEX ));
  1806. ExInitializeFastMutex( Scb->Header.FastMutex );
  1807. NtfsInitializeNtfsMcb( &Scb->Mcb, &Scb->Header, &Scb->McbStructs, NonPagedPool );
  1808. //
  1809. // If the attribute name is present and the name length is greater than 0
  1810. // then allocate a buffer for the attribute name and initialize it.
  1811. //
  1812. if (ARGUMENT_PRESENT( AttributeName ) && (AttributeName->Length != 0)) {
  1813. //
  1814. // The typical case is the $I30 string. If this matches then
  1815. // point to a common string.
  1816. //
  1817. if ((AttributeName->Length == NtfsFileNameIndex.Length) &&
  1818. (RtlEqualMemory( AttributeName->Buffer,
  1819. NtfsFileNameIndex.Buffer,
  1820. AttributeName->Length ) )) {
  1821. Scb->AttributeName = NtfsFileNameIndex;
  1822. } else {
  1823. Scb->AttributeName.Length = AttributeName->Length;
  1824. Scb->AttributeName.MaximumLength = (USHORT)(AttributeName->Length + sizeof( WCHAR ));
  1825. Scb->AttributeName.Buffer = NtfsAllocatePool(PagedPool, AttributeName->Length + sizeof( WCHAR ));
  1826. RtlCopyMemory( Scb->AttributeName.Buffer, AttributeName->Buffer, AttributeName->Length );
  1827. Scb->AttributeName.Buffer[AttributeName->Length / sizeof( WCHAR )] = L'\0';
  1828. }
  1829. }
  1830. //
  1831. // If this Scb should be marked as containing Lsn's or
  1832. // Update Sequence Arrays, do so now.
  1833. //
  1834. NtfsCheckScbForCache( Scb );
  1835. //
  1836. // Always mark the prerestart Scb's as MODIFIED_NO_WRITE.
  1837. //
  1838. SetFlag( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE );
  1839. }
  1840. DebugTrace( -1, Dbg, ("NtfsCreatePrerestartScb -> %08lx\n", Scb) );
  1841. return Scb;
  1842. }
  1843. VOID
  1844. NtfsFreeScbAttributeName (
  1845. IN PWSTR AttributeNameBuffer
  1846. )
  1847. /*++
  1848. Routine Description:
  1849. This routine frees the pool used by an Scb attribute name iff it is
  1850. not one of the default system attribute names.
  1851. Arguments:
  1852. AttributeName - Supplies the attribute name buffer to free
  1853. Return Value:
  1854. None.
  1855. --*/
  1856. {
  1857. if ((AttributeNameBuffer != NULL) &&
  1858. (AttributeNameBuffer != NtfsFileNameIndex.Buffer) &&
  1859. (AttributeNameBuffer != NtfsObjId.Buffer) &&
  1860. (AttributeNameBuffer != NtfsQuota.Buffer)) {
  1861. NtfsFreePool( AttributeNameBuffer );
  1862. }
  1863. }
  1864. VOID
  1865. NtfsDeleteScb (
  1866. IN PIRP_CONTEXT IrpContext,
  1867. IN OUT PSCB *Scb
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. This routine deallocates and removes an Scb record
  1872. from Ntfs's in-memory data structures. It assume that is does not have
  1873. any children lcb emanating from it.
  1874. Arguments:
  1875. Scb - Supplies the SCB to be removed
  1876. Return Value:
  1877. None.
  1878. --*/
  1879. {
  1880. PVCB Vcb;
  1881. PFCB Fcb;
  1882. POPEN_ATTRIBUTE_ENTRY AttributeEntry;
  1883. USHORT ThisNodeType;
  1884. PAGED_CODE();
  1885. ASSERT_IRP_CONTEXT( IrpContext );
  1886. ASSERT_SCB( *Scb );
  1887. ASSERT( (*Scb)->CleanupCount == 0 );
  1888. DebugTrace( +1, Dbg, ("NtfsDeleteScb, *Scb = %08lx\n", *Scb) );
  1889. Fcb = (*Scb)->Fcb;
  1890. Vcb = Fcb->Vcb;
  1891. RemoveEntryList( &(*Scb)->FcbLinks );
  1892. ThisNodeType = SafeNodeType( *Scb );
  1893. //
  1894. // If this is a bitmap Scb for a directory then make sure the record
  1895. // allocation structure is uninitialized. Otherwise we will leave a
  1896. // stale pointer for the record allocation package.
  1897. //
  1898. if (((*Scb)->AttributeTypeCode == $BITMAP) &&
  1899. IsDirectory( &Fcb->Info)) {
  1900. PLIST_ENTRY Links;
  1901. PSCB IndexAllocationScb;
  1902. Links = Fcb->ScbQueue.Flink;
  1903. while (Links != &Fcb->ScbQueue) {
  1904. IndexAllocationScb = CONTAINING_RECORD( Links, SCB, FcbLinks );
  1905. if (IndexAllocationScb->AttributeTypeCode == $INDEX_ALLOCATION) {
  1906. NtfsUninitializeRecordAllocation( IrpContext,
  1907. &IndexAllocationScb->ScbType.Index.RecordAllocationContext );
  1908. IndexAllocationScb->ScbType.Index.AllocationInitialized = FALSE;
  1909. break;
  1910. }
  1911. Links = Links->Flink;
  1912. }
  1913. }
  1914. //
  1915. // Delete the write mask, if one is being maintained.
  1916. //
  1917. #ifdef SYSCACHE
  1918. if ((ThisNodeType == NTFS_NTC_SCB_DATA) &&
  1919. ((*Scb)->ScbType.Data.WriteMask != (PULONG)NULL)) {
  1920. NtfsFreePool((*Scb)->ScbType.Data.WriteMask);
  1921. }
  1922. #endif
  1923. //
  1924. // Mark our entry in the Open Attribute Table as free,
  1925. // although it will not be deleted until some future
  1926. // checkpoint. Log this change as well, as long as the
  1927. // log file is active.
  1928. //
  1929. if (((*Scb)->NonpagedScb != NULL) &&
  1930. ((*Scb)->NonpagedScb->OpenAttributeTableIndex != 0)) {
  1931. NtfsAcquireSharedRestartTable( &Vcb->OpenAttributeTable, TRUE );
  1932. AttributeEntry = GetRestartEntryFromIndex( &Vcb->OpenAttributeTable,
  1933. (*Scb)->NonpagedScb->OpenAttributeTableIndex );
  1934. AttributeEntry->OatData->Overlay.Scb = NULL;
  1935. NtfsReleaseRestartTable( &Vcb->OpenAttributeTable );
  1936. //
  1937. // "Steal" the name, and let it belong to the Open Attribute Table
  1938. // entry and deallocate it only during checkpoints.
  1939. //
  1940. (*Scb)->AttributeName.Buffer = NULL;
  1941. }
  1942. //
  1943. // Uninitialize the file lock and oplock variables if this
  1944. // a data Scb. For the index case make sure that the lcb queue
  1945. // is empty. If this is for an Mft Scb then uninitialize the
  1946. // allocation Mcb's.
  1947. //
  1948. NtfsUninitializeNtfsMcb( &(*Scb)->Mcb );
  1949. if (ThisNodeType == NTFS_NTC_SCB_DATA ) {
  1950. FsRtlUninitializeOplock( &(*Scb)->ScbType.Data.Oplock );
  1951. if ((*Scb)->ScbType.Data.FileLock != NULL) {
  1952. FsRtlFreeFileLock( (*Scb)->ScbType.Data.FileLock );
  1953. }
  1954. #ifdef SYSCACHE
  1955. while (!IsListEmpty( &(*Scb)->ScbType.Data.SyscacheEventList )) {
  1956. PSYSCACHE_EVENT SyscacheEvent;
  1957. SyscacheEvent = CONTAINING_RECORD( (*Scb)->ScbType.Data.SyscacheEventList.Flink,
  1958. SYSCACHE_EVENT,
  1959. EventList );
  1960. RemoveEntryList( &SyscacheEvent->EventList );
  1961. NtfsFreePool( SyscacheEvent );
  1962. }
  1963. #endif
  1964. ASSERT( IsListEmpty( &(*Scb)->ScbType.Data.CompressionSyncList ));
  1965. #ifdef NTFS_RWC_DEBUG
  1966. if ((*Scb)->ScbType.Data.HistoryBuffer != NULL) {
  1967. NtfsFreePool( (*Scb)->ScbType.Data.HistoryBuffer );
  1968. (*Scb)->ScbType.Data.HistoryBuffer = NULL;
  1969. }
  1970. #endif
  1971. } else if (ThisNodeType != NTFS_NTC_SCB_MFT) {
  1972. //
  1973. // Walk through and remove any Lcb's from the queue.
  1974. //
  1975. while (!IsListEmpty( &(*Scb)->ScbType.Index.LcbQueue )) {
  1976. PLCB NextLcb;
  1977. NextLcb = CONTAINING_RECORD( (*Scb)->ScbType.Index.LcbQueue.Flink,
  1978. LCB,
  1979. ScbLinks );
  1980. NtfsDeleteLcb( IrpContext, &NextLcb );
  1981. }
  1982. if ((*Scb)->ScbType.Index.NormalizedName.Buffer != NULL) {
  1983. NtfsDeleteNormalizedName( *Scb );
  1984. }
  1985. } else {
  1986. FsRtlUninitializeLargeMcb( &(*Scb)->ScbType.Mft.AddedClusters );
  1987. FsRtlUninitializeLargeMcb( &(*Scb)->ScbType.Mft.RemovedClusters );
  1988. }
  1989. if ((*Scb)->EncryptionContext != NULL) {
  1990. //
  1991. // Let the encryption driver do anything necessary to clean up
  1992. // its private data structures.
  1993. //
  1994. if (NtfsData.EncryptionCallBackTable.CleanUp != NULL) {
  1995. NtfsData.EncryptionCallBackTable.CleanUp( &(*Scb)->EncryptionContext );
  1996. }
  1997. //
  1998. // If the encryption driver didn't clear this in its cleanup routine,
  1999. // or if there is no cleanup routine registered, we should free any
  2000. // for the encryption context ourselves.
  2001. //
  2002. if ((*Scb)->EncryptionContext != NULL) {
  2003. NtfsFreePool( (*Scb)->EncryptionContext );
  2004. (*Scb)->EncryptionContext = NULL;
  2005. }
  2006. }
  2007. //
  2008. // Show there is no longer a snapshot Scb, if there is a snapshot.
  2009. // We rely on the snapshot package to correctly recognize the
  2010. // the case where the Scb field is gone.
  2011. //
  2012. if ((*Scb)->ScbSnapshot != NULL) {
  2013. (*Scb)->ScbSnapshot->Scb = NULL;
  2014. }
  2015. //
  2016. // Cleanup Filesystem Filter contexts (this was moved to the point
  2017. // before the FastMutex is freed because this routine now uses it)
  2018. //
  2019. if (FlagOn( (*Scb)->Header.Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS )) {
  2020. FsRtlTeardownPerStreamContexts( (PFSRTL_ADVANCED_FCB_HEADER)&(*Scb)->Header );
  2021. }
  2022. //
  2023. // Deallocate the fast mutex if not in the Fcb.
  2024. //
  2025. if (((*Scb)->Header.FastMutex != (*Scb)->Fcb->FcbMutex) &&
  2026. ((*Scb)->Header.FastMutex != NULL)) {
  2027. NtfsFreePool( (*Scb)->Header.FastMutex );
  2028. }
  2029. //
  2030. // Deallocate the non-paged scb.
  2031. //
  2032. if ((*Scb)->NonpagedScb != NULL) {
  2033. ExFreeToNPagedLookasideList( &NtfsScbNonpagedLookasideList, (*Scb)->NonpagedScb );
  2034. }
  2035. //
  2036. // Deallocate the attribute name.
  2037. //
  2038. NtfsFreeScbAttributeName( (*Scb)->AttributeName.Buffer );
  2039. //
  2040. // See if CollationData is to be deleted.
  2041. //
  2042. if (FlagOn((*Scb)->ScbState, SCB_STATE_DELETE_COLLATION_DATA)) {
  2043. NtfsFreePool((*Scb)->ScbType.Index.CollationData);
  2044. }
  2045. //
  2046. // Always directly free the Mft and non-paged Scb's.
  2047. //
  2048. if (FlagOn( (*Scb)->ScbState, SCB_STATE_NONPAGED ) ||
  2049. (ThisNodeType == NTFS_NTC_SCB_MFT)) {
  2050. NtfsFreePool( *Scb );
  2051. } else {
  2052. //
  2053. // Free any final reserved clusters for data Scb's.
  2054. //
  2055. if (ThisNodeType == NTFS_NTC_SCB_DATA) {
  2056. //
  2057. // Free the reserved bitmap and reserved clusters if present.
  2058. //
  2059. if ((*Scb)->ScbType.Data.ReservedBitMap != NULL) {
  2060. NtfsDeleteReservedBitmap( *Scb );
  2061. }
  2062. }
  2063. //
  2064. // Now free the Scb itself.
  2065. //
  2066. // Check if this is an embedded Scb. This could be part of either an INDEX_FCB
  2067. // or a DATA_FCB. We depend on the fact that the Scb would be in the same
  2068. // location in either case.
  2069. //
  2070. if ((*Scb) == (PSCB) &((PFCB_DATA) (*Scb)->Fcb)->Scb) {
  2071. (*Scb)->Header.NodeTypeCode = 0;
  2072. } else if (SafeNodeType( *Scb ) == NTFS_NTC_SCB_DATA) {
  2073. ExFreeToPagedLookasideList( &NtfsScbDataLookasideList, *Scb );
  2074. } else {
  2075. NtfsFreePool( *Scb );
  2076. }
  2077. }
  2078. //
  2079. // Zero out the input pointer
  2080. //
  2081. *Scb = NULL;
  2082. //
  2083. // And return to our caller
  2084. //
  2085. DebugTrace( -1, Dbg, ("NtfsDeleteScb -> VOID\n") );
  2086. return;
  2087. }
  2088. BOOLEAN
  2089. NtfsUpdateNormalizedName (
  2090. IN PIRP_CONTEXT IrpContext,
  2091. IN PSCB ParentScb,
  2092. IN PSCB Scb,
  2093. IN PFILE_NAME FileName OPTIONAL,
  2094. IN BOOLEAN CheckBufferSizeOnly
  2095. )
  2096. /*++
  2097. Routine Description:
  2098. This routine is called to update the normalized name in an IndexScb.
  2099. This name will be the path from the root without any short name components.
  2100. This routine will append the given name if present provided this is not a
  2101. DOS only name. In any other case this routine will go to the disk to
  2102. find the name. This routine will handle the case where there is an existing buffer
  2103. and the data will fit, as well as the case where the buffer doesn't exist
  2104. or is too small.
  2105. Arguments:
  2106. ParentScb - Supplies the parent of the current Scb. The name for the target
  2107. scb is appended to the name in this Scb.
  2108. Scb - Supplies the target Scb to add the name to.
  2109. FileName - If present this is a filename attribute for this Scb. We check
  2110. that it is not a DOS-only name.
  2111. CheckBufferSizeOnly - Indicates that we don't want to change the name yet. Just
  2112. verify that the buffer is the correct size.
  2113. Return Value:
  2114. BOOLEAN - TRUE if we updated the name in the Scb, FALSE otherwise. We would return
  2115. FALSE only if the parent becomes uninitialized on us. Any callers who can't
  2116. tolerate this must own the parent.
  2117. --*/
  2118. {
  2119. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  2120. PFILE_NAME OriginalFileName;
  2121. BOOLEAN CleanupContext = FALSE;
  2122. ULONG Length;
  2123. ULONG UnsafeLength;
  2124. ULONG SeparatorLength;
  2125. BOOLEAN UpdatedName = TRUE;
  2126. PAGED_CODE();
  2127. ASSERT( NodeType( Scb ) == NTFS_NTC_SCB_INDEX );
  2128. ASSERT( NodeType( ParentScb ) == NTFS_NTC_SCB_INDEX ||
  2129. NodeType( ParentScb ) == NTFS_NTC_SCB_ROOT_INDEX );
  2130. //
  2131. // Use a try-finally to clean up the attribute context.
  2132. //
  2133. try {
  2134. //
  2135. // If the parent is the root then we don't need an extra separator.
  2136. //
  2137. SeparatorLength = 1;
  2138. if (ParentScb == ParentScb->Vcb->RootIndexScb) {
  2139. SeparatorLength = 0;
  2140. }
  2141. //
  2142. // Remember if we got a file name from our caller.
  2143. //
  2144. OriginalFileName = FileName;
  2145. //
  2146. // The only safe time to examine the normalized name structures are
  2147. // when holding the hash table mutex. These values shouldn't change
  2148. // often but if they do (and we are doing unsynchronized tests) then
  2149. // we will simply restart the logic.
  2150. //
  2151. do {
  2152. //
  2153. // If the filename isn't present or is a DOS-only name then go to
  2154. // disk to find another name for this Scb.
  2155. //
  2156. if (!ARGUMENT_PRESENT( FileName ) || (FileName->Flags == FILE_NAME_DOS)) {
  2157. BOOLEAN Found;
  2158. NtfsInitializeAttributeContext( &Context );
  2159. CleanupContext = TRUE;
  2160. //
  2161. // Walk through the names for this entry. There better
  2162. // be one which is not a DOS-only name.
  2163. //
  2164. Found = NtfsLookupAttributeByCode( IrpContext,
  2165. Scb->Fcb,
  2166. &Scb->Fcb->FileReference,
  2167. $FILE_NAME,
  2168. &Context );
  2169. while (Found) {
  2170. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &Context ));
  2171. if (FileName->Flags != FILE_NAME_DOS) { break; }
  2172. Found = NtfsLookupNextAttributeByCode( IrpContext,
  2173. Scb->Fcb,
  2174. $FILE_NAME,
  2175. &Context );
  2176. }
  2177. //
  2178. // We should have found the entry.
  2179. //
  2180. if (!Found) {
  2181. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  2182. }
  2183. }
  2184. //
  2185. // Compute the length we need for the name. This is unsynchronized so
  2186. // we will verify it later.
  2187. UnsafeLength = ParentScb->ScbType.Index.NormalizedName.Length + (FileName->FileNameLength + SeparatorLength) * sizeof( WCHAR );
  2188. //
  2189. // If the current buffer is insufficient then allocate a new one.
  2190. // Note that these are all unsafe tests. We will have to
  2191. // verify the values after acquiring the hash table mutex.
  2192. //
  2193. if (Scb->ScbType.Index.NormalizedName.MaximumLength < UnsafeLength) {
  2194. PVOID OldBuffer;
  2195. PVOID NewBuffer;
  2196. NewBuffer = NtfsAllocatePoolWithTag( PagedPool, UnsafeLength, 'oftN' );
  2197. //
  2198. // Now acquire the Hash table mutex and verify the numbers. If they
  2199. // are still valid then continue.
  2200. //
  2201. NtfsAcquireHashTable( Scb->Vcb );
  2202. //
  2203. // Check for unexpected changes.
  2204. //
  2205. Length = ParentScb->ScbType.Index.NormalizedName.Length + (FileName->FileNameLength + SeparatorLength) * sizeof( WCHAR );
  2206. if ((ParentScb->ScbType.Index.NormalizedName.Length == 0) ||
  2207. (Length > UnsafeLength)) {
  2208. //
  2209. // The following is an exit condition for us.
  2210. //
  2211. if (ParentScb->ScbType.Index.NormalizedName.Length == 0) {
  2212. UpdatedName = FALSE;
  2213. }
  2214. NtfsReleaseHashTable( Scb->Vcb );
  2215. //
  2216. // Free pool and clean up.
  2217. //
  2218. NtfsFreePool( NewBuffer );
  2219. if (CleanupContext) {
  2220. NtfsCleanupAttributeContext( IrpContext, &Context );
  2221. CleanupContext = FALSE;
  2222. }
  2223. FileName = OriginalFileName;
  2224. continue;
  2225. }
  2226. //
  2227. // Now copy over the existing data.
  2228. //
  2229. OldBuffer = Scb->ScbType.Index.NormalizedName.Buffer;
  2230. if (OldBuffer != NULL) {
  2231. RtlCopyMemory( NewBuffer,
  2232. OldBuffer,
  2233. Scb->ScbType.Index.NormalizedName.MaximumLength );
  2234. NtfsFreePool( OldBuffer );
  2235. }
  2236. //
  2237. // Swap out the old buffer and max length. No change to the hash value at
  2238. // this point.
  2239. //
  2240. Scb->ScbType.Index.NormalizedName.Buffer = NewBuffer;
  2241. Scb->ScbType.Index.NormalizedName.MaximumLength = (USHORT) Length;
  2242. //
  2243. // Acquire the hash table and verify that nothing has changed on us.
  2244. //
  2245. } else {
  2246. NtfsAcquireHashTable( Scb->Vcb );
  2247. //
  2248. // Check for unexpected changes.
  2249. //
  2250. Length = ParentScb->ScbType.Index.NormalizedName.Length + (FileName->FileNameLength + SeparatorLength) * sizeof( WCHAR );
  2251. if ((ParentScb->ScbType.Index.NormalizedName.Length == 0) ||
  2252. (Length > UnsafeLength)) {
  2253. //
  2254. // The following is an exit condition for us.
  2255. //
  2256. if (ParentScb->ScbType.Index.NormalizedName.Length == 0) {
  2257. UpdatedName = FALSE;
  2258. }
  2259. NtfsReleaseHashTable( Scb->Vcb );
  2260. //
  2261. // Cleanup for retry.
  2262. //
  2263. if (CleanupContext) {
  2264. NtfsCleanupAttributeContext( IrpContext, &Context );
  2265. CleanupContext = FALSE;
  2266. }
  2267. FileName = OriginalFileName;
  2268. continue;
  2269. }
  2270. }
  2271. //
  2272. // At this point we hold the hash table and know that the buffer is sufficient
  2273. // for the new data. However it still contains the previous data. If we aren't
  2274. // just updating the buffer lengths then store the new data.
  2275. //
  2276. if (!CheckBufferSizeOnly) {
  2277. PCHAR NextChar;
  2278. //
  2279. // Copy the new name into the buffer.
  2280. //
  2281. Scb->ScbType.Index.NormalizedName.Length = (USHORT) Length;
  2282. NextChar = (PCHAR) Scb->ScbType.Index.NormalizedName.Buffer;
  2283. //
  2284. // Now copy the name in. Don't forget to add the separator if the parent isn't
  2285. // the root.
  2286. //
  2287. RtlCopyMemory( NextChar,
  2288. ParentScb->ScbType.Index.NormalizedName.Buffer,
  2289. ParentScb->ScbType.Index.NormalizedName.Length );
  2290. NextChar += ParentScb->ScbType.Index.NormalizedName.Length;
  2291. if (SeparatorLength == 1) {
  2292. *((PWCHAR) NextChar) = L'\\';
  2293. NextChar += sizeof( WCHAR );
  2294. }
  2295. //
  2296. // Now append this name to the parent name.
  2297. //
  2298. RtlCopyMemory( NextChar,
  2299. FileName->FileName,
  2300. FileName->FileNameLength * sizeof( WCHAR ));
  2301. Scb->ScbType.Index.HashValue = 0;
  2302. NtfsConvertNameToHash( Scb->ScbType.Index.NormalizedName.Buffer,
  2303. Scb->ScbType.Index.NormalizedName.Length,
  2304. Scb->Vcb->UpcaseTable,
  2305. &Scb->ScbType.Index.HashValue );
  2306. }
  2307. NtfsReleaseHashTable( Scb->Vcb );
  2308. //
  2309. // Only one pass required in the typical case.
  2310. //
  2311. break;
  2312. //
  2313. // We either break out specifically or set this to FALSE.
  2314. //
  2315. } while (UpdatedName);
  2316. } finally {
  2317. if (CleanupContext) {
  2318. NtfsCleanupAttributeContext( IrpContext, &Context );
  2319. }
  2320. }
  2321. return UpdatedName;
  2322. }
  2323. VOID
  2324. NtfsDeleteNormalizedName (
  2325. IN PSCB Scb
  2326. )
  2327. /*++
  2328. Routine Description:
  2329. This routine is called to delete the normalized name from an Scb.
  2330. We make this a function in order to serialize the normalized name
  2331. deletion with the hash package. The user has already done
  2332. the check to see if this Scb has a normalized name. Note that the
  2333. name may not be valid (Length == 0) but it does have a buffer
  2334. requiring cleanup.
  2335. Arguments:
  2336. Scb - Index Scb with a normalized name.
  2337. Return Value:
  2338. None
  2339. --*/
  2340. {
  2341. PVOID OldBuffer;
  2342. PAGED_CODE();
  2343. ASSERT( Scb->AttributeTypeCode == $INDEX_ALLOCATION );
  2344. ASSERT( Scb->ScbType.Index.NormalizedName.Buffer != NULL );
  2345. //
  2346. // The hash table mutex is needed to synchronize with callers in the hash
  2347. // package who look at this Scb name without serializing with the Scb.
  2348. // They must hold the hash mutex for their entire operation.
  2349. //
  2350. NtfsAcquireHashTable( Scb->Vcb );
  2351. OldBuffer = Scb->ScbType.Index.NormalizedName.Buffer;
  2352. Scb->ScbType.Index.NormalizedName.Buffer = NULL;
  2353. Scb->ScbType.Index.NormalizedName.MaximumLength = Scb->ScbType.Index.NormalizedName.Length = 0;
  2354. NtfsReleaseHashTable( Scb->Vcb );
  2355. NtfsFreePool( OldBuffer );
  2356. return;
  2357. }
  2358. NTSTATUS
  2359. NtfsWalkUpTree (
  2360. IN PIRP_CONTEXT IrpContext,
  2361. IN PFCB Fcb,
  2362. IN NTFSWALKUPFUNCTION WalkUpFunction,
  2363. IN OUT PVOID Context
  2364. )
  2365. /*++
  2366. Routine Description:
  2367. This routine walks up the tree from child to parent, applying
  2368. a function at each level. Processing terminates when WalkUpFunction
  2369. returns a failure status code. The current convention is that
  2370. WalkUpFunctions return STATUS_NO_MORE_FILES when a successful upward
  2371. traversal occurs. Other status codes are private to
  2372. caller/WalkUpFunction.
  2373. Arguments:
  2374. IrpContext - context of the call
  2375. Fcb - beginning file
  2376. WalkUpFunction - function that is applied to each level
  2377. Context - Pointer to caller-private data passed to WalkUpFunction
  2378. Return Value:
  2379. STATUS_SUCCESS - at end of complete walk
  2380. Status code returned by WalkUpFunction otherwise
  2381. --*/
  2382. {
  2383. PFCB ThisFcb = Fcb;
  2384. PFCB NextFcb = NULL;
  2385. PSCB NextScb = NULL;
  2386. PLCB NextLcb;
  2387. BOOLEAN AcquiredNextFcb = FALSE;
  2388. BOOLEAN AcquiredThisFcb = FALSE;
  2389. BOOLEAN AcquiredFcbTable = FALSE;
  2390. BOOLEAN FoundEntry = TRUE;
  2391. BOOLEAN CleanupAttrContext = FALSE;
  2392. PFILE_NAME FileName;
  2393. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  2394. NTSTATUS Status = STATUS_SUCCESS;
  2395. PAGED_CODE();
  2396. ASSERT_SHARED_RESOURCE( &Fcb->Vcb->Resource );
  2397. //
  2398. // Use a try-finally to facilitate cleanup.
  2399. //
  2400. try {
  2401. while (TRUE) {
  2402. //
  2403. // If we reach the root then exit.
  2404. //
  2405. if (ThisFcb == ThisFcb->Vcb->RootIndexScb->Fcb) {
  2406. //
  2407. // Special case root directory
  2408. //
  2409. Status = WalkUpFunction( IrpContext, ThisFcb, ThisFcb->Vcb->RootIndexScb, NULL, Context );
  2410. break;
  2411. }
  2412. //
  2413. // Find a non-dos name for the current Scb. There better be one.
  2414. //
  2415. NtfsInitializeAttributeContext( &AttrContext );
  2416. CleanupAttrContext = TRUE;
  2417. FoundEntry = NtfsLookupAttributeByCode( IrpContext,
  2418. ThisFcb,
  2419. &ThisFcb->FileReference,
  2420. $FILE_NAME,
  2421. &AttrContext );
  2422. while (FoundEntry) {
  2423. FileName = (PFILE_NAME)
  2424. NtfsAttributeValue( NtfsFoundAttribute( &AttrContext ));
  2425. if (FileName->Flags != FILE_NAME_DOS ) {
  2426. break;
  2427. }
  2428. FoundEntry = NtfsLookupNextAttributeByCode( IrpContext,
  2429. ThisFcb,
  2430. $FILE_NAME,
  2431. &AttrContext );
  2432. }
  2433. if (!FoundEntry) {
  2434. NtfsRaiseStatus( IrpContext,
  2435. STATUS_FILE_CORRUPT_ERROR,
  2436. NULL,
  2437. NextFcb );
  2438. }
  2439. ASSERT( NextScb == NULL || NextScb->Fcb == ThisFcb );
  2440. Status = WalkUpFunction( IrpContext, ThisFcb, NextScb, FileName, Context );
  2441. if (!NT_SUCCESS( Status )) {
  2442. break;
  2443. }
  2444. //
  2445. // Now get the parent for the current component. Acquire the Fcb for
  2446. // synchronization. We can either walk up the Lcb chain or look it up
  2447. // in the Fcb table. It must be for the same name as the file name
  2448. // since there is only one path up the tree for a directory.
  2449. //
  2450. if (!IsListEmpty( &ThisFcb->LcbQueue ) && IsDirectory( &ThisFcb->Info )) {
  2451. NextLcb =
  2452. (PLCB) CONTAINING_RECORD( ThisFcb->LcbQueue.Flink, LCB, FcbLinks );
  2453. NextScb = NextLcb->Scb;
  2454. NextFcb = NextScb->Fcb;
  2455. NtfsAcquireExclusiveFcb( IrpContext, NextFcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  2456. AcquiredNextFcb = TRUE;
  2457. ASSERT( NtfsEqualMftRef( &FileName->ParentDirectory,
  2458. &NextFcb->FileReference ));
  2459. } else {
  2460. UNICODE_STRING ComponentName;
  2461. NtfsAcquireFcbTable( IrpContext, Fcb->Vcb );
  2462. AcquiredFcbTable = TRUE;
  2463. NextFcb = NtfsCreateFcb( IrpContext,
  2464. Fcb->Vcb,
  2465. FileName->ParentDirectory,
  2466. FALSE,
  2467. TRUE,
  2468. NULL );
  2469. NextFcb->ReferenceCount += 1;
  2470. //
  2471. // Try to do an unsafe acquire. Otherwise we must drop the Fcb table
  2472. // and acquire the Fcb and then reacquire the Fcb table.
  2473. //
  2474. if (!NtfsAcquireExclusiveFcb( IrpContext, NextFcb, NULL, ACQUIRE_NO_DELETE_CHECK | ACQUIRE_DONT_WAIT )) {
  2475. NtfsReleaseFcbTable( IrpContext, Fcb->Vcb );
  2476. NtfsAcquireExclusiveFcb( IrpContext, NextFcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  2477. NtfsAcquireFcbTable( IrpContext, Fcb->Vcb );
  2478. }
  2479. NextFcb->ReferenceCount -= 1;
  2480. NtfsReleaseFcbTable( IrpContext, Fcb->Vcb );
  2481. AcquiredFcbTable = FALSE;
  2482. AcquiredNextFcb = TRUE;
  2483. NextScb = NtfsCreateScb( IrpContext,
  2484. NextFcb,
  2485. $INDEX_ALLOCATION,
  2486. &NtfsFileNameIndex,
  2487. FALSE,
  2488. NULL );
  2489. ComponentName.Buffer = FileName->FileName;
  2490. ComponentName.MaximumLength =
  2491. ComponentName.Length = FileName->FileNameLength * sizeof( WCHAR );
  2492. NextLcb = NtfsCreateLcb( IrpContext,
  2493. NextScb,
  2494. ThisFcb,
  2495. ComponentName,
  2496. FileName->Flags,
  2497. NULL );
  2498. }
  2499. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  2500. CleanupAttrContext = FALSE;
  2501. //
  2502. // Release the current Fcb and move up the tree.
  2503. //
  2504. if (AcquiredThisFcb) {
  2505. NtfsReleaseFcb( IrpContext, ThisFcb );
  2506. }
  2507. ThisFcb = NextFcb;
  2508. AcquiredThisFcb = TRUE;
  2509. AcquiredNextFcb = FALSE;
  2510. }
  2511. } finally {
  2512. if (AcquiredFcbTable) { NtfsReleaseFcbTable( IrpContext, Fcb->Vcb ); }
  2513. if (AcquiredNextFcb) { NtfsReleaseFcb( IrpContext, NextFcb ); }
  2514. if (AcquiredThisFcb) { NtfsReleaseFcb( IrpContext, ThisFcb ); }
  2515. if (CleanupAttrContext) {
  2516. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  2517. }
  2518. }
  2519. return Status;
  2520. }
  2521. NTSTATUS
  2522. NtfsBuildRelativeName (
  2523. IN PIRP_CONTEXT IrpContext,
  2524. IN PFCB Fcb,
  2525. IN PSCB Scb,
  2526. IN PFILE_NAME FileName,
  2527. IN OUT PVOID Context
  2528. )
  2529. /*++
  2530. Routine Description:
  2531. This routine is called for each parent directory up to the root. We
  2532. prepend the name of the current node to the ScopeContext as we walk
  2533. up. We terminate this walk when we hit the top of the scope or the
  2534. root.
  2535. Arguments:
  2536. IrpContext - context of the call
  2537. Fcb - parent
  2538. FileName - FILE_NAME of self relative to parent
  2539. Context - Pointer to caller-private data passed to WalkUpFunction
  2540. Return Value:
  2541. STATUS_SUCCESS - if we're still walking up the tree
  2542. STATUS_NO_MORE_FILES - if we've found the specified scope
  2543. STATUS_OBJECT_PATH_NOT_FOUND - if we've reached the root and did not
  2544. hit the scope.
  2545. --*/
  2546. {
  2547. PSCOPE_CONTEXT ScopeContext = (PSCOPE_CONTEXT) Context;
  2548. ULONG SlashCount;
  2549. WCHAR *Name;
  2550. ULONG Count;
  2551. USHORT NewLength;
  2552. UNREFERENCED_PARAMETER( IrpContext );
  2553. PAGED_CODE();
  2554. //
  2555. // If we've reached the passed-in scope then we're done
  2556. //
  2557. if (NtfsEqualMftRef( &ScopeContext->Scope, &Fcb->FileReference )) {
  2558. return STATUS_NO_MORE_FILES;
  2559. }
  2560. //
  2561. // If we've reached the root then we're totally outside the scope
  2562. //
  2563. if (NtfsEqualMftRef( &RootIndexFileReference, &Fcb->FileReference )) {
  2564. return STATUS_OBJECT_PATH_NOT_FOUND;
  2565. }
  2566. //
  2567. // Set up Name from input. We take the shortcut to building the name
  2568. // only if we're looking from the root. Also, if we are starting at
  2569. // the root, then we should use the canned name as well.
  2570. //
  2571. if (
  2572. //
  2573. // No file name (i.e., root)
  2574. //
  2575. FileName == NULL ||
  2576. //
  2577. // We're searching to the root and
  2578. // we have an Scb and
  2579. // the Scb has a normalized name
  2580. //
  2581. (ScopeContext->IsRoot &&
  2582. (Scb != NULL) &&
  2583. (Scb->ScbType.Index.NormalizedName.Length != 0))) {
  2584. Name = Scb->ScbType.Index.NormalizedName.Buffer;
  2585. Count = Scb->ScbType.Index.NormalizedName.Length / sizeof( WCHAR );
  2586. SlashCount = 0;
  2587. } else {
  2588. Name = FileName->FileName;
  2589. Count = FileName->FileNameLength;
  2590. SlashCount = 1;
  2591. }
  2592. //
  2593. // If there's not enough room in the string to allow for prepending
  2594. //
  2595. NewLength = (USHORT) ((SlashCount + Count) * sizeof( WCHAR ) + ScopeContext->Name.Length);
  2596. if (NewLength > ScopeContext->Name.MaximumLength ) {
  2597. WCHAR *NewBuffer;
  2598. //
  2599. // Reallocate string. Adjust size of string for pool boundaries.
  2600. //
  2601. NewLength = ((NewLength + 8 + 0x40 - 1) & ~(0x40 - 1)) - 8;
  2602. NewBuffer = NtfsAllocatePool( PagedPool, NewLength );
  2603. //
  2604. // Copy over previous contents into new buffer
  2605. //
  2606. if (ScopeContext->Name.Length != 0) {
  2607. RtlCopyMemory( NewBuffer,
  2608. ScopeContext->Name.Buffer,
  2609. ScopeContext->Name.Length );
  2610. NtfsFreePool( ScopeContext->Name.Buffer );
  2611. }
  2612. ScopeContext->Name.Buffer = NewBuffer;
  2613. ScopeContext->Name.MaximumLength = NewLength;
  2614. }
  2615. //
  2616. // Shift string over to make new room
  2617. //
  2618. RtlMoveMemory( &ScopeContext->Name.Buffer[SlashCount + Count],
  2619. ScopeContext->Name.Buffer,
  2620. ScopeContext->Name.Length );
  2621. //
  2622. // copy name
  2623. //
  2624. RtlCopyMemory( &ScopeContext->Name.Buffer[SlashCount],
  2625. Name,
  2626. Count * sizeof( WCHAR ) );
  2627. //
  2628. // Stick in the slash
  2629. //
  2630. if (SlashCount != 0) {
  2631. ScopeContext->Name.Buffer[0] = L'\\';
  2632. }
  2633. ScopeContext->Name.Length += (USHORT)((SlashCount + Count) * sizeof( WCHAR ));
  2634. return SlashCount == 0 ? STATUS_NO_MORE_FILES : STATUS_SUCCESS;
  2635. }
  2636. VOID
  2637. NtfsBuildNormalizedName (
  2638. IN PIRP_CONTEXT IrpContext,
  2639. IN PFCB Fcb,
  2640. IN PSCB IndexScb OPTIONAL,
  2641. OUT PUNICODE_STRING PathName
  2642. )
  2643. /*++
  2644. Routine Description:
  2645. This routine is called to build a normalized name for an Fcb by looking
  2646. up the file name attributes up to the root directory.
  2647. Arguments:
  2648. IrpContext - context of call
  2649. Fcb - Supplies the starting point.
  2650. IndexScb - Indicates that we are storing this name into an Scb so we
  2651. we need to serialize with the hash package and also generate a
  2652. hash for this.
  2653. PathName - location where full name is stored
  2654. Return Value:
  2655. None. This routine either succeeds or raises.
  2656. --*/
  2657. {
  2658. SCOPE_CONTEXT ScopeContext;
  2659. PAGED_CODE();
  2660. RtlZeroMemory( &ScopeContext, sizeof( ScopeContext ));
  2661. ScopeContext.Scope = RootIndexFileReference;
  2662. ScopeContext.IsRoot = TRUE;
  2663. try {
  2664. NtfsWalkUpTree( IrpContext, Fcb, NtfsBuildRelativeName, &ScopeContext );
  2665. if (ARGUMENT_PRESENT( IndexScb )) {
  2666. NtfsAcquireHashTable( Fcb->Vcb );
  2667. *PathName = ScopeContext.Name;
  2668. IndexScb->ScbType.Index.HashValue = 0;
  2669. NtfsConvertNameToHash( PathName->Buffer,
  2670. PathName->Length,
  2671. IndexScb->Vcb->UpcaseTable,
  2672. &IndexScb->ScbType.Index.HashValue );
  2673. NtfsReleaseHashTable( Fcb->Vcb );
  2674. } else {
  2675. *PathName = ScopeContext.Name;
  2676. }
  2677. ScopeContext.Name.Buffer = NULL;
  2678. } finally {
  2679. if (ScopeContext.Name.Buffer != NULL) {
  2680. NtfsFreePool( ScopeContext.Name.Buffer );
  2681. }
  2682. }
  2683. }
  2684. VOID
  2685. NtfsSnapshotScb (
  2686. IN PIRP_CONTEXT IrpContext,
  2687. IN PSCB Scb
  2688. )
  2689. /*++
  2690. Routine Description:
  2691. This routine snapshots necessary Scb data, such as the Scb file sizes,
  2692. so that they may be correctly restored if the caller's I/O request is
  2693. aborted for any reason. The restoring of these values and the freeing
  2694. of any pool involved is automatic.
  2695. Arguments:
  2696. Scb - Supplies the current Scb
  2697. Return Value:
  2698. None
  2699. --*/
  2700. {
  2701. PSCB_SNAPSHOT ScbSnapshot;
  2702. ASSERT_EXCLUSIVE_SCB(Scb);
  2703. ScbSnapshot = &IrpContext->ScbSnapshot;
  2704. //
  2705. // Only do the snapshot if the Scb is initialized, we have not done
  2706. // so already, and it is worth special-casing the bitmap, as it never changes!
  2707. // We will snapshot the volume bitmap if it is on the exclusive Fcb list however.
  2708. // This should only happen if we are extending the volume bitmap through the
  2709. // ExtendVolume fsctl.
  2710. //
  2711. if (FlagOn(Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED) &&
  2712. (Scb->ScbSnapshot == NULL) &&
  2713. ((Scb != Scb->Vcb->BitmapScb) ||
  2714. (Scb->Fcb->ExclusiveFcbLinks.Flink != NULL))) {
  2715. //
  2716. // If the snapshot structure in the IrpContext is in use, then we have
  2717. // to allocate one and insert it in the list.
  2718. //
  2719. if (ScbSnapshot->SnapshotLinks.Flink != NULL) {
  2720. ScbSnapshot = (PSCB_SNAPSHOT)ExAllocateFromNPagedLookasideList( &NtfsScbSnapshotLookasideList );
  2721. InsertTailList( &IrpContext->ScbSnapshot.SnapshotLinks,
  2722. &ScbSnapshot->SnapshotLinks );
  2723. //
  2724. // Otherwise we will initialize the listhead to show that the structure
  2725. // in the IrpContext is in use.
  2726. //
  2727. } else {
  2728. InitializeListHead( &ScbSnapshot->SnapshotLinks );
  2729. }
  2730. //
  2731. // We should never be writing compressed if the file isn't compressed.
  2732. //
  2733. ASSERT( FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED ) ||
  2734. !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) ||
  2735. (Scb->CompressionUnit != 0) );
  2736. //
  2737. // Snapshot the Scb values and point the Scb and snapshot structure
  2738. // at each other.
  2739. //
  2740. NtfsVerifySizes( &Scb->Header );
  2741. ScbSnapshot->AllocationSize = Scb->Header.AllocationSize.QuadPart;
  2742. ScbSnapshot->FileSize = Scb->Header.FileSize.QuadPart;
  2743. ScbSnapshot->ValidDataLength = Scb->Header.ValidDataLength.QuadPart;
  2744. ScbSnapshot->ValidDataToDisk = Scb->ValidDataToDisk;
  2745. ScbSnapshot->Scb = Scb;
  2746. ScbSnapshot->LowestModifiedVcn = MAXLONGLONG;
  2747. ScbSnapshot->HighestModifiedVcn = 0;
  2748. ScbSnapshot->TotalAllocated = Scb->TotalAllocated;
  2749. ScbSnapshot->ScbState = FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT );
  2750. Scb->ScbSnapshot = ScbSnapshot;
  2751. NtfsVerifySizesLongLong( ScbSnapshot );
  2752. //
  2753. // If this is the Mft Scb then initialize the cluster Mcb structures.
  2754. //
  2755. if (Scb == Scb->Vcb->MftScb) {
  2756. FsRtlTruncateLargeMcb( &Scb->ScbType.Mft.AddedClusters, 0 );
  2757. FsRtlTruncateLargeMcb( &Scb->ScbType.Mft.RemovedClusters, 0 );
  2758. Scb->ScbType.Mft.FreeRecordChange = 0;
  2759. Scb->ScbType.Mft.HoleRecordChange = 0;
  2760. }
  2761. //
  2762. // Determine if we can use the snapshot for rollback of file sizes
  2763. // The 4 cases are we own the pagingio, we own io at eof, its being converted to non-res
  2764. // or its a mod-no write stream which we explicity control like the usn journal
  2765. //
  2766. if (NtfsSnapshotFileSizesTest( IrpContext, Scb )) {
  2767. Scb->ScbSnapshot->OwnerIrpContext = IrpContext;
  2768. } else {
  2769. Scb->ScbSnapshot->OwnerIrpContext = NULL;
  2770. }
  2771. }
  2772. }
  2773. VOID
  2774. NtfsUpdateScbSnapshots (
  2775. IN PIRP_CONTEXT IrpContext
  2776. )
  2777. /*++
  2778. Routine Description:
  2779. This routine may be called to update the snapshot values for all Scbs,
  2780. after completing a transaction checkpoint.
  2781. Arguments:
  2782. Return Value:
  2783. None
  2784. --*/
  2785. {
  2786. PSCB_SNAPSHOT ScbSnapshot;
  2787. PSCB Scb;
  2788. ASSERT(FIELD_OFFSET(SCB_SNAPSHOT, SnapshotLinks) == 0);
  2789. PAGED_CODE();
  2790. ScbSnapshot = &IrpContext->ScbSnapshot;
  2791. //
  2792. // There is no snapshot data to update if the Flink is still NULL.
  2793. //
  2794. if (ScbSnapshot->SnapshotLinks.Flink != NULL) {
  2795. //
  2796. // Loop to update first the Scb data from the snapshot in the
  2797. // IrpContext, and then 0 or more additional snapshots linked
  2798. // to the IrpContext.
  2799. //
  2800. do {
  2801. Scb = ScbSnapshot->Scb;
  2802. //
  2803. // Update the Scb values.
  2804. //
  2805. if (Scb != NULL) {
  2806. ScbSnapshot->AllocationSize = Scb->Header.AllocationSize.QuadPart;
  2807. //
  2808. // If this is the MftScb then clear out the added/removed
  2809. // cluster Mcbs.
  2810. //
  2811. if (Scb == Scb->Vcb->MftScb) {
  2812. FsRtlTruncateLargeMcb( &Scb->ScbType.Mft.AddedClusters, (LONGLONG)0 );
  2813. FsRtlTruncateLargeMcb( &Scb->ScbType.Mft.RemovedClusters, (LONGLONG)0 );
  2814. Scb->ScbType.Mft.FreeRecordChange = 0;
  2815. Scb->ScbType.Mft.HoleRecordChange = 0;
  2816. }
  2817. ScbSnapshot->FileSize = Scb->Header.FileSize.QuadPart;
  2818. ScbSnapshot->ValidDataLength = Scb->Header.ValidDataLength.QuadPart;
  2819. ScbSnapshot->ValidDataToDisk = Scb->ValidDataToDisk;
  2820. ScbSnapshot->TotalAllocated = Scb->TotalAllocated;
  2821. ScbSnapshot->ScbState = FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT );
  2822. NtfsVerifySizesLongLong( ScbSnapshot );
  2823. }
  2824. ScbSnapshot = (PSCB_SNAPSHOT)ScbSnapshot->SnapshotLinks.Flink;
  2825. } while (ScbSnapshot != &IrpContext->ScbSnapshot);
  2826. }
  2827. }
  2828. VOID
  2829. NtfsRestoreScbSnapshots (
  2830. IN PIRP_CONTEXT IrpContext,
  2831. IN BOOLEAN Higher
  2832. )
  2833. /*++
  2834. Routine Description:
  2835. This routine restores snapshot Scb data in the event of an aborted request.
  2836. Arguments:
  2837. Higher - Specified as TRUE to restore only those Scb values which are
  2838. higher than current values. Specified as FALSE to restore
  2839. only those Scb values which are lower (or same!).
  2840. Return Value:
  2841. None
  2842. --*/
  2843. {
  2844. BOOLEAN UpdateCc;
  2845. PSCB_SNAPSHOT ScbSnapshot;
  2846. PSCB Scb;
  2847. PVCB Vcb = IrpContext->Vcb;
  2848. ASSERT(FIELD_OFFSET(SCB_SNAPSHOT, SnapshotLinks) == 0);
  2849. ScbSnapshot = &IrpContext->ScbSnapshot;
  2850. //
  2851. // There is no snapshot data to restore if the Flink is still NULL.
  2852. //
  2853. if (ScbSnapshot->SnapshotLinks.Flink != NULL) {
  2854. //
  2855. // Loop to retore first the Scb data from the snapshot in the
  2856. // IrpContext, and then 0 or more additional snapshots linked
  2857. // to the IrpContext.
  2858. //
  2859. do {
  2860. PSECTION_OBJECT_POINTERS SectionObjectPointer;
  2861. PFILE_OBJECT PseudoFileObject;
  2862. Scb = ScbSnapshot->Scb;
  2863. if (Scb == NULL) {
  2864. ScbSnapshot = (PSCB_SNAPSHOT)ScbSnapshot->SnapshotLinks.Flink;
  2865. continue;
  2866. }
  2867. //
  2868. // Increment the cleanup count so the Scb won't go away.
  2869. //
  2870. InterlockedIncrement( &Scb->CleanupCount );
  2871. //
  2872. // We update the Scb file size in the correct pass. We always do
  2873. // the extend/truncate pair.
  2874. //
  2875. // Only do sizes if our caller was changing these fields, which we marked
  2876. // by setting the irpcontext owner when we snapped
  2877. //
  2878. // The one unusual case is where we are converting a stream to
  2879. // nonresident when this is not the stream for the request. We
  2880. // must restore the Scb for this case as well.
  2881. //
  2882. UpdateCc = FALSE;
  2883. if ((ScbSnapshot->OwnerIrpContext == IrpContext) || (ScbSnapshot->OwnerIrpContext == IrpContext->TopLevelIrpContext)) {
  2884. //
  2885. // Proceed to restore all values which are in higher or not
  2886. // higher.
  2887. //
  2888. if (Higher == (ScbSnapshot->AllocationSize >= Scb->Header.AllocationSize.QuadPart)) {
  2889. //
  2890. // If this is the maximize pass, we want to extend the cache section.
  2891. // In all cases we restore the allocation size in the Scb and
  2892. // recover the resident bit.
  2893. //
  2894. Scb->Header.AllocationSize.QuadPart = ScbSnapshot->AllocationSize;
  2895. ClearFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT );
  2896. SetFlag( Scb->ScbState,
  2897. FlagOn( ScbSnapshot->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT ));
  2898. //
  2899. // Calculate FastIoPossible
  2900. //
  2901. if (Scb->CompressionUnit != 0) {
  2902. NtfsAcquireFsrtlHeader( Scb );
  2903. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  2904. NtfsReleaseFsrtlHeader( Scb );
  2905. }
  2906. }
  2907. NtfsAcquireFsrtlHeader( Scb );
  2908. if (Higher ?
  2909. (ScbSnapshot->FileSize > Scb->Header.FileSize.QuadPart) :
  2910. (ScbSnapshot->FileSize < Scb->Header.FileSize.QuadPart)) {
  2911. Scb->Header.FileSize.QuadPart = ScbSnapshot->FileSize;
  2912. //
  2913. // We really only need to update Cc if FileSize changes,
  2914. // since he does not look at ValidDataLength, and he
  2915. // only cares about successfully reached highwatermarks
  2916. // on AllocationSize (making section big enough).
  2917. //
  2918. // Note that setting this flag TRUE also implies we
  2919. // are correctly synchronized with FileSize!
  2920. //
  2921. UpdateCc = TRUE;
  2922. }
  2923. if (Higher == (ScbSnapshot->ValidDataLength >
  2924. Scb->Header.ValidDataLength.QuadPart)) {
  2925. Scb->Header.ValidDataLength.QuadPart = ScbSnapshot->ValidDataLength;
  2926. }
  2927. ASSERT( (Scb->Header.ValidDataLength.QuadPart <= Scb->Header.FileSize.QuadPart) ||
  2928. (Scb->Header.ValidDataLength.QuadPart == MAXLONGLONG) );
  2929. //
  2930. // If this is the unnamed data attribute, we have to update
  2931. // some Fcb fields for standard information as well.
  2932. //
  2933. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  2934. Scb->Fcb->Info.FileSize = Scb->Header.FileSize.QuadPart;
  2935. }
  2936. NtfsReleaseFsrtlHeader( Scb );
  2937. }
  2938. if (!Higher) {
  2939. Scb->ValidDataToDisk = ScbSnapshot->ValidDataToDisk;
  2940. //
  2941. // We always truncate the Mcb to the original allocation size.
  2942. // If the Mcb has shrunk beyond this, this becomes a noop.
  2943. // If the file is resident, then we will uninitialize
  2944. // and reinitialize the Mcb.
  2945. //
  2946. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  2947. //
  2948. // Remove all of the mappings in the Mcb.
  2949. //
  2950. NtfsUnloadNtfsMcbRange( &Scb->Mcb, (LONGLONG)0, MAXLONGLONG, FALSE, FALSE );
  2951. //
  2952. // If we attempted a convert a data attribute to non-
  2953. // resident and failed then need to nuke the pages in the
  2954. // section if this is not a user file. This is because for
  2955. // resident system attributes we always update the attribute
  2956. // directly and don't want to reference stale data in the
  2957. // section if we do a convert to non-resident later.
  2958. //
  2959. if (Scb->AttributeTypeCode != $DATA) {
  2960. if (Scb->NonpagedScb->SegmentObject.SharedCacheMap != NULL) {
  2961. //
  2962. // If we're not synchronized with the lazy writer, we shouldn't
  2963. // be attempting this purge. Otherwise there's a potential for
  2964. // deadlock when this thread waits on the active count, while the
  2965. // thread trying to get rid of his reference is waiting for the
  2966. // main resource on this scb.
  2967. //
  2968. ASSERT( (Scb->Header.PagingIoResource == NULL) ||
  2969. NtfsIsExclusiveScbPagingIo( Scb ) );
  2970. if (!CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject,
  2971. NULL,
  2972. 0,
  2973. FALSE )) {
  2974. ASSERTMSG( "Failed to purge Scb during restore\n", FALSE );
  2975. }
  2976. }
  2977. //
  2978. // If the attribute is for non-user data
  2979. // (which is not opened explicitly by a user), then we
  2980. // want to modify this Scb so it won't be used again.
  2981. // Set the sizes to zero, mark it as being initialized
  2982. // and deleted and then change the attribute type code
  2983. // so we won't ever return it via NtfsCreateScb.
  2984. //
  2985. if (IsListEmpty( &Scb->CcbQueue )) {
  2986. NtfsAcquireFsrtlHeader( Scb );
  2987. Scb->Header.AllocationSize =
  2988. Scb->Header.FileSize =
  2989. Scb->Header.ValidDataLength = Li0;
  2990. NtfsReleaseFsrtlHeader( Scb );
  2991. Scb->ValidDataToDisk = 0;
  2992. SetFlag( Scb->ScbState,
  2993. SCB_STATE_FILE_SIZE_LOADED |
  2994. SCB_STATE_HEADER_INITIALIZED |
  2995. SCB_STATE_ATTRIBUTE_DELETED );
  2996. Scb->AttributeTypeCode = $UNUSED;
  2997. }
  2998. }
  2999. //
  3000. // If we have modified this Mcb and want to back out any
  3001. // changes then truncate the Mcb. Don't do the Mft, because
  3002. // that is handled elsewhere.
  3003. //
  3004. } else if ((ScbSnapshot->LowestModifiedVcn != MAXLONGLONG) &&
  3005. (Scb != Vcb->MftScb)) {
  3006. //
  3007. // Truncate the Mcb.
  3008. //
  3009. NtfsUnloadNtfsMcbRange( &Scb->Mcb, ScbSnapshot->LowestModifiedVcn, ScbSnapshot->HighestModifiedVcn, FALSE, FALSE );
  3010. }
  3011. Scb->TotalAllocated = ScbSnapshot->TotalAllocated;
  3012. } else {
  3013. //
  3014. // Set the flag to indicate that we're performing a restore on this
  3015. // Scb. We don't want to write any new log records as a result of
  3016. // this operation other than the abort records.
  3017. //
  3018. SetFlag( Scb->ScbState, SCB_STATE_RESTORE_UNDERWAY );
  3019. }
  3020. //
  3021. // Be sure to update Cache Manager. The interface here uses a file
  3022. // object but the routine itself only uses the section object pointers.
  3023. // We put a pointer to the segment object pointers on the stack and
  3024. // cast some prior value as a file object pointer.
  3025. //
  3026. PseudoFileObject = (PFILE_OBJECT) CONTAINING_RECORD( &SectionObjectPointer,
  3027. FILE_OBJECT,
  3028. SectionObjectPointer );
  3029. PseudoFileObject->SectionObjectPointer = &Scb->NonpagedScb->SegmentObject;
  3030. //
  3031. // Now tell the cache manager the sizes.
  3032. //
  3033. // If we fail in this call, we definitely want to charge on anyway.
  3034. // It should only fail if it tries to extend the section and cannot,
  3035. // in which case we do not care because we cannot need the extended
  3036. // part to the section anyway. (This is probably the very error that
  3037. // is causing us to clean up in the first place!)
  3038. //
  3039. // We don't need to make this call if the top level request is a
  3040. // paging Io write.
  3041. //
  3042. // We only do this if there is a shared cache map for this stream.
  3043. // Otherwise CC will cause a flush to happen which could mess up
  3044. // the transaction and abort logic.
  3045. //
  3046. if (UpdateCc &&
  3047. (IrpContext->OriginatingIrp == NULL ||
  3048. IrpContext->OriginatingIrp->Type != IO_TYPE_IRP ||
  3049. IrpContext->MajorFunction != IRP_MJ_WRITE ||
  3050. !FlagOn( IrpContext->OriginatingIrp->Flags, IRP_PAGING_IO ))) {
  3051. try {
  3052. NtfsSetBothCacheSizes( PseudoFileObject,
  3053. (PCC_FILE_SIZES)&Scb->Header.AllocationSize,
  3054. Scb );
  3055. } except(FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  3056. EXCEPTION_EXECUTE_HANDLER :
  3057. EXCEPTION_CONTINUE_SEARCH) {
  3058. NtfsMinimumExceptionProcessing( IrpContext );
  3059. }
  3060. }
  3061. //
  3062. // If this is the unnamed data attribute, we have to update
  3063. // some Fcb fields for standard information as well.
  3064. //
  3065. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  3066. Scb->Fcb->Info.AllocatedLength = Scb->TotalAllocated;
  3067. }
  3068. //
  3069. // We always clear the Scb deleted flag and the deleted flag in the Fcb
  3070. // unless this was a create new file operation which failed. We recognize
  3071. // this by looking for the major Irp code in the IrpContext, and the
  3072. // deleted bit in the Fcb.
  3073. //
  3074. if (Scb->AttributeTypeCode != $UNUSED &&
  3075. (IrpContext->MajorFunction != IRP_MJ_CREATE ||
  3076. !FlagOn( Scb->Fcb->FcbState, FCB_STATE_FILE_DELETED ))) {
  3077. ClearFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  3078. ClearFlag( Scb->Fcb->FcbState, FCB_STATE_FILE_DELETED );
  3079. }
  3080. //
  3081. // Clear the flags in the Scb if this Scb is from a create
  3082. // that failed. We always clear our RESTORE_UNDERWAY flag.
  3083. //
  3084. // If this is an Index allocation or Mft bitmap, then we
  3085. // store MAXULONG in the record allocation context to indicate
  3086. // that we should reinitialize it.
  3087. //
  3088. if (!Higher) {
  3089. ClearFlag( Scb->ScbState, SCB_STATE_RESTORE_UNDERWAY );
  3090. if (FlagOn( Scb->ScbState, SCB_STATE_UNINITIALIZE_ON_RESTORE )) {
  3091. ClearFlag( Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED |
  3092. SCB_STATE_HEADER_INITIALIZED |
  3093. SCB_STATE_UNINITIALIZE_ON_RESTORE );
  3094. }
  3095. //
  3096. // If this is the MftScb we have several jobs to do.
  3097. //
  3098. // - Force the record allocation context to be reinitialized
  3099. // - Back out the changes to the Vcb->MftFreeRecords field
  3100. // - Back changes to the Vcb->MftHoleRecords field
  3101. // - Clear the flag indicating we allocated file record 15
  3102. // - Clear the flag indicating we reserved a record
  3103. // - Remove any clusters added to the Scb Mcb
  3104. // - Restore any clusters removed from the Scb Mcb
  3105. //
  3106. if (Scb == Vcb->MftScb) {
  3107. ULONG RunIndex;
  3108. VCN Vcn;
  3109. LCN Lcn;
  3110. LONGLONG Clusters;
  3111. Scb->ScbType.Index.RecordAllocationContext.CurrentBitmapSize = MAXULONG;
  3112. (LONG) Vcb->MftFreeRecords -= Scb->ScbType.Mft.FreeRecordChange;
  3113. (LONG) Vcb->MftHoleRecords -= Scb->ScbType.Mft.HoleRecordChange;
  3114. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MFT_REC_15_USED )) {
  3115. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MFT_REC_15_USED );
  3116. ClearFlag( Vcb->MftReserveFlags, VCB_MFT_RECORD_15_USED );
  3117. }
  3118. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MFT_REC_RESERVED )) {
  3119. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MFT_REC_RESERVED );
  3120. ClearFlag( Vcb->MftReserveFlags, VCB_MFT_RECORD_RESERVED );
  3121. Scb->ScbType.Mft.ReservedIndex = 0;
  3122. }
  3123. RunIndex = 0;
  3124. while (FsRtlGetNextLargeMcbEntry( &Scb->ScbType.Mft.AddedClusters,
  3125. RunIndex,
  3126. &Vcn,
  3127. &Lcn,
  3128. &Clusters )) {
  3129. if (Lcn != UNUSED_LCN) {
  3130. NtfsRemoveNtfsMcbEntry( &Scb->Mcb, Vcn, Clusters );
  3131. }
  3132. RunIndex += 1;
  3133. }
  3134. RunIndex = 0;
  3135. while (FsRtlGetNextLargeMcbEntry( &Scb->ScbType.Mft.RemovedClusters,
  3136. RunIndex,
  3137. &Vcn,
  3138. &Lcn,
  3139. &Clusters )) {
  3140. if (Lcn != UNUSED_LCN) {
  3141. NtfsAddNtfsMcbEntry( &Scb->Mcb, Vcn, Lcn, Clusters, FALSE );
  3142. }
  3143. RunIndex += 1;
  3144. }
  3145. } else if (Scb->AttributeTypeCode == $INDEX_ALLOCATION) {
  3146. Scb->ScbType.Index.RecordAllocationContext.CurrentBitmapSize = MAXULONG;
  3147. }
  3148. }
  3149. //
  3150. // Decrement the cleanup count to restore the previous value.
  3151. //
  3152. InterlockedDecrement( &Scb->CleanupCount );
  3153. ScbSnapshot = (PSCB_SNAPSHOT)ScbSnapshot->SnapshotLinks.Flink;
  3154. } while (ScbSnapshot != &IrpContext->ScbSnapshot);
  3155. }
  3156. }
  3157. VOID
  3158. NtfsMungeScbSnapshot (
  3159. IN PIRP_CONTEXT IrpContext,
  3160. IN PSCB Scb,
  3161. IN LONGLONG FileSize
  3162. )
  3163. /*++
  3164. Routine Description:
  3165. This routine is called to modify the Scb snapshot when we need the snapshot to
  3166. have different values than the Scb when it was acquired. One case is when NtfsCommonWrite
  3167. updates the file size in the Scb for the duration of the transaction.
  3168. Arguments:
  3169. Scb - Scb whose snapshot should be updated. There should always be a snapshot here.
  3170. FileSize - Value for file size to store in the snapshot. Also check that valid data and
  3171. ValidDataToDisk are not larger than this value.
  3172. Return Value:
  3173. None
  3174. --*/
  3175. {
  3176. //
  3177. // We should have a snapshot in most cases but if not build it now.
  3178. //
  3179. if (Scb->ScbSnapshot == NULL) {
  3180. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  3181. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  3182. }
  3183. NtfsSnapshotScb( IrpContext, Scb );
  3184. ASSERT( Scb->ScbSnapshot != NULL );
  3185. }
  3186. NtfsAcquireFsrtlHeader( Scb );
  3187. Scb->ScbSnapshot->FileSize = FileSize;
  3188. if (Scb->ScbSnapshot->ValidDataLength > FileSize) {
  3189. Scb->ScbSnapshot->ValidDataLength = FileSize;
  3190. }
  3191. if (Scb->ScbSnapshot->ValidDataToDisk > FileSize) {
  3192. Scb->ScbSnapshot->ValidDataToDisk = FileSize;
  3193. }
  3194. NtfsVerifySizes( &Scb->Header );
  3195. NtfsReleaseFsrtlHeader( Scb );
  3196. return;
  3197. }
  3198. VOID
  3199. NtfsFreeSnapshotsForFcb (
  3200. IN PIRP_CONTEXT IrpContext,
  3201. IN PFCB Fcb
  3202. )
  3203. /*++
  3204. Routine Description:
  3205. This routine restores snapshot Scb data in the event of an aborted request.
  3206. Arguments:
  3207. Fcb - Fcb for which all snapshots are to be freed, or NULL to free all
  3208. snapshots.
  3209. Return Value:
  3210. None
  3211. --*/
  3212. {
  3213. PSCB_SNAPSHOT ScbSnapshot;
  3214. ASSERT(FIELD_OFFSET(SCB_SNAPSHOT, SnapshotLinks) == 0);
  3215. ScbSnapshot = &IrpContext->ScbSnapshot;
  3216. //
  3217. // There is no snapshot data to free if the Flink is still NULL.
  3218. // We also don't free the snapshot if this isn't a top-level action.
  3219. //
  3220. if (ScbSnapshot->SnapshotLinks.Flink != NULL) {
  3221. //
  3222. // Loop to free first the Scb data from the snapshot in the
  3223. // IrpContext, and then 0 or more additional snapshots linked
  3224. // to the IrpContext.
  3225. //
  3226. do {
  3227. PSCB_SNAPSHOT NextScbSnapshot;
  3228. //
  3229. // Move to next snapshot before we delete the current one.
  3230. //
  3231. NextScbSnapshot = (PSCB_SNAPSHOT)ScbSnapshot->SnapshotLinks.Flink;
  3232. //
  3233. // We are now at a snapshot in the snapshot list. We skip
  3234. // over this entry if it has an Scb and the Fcb for that
  3235. // Scb does not match the input Fcb. If there is no
  3236. // input Fcb we always deal with this snapshot.
  3237. //
  3238. if (ScbSnapshot->Scb != NULL
  3239. && Fcb != NULL
  3240. && ScbSnapshot->Scb->Fcb != Fcb) {
  3241. ScbSnapshot = NextScbSnapshot;
  3242. continue;
  3243. }
  3244. //
  3245. // If there is an Scb, then clear its snapshot pointer.
  3246. // Always clear the UNINITIALIZE_ON_RESTORE flag, RESTORE_UNDERWAY, PROTECT_SPARSE_MCB and
  3247. // CONVERT_UNDERWAY flags.
  3248. //
  3249. if (ScbSnapshot->Scb != NULL) {
  3250. //
  3251. // Check if there is any special processing we need to do for the Scb based on the state.
  3252. // Do a single test now and then retest below to reduce the work in the mainline path.
  3253. //
  3254. if (FlagOn( ScbSnapshot->Scb->ScbState,
  3255. (SCB_STATE_UNINITIALIZE_ON_RESTORE |
  3256. SCB_STATE_RESTORE_UNDERWAY |
  3257. SCB_STATE_PROTECT_SPARSE_MCB |
  3258. SCB_STATE_CONVERT_UNDERWAY |
  3259. SCB_STATE_ATTRIBUTE_DELETED))) {
  3260. //
  3261. // If the attribute is deleted and the type is a user logged stream then
  3262. // mark the Scb as type $UNUSED to keep us from ever accessing it again.
  3263. //
  3264. if ((ScbSnapshot->Scb->AttributeTypeCode == $LOGGED_UTILITY_STREAM ) &&
  3265. FlagOn( ScbSnapshot->Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )) {
  3266. ScbSnapshot->Scb->AttributeTypeCode = $UNUSED;
  3267. }
  3268. //
  3269. // Clear the state flags which indicate whether there is a transitional change
  3270. // underway.
  3271. //
  3272. if (FlagOn( ScbSnapshot->Scb->ScbState,
  3273. (SCB_STATE_UNINITIALIZE_ON_RESTORE |
  3274. SCB_STATE_RESTORE_UNDERWAY |
  3275. SCB_STATE_PROTECT_SPARSE_MCB |
  3276. SCB_STATE_CONVERT_UNDERWAY ))) {
  3277. NtfsAcquireFsrtlHeader( ScbSnapshot->Scb );
  3278. ClearFlag( ScbSnapshot->Scb->ScbState,
  3279. SCB_STATE_UNINITIALIZE_ON_RESTORE | SCB_STATE_RESTORE_UNDERWAY | SCB_STATE_PROTECT_SPARSE_MCB | SCB_STATE_CONVERT_UNDERWAY );
  3280. NtfsReleaseFsrtlHeader( ScbSnapshot->Scb );
  3281. }
  3282. }
  3283. ScbSnapshot->Scb->ScbSnapshot = NULL;
  3284. }
  3285. if (ScbSnapshot == &IrpContext->ScbSnapshot) {
  3286. IrpContext->ScbSnapshot.Scb = NULL;
  3287. //
  3288. // Else delete the snapshot structure
  3289. //
  3290. } else {
  3291. RemoveEntryList(&ScbSnapshot->SnapshotLinks);
  3292. ExFreeToNPagedLookasideList( &NtfsScbSnapshotLookasideList, ScbSnapshot );
  3293. }
  3294. ScbSnapshot = NextScbSnapshot;
  3295. } while (ScbSnapshot != &IrpContext->ScbSnapshot);
  3296. }
  3297. }
  3298. BOOLEAN
  3299. NtfsCreateFileLock (
  3300. IN PSCB Scb,
  3301. IN BOOLEAN RaiseOnError
  3302. )
  3303. /*++
  3304. Routine Description:
  3305. This routine is called to create and initialize a file lock structure.
  3306. A try-except is used to catch allocation failures if the caller doesn't
  3307. want the exception raised.
  3308. Arguments:
  3309. Scb - Supplies the Scb to attach the file lock to.
  3310. RaiseOnError - If TRUE then don't catch the allocation failure.
  3311. Return Value:
  3312. TRUE if the lock is allocated and initialized. FALSE if there is an
  3313. error and the caller didn't specify RaiseOnError.
  3314. --*/
  3315. {
  3316. PFILE_LOCK FileLock = NULL;
  3317. BOOLEAN Success = TRUE;
  3318. PAGED_CODE();
  3319. FileLock = FsRtlAllocateFileLock( NULL, NULL );
  3320. if (FileLock != NULL) {
  3321. //
  3322. // Use the FsRtl header mutex to synchronize storing
  3323. // the lock structure, and only store it if no one
  3324. // else beat us.
  3325. //
  3326. NtfsAcquireFsrtlHeader(Scb);
  3327. if (Scb->ScbType.Data.FileLock == NULL) {
  3328. Scb->ScbType.Data.FileLock = FileLock;
  3329. FileLock = NULL;
  3330. }
  3331. NtfsReleaseFsrtlHeader(Scb);
  3332. if (FileLock != NULL) {
  3333. FsRtlFreeFileLock( FileLock );
  3334. }
  3335. } else {
  3336. //
  3337. // Fail appropriately.
  3338. //
  3339. if (RaiseOnError) {
  3340. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  3341. }
  3342. Success = FALSE;
  3343. }
  3344. return Success;
  3345. }
  3346. PSCB
  3347. NtfsGetNextScb (
  3348. IN PSCB Scb,
  3349. IN PSCB TerminationScb
  3350. )
  3351. /*++
  3352. Routine Description:
  3353. This routine is used to iterate through Scbs in a tree.
  3354. The rules are:
  3355. . If you have a child, go to it, else
  3356. . If you have a next sibling, go to it, else
  3357. . Go to your parent's next sibling.
  3358. If this routine is called with in invalid TerminationScb it will fail,
  3359. badly.
  3360. Arguments:
  3361. Scb - Supplies the current Scb
  3362. TerminationScb - The Scb at which the enumeration should (non-inclusively)
  3363. stop. Assumed to be a directory.
  3364. Return Value:
  3365. The next Scb in the enumeration, or NULL if Scb was the final one.
  3366. --*/
  3367. {
  3368. PSCB Results;
  3369. PAGED_CODE();
  3370. DebugTrace( +1, Dbg, ("NtfsGetNextScb, Scb = %08lx, TerminationScb = %08lx\n", Scb, TerminationScb) );
  3371. //
  3372. // If this is an index (i.e., not a file) and it has children then return
  3373. // the scb for the first child
  3374. //
  3375. // Scb
  3376. //
  3377. // / \.
  3378. // / \.
  3379. //
  3380. // ChildLcb
  3381. //
  3382. // |
  3383. // |
  3384. //
  3385. // ChildFcb
  3386. //
  3387. // / \.
  3388. // / \.
  3389. //
  3390. // Results
  3391. //
  3392. if (((SafeNodeType(Scb) == NTFS_NTC_SCB_INDEX) || (SafeNodeType(Scb) == NTFS_NTC_SCB_ROOT_INDEX))
  3393. &&
  3394. !IsListEmpty(&Scb->ScbType.Index.LcbQueue)) {
  3395. PLCB ChildLcb;
  3396. PFCB ChildFcb;
  3397. //
  3398. // locate the first lcb out of this scb and also the corresponding fcb
  3399. //
  3400. ChildLcb = NtfsGetNextChildLcb(Scb, NULL);
  3401. ChildFcb = ChildLcb->Fcb;
  3402. //
  3403. // Then as a bookkeeping means for ourselves we will move this
  3404. // lcb to the head of the fcb's lcb queue that way when we
  3405. // need to ask which link we went through to get here we will know
  3406. //
  3407. RemoveEntryList( &ChildLcb->FcbLinks );
  3408. InsertHeadList( &ChildFcb->LcbQueue, &ChildLcb->FcbLinks );
  3409. //
  3410. // And our return value is the first scb of this fcb
  3411. //
  3412. ASSERT( !IsListEmpty(&ChildFcb->ScbQueue) );
  3413. //
  3414. // Acquire and drop the Fcb in order to look at the Scb list.
  3415. //
  3416. ExAcquireResourceExclusiveLite( ChildFcb->Resource, TRUE );
  3417. Results = NtfsGetNextChildScb( ChildFcb, NULL );
  3418. ExReleaseResourceLite( ChildFcb->Resource );
  3419. //
  3420. // We could be processing an empty index
  3421. //
  3422. } else if ( Scb == TerminationScb ) {
  3423. Results = NULL;
  3424. } else {
  3425. PSCB SiblingScb;
  3426. PFCB ParentFcb;
  3427. PLCB ParentLcb;
  3428. PLCB SiblingLcb;
  3429. PFCB SiblingFcb;
  3430. //
  3431. // Acquire and drop the Fcb in order to look at the Scb list.
  3432. //
  3433. ExAcquireResourceExclusiveLite( Scb->Fcb->Resource, TRUE );
  3434. SiblingScb = NtfsGetNextChildScb( Scb->Fcb, Scb );
  3435. ExReleaseResourceLite( Scb->Fcb->Resource );
  3436. while (TRUE) {
  3437. //
  3438. // If there is a sibling scb to the input scb then return it
  3439. //
  3440. // Fcb
  3441. //
  3442. // / \.
  3443. // / \.
  3444. //
  3445. // Scb Sibling
  3446. // Scb
  3447. //
  3448. if (SiblingScb != NULL) {
  3449. Results = SiblingScb;
  3450. break;
  3451. }
  3452. //
  3453. // The scb doesn't have any more siblings. See if our fcb has a sibling
  3454. //
  3455. // S
  3456. //
  3457. // / \.
  3458. // / \.
  3459. //
  3460. // ParentLcb SiblingLcb
  3461. //
  3462. // | |
  3463. // | |
  3464. //
  3465. // ParentFcb SiblingFcb
  3466. //
  3467. // / / \.
  3468. // / / \.
  3469. //
  3470. // Scb Results
  3471. //
  3472. // It's possible that the SiblingFcb has already been traversed.
  3473. // Consider the case where there are multiple links between the
  3474. // same Scb and Fcb. We want to ignore this case or else face
  3475. // an infinite loop by moving the Lcb to the beginning of the
  3476. // Fcb queue and then later finding an Lcb that we have already
  3477. // traverse. We use the fact that we haven't modified the
  3478. // ordering of the Lcb off the parent Scb. When we find a
  3479. // candidate for the next Fcb, we walk backwards through the
  3480. // list of Lcb's off the Scb to make sure this is not a
  3481. // duplicate Fcb.
  3482. //
  3483. ParentFcb = Scb->Fcb;
  3484. ParentLcb = NtfsGetNextParentLcb(ParentFcb, NULL);
  3485. //
  3486. // Try to find a sibling Lcb which does not point to an Fcb
  3487. // we've already visited.
  3488. //
  3489. SiblingLcb = ParentLcb;
  3490. while ((SiblingLcb = NtfsGetNextChildLcb( ParentLcb->Scb, SiblingLcb)) != NULL) {
  3491. PLCB PrevChildLcb;
  3492. PFCB PotentialSiblingFcb;
  3493. //
  3494. // Now walk through the child Lcb's of the Scb which we have
  3495. // already visited.
  3496. //
  3497. PrevChildLcb = SiblingLcb;
  3498. PotentialSiblingFcb = SiblingLcb->Fcb;
  3499. //
  3500. // Skip this Lcb if the Fcb has no children.
  3501. //
  3502. if (IsListEmpty( &PotentialSiblingFcb->ScbQueue )) {
  3503. continue;
  3504. }
  3505. while ((PrevChildLcb = NtfsGetPrevChildLcb( ParentLcb->Scb, PrevChildLcb )) != NULL) {
  3506. //
  3507. // If the parent Fcb and the Fcb for this Lcb are the same,
  3508. // then we have already returned the Scb's for this Fcb.
  3509. //
  3510. if (PrevChildLcb->Fcb == PotentialSiblingFcb) {
  3511. break;
  3512. }
  3513. }
  3514. //
  3515. // If we don't have a PrevChildLcb, that means that we have a valid
  3516. // sibling Lcb. We will ignore any sibling Lcb's whose
  3517. // Fcb's don't have any Scb's.
  3518. //
  3519. if (PrevChildLcb == NULL) {
  3520. break;
  3521. }
  3522. }
  3523. if (SiblingLcb != NULL) {
  3524. SiblingFcb = SiblingLcb->Fcb;
  3525. //
  3526. // Then as a bookkeeping means for ourselves we will move this
  3527. // lcb to the head of the fcb's lcb queue that way when we
  3528. // need to ask which link we went through to get here we will know
  3529. //
  3530. RemoveEntryList( &SiblingLcb->FcbLinks );
  3531. InsertHeadList( &SiblingFcb->LcbQueue, &SiblingLcb->FcbLinks );
  3532. //
  3533. // And our return value is the first scb of this fcb
  3534. //
  3535. ASSERT( !IsListEmpty(&SiblingFcb->ScbQueue) );
  3536. //
  3537. // Acquire and drop the Fcb in order to look at the Scb list.
  3538. //
  3539. ExAcquireResourceExclusiveLite( SiblingFcb->Resource, TRUE );
  3540. Results = NtfsGetNextChildScb( SiblingFcb, NULL );
  3541. ExReleaseResourceLite( SiblingFcb->Resource );
  3542. break;
  3543. }
  3544. //
  3545. // The Fcb has no sibling so bounce up one and see if we
  3546. // have reached our termination scb yet
  3547. //
  3548. // NewScb
  3549. //
  3550. // /
  3551. // /
  3552. //
  3553. // ParentLcb
  3554. //
  3555. // |
  3556. // |
  3557. //
  3558. // ParentFcb
  3559. //
  3560. // /
  3561. // /
  3562. //
  3563. // Scb
  3564. //
  3565. //
  3566. Scb = ParentLcb->Scb;
  3567. if (Scb == TerminationScb) {
  3568. Results = NULL;
  3569. break;
  3570. }
  3571. //
  3572. // Acquire and drop the Fcb in order to look at the Scb list.
  3573. //
  3574. ExAcquireResourceExclusiveLite( Scb->Fcb->Resource, TRUE );
  3575. SiblingScb = NtfsGetNextChildScb( Scb->Fcb, Scb );
  3576. ExReleaseResourceLite( Scb->Fcb->Resource );
  3577. }
  3578. }
  3579. DebugTrace( -1, Dbg, ("NtfsGetNextScb -> %08lx\n", Results) );
  3580. return Results;
  3581. }
  3582. PLCB
  3583. NtfsCreateLcb (
  3584. IN PIRP_CONTEXT IrpContext,
  3585. IN PSCB Scb,
  3586. IN PFCB Fcb,
  3587. IN UNICODE_STRING LastComponentFileName,
  3588. IN UCHAR FileNameFlags,
  3589. IN OUT PBOOLEAN ReturnedExistingLcb OPTIONAL
  3590. )
  3591. /*++
  3592. Routine Description:
  3593. This routine allocates and creates a new lcb between an
  3594. existing scb and fcb. If a component of the exact
  3595. name already exists we return that one instead of creating
  3596. a new lcb
  3597. Arguments:
  3598. Scb - Supplies the parent scb to use
  3599. Fcb - Supplies the child fcb to use
  3600. LastComponentFileName - Supplies the last component of the
  3601. path that this link represents
  3602. FileNameFlags - Indicates if this is an NTFS, DOS or hard link
  3603. ReturnedExistingLcb - Optionally tells the caller if the
  3604. lcb returned already existed. If specified and points to a
  3605. FALSE value on entry then we won't create the new Lcb.
  3606. Return Value:
  3607. LCB - returns a pointer the newly created lcb. NULL if our caller doesn't
  3608. want to create an Lcb and it didn't already exist.
  3609. --*/
  3610. {
  3611. PLCB Lcb = NULL;
  3612. BOOLEAN LocalReturnedExistingLcb = TRUE;
  3613. //
  3614. // The following variables are only used for abnormal termination
  3615. //
  3616. PVOID UnwindStorage[2] = { NULL, NULL };
  3617. PAGED_CODE();
  3618. ASSERT_IRP_CONTEXT( IrpContext );
  3619. ASSERT_SCB( Scb );
  3620. ASSERT_FCB( Fcb );
  3621. ASSERT(NodeType(Scb) != NTFS_NTC_SCB_DATA);
  3622. DebugTrace( +1, Dbg, ("NtfsCreateLcb...\n") );
  3623. if (!ARGUMENT_PRESENT(ReturnedExistingLcb)) { ReturnedExistingLcb = &LocalReturnedExistingLcb; }
  3624. //
  3625. // Search the lcb children of the input Scb to see if we have an Lcb that matches
  3626. // this one. We match if the Lcb points to the same fcb and the last component file name
  3627. // and flags match. We ignore any Lcb's that indicate links that have been
  3628. // removed.
  3629. //
  3630. Lcb = NULL;
  3631. while ((Lcb = NtfsGetNextParentLcb(Fcb, Lcb)) != NULL) {
  3632. ASSERT_LCB( Lcb );
  3633. if ((Scb == Lcb->Scb)
  3634. &&
  3635. (!FlagOn( Lcb->LcbState, LCB_STATE_LINK_IS_GONE ))
  3636. &&
  3637. (FileNameFlags == Lcb->FileNameAttr->Flags)
  3638. &&
  3639. (LastComponentFileName.Length == Lcb->ExactCaseLink.LinkName.Length)
  3640. &&
  3641. (RtlEqualMemory( LastComponentFileName.Buffer,
  3642. Lcb->ExactCaseLink.LinkName.Buffer,
  3643. LastComponentFileName.Length ) )) {
  3644. *ReturnedExistingLcb = TRUE;
  3645. DebugTrace( -1, Dbg, ("NtfsCreateLcb -> %08lx\n", Lcb) );
  3646. return Lcb;
  3647. }
  3648. }
  3649. //
  3650. // If our caller does not want us to create a new Lcb then return FALSE.
  3651. //
  3652. if (!(*ReturnedExistingLcb)) {
  3653. DebugTrace( -1, Dbg, ("NtfsCreateLcb -> %08lx\n", NULL) );
  3654. return NULL;
  3655. }
  3656. *ReturnedExistingLcb = FALSE;
  3657. try {
  3658. UCHAR MaxNameLength;
  3659. //
  3660. // Allocate a new lcb, zero it out and set the node type information
  3661. // Check if we can allocate the Lcb out of a compound Fcb. Check here if
  3662. // we can use the embedded name as well.
  3663. //
  3664. if (FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_DATA) &&
  3665. (SafeNodeType( &((PFCB_DATA) Fcb)->Lcb ) == 0)) {
  3666. Lcb = (PLCB) &((PFCB_DATA) Fcb)->Lcb;
  3667. MaxNameLength = MAX_DATA_FILE_NAME;
  3668. } else if (FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_INDEX ) &&
  3669. (SafeNodeType( &((PFCB_INDEX) Fcb)->Lcb ) == 0)) {
  3670. Lcb = (PLCB) &((PFCB_INDEX) Fcb)->Lcb;
  3671. MaxNameLength = MAX_INDEX_FILE_NAME;
  3672. } else {
  3673. Lcb = UnwindStorage[0] = ExAllocateFromPagedLookasideList( &NtfsLcbLookasideList );
  3674. MaxNameLength = 0;
  3675. }
  3676. RtlZeroMemory( Lcb, sizeof(LCB) );
  3677. Lcb->NodeTypeCode = NTFS_NTC_LCB;
  3678. Lcb->NodeByteSize = sizeof(LCB);
  3679. //
  3680. // Check if we will have to allocate a separate filename attr.
  3681. //
  3682. if (MaxNameLength < (USHORT) (LastComponentFileName.Length / sizeof( WCHAR ))) {
  3683. //
  3684. // Allocate the last component part of the lcb and copy over the data.
  3685. // Check if there is space in the Fcb for this.
  3686. //
  3687. Lcb->FileNameAttr =
  3688. UnwindStorage[1] = NtfsAllocatePool(PagedPool, LastComponentFileName.Length +
  3689. NtfsFileNameSizeFromLength( LastComponentFileName.Length ));
  3690. MaxNameLength = (UCHAR)(LastComponentFileName.Length / sizeof( WCHAR ));
  3691. } else {
  3692. Lcb->FileNameAttr = (PFILE_NAME) &Lcb->ParentDirectory;
  3693. }
  3694. Lcb->FileNameAttr->ParentDirectory = Scb->Fcb->FileReference;
  3695. Lcb->FileNameAttr->FileNameLength = (UCHAR) (LastComponentFileName.Length / sizeof( WCHAR ));
  3696. Lcb->FileNameAttr->Flags = FileNameFlags;
  3697. Lcb->ExactCaseLink.LinkName.Buffer = (PWCHAR) &Lcb->FileNameAttr->FileName;
  3698. Lcb->IgnoreCaseLink.LinkName.Buffer = Add2Ptr( Lcb->FileNameAttr,
  3699. NtfsFileNameSizeFromLength( MaxNameLength * sizeof( WCHAR )));
  3700. Lcb->ExactCaseLink.LinkName.Length =
  3701. Lcb->IgnoreCaseLink.LinkName.Length = LastComponentFileName.Length;
  3702. Lcb->ExactCaseLink.LinkName.MaximumLength =
  3703. Lcb->IgnoreCaseLink.LinkName.MaximumLength = MaxNameLength * sizeof( WCHAR );
  3704. RtlCopyMemory( Lcb->ExactCaseLink.LinkName.Buffer,
  3705. LastComponentFileName.Buffer,
  3706. LastComponentFileName.Length );
  3707. RtlCopyMemory( Lcb->IgnoreCaseLink.LinkName.Buffer,
  3708. LastComponentFileName.Buffer,
  3709. LastComponentFileName.Length );
  3710. NtfsUpcaseName( IrpContext->Vcb->UpcaseTable,
  3711. IrpContext->Vcb->UpcaseTableSize,
  3712. &Lcb->IgnoreCaseLink.LinkName );
  3713. //
  3714. // Now put this Lcb into the queues for the scb and the fcb
  3715. //
  3716. InsertTailList( &Scb->ScbType.Index.LcbQueue, &Lcb->ScbLinks );
  3717. Lcb->Scb = Scb;
  3718. InsertTailList( &Fcb->LcbQueue, &Lcb->FcbLinks );
  3719. Lcb->Fcb = Fcb;
  3720. //
  3721. // Now initialize the ccb queue.
  3722. //
  3723. InitializeListHead( &Lcb->CcbQueue );
  3724. } finally {
  3725. DebugUnwind( NtfsCreateLcb );
  3726. if (AbnormalTermination()) {
  3727. if (UnwindStorage[0]) { NtfsFreePool( UnwindStorage[0] );
  3728. } else if (Lcb != NULL) { Lcb->NodeTypeCode = 0; }
  3729. if (UnwindStorage[1]) { NtfsFreePool( UnwindStorage[1] ); }
  3730. }
  3731. }
  3732. DebugTrace( -1, Dbg, ("NtfsCreateLcb -> %08lx\n", Lcb) );
  3733. return Lcb;
  3734. }
  3735. VOID
  3736. NtfsDeleteLcb (
  3737. IN PIRP_CONTEXT IrpContext,
  3738. IN OUT PLCB *Lcb
  3739. )
  3740. /*++
  3741. Routine Description:
  3742. This routine deallocated and removes the lcb record from Ntfs's in-memory
  3743. data structures. It assumes that the ccb queue is empty. We also assume
  3744. that this is not the root lcb that we are trying to delete.
  3745. Arguments:
  3746. Lcb - Supplise the Lcb to be removed
  3747. Return Value:
  3748. None.
  3749. --*/
  3750. {
  3751. PCCB Ccb;
  3752. PLIST_ENTRY Links;
  3753. PAGED_CODE();
  3754. ASSERT_IRP_CONTEXT( IrpContext );
  3755. DebugTrace( +1, Dbg, ("NtfsDeleteLcb, *Lcb = %08lx\n", *Lcb) );
  3756. //
  3757. // Get rid of any prefixes that might still be attached to us
  3758. //
  3759. NtfsRemovePrefix( (*Lcb) );
  3760. //
  3761. // Remove any hash table entries for this Lcb.
  3762. //
  3763. NtfsRemoveHashEntriesForLcb( *Lcb );
  3764. //
  3765. // Walk through the Ccb's for this link and clear the Lcb
  3766. // pointer. This can only be for Ccb's which there is no
  3767. // more user handle.
  3768. //
  3769. Links = (*Lcb)->CcbQueue.Flink;
  3770. while (Links != &(*Lcb)->CcbQueue) {
  3771. Ccb = CONTAINING_RECORD( Links,
  3772. CCB,
  3773. LcbLinks );
  3774. Links = Links->Flink;
  3775. NtfsUnlinkCcbFromLcb( IrpContext, Ccb );
  3776. }
  3777. //
  3778. //
  3779. // Now remove ourselves from our scb and fcb
  3780. //
  3781. RemoveEntryList( &(*Lcb)->ScbLinks );
  3782. RemoveEntryList( &(*Lcb)->FcbLinks );
  3783. //
  3784. // Free up the last component part and then free ourselves
  3785. //
  3786. if ((*Lcb)->FileNameAttr != (PFILE_NAME) &(*Lcb)->ParentDirectory) {
  3787. NtfsFreePool( (*Lcb)->FileNameAttr );
  3788. DebugDoit( (*Lcb)->FileNameAttr = NULL );
  3789. }
  3790. //
  3791. // Check if we are part of an embedded structure otherwise free back to the
  3792. // lookaside list
  3793. //
  3794. if (((*Lcb) == (PLCB) &((PFCB_DATA) (*Lcb)->Fcb)->Lcb) ||
  3795. ((*Lcb) == (PLCB) &((PFCB_INDEX) (*Lcb)->Fcb)->Lcb)) {
  3796. #ifdef KEITHKADBG
  3797. RtlZeroMemory( *Lcb, sizeof( LCB ) );
  3798. #endif
  3799. (*Lcb)->NodeTypeCode = 0;
  3800. } else {
  3801. #ifdef KEITHKADBG
  3802. RtlZeroMemory( *Lcb, sizeof( LCB ) );
  3803. #endif
  3804. ExFreeToPagedLookasideList( &NtfsLcbLookasideList, *Lcb );
  3805. }
  3806. //
  3807. // And for safety sake null out the pointer
  3808. //
  3809. *Lcb = NULL;
  3810. DebugTrace( -1, Dbg, ("NtfsDeleteLcb -> VOID\n") );
  3811. return;
  3812. }
  3813. VOID
  3814. NtfsMoveLcb (
  3815. IN PIRP_CONTEXT IrpContext,
  3816. IN PLCB Lcb,
  3817. IN PSCB Scb,
  3818. IN PFCB Fcb,
  3819. IN PUNICODE_STRING TargetDirectoryName,
  3820. IN PUNICODE_STRING LastComponentName,
  3821. IN UCHAR FileNameFlags,
  3822. IN BOOLEAN CheckBufferSizeOnly
  3823. )
  3824. /*++
  3825. Routine Description:
  3826. This routine completely moves the input lcb to join different fcbs and
  3827. scbs. It hasIt uses the target directory
  3828. file object to supply the complete new name to use.
  3829. Arguments:
  3830. Lcb - Supplies the Lcb being moved.
  3831. Scb - Supplies the new parent scb
  3832. Fcb - Supplies the new child fcb
  3833. TargetDirectoryName - This is the path used to reach the new parent directory
  3834. for this Lcb. It will only be from the root.
  3835. LastComponentName - This is the last component name to store in this relocated Lcb.
  3836. FileNameFlags - Indicates if this is an NTFS, DOS or hard link
  3837. CheckBufferSizeOnly - If TRUE we just want to pass through and verify that
  3838. the buffer sizes of the various structures will be large enough for the
  3839. new name.
  3840. Return Value:
  3841. None.
  3842. --*/
  3843. {
  3844. PVCB Vcb = Scb->Vcb;
  3845. ULONG BytesNeeded;
  3846. PVOID NewAllocation;
  3847. PCHAR NextChar;
  3848. PCCB Ccb;
  3849. ASSERT_IRP_CONTEXT( IrpContext );
  3850. ASSERT_LCB( Lcb );
  3851. ASSERT_SCB( Scb );
  3852. ASSERT_FCB( Fcb );
  3853. ASSERT( NodeType( Scb ) != NTFS_NTC_SCB_DATA );
  3854. PAGED_CODE();
  3855. DebugTrace( +1, Dbg, ("NtfsMoveLcb, Lcb = %08lx\n", Lcb) );
  3856. //
  3857. // If we're not just checking sizes then remove entries from the prefix table
  3858. // and the normalized name for descendents of the current scb.
  3859. //
  3860. if (!CheckBufferSizeOnly) {
  3861. NtfsClearRecursiveLcb ( Lcb );
  3862. }
  3863. //
  3864. // Remember the number of bytes needed for the last component.
  3865. //
  3866. BytesNeeded = LastComponentName->Length;
  3867. //
  3868. // Check if we need to allocate a new filename attribute. If so allocate
  3869. // it and store it into the new allocation buffer.
  3870. //
  3871. if (Lcb->ExactCaseLink.LinkName.MaximumLength < BytesNeeded) {
  3872. NewAllocation = NtfsAllocatePool( PagedPool,
  3873. BytesNeeded + NtfsFileNameSizeFromLength( BytesNeeded ));
  3874. //
  3875. // Set up the existing names into the new buffer. That way if we have an allocation
  3876. // failure below with the Ccb's the Lcb is still in a valid state.
  3877. //
  3878. RtlCopyMemory( NewAllocation,
  3879. Lcb->FileNameAttr,
  3880. NtfsFileNameSizeFromLength( Lcb->ExactCaseLink.LinkName.MaximumLength ));
  3881. RtlCopyMemory( Add2Ptr( NewAllocation, NtfsFileNameSizeFromLength( BytesNeeded )),
  3882. Lcb->IgnoreCaseLink.LinkName.Buffer,
  3883. Lcb->IgnoreCaseLink.LinkName.MaximumLength );
  3884. if (Lcb->FileNameAttr != (PFILE_NAME) &Lcb->ParentDirectory) {
  3885. NtfsFreePool( Lcb->FileNameAttr );
  3886. }
  3887. Lcb->FileNameAttr = NewAllocation;
  3888. Lcb->ExactCaseLink.LinkName.MaximumLength =
  3889. Lcb->IgnoreCaseLink.LinkName.MaximumLength = (USHORT) BytesNeeded;
  3890. Lcb->ExactCaseLink.LinkName.Buffer = (PWCHAR) &Lcb->FileNameAttr->FileName;
  3891. Lcb->IgnoreCaseLink.LinkName.Buffer = Add2Ptr( Lcb->FileNameAttr,
  3892. NtfsFileNameSizeFromLength( BytesNeeded ));
  3893. }
  3894. //
  3895. // Compute the full length of the name for the CCB, assume we will need a
  3896. // separator.
  3897. //
  3898. BytesNeeded = TargetDirectoryName->Length + sizeof( WCHAR );
  3899. //
  3900. // Now for every ccb attached to us we need to check if we need a new
  3901. // filename buffer.
  3902. //
  3903. NtfsReserveCcbNamesInLcb( IrpContext, Lcb, &BytesNeeded, LastComponentName->Length );
  3904. //
  3905. // Add back in the last component.
  3906. //
  3907. BytesNeeded += LastComponentName->Length;
  3908. //
  3909. // Now update the Lcb with the new values if we are to rewrite the buffers.
  3910. //
  3911. if (!CheckBufferSizeOnly) {
  3912. Lcb->FileNameAttr->ParentDirectory = Scb->Fcb->FileReference;
  3913. Lcb->FileNameAttr->FileNameLength = (UCHAR) (LastComponentName->Length / sizeof( WCHAR ));
  3914. Lcb->FileNameAttr->Flags = FileNameFlags;
  3915. Lcb->ExactCaseLink.LinkName.Length =
  3916. Lcb->IgnoreCaseLink.LinkName.Length = (USHORT) LastComponentName->Length;
  3917. RtlCopyMemory( Lcb->ExactCaseLink.LinkName.Buffer,
  3918. LastComponentName->Buffer,
  3919. LastComponentName->Length );
  3920. RtlCopyMemory( Lcb->IgnoreCaseLink.LinkName.Buffer,
  3921. LastComponentName->Buffer,
  3922. LastComponentName->Length );
  3923. NtfsUpcaseName( IrpContext->Vcb->UpcaseTable,
  3924. IrpContext->Vcb->UpcaseTableSize,
  3925. &Lcb->IgnoreCaseLink.LinkName );
  3926. //
  3927. // Now for every ccb attached to us we need to munge it file object name by
  3928. // copying over the entire new name
  3929. //
  3930. Ccb = NULL;
  3931. while ((Ccb = NtfsGetNextCcb(Lcb, Ccb)) != NULL) {
  3932. //
  3933. // We ignore any Ccb's which are associated with open by File Id
  3934. // file objects or their file objects have gone through cleanup.
  3935. // Lock and unlock the Fcb to serialize access to the close flag.
  3936. //
  3937. NtfsLockFcb( IrpContext, Ccb->Lcb->Fcb );
  3938. if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_FILE_ID | CCB_FLAG_CLOSE )) {
  3939. Ccb->FullFileName.Length = (USHORT) BytesNeeded;
  3940. NextChar = (PCHAR) Ccb->FullFileName.Buffer;
  3941. RtlCopyMemory( NextChar,
  3942. TargetDirectoryName->Buffer,
  3943. TargetDirectoryName->Length );
  3944. NextChar += TargetDirectoryName->Length;
  3945. if (TargetDirectoryName->Length != sizeof( WCHAR )) {
  3946. *((PWCHAR) NextChar) = L'\\';
  3947. NextChar += sizeof( WCHAR );
  3948. } else {
  3949. Ccb->FullFileName.Length -= sizeof( WCHAR );
  3950. }
  3951. RtlCopyMemory( NextChar,
  3952. LastComponentName->Buffer,
  3953. LastComponentName->Length );
  3954. Ccb->LastFileNameOffset = (USHORT) (Ccb->FullFileName.Length - LastComponentName->Length);
  3955. }
  3956. NtfsUnlockFcb( IrpContext, Ccb->Lcb->Fcb );
  3957. }
  3958. //
  3959. // Now dequeue ourselves from our old scb and fcb and put us in the
  3960. // new fcb and scb queues.
  3961. //
  3962. RemoveEntryList( &Lcb->ScbLinks );
  3963. RemoveEntryList( &Lcb->FcbLinks );
  3964. InsertTailList( &Scb->ScbType.Index.LcbQueue, &Lcb->ScbLinks );
  3965. Lcb->Scb = Scb;
  3966. InsertTailList( &Fcb->LcbQueue, &Lcb->FcbLinks );
  3967. Lcb->Fcb = Fcb;
  3968. }
  3969. //
  3970. // And return to our caller
  3971. //
  3972. return;
  3973. }
  3974. VOID
  3975. NtfsRenameLcb (
  3976. IN PIRP_CONTEXT IrpContext,
  3977. IN PLCB Lcb,
  3978. IN PUNICODE_STRING LastComponentFileName,
  3979. IN UCHAR FileNameFlags,
  3980. IN BOOLEAN CheckBufferSizeOnly
  3981. )
  3982. /*++
  3983. Routine Description:
  3984. This routine changes the last component name of the input lcb
  3985. It also walks through the opened ccb and munges their names and
  3986. also removes the lcb from the prefix table
  3987. Arguments:
  3988. Lcb - Supplies the Lcb being renamed
  3989. LastComponentFileName - Supplies the new last component to use
  3990. for the lcb name
  3991. FileNameFlags - Indicates if this is an NTFS, DOS or hard link
  3992. CheckBufferSizeOnly - If TRUE we just want to pass through and verify that
  3993. the buffer sizes of the various structures will be large enough for the
  3994. new name.
  3995. Return Value:
  3996. None.
  3997. --*/
  3998. {
  3999. PVCB Vcb = Lcb->Fcb->Vcb;
  4000. ULONG BytesNeeded;
  4001. PVOID NewAllocation;
  4002. PCCB Ccb;
  4003. ASSERT_IRP_CONTEXT( IrpContext );
  4004. ASSERT_LCB( Lcb );
  4005. PAGED_CODE();
  4006. //
  4007. // If we're not just checking sizes then remove entries from the prefix table
  4008. // and the normalized name for descendents of the current scb.
  4009. //
  4010. if (!CheckBufferSizeOnly) {
  4011. NtfsClearRecursiveLcb ( Lcb );
  4012. }
  4013. //
  4014. // Remember the number of bytes needed for the last component.
  4015. //
  4016. BytesNeeded = LastComponentFileName->Length;
  4017. //
  4018. // Check if we need to allocate a new filename attribute. If so allocate
  4019. // it and store it into the new allocation buffer.
  4020. //
  4021. if (Lcb->ExactCaseLink.LinkName.MaximumLength < BytesNeeded) {
  4022. NewAllocation = NtfsAllocatePool( PagedPool,
  4023. BytesNeeded + NtfsFileNameSizeFromLength( BytesNeeded ));
  4024. //
  4025. // Set up the existing names into the new buffer. That way if we have an allocation
  4026. // failure below with the Ccb's the Lcb is still in a valid state.
  4027. //
  4028. RtlCopyMemory( NewAllocation,
  4029. Lcb->FileNameAttr,
  4030. NtfsFileNameSizeFromLength( Lcb->ExactCaseLink.LinkName.MaximumLength ));
  4031. RtlCopyMemory( Add2Ptr( NewAllocation, NtfsFileNameSizeFromLength( BytesNeeded )),
  4032. Lcb->IgnoreCaseLink.LinkName.Buffer,
  4033. Lcb->IgnoreCaseLink.LinkName.MaximumLength );
  4034. if (Lcb->FileNameAttr != (PFILE_NAME) &Lcb->ParentDirectory) {
  4035. NtfsFreePool( Lcb->FileNameAttr );
  4036. }
  4037. Lcb->FileNameAttr = NewAllocation;
  4038. Lcb->ExactCaseLink.LinkName.MaximumLength =
  4039. Lcb->IgnoreCaseLink.LinkName.MaximumLength = (USHORT) BytesNeeded;
  4040. Lcb->ExactCaseLink.LinkName.Buffer = (PWCHAR) &Lcb->FileNameAttr->FileName;
  4041. Lcb->IgnoreCaseLink.LinkName.Buffer = Add2Ptr( Lcb->FileNameAttr,
  4042. NtfsFileNameSizeFromLength( BytesNeeded ));
  4043. }
  4044. //
  4045. // Now for every ccb attached to us we need to check if we need a new
  4046. // filename buffer.
  4047. //
  4048. NtfsReserveCcbNamesInLcb( IrpContext, Lcb, NULL, BytesNeeded );
  4049. //
  4050. // Now update the Lcb and Ccb's with the new values if we are to rewrite the buffers.
  4051. //
  4052. if (!CheckBufferSizeOnly) {
  4053. BytesNeeded = LastComponentFileName->Length;
  4054. Lcb->FileNameAttr->FileNameLength = (UCHAR) (BytesNeeded / sizeof( WCHAR ));
  4055. Lcb->FileNameAttr->Flags = FileNameFlags;
  4056. Lcb->ExactCaseLink.LinkName.Length =
  4057. Lcb->IgnoreCaseLink.LinkName.Length = (USHORT) LastComponentFileName->Length;
  4058. RtlCopyMemory( Lcb->ExactCaseLink.LinkName.Buffer,
  4059. LastComponentFileName->Buffer,
  4060. BytesNeeded );
  4061. RtlCopyMemory( Lcb->IgnoreCaseLink.LinkName.Buffer,
  4062. LastComponentFileName->Buffer,
  4063. BytesNeeded );
  4064. NtfsUpcaseName( IrpContext->Vcb->UpcaseTable,
  4065. IrpContext->Vcb->UpcaseTableSize,
  4066. &Lcb->IgnoreCaseLink.LinkName );
  4067. //
  4068. // Now for every ccb attached to us we need to munge it file object name by
  4069. // copying over the entire new name
  4070. //
  4071. Ccb = NULL;
  4072. while ((Ccb = NtfsGetNextCcb(Lcb, Ccb)) != NULL) {
  4073. //
  4074. // We ignore any Ccb's which are associated with open by File Id
  4075. // file objects. We also ignore any Ccb's which don't have a file
  4076. // object pointer. Lock and unlock the Fcb to serialize access
  4077. // to the close flag.
  4078. //
  4079. NtfsLockFcb( IrpContext, Ccb->Lcb->Fcb );
  4080. if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_FILE_ID | CCB_FLAG_CLOSE )) {
  4081. RtlCopyMemory( &Ccb->FullFileName.Buffer[ Ccb->LastFileNameOffset / sizeof( WCHAR ) ],
  4082. LastComponentFileName->Buffer,
  4083. BytesNeeded );
  4084. Ccb->FullFileName.Length = Ccb->LastFileNameOffset + (USHORT) BytesNeeded;
  4085. }
  4086. NtfsUnlockFcb( IrpContext, Ccb->Lcb->Fcb );
  4087. }
  4088. }
  4089. return;
  4090. }
  4091. VOID
  4092. NtfsCombineLcbs (
  4093. IN PIRP_CONTEXT IrpContext,
  4094. IN PLCB PrimaryLcb,
  4095. IN PLCB AuxLcb
  4096. )
  4097. /*++
  4098. Routine Description:
  4099. This routine is called for the case where we have multiple Lcb's for a
  4100. file which connect to the same Scb. We are performing a link rename
  4101. operation which causes the links to be combined and we need to
  4102. move all of the Ccb's to the same Lcb. This routine will be called only
  4103. after the names have been munged so that they are identical.
  4104. (i.e. call NtfsRenameLcb first)
  4105. Arguments:
  4106. PrimaryLcb - Supplies the Lcb to receive all the Ccb's and Pcb's.
  4107. AuxLcb - Supplies the Lcb to strip.
  4108. Return Value:
  4109. None.
  4110. --*/
  4111. {
  4112. PLIST_ENTRY Links;
  4113. PCCB NextCcb;
  4114. DebugTrace( +1, Dbg, ("NtfsCombineLcbs: Entered\n") );
  4115. ASSERT_IRP_CONTEXT( IrpContext );
  4116. ASSERT_LCB( PrimaryLcb );
  4117. ASSERT_LCB( AuxLcb );
  4118. PAGED_CODE();
  4119. //
  4120. // Move all of the Ccb's first.
  4121. //
  4122. for (Links = AuxLcb->CcbQueue.Flink;
  4123. Links != &AuxLcb->CcbQueue;
  4124. Links = AuxLcb->CcbQueue.Flink) {
  4125. NextCcb = CONTAINING_RECORD( Links, CCB, LcbLinks );
  4126. NtfsUnlinkCcbFromLcb( IrpContext, NextCcb );
  4127. NtfsLinkCcbToLcb( IrpContext, NextCcb, PrimaryLcb );
  4128. }
  4129. //
  4130. // Now do the prefix entries.
  4131. //
  4132. ASSERT( NtfsIsExclusiveScb( AuxLcb->Scb ) );
  4133. NtfsRemovePrefix( AuxLcb );
  4134. //
  4135. // Remove any hash table entries for this Lcb.
  4136. //
  4137. NtfsRemoveHashEntriesForLcb( AuxLcb );
  4138. //
  4139. // Finally we need to transfer the unclean counts from the
  4140. // Lcb being merged to the primary Lcb.
  4141. //
  4142. PrimaryLcb->CleanupCount += AuxLcb->CleanupCount;
  4143. DebugTrace( -1, Dbg, ("NtfsCombineLcbs: Entered\n") );
  4144. return;
  4145. }
  4146. PLCB
  4147. NtfsLookupLcbByFlags (
  4148. IN PFCB Fcb,
  4149. IN UCHAR FileNameFlags
  4150. )
  4151. /*++
  4152. Routine Description:
  4153. This routine is called to find a split primary link by the file flag
  4154. only.
  4155. Arguments:
  4156. Fcb - This is the Fcb for the file.
  4157. FileNameFlags - This is the file flag to search for. We will return
  4158. a link which matches this exactly.
  4159. Return Value:
  4160. PLCB - The Lcb which has the desired flag, NULL otherwise.
  4161. --*/
  4162. {
  4163. PLCB Lcb;
  4164. PLIST_ENTRY Links;
  4165. PLCB ThisLcb;
  4166. PAGED_CODE();
  4167. DebugTrace( +1, Dbg, ("NtfsLookupLcbByFlags: Entered\n") );
  4168. Lcb = NULL;
  4169. //
  4170. // Walk through the Lcb's for the file, looking for an exact match.
  4171. //
  4172. for (Links = Fcb->LcbQueue.Flink; Links != &Fcb->LcbQueue; Links = Links->Flink) {
  4173. ThisLcb = CONTAINING_RECORD( Links, LCB, FcbLinks );
  4174. if (ThisLcb->FileNameAttr->Flags == FileNameFlags) {
  4175. Lcb = ThisLcb;
  4176. break;
  4177. }
  4178. }
  4179. DebugTrace( -1, Dbg, ("NtfsLookupLcbByFlags: Exit\n") );
  4180. return Lcb;
  4181. }
  4182. ULONG
  4183. NtfsLookupNameLengthViaLcb (
  4184. IN PFCB Fcb,
  4185. OUT PBOOLEAN LeadingBackslash
  4186. )
  4187. /*++
  4188. Routine Description:
  4189. This routine is called to find the length of the file name by walking
  4190. backwards through the Lcb links.
  4191. Arguments:
  4192. Fcb - This is the Fcb for the file.
  4193. LeadingBackslash - On return, indicates whether this chain begins with a
  4194. backslash.
  4195. Return Value:
  4196. ULONG This is the length of the bytes found in the Lcb chain.
  4197. --*/
  4198. {
  4199. ULONG NameLength;
  4200. DebugTrace( +1, Dbg, ("NtfsLookupNameLengthViaLcb: Entered\n") );
  4201. //
  4202. // Initialize the return values.
  4203. //
  4204. NameLength = 0;
  4205. *LeadingBackslash = FALSE;
  4206. //
  4207. // If there is no Lcb we are done.
  4208. //
  4209. if (!IsListEmpty( &Fcb->LcbQueue )) {
  4210. PLCB ThisLcb;
  4211. BOOLEAN FirstComponent;
  4212. //
  4213. // Walk up the list of Lcb's and count the name elements.
  4214. //
  4215. FirstComponent = TRUE;
  4216. ThisLcb = CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  4217. LCB,
  4218. FcbLinks );
  4219. //
  4220. // Loop until we have reached the root or there are no more Lcb's.
  4221. //
  4222. while (TRUE) {
  4223. if (ThisLcb == Fcb->Vcb->RootLcb) {
  4224. NameLength += sizeof( WCHAR );
  4225. *LeadingBackslash = TRUE;
  4226. break;
  4227. }
  4228. //
  4229. // If this is not the first component, we add room for a separating
  4230. // forward slash.
  4231. //
  4232. if (!FirstComponent) {
  4233. NameLength += sizeof( WCHAR );
  4234. } else {
  4235. FirstComponent = FALSE;
  4236. }
  4237. NameLength += ThisLcb->ExactCaseLink.LinkName.Length;
  4238. //
  4239. // If the next Fcb has no Lcb we exit.
  4240. //
  4241. Fcb = ((PSCB) ThisLcb->Scb)->Fcb;
  4242. if (IsListEmpty( &Fcb->LcbQueue)) {
  4243. break;
  4244. }
  4245. ThisLcb = CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  4246. LCB,
  4247. FcbLinks );
  4248. }
  4249. //
  4250. // If this is a system file we use the hard coded name.
  4251. //
  4252. } else if (NtfsSegmentNumber( &Fcb->FileReference ) <= UPCASE_TABLE_NUMBER) {
  4253. NameLength = NtfsSystemFiles[NtfsSegmentNumber( &Fcb->FileReference )].Length;
  4254. *LeadingBackslash = TRUE;
  4255. }
  4256. DebugTrace( -1, Dbg, ("NtfsLookupNameLengthViaLcb: Exit - %08lx\n", NameLength) );
  4257. return NameLength;
  4258. }
  4259. VOID
  4260. NtfsFileNameViaLcb (
  4261. IN PFCB Fcb,
  4262. IN PWCHAR FileName,
  4263. ULONG Length,
  4264. ULONG BytesToCopy
  4265. )
  4266. /*++
  4267. Routine Description:
  4268. This routine is called to fill a buffer with the generated filename. The name
  4269. is constructed by walking backwards through the Lcb chain from the current Fcb.
  4270. Arguments:
  4271. Fcb - This is the Fcb for the file.
  4272. FileName - This is the buffer to fill with the name.
  4273. Length - This is the length of the name. Already calculated by calling
  4274. NtfsLookupNameLengthViaLcb.
  4275. BytesToCopy - This indicates the number of bytes we are to copy. We drop
  4276. any characters out of the trailing Lcb's to only insert the beginning
  4277. of the path.
  4278. Return Value:
  4279. None.
  4280. --*/
  4281. {
  4282. ULONG BytesToDrop;
  4283. PWCHAR ThisName;
  4284. DebugTrace( +1, Dbg, ("NtfsFileNameViaLcb: Entered\n") );
  4285. //
  4286. // If there is no Lcb or there are no bytes to copy we are done.
  4287. //
  4288. if (BytesToCopy) {
  4289. if (!IsListEmpty( &Fcb->LcbQueue )) {
  4290. PLCB ThisLcb;
  4291. BOOLEAN FirstComponent;
  4292. //
  4293. // Walk up the list of Lcb's and count the name elements.
  4294. //
  4295. FirstComponent = TRUE;
  4296. ThisLcb = CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  4297. LCB,
  4298. FcbLinks );
  4299. //
  4300. // Loop until we have reached the root or there are no more Lcb's.
  4301. //
  4302. while (TRUE) {
  4303. if (ThisLcb == Fcb->Vcb->RootLcb) {
  4304. *FileName = L'\\';
  4305. break;
  4306. }
  4307. //
  4308. // If this is not the first component, we add room for a separating
  4309. // forward slash.
  4310. //
  4311. if (!FirstComponent) {
  4312. Length -= sizeof( WCHAR );
  4313. ThisName = (PWCHAR) Add2Ptr( FileName,
  4314. Length );
  4315. if (Length < BytesToCopy) {
  4316. *ThisName = L'\\';
  4317. }
  4318. } else {
  4319. FirstComponent = FALSE;
  4320. }
  4321. //
  4322. // Length is current pointing just beyond where the next
  4323. // copy will end. If we are beyond the number of bytes to copy
  4324. // then we will truncate the copy.
  4325. //
  4326. if (Length > BytesToCopy) {
  4327. BytesToDrop = Length - BytesToCopy;
  4328. } else {
  4329. BytesToDrop = 0;
  4330. }
  4331. Length -= ThisLcb->ExactCaseLink.LinkName.Length;
  4332. ThisName = (PWCHAR) Add2Ptr( FileName,
  4333. Length );
  4334. //
  4335. // Only perform the copy if we are in the range of bytes to copy.
  4336. //
  4337. if (Length < BytesToCopy) {
  4338. RtlCopyMemory( ThisName,
  4339. ThisLcb->ExactCaseLink.LinkName.Buffer,
  4340. ThisLcb->ExactCaseLink.LinkName.Length - BytesToDrop );
  4341. }
  4342. //
  4343. // If the next Fcb has no Lcb we exit.
  4344. //
  4345. Fcb = ((PSCB) ThisLcb->Scb)->Fcb;
  4346. if (IsListEmpty( &Fcb->LcbQueue)) {
  4347. break;
  4348. }
  4349. ThisLcb = CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  4350. LCB,
  4351. FcbLinks );
  4352. }
  4353. //
  4354. // If this is a system file, we use the hard coded name.
  4355. //
  4356. } else if (NtfsSegmentNumber(&Fcb->FileReference) <= UPCASE_TABLE_NUMBER) {
  4357. if (BytesToCopy > NtfsSystemFiles[NtfsSegmentNumber( &Fcb->FileReference )].Length) {
  4358. BytesToCopy = NtfsSystemFiles[NtfsSegmentNumber( &Fcb->FileReference )].Length;
  4359. }
  4360. RtlCopyMemory( FileName,
  4361. NtfsSystemFiles[NtfsSegmentNumber( &Fcb->FileReference )].Buffer,
  4362. BytesToCopy );
  4363. }
  4364. }
  4365. DebugTrace( -1, Dbg, ("NtfsFileNameViaLcb: Exit\n") );
  4366. return;
  4367. }
  4368. PCCB
  4369. NtfsCreateCcb (
  4370. IN PIRP_CONTEXT IrpContext,
  4371. IN PFCB Fcb,
  4372. IN PSCB Scb,
  4373. IN BOOLEAN Indexed,
  4374. IN USHORT EaModificationCount,
  4375. IN ULONG Flags,
  4376. IN PFILE_OBJECT FileObject,
  4377. IN ULONG LastFileNameOffset
  4378. )
  4379. /*++
  4380. Routine Description:
  4381. This routine creates a new CCB record
  4382. Arguments:
  4383. Fcb - This is the Fcb for the file. We will check if we can allocate
  4384. the Ccb from an embedded structure.
  4385. Indexed - Indicates if we need an index Ccb.
  4386. EaModificationCount - This is the current modification count in the
  4387. Fcb for this file.
  4388. Flags - Informational flags for this Ccb.
  4389. FileObject - Object containing full path used to open this file.
  4390. LastFileNameOffset - Supplies the offset (in bytes) of the last component
  4391. for the name that the user is opening. If this is the root
  4392. directory it should denote "\" and all other ones should not
  4393. start with a backslash.
  4394. Return Value:
  4395. CCB - returns a pointer to the newly allocate CCB
  4396. --*/
  4397. {
  4398. PCCB Ccb;
  4399. PAGED_CODE();
  4400. ASSERT_IRP_CONTEXT( IrpContext );
  4401. DebugTrace( +1, Dbg, ("NtfsCreateCcb\n") );
  4402. //
  4403. // Allocate a new CCB Record. If the Fcb is nonpaged then we must allocate
  4404. // a non-paged ccb. Then test if we can allocate this out of the Fcb.
  4405. //
  4406. if (FlagOn( Fcb->FcbState, FCB_STATE_NONPAGED )) {
  4407. if (Indexed) {
  4408. Ccb = NtfsAllocatePoolWithTag( NonPagedPool, sizeof(CCB), 'CftN' );
  4409. } else {
  4410. Ccb = NtfsAllocatePoolWithTag( NonPagedPool, sizeof(CCB_DATA), 'cftN' );
  4411. }
  4412. } else if (FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_INDEX ) &&
  4413. (SafeNodeType( &((PFCB_INDEX) Fcb)->Ccb ) == 0)) {
  4414. Ccb = (PCCB) &((PFCB_INDEX) Fcb)->Ccb;
  4415. } else if (!Indexed &&
  4416. FlagOn( Fcb->FcbState, FCB_STATE_COMPOUND_DATA ) &&
  4417. (SafeNodeType( &((PFCB_DATA) Fcb)->Ccb ) == 0)) {
  4418. Ccb = (PCCB) &((PFCB_DATA) Fcb)->Ccb;
  4419. } else {
  4420. if (Indexed) {
  4421. Ccb = (PCCB)ExAllocateFromPagedLookasideList( &NtfsCcbLookasideList );
  4422. } else {
  4423. Ccb = (PCCB)ExAllocateFromPagedLookasideList( &NtfsCcbDataLookasideList );
  4424. }
  4425. }
  4426. //
  4427. // Zero and initialize the correct structure.
  4428. //
  4429. if (Indexed) {
  4430. RtlZeroMemory( Ccb, sizeof(CCB) );
  4431. //
  4432. // Set the proper node type code and node byte size
  4433. //
  4434. Ccb->NodeTypeCode = NTFS_NTC_CCB_INDEX;
  4435. Ccb->NodeByteSize = sizeof(CCB);
  4436. } else {
  4437. RtlZeroMemory( Ccb, sizeof(CCB_DATA) );
  4438. //
  4439. // Set the proper node type code and node byte size
  4440. //
  4441. Ccb->NodeTypeCode = NTFS_NTC_CCB_DATA;
  4442. Ccb->NodeByteSize = sizeof(CCB_DATA);
  4443. }
  4444. //
  4445. // Copy the Ea modification count.
  4446. //
  4447. Ccb->EaModificationCount = EaModificationCount;
  4448. //
  4449. // Copy the flags field
  4450. //
  4451. Ccb->Flags = Flags;
  4452. //
  4453. // Set the file object and last file name offset fields
  4454. //
  4455. Ccb->FullFileName = FileObject->FileName;
  4456. Ccb->LastFileNameOffset = (USHORT)LastFileNameOffset;
  4457. //
  4458. // Initialize the Lcb queue.
  4459. //
  4460. InitializeListHead( &Ccb->LcbLinks );
  4461. //
  4462. // Add the Ccb onto the Scb
  4463. //
  4464. InsertTailList( &Scb->CcbQueue, &Ccb->CcbLinks );
  4465. #ifdef CCB_FILE_OBJECT
  4466. Ccb->FileObject = FileObject;
  4467. Ccb->Process = PsGetCurrentProcess();
  4468. #endif
  4469. DebugTrace( -1, Dbg, ("NtfsCreateCcb -> %08lx\n", Ccb) );
  4470. return Ccb;
  4471. }
  4472. VOID
  4473. NtfsDeleteCcb (
  4474. IN PFCB Fcb,
  4475. IN OUT PCCB *Ccb
  4476. )
  4477. /*++
  4478. Routine Description:
  4479. This routine deallocates the specified CCB record.
  4480. Arguments:
  4481. Fcb - This is the Fcb for the file. We will check if we can allocate
  4482. the Ccb from an embedded structure.
  4483. Ccb - Supplies the CCB to remove
  4484. Return Value:
  4485. None
  4486. --*/
  4487. {
  4488. ASSERT_CCB( *Ccb );
  4489. PAGED_CODE();
  4490. DebugTrace( +1, Dbg, ("NtfsDeleteCcb, Ccb = %08lx\n", Ccb) );
  4491. //
  4492. // Deallocate any structures the Ccb is pointing to. The following
  4493. // are only in index Ccb.
  4494. //
  4495. if (SafeNodeType( *Ccb ) == NTFS_NTC_CCB_INDEX) {
  4496. //
  4497. // Make sure we aren't deleting this with any waiters.
  4498. //
  4499. ASSERT( (*Ccb)->EnumQueue.Flink == NULL );
  4500. //
  4501. // If this Ccb was for a view index, we may need to
  4502. // free the read context used for directory enumeration.
  4503. //
  4504. if (FlagOn( (*Ccb)->Flags, CCB_FLAG_READ_CONTEXT_ALLOCATED )) {
  4505. NtOfsFreeReadContext( (*Ccb)->QueryBuffer );
  4506. } else if ((*Ccb)->QueryBuffer != NULL) {
  4507. NtfsFreePool( (*Ccb)->QueryBuffer );
  4508. }
  4509. if ((*Ccb)->IndexEntry != NULL) { NtfsFreePool( (*Ccb)->IndexEntry ); }
  4510. if ((*Ccb)->IndexContext != NULL) {
  4511. PINDEX_CONTEXT IndexContext;
  4512. if ((*Ccb)->IndexContext->Base != (*Ccb)->IndexContext->LookupStack) {
  4513. NtfsFreePool( (*Ccb)->IndexContext->Base );
  4514. }
  4515. //
  4516. // Copy the IndexContext pointer into the stack so we don't dereference the
  4517. // paged Ccb while holding a spinlock.
  4518. //
  4519. IndexContext = (*Ccb)->IndexContext;
  4520. ExFreeToPagedLookasideList( &NtfsIndexContextLookasideList, IndexContext );
  4521. }
  4522. }
  4523. if (FlagOn( (*Ccb)->Flags, CCB_FLAG_ALLOCATED_FILE_NAME )) {
  4524. NtfsFreePool( (*Ccb)->FullFileName.Buffer );
  4525. }
  4526. //
  4527. // Unhook Ccb from Scb list
  4528. //
  4529. RemoveEntryList( &(*Ccb)->CcbLinks );
  4530. //
  4531. // Deallocate the Ccb simply clear the flag in the Ccb header.
  4532. //
  4533. if ((*Ccb == (PCCB) &((PFCB_DATA) Fcb)->Ccb) ||
  4534. (*Ccb == (PCCB) &((PFCB_INDEX) Fcb)->Ccb)) {
  4535. (*Ccb)->NodeTypeCode = 0;
  4536. } else {
  4537. if (SafeNodeType( *Ccb ) == NTFS_NTC_CCB_INDEX) {
  4538. ExFreeToPagedLookasideList( &NtfsCcbLookasideList, *Ccb );
  4539. } else {
  4540. ExFreeToPagedLookasideList( &NtfsCcbDataLookasideList, *Ccb );
  4541. }
  4542. }
  4543. //
  4544. // Zero out the input pointer
  4545. //
  4546. *Ccb = NULL;
  4547. //
  4548. // And return to our caller
  4549. //
  4550. DebugTrace( -1, Dbg, ("NtfsDeleteCcb -> VOID\n") );
  4551. return;
  4552. }
  4553. VOID
  4554. NtfsInitializeIrpContext (
  4555. IN PIRP Irp OPTIONAL,
  4556. IN BOOLEAN Wait,
  4557. IN OUT PIRP_CONTEXT *IrpContext
  4558. )
  4559. /*++
  4560. Routine Description:
  4561. This routine creates and/or initializes a new IRP_CONTEXT record. The context
  4562. may be on the stack already or we might need to allocate it here.
  4563. Arguments:
  4564. Irp - Supplies the originating Irp. In many cases we won't be given an IrpContext for
  4565. operations where we are doing work for Ntfs not for the user.
  4566. operation.
  4567. Wait - Supplies the wait value to store in the context.
  4568. IrpContext - Address to store the IrpContext on return. If this initially points to
  4569. a non-NULL value then the IrpContext is on the stack.
  4570. Return Value:
  4571. None.
  4572. --*/
  4573. {
  4574. PIO_STACK_LOCATION IrpSp;
  4575. PVCB Vcb;
  4576. ULONG StateFlags = 0;
  4577. UCHAR MajorFunction;
  4578. UCHAR MinorFunction;
  4579. ASSERT_OPTIONAL_IRP( Irp );
  4580. //
  4581. // If the Irp is present then check that this is a legal operation for Ntfs.
  4582. //
  4583. // Also capture the Vcb, function codes and write-through state if we have
  4584. // a legal Irp.
  4585. //
  4586. if (ARGUMENT_PRESENT( Irp )) {
  4587. ASSERT( (DWORD_PTR)(Irp->Tail.Overlay.AuxiliaryBuffer) != 0xFFFFFFFF );
  4588. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  4589. //
  4590. // If we were called with our file system device object instead of a
  4591. // volume device object and this is not a mount, the request is illegal.
  4592. //
  4593. if ((IrpSp->DeviceObject->Size == (USHORT)sizeof(DEVICE_OBJECT)) &&
  4594. (IrpSp->FileObject != NULL)) {
  4595. //
  4596. // Clear the IrpContext pointer so our caller knows the request failed.
  4597. //
  4598. *IrpContext = NULL;
  4599. ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
  4600. }
  4601. //
  4602. // Copy RealDevice for workque algorithms, and also set WriteThrough
  4603. // if there is a file object.
  4604. //
  4605. if (IrpSp->FileObject != NULL) {
  4606. //
  4607. // Locate the volume device object and Vcb that we are trying to access
  4608. // so we can see if the request is WriteThrough. We ignore the
  4609. // write-through flag for close and cleanup.
  4610. //
  4611. Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
  4612. ASSERT( NodeType(Vcb) == NTFS_NTC_VCB );
  4613. ASSERTMSG( "No correspondence btwn file and device in irp",
  4614. ((IrpSp->FileObject->Vpb == NULL) &&
  4615. ((IrpSp->FileObject->DeviceObject != NULL) &&
  4616. (IrpSp->FileObject->DeviceObject->Vpb != NULL) &&
  4617. (IrpSp->DeviceObject == IrpSp->FileObject->DeviceObject->Vpb->DeviceObject))) ||
  4618. ((IrpSp->FileObject->Vpb != NULL) &&
  4619. (IrpSp->DeviceObject == IrpSp->FileObject->Vpb->DeviceObject)) ||
  4620. (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) );
  4621. if (IsFileWriteThrough( IrpSp->FileObject, Vcb )) {
  4622. StateFlags = IRP_CONTEXT_STATE_WRITE_THROUGH;
  4623. }
  4624. //
  4625. // We would still like to find out the Vcb in all cases except for
  4626. // mount.
  4627. //
  4628. } else if (IrpSp->DeviceObject != NULL) {
  4629. Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
  4630. } else {
  4631. Vcb = NULL;
  4632. }
  4633. //
  4634. // Major/Minor Function codes
  4635. //
  4636. MajorFunction = IrpSp->MajorFunction;
  4637. MinorFunction = IrpSp->MinorFunction;
  4638. } else {
  4639. Vcb = NULL;
  4640. MajorFunction = 0;
  4641. MinorFunction = 0;
  4642. }
  4643. //
  4644. // Allocate an IrpContext from zone if available, otherwise from
  4645. // non-paged pool.
  4646. //
  4647. if (*IrpContext == NULL) {
  4648. *IrpContext = (PIRP_CONTEXT)ExAllocateFromNPagedLookasideList( &NtfsIrpContextLookasideList );
  4649. SetFlag( StateFlags, IRP_CONTEXT_STATE_ALLOC_FROM_POOL );
  4650. }
  4651. DebugDoit( NtfsFsdEntryCount += 1);
  4652. RtlZeroMemory( *IrpContext, sizeof( IRP_CONTEXT ));
  4653. //
  4654. // Set the proper node type code and node byte size
  4655. //
  4656. (*IrpContext)->NodeTypeCode = NTFS_NTC_IRP_CONTEXT;
  4657. (*IrpContext)->NodeByteSize = sizeof(IRP_CONTEXT);
  4658. //
  4659. // Set the originating Irp field
  4660. //
  4661. (*IrpContext)->OriginatingIrp = Irp;
  4662. //
  4663. // Set the Vcb and function codes we found (or NULL).
  4664. //
  4665. (*IrpContext)->Vcb = Vcb;
  4666. (*IrpContext)->MajorFunction = MajorFunction;
  4667. (*IrpContext)->MinorFunction = MinorFunction;
  4668. //
  4669. // Set the wait and write through flags.
  4670. //
  4671. if (Wait) { SetFlag( (*IrpContext)->State, IRP_CONTEXT_STATE_WAIT ); }
  4672. SetFlag( (*IrpContext)->State, StateFlags );
  4673. //
  4674. // Initialize the recently deallocated record queue and exclusive Scb queue
  4675. //
  4676. InitializeListHead( &(*IrpContext)->RecentlyDeallocatedQueue );
  4677. InitializeListHead( &(*IrpContext)->ExclusiveFcbList );
  4678. //
  4679. // Always point to ourselves as the TopLevelIrpContext.
  4680. //
  4681. (*IrpContext)->TopLevelIrpContext = *IrpContext;
  4682. //
  4683. // Set up LogFull testing
  4684. //
  4685. #ifdef NTFS_LOG_FULL_TEST
  4686. (*IrpContext)->CurrentFailCount = (*IrpContext)->NextFailCount = NtfsFailCheck;
  4687. #endif
  4688. return;
  4689. }
  4690. VOID
  4691. NtfsCleanupIrpContext (
  4692. IN OUT PIRP_CONTEXT IrpContext,
  4693. IN ULONG Retry
  4694. )
  4695. /*++
  4696. Routine Description:
  4697. This routine performs cleanup on an IrpContext when we are finished using it in the current
  4698. thread. This can be because we are completing, retrying or posting a request. It may be
  4699. from the stack or allocated from pool.
  4700. This request can also be called after a transaction has committed to cleanup all of
  4701. the state information and resources held as part of the transaction. The user can set
  4702. the appropriate flags to prevent it from being deleted.
  4703. Arguments:
  4704. IrpContext - Supplies the IRP_CONTEXT to cleanup.
  4705. Retry - Indicates if we are retrying in the same thread or posting.
  4706. Return Value:
  4707. None
  4708. --*/
  4709. {
  4710. ASSERT_IRP_CONTEXT( IrpContext );
  4711. //
  4712. // Start with the recently deallocated records.
  4713. //
  4714. if (!IsListEmpty( &IrpContext->RecentlyDeallocatedQueue )) {
  4715. NtfsDeallocateRecordsComplete( IrpContext );
  4716. }
  4717. //
  4718. // Just in case we somehow get here with a transaction ID, clear
  4719. // it here so we do not loop forever.
  4720. //
  4721. ASSERT(IrpContext->TransactionId == 0);
  4722. IrpContext->TransactionId = 0;
  4723. NtfsReleaseAllResources( IrpContext );
  4724. #ifdef MAPCOUNT_DBG
  4725. //
  4726. // Check all mapping are gone now that we cleaned out cache
  4727. //
  4728. ASSERT( IrpContext->MapCount == 0 );
  4729. #endif
  4730. //
  4731. // Make sure there are no Scb snapshots left. Most are freed above when the fcb's are released
  4732. // but preacquires from mm - for example doing a flushuserstream or deleted scbs will need to be
  4733. // cleaned up here
  4734. //
  4735. NtfsFreeSnapshotsForFcb( IrpContext, NULL );
  4736. //
  4737. // Make sure we don't need to deallocate a UsnFcb structure.
  4738. //
  4739. while (IrpContext->Usn.NextUsnFcb != NULL) {
  4740. PUSN_FCB ThisUsn;
  4741. ThisUsn = IrpContext->Usn.NextUsnFcb;
  4742. IrpContext->Usn.NextUsnFcb = ThisUsn->NextUsnFcb;
  4743. NtfsFreePool( ThisUsn );
  4744. }
  4745. //
  4746. // If we can delete this Irp Context do so now.
  4747. //
  4748. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE ) &&
  4749. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT )) {
  4750. if (IrpContext->Union.NtfsIoContext != NULL) {
  4751. //
  4752. // If there is an Io context pointer in the irp context and it is not
  4753. // on the stack, then free it.
  4754. //
  4755. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_IO_CONTEXT )) {
  4756. ExFreeToNPagedLookasideList( &NtfsIoContextLookasideList, IrpContext->Union.NtfsIoContext );
  4757. //
  4758. // If we have captured the subject context then free it now.
  4759. //
  4760. } else if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_SECURITY )) {
  4761. SeReleaseSubjectContext( IrpContext->Union.SubjectContext );
  4762. NtfsFreePool( IrpContext->Union.SubjectContext );
  4763. //
  4764. // Else if we locked the user buffer in a sep. mdl in ReadUsnFile
  4765. //
  4766. } else if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_MDL )) {
  4767. MmUnlockPages( IrpContext->Union.MdlToCleanup );
  4768. IoFreeMdl( IrpContext->Union.MdlToCleanup );
  4769. }
  4770. IrpContext->Union.NtfsIoContext = NULL;
  4771. }
  4772. //
  4773. // Restore the thread context pointer if associated with this IrpContext.
  4774. //
  4775. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )) {
  4776. NtfsRestoreTopLevelIrp();
  4777. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL );
  4778. }
  4779. //
  4780. // Return the IRP context record to the lookaside or to pool depending
  4781. // how much is currently in the lookaside
  4782. //
  4783. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_FROM_POOL )) {
  4784. ExFreeToNPagedLookasideList( &NtfsIrpContextLookasideList, IrpContext );
  4785. }
  4786. } else {
  4787. //
  4788. // Do all any necessary to reinitialize IrpContext fields. We avoid doing
  4789. // these if the IrpContext is going away.
  4790. //
  4791. RtlZeroMemory( &IrpContext->ScbSnapshot, sizeof( SCB_SNAPSHOT ));
  4792. //
  4793. // Clear the appropriate flags unless our caller wanted to preserve them.
  4794. //
  4795. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_RETAIN_FLAGS )) {
  4796. //
  4797. // Set up the Irp Context for retry or post.
  4798. //
  4799. if (Retry) {
  4800. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY );
  4801. } else {
  4802. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
  4803. }
  4804. } else {
  4805. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RETAIN_FLAGS | IRP_CONTEXT_FLAG_DONT_DELETE );
  4806. }
  4807. //
  4808. // Always clear the counts of free records and clusters.
  4809. //
  4810. IrpContext->DeallocatedClusters = 0;
  4811. IrpContext->FreeClusterChange = 0;
  4812. }
  4813. //
  4814. // And return to our caller
  4815. //
  4816. return;
  4817. }
  4818. VOID
  4819. NtfsTeardownStructures (
  4820. IN PIRP_CONTEXT IrpContext,
  4821. IN PVOID FcbOrScb,
  4822. IN PLCB Lcb OPTIONAL,
  4823. IN BOOLEAN CheckForAttributeTable,
  4824. IN ULONG AcquireFlags,
  4825. OUT PBOOLEAN RemovedFcb OPTIONAL
  4826. )
  4827. /*++
  4828. Routine Description:
  4829. This routine is called to start the teardown process on a node in
  4830. the Fcb/Scb tree. We will attempt to remove this node and then
  4831. move up the tree removing any nodes held by this node.
  4832. This routine deals with the case where a single node may be holding
  4833. multiple parents in memory. If we are passed an input Lcb we will
  4834. use that to walk up the tree. If the Vcb is held exclusively we
  4835. will try to trim any nodes that have no open files on them.
  4836. This routine takes the following steps:
  4837. Remove as many Scb's and file objects from the starting
  4838. Fcb.
  4839. If the Fcb can't go away but has multiple links then remove
  4840. whatever links possible. If we have the Vcb we can
  4841. do all of them but we will leave a single link behind
  4842. to optimize prefix lookups. Otherwise we will traverse the
  4843. single link we were given.
  4844. If the Fcb can go away then we should have the Vcb if there are
  4845. multiple links to remove. Otherwise we only remove the link
  4846. we were given if there are multiple links. In the single link
  4847. case just remove that link.
  4848. Arguments:
  4849. FcbOrScb - Supplies either an Fcb or an Scb as the start of the
  4850. teardown point. The Fcb for this element must be held exclusively.
  4851. Lcb - If specified, this is the path up the tree to perform the
  4852. teardown.
  4853. CheckForAttributeTable - Indicates that we should not teardown an
  4854. Scb which is in the attribute table. Instead we will attempt
  4855. to put an entry on the async close queue. This will be TRUE
  4856. if we may need the Scb to abort the current transaction.
  4857. AcquireFlags - Indicates whether we should abort the teardown when
  4858. we can't acquire a parent. When called from some path where we may
  4859. hold the MftScb or another resource in another path up the tree.
  4860. ACQUIRE_NO_DELETE_CHECK
  4861. ACQUIRE_DONT_WAIT
  4862. ACQUIRE_HOLD_BITMAP
  4863. RemovedFcb - Address to store TRUE if we delete the starting Fcb.
  4864. Return Value:
  4865. None
  4866. --*/
  4867. {
  4868. PSCB StartingScb = NULL;
  4869. PFCB Fcb;
  4870. BOOLEAN FcbCanBeRemoved;
  4871. BOOLEAN RemovedLcb;
  4872. BOOLEAN LocalRemovedFcb = FALSE;
  4873. PLIST_ENTRY Links;
  4874. PLIST_ENTRY NextLink;
  4875. PAGED_CODE();
  4876. //
  4877. // If this is a recursive call to TearDownStructures we return immediately
  4878. // doing no operation.
  4879. //
  4880. if (FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_IN_TEARDOWN )) {
  4881. DebugTrace( 0, Dbg, ("Recursive teardown call\n") );
  4882. DebugTrace( -1, Dbg, ("NtfsTeardownStructures -> VOID\n") );
  4883. return;
  4884. }
  4885. if (SafeNodeType(FcbOrScb) == NTFS_NTC_FCB) {
  4886. Fcb = FcbOrScb;
  4887. } else {
  4888. StartingScb = FcbOrScb;
  4889. FcbOrScb = Fcb = StartingScb->Fcb;
  4890. }
  4891. SetFlag( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_IN_TEARDOWN );
  4892. //
  4893. // Use a try-finally to clear the top level irp field.
  4894. //
  4895. try {
  4896. //
  4897. // Use our local boolean if the caller didn't supply one.
  4898. //
  4899. if (!ARGUMENT_PRESENT( RemovedFcb )) {
  4900. RemovedFcb = &LocalRemovedFcb;
  4901. }
  4902. //
  4903. // Check this Fcb for removal. Remember if all of the Scb's
  4904. // and file objects are gone. We will try to remove the Fcb
  4905. // if the cleanup count is zero or if we are walking up
  4906. // one directory path of a mult-link file. If the Fcb has
  4907. // a non-zero cleanup count but the current Scb has a zero
  4908. // cleanup count then try to delete the Scb at the very least.
  4909. //
  4910. FcbCanBeRemoved = FALSE;
  4911. if (Fcb->CleanupCount == 0) {
  4912. FcbCanBeRemoved = NtfsPrepareFcbForRemoval( IrpContext,
  4913. Fcb,
  4914. StartingScb,
  4915. CheckForAttributeTable );
  4916. } else if (ARGUMENT_PRESENT( StartingScb ) &&
  4917. (StartingScb->CleanupCount == 0) &&
  4918. (StartingScb->AttributeTypeCode != $ATTRIBUTE_LIST)) {
  4919. NtfsRemoveScb( IrpContext, StartingScb, CheckForAttributeTable );
  4920. }
  4921. //
  4922. // There is a single link (typical case) we either try to
  4923. // remove that link or we simply return.
  4924. //
  4925. if (Fcb->LcbQueue.Flink == Fcb->LcbQueue.Blink) {
  4926. if (FcbCanBeRemoved) {
  4927. NtfsTeardownFromLcb( IrpContext,
  4928. Fcb->Vcb,
  4929. Fcb,
  4930. CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  4931. LCB,
  4932. FcbLinks ),
  4933. CheckForAttributeTable,
  4934. AcquireFlags,
  4935. &RemovedLcb,
  4936. RemovedFcb );
  4937. }
  4938. leave;
  4939. //
  4940. // If there are multiple links we will try to either remove
  4941. // them all or all but one (if the Fcb is not going away) if
  4942. // we own the Vcb. We will try to delete the one we were
  4943. // given otherwise.
  4944. //
  4945. } else {
  4946. //
  4947. // If we have the Vcb we will remove all if the Fcb can
  4948. // go away. Otherwise we will leave one.
  4949. //
  4950. if (NtfsIsExclusiveVcb( Fcb->Vcb )) {
  4951. Links = Fcb->LcbQueue.Flink;
  4952. while (TRUE) {
  4953. //
  4954. // Remember the next entry in case the current link
  4955. // goes away.
  4956. //
  4957. NextLink = Links->Flink;
  4958. RemovedLcb = FALSE;
  4959. NtfsTeardownFromLcb( IrpContext,
  4960. Fcb->Vcb,
  4961. Fcb,
  4962. CONTAINING_RECORD( Links, LCB, FcbLinks ),
  4963. CheckForAttributeTable,
  4964. 0,
  4965. &RemovedLcb,
  4966. RemovedFcb );
  4967. //
  4968. // If couldn't remove this link then munge the
  4969. // boolean indicating if the Fcb can be removed
  4970. // to make it appear we need to remove all of
  4971. // the Lcb's.
  4972. //
  4973. if (!RemovedLcb) {
  4974. FcbCanBeRemoved = TRUE;
  4975. }
  4976. //
  4977. // If the Fcb has been removed then we exit.
  4978. // If the next link is the beginning of the
  4979. // Lcb queue then we also exit.
  4980. // If the next link is the last entry and
  4981. // we want to leave a single entry then we
  4982. // exit.
  4983. //
  4984. if (*RemovedFcb ||
  4985. (NextLink == &Fcb->LcbQueue) ||
  4986. (!FcbCanBeRemoved &&
  4987. (NextLink->Flink == &Fcb->LcbQueue))) {
  4988. leave;
  4989. }
  4990. //
  4991. // Move to the next link.
  4992. //
  4993. Links = NextLink;
  4994. }
  4995. //
  4996. // If we have an Lcb just move up that path.
  4997. //
  4998. } else if (ARGUMENT_PRESENT( Lcb )) {
  4999. NtfsTeardownFromLcb( IrpContext,
  5000. Fcb->Vcb,
  5001. Fcb,
  5002. Lcb,
  5003. CheckForAttributeTable,
  5004. AcquireFlags,
  5005. &RemovedLcb,
  5006. RemovedFcb );
  5007. }
  5008. }
  5009. } finally {
  5010. DebugUnwind( NtfsTeardownStructures );
  5011. ClearFlag( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_IN_TEARDOWN );
  5012. }
  5013. return;
  5014. }
  5015. //
  5016. //
  5017. //
  5018. PVOID
  5019. NtfsAllocateCompressionSync (
  5020. IN POOL_TYPE PoolType,
  5021. IN SIZE_T NumberOfBytes,
  5022. IN ULONG Tag
  5023. )
  5024. /*++
  5025. Routine Description:
  5026. This routine is called by the lookaside package to allocation a new compression
  5027. sync structure. We have a dedicated routine in order to perform the resource
  5028. initialization if necessary. Otherwise the caller will need to defensively
  5029. test and initialize the resource.
  5030. Arguments:
  5031. PoolType - Type of pool associated with the lookaside list.
  5032. NumberOfBytes - Size of pool block to allocate.
  5033. Tag - Tag to associate with the block.
  5034. Return Value:
  5035. NULL if we are unable to allocate the pool. Otherwise a pointer to the block of
  5036. of pool is returned.
  5037. --*/
  5038. {
  5039. PCOMPRESSION_SYNC CompressionSync;
  5040. PAGED_CODE();
  5041. CompressionSync = NtfsAllocatePoolWithTagNoRaise( PoolType,
  5042. NumberOfBytes,
  5043. Tag );
  5044. if (CompressionSync != NULL) {
  5045. ExInitializeResourceLite( &CompressionSync->Resource );
  5046. CompressionSync->ReferenceCount = 0;
  5047. }
  5048. return CompressionSync;
  5049. }
  5050. VOID
  5051. NtfsDeallocateCompressionSync (
  5052. IN PVOID CompressionSync
  5053. )
  5054. /*++
  5055. Routine Description:
  5056. This routine is called to deallocate the pool for a single CompressionSync structure.
  5057. We have our own routine in order to unitialize the embedded resource.
  5058. Arguments:
  5059. CompressionSync - Structure to deallocate.
  5060. Return Value:
  5061. None.
  5062. --*/
  5063. {
  5064. PAGED_CODE();
  5065. ExDeleteResourceLite( &((PCOMPRESSION_SYNC) CompressionSync)->Resource );
  5066. NtfsFreePool( CompressionSync );
  5067. return;
  5068. }
  5069. VOID
  5070. NtfsIncrementCleanupCounts (
  5071. IN PSCB Scb,
  5072. IN PLCB Lcb OPTIONAL,
  5073. IN BOOLEAN NonCachedHandle
  5074. )
  5075. /*++
  5076. Routine Description:
  5077. This routine increments the cleanup counts for the associated data structures
  5078. Arguments:
  5079. Scb - Supplies the Scb used in this operation
  5080. Lcb - Optionally supplies the Lcb used in this operation
  5081. NonCachedHandle - Indicates this handle is for a user non-cached handle.
  5082. Return Value:
  5083. None.
  5084. --*/
  5085. {
  5086. PVCB Vcb = Scb->Vcb;
  5087. //
  5088. // This is really a pretty light weight procedure but having it be a procedure
  5089. // really helps in debugging the system and keeping track of who increments
  5090. // and decrements cleanup counts
  5091. //
  5092. if (ARGUMENT_PRESENT(Lcb)) { Lcb->CleanupCount += 1; }
  5093. InterlockedIncrement( &Scb->CleanupCount );
  5094. Scb->Fcb->CleanupCount += 1;
  5095. if (NonCachedHandle) {
  5096. Scb->NonCachedCleanupCount += 1;
  5097. }
  5098. InterlockedIncrement( &Vcb->CleanupCount );
  5099. return;
  5100. }
  5101. VOID
  5102. NtfsIncrementCloseCounts (
  5103. IN PSCB Scb,
  5104. IN BOOLEAN SystemFile,
  5105. IN BOOLEAN ReadOnly
  5106. )
  5107. /*++
  5108. Routine Description:
  5109. This routine increments the close counts for the associated data structures
  5110. Arguments:
  5111. Scb - Supplies the Scb used in this operation
  5112. SystemFile - Indicates if the Scb is for a system file (if so then
  5113. the Vcb system file close count in also incremented)
  5114. ReadOnly - Indicates if the Scb is opened readonly. (if so then the
  5115. Vcb Read Only close count is also incremented)
  5116. Return Value:
  5117. None.
  5118. --*/
  5119. {
  5120. PVCB Vcb = Scb->Vcb;
  5121. //
  5122. // This is really a pretty light weight procedure but having it be a procedure
  5123. // really helps in debugging the system and keeping track of who increments
  5124. // and decrements close counts
  5125. //
  5126. //
  5127. // If this is someone other than the first open, remember that.
  5128. //
  5129. if (InterlockedIncrement( &Scb->CloseCount ) >= 2) {
  5130. SetFlag( Scb->ScbState, SCB_STATE_MULTIPLE_OPENS );
  5131. }
  5132. InterlockedIncrement( &Scb->Fcb->CloseCount );
  5133. InterlockedIncrement( &Vcb->CloseCount );
  5134. if (SystemFile) {
  5135. InterlockedIncrement( &Vcb->SystemFileCloseCount );
  5136. }
  5137. if (ReadOnly) {
  5138. InterlockedIncrement( &Vcb->ReadOnlyCloseCount );
  5139. }
  5140. //
  5141. // We will always clear the delay close flag in this routine.
  5142. //
  5143. ClearFlag( Scb->ScbState, SCB_STATE_DELAY_CLOSE );
  5144. return;
  5145. }
  5146. VOID
  5147. NtfsDecrementCleanupCounts (
  5148. IN PSCB Scb,
  5149. IN PLCB Lcb OPTIONAL,
  5150. IN BOOLEAN NonCachedHandle
  5151. )
  5152. /*++
  5153. Routine Description:
  5154. This procedure decrements the cleanup counts for the associated data structures
  5155. and if necessary it also start to cleanup associated internal attribute streams
  5156. Arguments:
  5157. Scb - Supplies the Scb used in this operation
  5158. Lcb - Optionally supplies the Lcb used in this operation
  5159. NonCachedHandle - Indicates this handle is for a user non-cached handle.
  5160. Return Value:
  5161. None.
  5162. --*/
  5163. {
  5164. PVCB Vcb = Scb->Vcb;
  5165. ASSERT_SCB( Scb );
  5166. ASSERT_FCB( Scb->Fcb );
  5167. ASSERT_VCB( Scb->Fcb->Vcb );
  5168. ASSERT_OPTIONAL_LCB( Lcb );
  5169. //
  5170. // First we decrement the appropriate cleanup counts
  5171. //
  5172. if (ARGUMENT_PRESENT(Lcb)) { Lcb->CleanupCount -= 1; }
  5173. InterlockedDecrement( &Scb->CleanupCount );
  5174. Scb->Fcb->CleanupCount -= 1;
  5175. if (NonCachedHandle) {
  5176. Scb->NonCachedCleanupCount -= 1;
  5177. }
  5178. InterlockedDecrement( &Vcb->CleanupCount );
  5179. //
  5180. // Now if the Fcb's cleanup count is zero that indicates that we are
  5181. // done with this Fcb from a user handle standpoint and we should
  5182. // now scan through all of the Scb's that are opened under this
  5183. // Fcb and shutdown any internal attributes streams we have open.
  5184. // For example, EAs and ACLs. We only need to do one. The domino effect
  5185. // will take of the rest.
  5186. //
  5187. if (Scb->Fcb->CleanupCount == 0) {
  5188. PSCB NextScb;
  5189. //
  5190. // Remember if we are dealing with a system file and return immediately.
  5191. //
  5192. if (FlagOn(Scb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE) &&
  5193. NtfsSegmentNumber( &Scb->Fcb->FileReference ) != ROOT_FILE_NAME_INDEX_NUMBER) {
  5194. return;
  5195. }
  5196. for (NextScb = CONTAINING_RECORD(Scb->Fcb->ScbQueue.Flink, SCB, FcbLinks);
  5197. &NextScb->FcbLinks != &Scb->Fcb->ScbQueue;
  5198. NextScb = CONTAINING_RECORD( NextScb->FcbLinks.Flink, SCB, FcbLinks )) {
  5199. //
  5200. // Skip the root index on the volume.
  5201. //
  5202. if (SafeNodeType( NextScb ) == NTFS_NTC_SCB_ROOT_INDEX) { continue; }
  5203. //
  5204. // It is possible that someone has referenced this Scb to keep it from going away.
  5205. // We can treat this the same as if there was a cleanup count in the Fcb. Someone
  5206. // else is responsible for doing the cleanup.
  5207. //
  5208. // We can also break out if we have an index with children.
  5209. //
  5210. if ((NextScb->CleanupCount != 0) ||
  5211. ((SafeNodeType( NextScb ) == NTFS_NTC_SCB_INDEX) &&
  5212. !IsListEmpty( &NextScb->ScbType.Index.LcbQueue ))) {
  5213. break;
  5214. }
  5215. //
  5216. // If there is an internal stream then dereference it and get out.
  5217. //
  5218. if (NextScb->FileObject != NULL) {
  5219. NtfsDeleteInternalAttributeStream( NextScb,
  5220. (BOOLEAN) (Scb->Fcb->LinkCount == 0),
  5221. FALSE );
  5222. break;
  5223. }
  5224. }
  5225. }
  5226. //
  5227. // And return to our caller
  5228. //
  5229. return;
  5230. }
  5231. BOOLEAN
  5232. NtfsDecrementCloseCounts (
  5233. IN PIRP_CONTEXT IrpContext,
  5234. IN PSCB Scb,
  5235. IN PLCB Lcb OPTIONAL,
  5236. IN BOOLEAN SystemFile,
  5237. IN BOOLEAN ReadOnly,
  5238. IN BOOLEAN DecrementCountsOnly
  5239. )
  5240. /*++
  5241. Routine Description:
  5242. This routine decrements the close counts for the associated data structures
  5243. and if necessary it will teardown structures that are no longer in use
  5244. Arguments:
  5245. Scb - Supplies the Scb used in this operation
  5246. Lcb - Used if calling teardown to know which path to take.
  5247. SystemFile - Indicates if the Scb is for a system file
  5248. ReadOnly - Indicates if the Scb was opened readonly
  5249. DecrementCountsOnly - Indicates if this operation should only modify the
  5250. count fields.
  5251. Return Value:
  5252. TRUE if the fcb for the input scb was torndown
  5253. --*/
  5254. {
  5255. PFCB Fcb = Scb->Fcb;
  5256. PVCB Vcb = Scb->Vcb;
  5257. BOOLEAN RemovedFcb = FALSE;
  5258. ASSERT_SCB( Scb );
  5259. ASSERT_FCB( Fcb );
  5260. ASSERT_VCB( Fcb->Vcb );
  5261. //
  5262. // Decrement the close counts
  5263. //
  5264. InterlockedDecrement( &Scb->CloseCount );
  5265. InterlockedDecrement( &Fcb->CloseCount );
  5266. InterlockedDecrement( &Vcb->CloseCount );
  5267. if (SystemFile) {
  5268. InterlockedDecrement( &Vcb->SystemFileCloseCount );
  5269. }
  5270. if (ReadOnly) {
  5271. InterlockedDecrement( &Vcb->ReadOnlyCloseCount );
  5272. }
  5273. //
  5274. // Now if the scb's close count is zero then we are ready to tear
  5275. // it down
  5276. //
  5277. if (!DecrementCountsOnly) {
  5278. //
  5279. // We want to try to start a teardown from this Scb if
  5280. //
  5281. // - The close count is zero
  5282. //
  5283. // or the following are all true
  5284. //
  5285. // - The cleanup count is zero
  5286. // - There is a file object in the Scb
  5287. // - It is a data Scb or an empty index Scb
  5288. // - It is not an Ntfs system file
  5289. //
  5290. // The teardown will be noopted if this is a recursive call.
  5291. //
  5292. if (Scb->CloseCount == 0
  5293. ||
  5294. (Scb->CleanupCount == 0
  5295. && Scb->FileObject != NULL
  5296. && !FlagOn(Fcb->FcbState, FCB_STATE_SYSTEM_FILE)
  5297. && ((SafeNodeType( Scb ) == NTFS_NTC_SCB_DATA)
  5298. || (SafeNodeType( Scb ) == NTFS_NTC_SCB_MFT)
  5299. || IsListEmpty( &Scb->ScbType.Index.LcbQueue )))) {
  5300. NtfsTeardownStructures( IrpContext,
  5301. Scb,
  5302. Lcb,
  5303. FALSE,
  5304. 0,
  5305. &RemovedFcb );
  5306. }
  5307. }
  5308. //
  5309. // And return to our caller
  5310. //
  5311. return RemovedFcb;
  5312. }
  5313. PERESOURCE
  5314. NtfsAllocateEresource (
  5315. )
  5316. {
  5317. KIRQL _SavedIrql;
  5318. PERESOURCE Eresource;
  5319. _SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  5320. if (NtfsData.FreeEresourceSize > 0) {
  5321. Eresource = NtfsData.FreeEresourceArray[--NtfsData.FreeEresourceSize];
  5322. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5323. } else {
  5324. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5325. Eresource = NtfsAllocatePoolWithTag( NonPagedPool, sizeof(ERESOURCE), 'rftN' );
  5326. ExInitializeResourceLite( Eresource );
  5327. NtfsData.FreeEresourceMiss += 1;
  5328. }
  5329. return Eresource;
  5330. }
  5331. VOID
  5332. NtfsFreeEresource (
  5333. IN PERESOURCE Eresource
  5334. )
  5335. {
  5336. KIRQL _SavedIrql;
  5337. //
  5338. // Do an unsafe test to see if we should put this on our list.
  5339. // We want to reinitialize this before adding to the list so
  5340. // we don't have a bunch of resources which appear to be held.
  5341. //
  5342. if (NtfsData.FreeEresourceSize < NtfsData.FreeEresourceTotal) {
  5343. ExReinitializeResourceLite( Eresource );
  5344. //
  5345. // Now acquire the spinlock and do a real test.
  5346. //
  5347. _SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  5348. if (NtfsData.FreeEresourceSize < NtfsData.FreeEresourceTotal) {
  5349. NtfsData.FreeEresourceArray[NtfsData.FreeEresourceSize++] = Eresource;
  5350. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5351. } else {
  5352. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5353. ExDeleteResourceLite( Eresource );
  5354. NtfsFreePool( Eresource );
  5355. }
  5356. } else {
  5357. ExDeleteResourceLite( Eresource );
  5358. NtfsFreePool( Eresource );
  5359. }
  5360. return;
  5361. }
  5362. PVOID
  5363. NtfsAllocateFcbTableEntry (
  5364. IN PRTL_GENERIC_TABLE FcbTable,
  5365. IN CLONG ByteSize
  5366. )
  5367. /*++
  5368. Routine Description:
  5369. This is a generic table support routine to allocate memory
  5370. Arguments:
  5371. FcbTable - Supplies the generic table being used
  5372. ByteSize - Supplies the number of bytes to allocate
  5373. Return Value:
  5374. PVOID - Returns a pointer to the allocated data
  5375. --*/
  5376. {
  5377. KIRQL _SavedIrql;
  5378. PVOID FcbTableEntry;
  5379. UNREFERENCED_PARAMETER( FcbTable );
  5380. _SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  5381. if (NtfsData.FreeFcbTableSize > 0) {
  5382. FcbTableEntry = NtfsData.FreeFcbTableArray[--NtfsData.FreeFcbTableSize];
  5383. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5384. } else {
  5385. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5386. FcbTableEntry = NtfsAllocatePool( PagedPool, ByteSize );
  5387. }
  5388. return FcbTableEntry;
  5389. }
  5390. VOID
  5391. NtfsFreeFcbTableEntry (
  5392. IN PRTL_GENERIC_TABLE FcbTable,
  5393. IN PVOID Buffer
  5394. )
  5395. /*++
  5396. Routine Description:
  5397. This is a generic table support routine that deallocates memory
  5398. Arguments:
  5399. FcbTable - Supplies the generic table being used
  5400. Buffer - Supplies the buffer being deallocated
  5401. Return Value:
  5402. None.
  5403. --*/
  5404. {
  5405. KIRQL _SavedIrql;
  5406. UNREFERENCED_PARAMETER( FcbTable );
  5407. _SavedIrql = KeAcquireQueuedSpinLock( LockQueueNtfsStructLock );
  5408. if (NtfsData.FreeFcbTableSize < FREE_FCB_TABLE_SIZE) {
  5409. NtfsData.FreeFcbTableArray[NtfsData.FreeFcbTableSize++] = Buffer;
  5410. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5411. } else {
  5412. KeReleaseQueuedSpinLock( LockQueueNtfsStructLock, _SavedIrql );
  5413. NtfsFreePool( Buffer );
  5414. }
  5415. return;
  5416. }
  5417. VOID
  5418. NtfsPostToNewLengthQueue (
  5419. IN PIRP_CONTEXT IrpContext,
  5420. IN PSCB Scb
  5421. )
  5422. /*++
  5423. Routine Description:
  5424. This routine is called to add an Scb to the queue of Scbs which have
  5425. waiters on extends. There is a single element embedded in the IrpContext.
  5426. Otherwise this field in the IrpContext will point to an array of elements.
  5427. Arguments:
  5428. Scb - This is the Scb to add to the queue.
  5429. Return Value:
  5430. None.
  5431. --*/
  5432. {
  5433. PAGED_CODE();
  5434. //
  5435. // Nothing to do if this Scb is in the IrpContext.
  5436. //
  5437. if (Scb != IrpContext->CheckNewLength) {
  5438. //
  5439. // If the IrpContext field is unused then stuff this into it.
  5440. //
  5441. if (IrpContext->CheckNewLength == NULL) {
  5442. IrpContext->CheckNewLength = Scb;
  5443. } else {
  5444. PULONG_PTR NewQueue;
  5445. //
  5446. // First case - there is an Scb in the IrpContext.
  5447. // Allocate a larger structure and put our element in it.
  5448. //
  5449. if (SafeNodeType( IrpContext->CheckNewLength ) == NTFS_NTC_SCB_DATA ) {
  5450. NewQueue = NtfsAllocatePool( PagedPool, sizeof( ULONG_PTR ) * 3 );
  5451. *NewQueue = (ULONG_PTR) IrpContext->CheckNewLength;
  5452. IrpContext->CheckNewLength = NewQueue;
  5453. *(NewQueue + 1) = (ULONG_PTR) Scb;
  5454. *(NewQueue + 2) = (ULONG_PTR) NULL;
  5455. //
  5456. // Second case - walk existing queue and look for an unused element or
  5457. // the current scb.
  5458. //
  5459. } else {
  5460. NewQueue = IrpContext->CheckNewLength;
  5461. do {
  5462. //
  5463. // Our scb is in the queue.
  5464. //
  5465. if (*NewQueue == (ULONG_PTR) Scb) { break; }
  5466. //
  5467. // The current position is unused.
  5468. //
  5469. if (*NewQueue == (ULONG_PTR) -1) {
  5470. *NewQueue = (ULONG_PTR) Scb;
  5471. break;
  5472. }
  5473. //
  5474. // We are at the end of the list.
  5475. //
  5476. if (*NewQueue == (ULONG_PTR) NULL) {
  5477. ULONG CurrentLength;
  5478. CurrentLength = PtrOffset( IrpContext->CheckNewLength, NewQueue );
  5479. NewQueue = NtfsAllocatePool( PagedPool,
  5480. CurrentLength + (4 * sizeof( ULONG_PTR )) );
  5481. RtlCopyMemory( NewQueue,
  5482. IrpContext->CheckNewLength,
  5483. CurrentLength );
  5484. NewQueue = Add2Ptr( NewQueue, CurrentLength );
  5485. *NewQueue = (ULONG_PTR) Scb;
  5486. *(NewQueue + 1) = -1;
  5487. *(NewQueue + 2) = -1;
  5488. *(NewQueue + 3) = (ULONG_PTR) NULL;
  5489. NtfsFreePool( IrpContext->CheckNewLength );
  5490. IrpContext->CheckNewLength = NewQueue;
  5491. break;
  5492. }
  5493. //
  5494. // Go to the next element.
  5495. //
  5496. NewQueue += 1;
  5497. } while (TRUE);
  5498. }
  5499. }
  5500. }
  5501. return;
  5502. }
  5503. VOID
  5504. NtfsProcessNewLengthQueue (
  5505. IN PIRP_CONTEXT IrpContext,
  5506. IN BOOLEAN CleanupOnly
  5507. )
  5508. /*++
  5509. Routine Description:
  5510. This routine is called when there is at least one Scb in the IrpContext
  5511. queue of streams which have waiters on the new length. We will call
  5512. NtOfsPostNewLength for each element unless we are cleaning up only.
  5513. Arguments:
  5514. IrpContext - Has a non-empty queue of Scbs for the current transaction.
  5515. CleanupOnly - Indicates if we only want to clean up the queue, not
  5516. alert any waiters (this is the error path).
  5517. Return Value:
  5518. None.
  5519. --*/
  5520. {
  5521. PULONG_PTR NextScb;
  5522. PAGED_CODE();
  5523. //
  5524. // Check if the only entry is resident in the IrpContext.
  5525. //
  5526. if (SafeNodeType( IrpContext->CheckNewLength ) == NTFS_NTC_SCB_DATA) {
  5527. if (!CleanupOnly) {
  5528. NtOfsPostNewLength( IrpContext, (PSCB) IrpContext->CheckNewLength, FALSE );
  5529. }
  5530. //
  5531. // Otherwise we want to walk through the external entries.
  5532. //
  5533. } else {
  5534. if (!CleanupOnly) {
  5535. NextScb = IrpContext->CheckNewLength;
  5536. //
  5537. // Continue until we run out of entries. The end of the block has a NULL, any unused entries
  5538. // will have a -1.
  5539. //
  5540. while ((*NextScb != (ULONG_PTR) -1) && (*NextScb != (ULONG_PTR) NULL)) {
  5541. ASSERT( SafeNodeType( *NextScb ) == NTFS_NTC_SCB_DATA );
  5542. NtOfsPostNewLength( IrpContext, (PSCB) *NextScb, FALSE );
  5543. NextScb += 1;
  5544. }
  5545. }
  5546. NtfsFreePool( IrpContext->CheckNewLength );
  5547. }
  5548. IrpContext->CheckNewLength = NULL;
  5549. return;
  5550. }
  5551. VOID
  5552. NtfsTestStatusProc (
  5553. )
  5554. /*++
  5555. Routine Description:
  5556. This routine is to catch specific status codes in the running system. It
  5557. is called only when NtfsTestStatus is TRUE and the current request is completing
  5558. with NtfsTestStatusCode.
  5559. Arguments:
  5560. None
  5561. Return Value:
  5562. None
  5563. --*/
  5564. {
  5565. ASSERT( FALSE );
  5566. }
  5567. //
  5568. // Local support routine
  5569. //
  5570. VOID
  5571. NtfsCheckScbForCache (
  5572. IN OUT PSCB Scb
  5573. )
  5574. /*++
  5575. Routine Description:
  5576. This routine checks if the Scb has blocks contining
  5577. Lsn's or Update sequence arrays and set the appropriate
  5578. bit in the Scb state word.
  5579. The Scb is Update sequence aware if it the Data Attribute for the
  5580. Mft or the Data Attribute for the log file or any index allocation
  5581. stream.
  5582. The Lsn aware Scb's are the ones above without the Log file.
  5583. Arguments:
  5584. Scb - Supplies the current Scb
  5585. Return Value:
  5586. The next Scb in the enumeration, or NULL if Scb was the final one.
  5587. --*/
  5588. {
  5589. //
  5590. // Temporarily either sequence 0 or 1 is ok.
  5591. //
  5592. FILE_REFERENCE MftTemp = {0,0,1};
  5593. PAGED_CODE();
  5594. //
  5595. // Check for Update Sequence Array files first.
  5596. //
  5597. if ((Scb->AttributeTypeCode == $INDEX_ALLOCATION)
  5598. ||
  5599. (Scb->AttributeTypeCode == $DATA
  5600. && Scb->AttributeName.Length == 0
  5601. && (NtfsEqualMftRef( &Scb->Fcb->FileReference, &MftFileReference )
  5602. || NtfsEqualMftRef( &Scb->Fcb->FileReference, &MftTemp )
  5603. || NtfsEqualMftRef( &Scb->Fcb->FileReference, &Mft2FileReference )
  5604. || NtfsEqualMftRef( &Scb->Fcb->FileReference, &LogFileReference )))) {
  5605. SetFlag( Scb->ScbState, SCB_STATE_USA_PRESENT );
  5606. }
  5607. return;
  5608. }
  5609. //
  5610. // Local support routine.
  5611. //
  5612. BOOLEAN
  5613. NtfsRemoveScb (
  5614. IN PIRP_CONTEXT IrpContext,
  5615. IN PSCB Scb,
  5616. IN BOOLEAN CheckForAttributeTable
  5617. )
  5618. /*++
  5619. Routine Description:
  5620. This routine will try to remove an Scb from the Fcb/Scb tree.
  5621. It deals with the case where we can make no attempt to remove
  5622. the Scb, the case where we start the process but can't complete
  5623. it, and finally the case where we remove the Scb entirely.
  5624. The following conditions prevent us from removing the Scb at all.
  5625. The open count is greater than 1.
  5626. It is the root directory.
  5627. It is an index Scb with no stream file and an outstanding close.
  5628. It is a data file with a non-zero close count.
  5629. We start the teardown under the following conditions.
  5630. It is an index with an open count of 1, and a stream file object.
  5631. We totally remove the Scb when the open count is zero.
  5632. Arguments:
  5633. Scb - Supplies the Scb to test
  5634. CheckForAttributeTable - Indicates that we don't want to remove this
  5635. Scb in this thread if it is in the open attribute table. We will
  5636. queue an async close in this case. This is to prevent us from
  5637. deleting an Scb which may be needed in the abort path.
  5638. Return Value:
  5639. BOOLEAN - TRUE if the Scb was removed, FALSE otherwise. We return FALSE for
  5640. the case where we start the process but don't finish.
  5641. --*/
  5642. {
  5643. BOOLEAN ScbRemoved;
  5644. ASSERT_SCB( Scb );
  5645. PAGED_CODE();
  5646. DebugTrace( +1, Dbg, ("NtfsRemoveScb: Entered\n") );
  5647. DebugTrace( 0, Dbg, ("Scb -> %08lx\n", Scb) );
  5648. ScbRemoved = FALSE;
  5649. //
  5650. // If the Scb is not the root Scb and the count is less than two,
  5651. // then this Scb is a candidate for removal.
  5652. //
  5653. if ((SafeNodeType( Scb ) != NTFS_NTC_SCB_ROOT_INDEX) && (Scb->CleanupCount == 0)) {
  5654. //
  5655. //
  5656. // If this is a data file or it is an index without children,
  5657. // we can get rid of the Scb if there are no children. If
  5658. // there is one open count and it is the file object, we
  5659. // can start the cleanup on the file object.
  5660. //
  5661. if ((SafeNodeType( Scb ) == NTFS_NTC_SCB_DATA) ||
  5662. (SafeNodeType( Scb ) == NTFS_NTC_SCB_MFT) ||
  5663. IsListEmpty( &Scb->ScbType.Index.LcbQueue )) {
  5664. //
  5665. // Check if we need to post a request to the async queue.
  5666. //
  5667. if (CheckForAttributeTable &&
  5668. (Scb->NonpagedScb->OpenAttributeTableIndex != 0)) {
  5669. NtfsAddScbToFspClose( IrpContext, Scb, FALSE );
  5670. } else {
  5671. if (Scb->CloseCount == 0) {
  5672. NtfsDeleteScb( IrpContext, &Scb );
  5673. ScbRemoved = TRUE;
  5674. //
  5675. // Else we know the open count is 1 or 2. If there is a stream
  5676. // file, we discard it (but not for the special system
  5677. // files) that get removed on dismount
  5678. //
  5679. } else if (((Scb->FileObject != NULL) ||
  5680. #ifdef COMPRESS_ON_WIRE
  5681. (Scb->Header.FileObjectC != NULL)
  5682. #else
  5683. FALSE
  5684. #endif
  5685. ) &&
  5686. !FlagOn(Scb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE)) {
  5687. NtfsDeleteInternalAttributeStream( Scb, (BOOLEAN) (Scb->Fcb->LinkCount == 0), FALSE );
  5688. //
  5689. // If the close count went to zero then remove the Scb.
  5690. //
  5691. if (Scb->CloseCount == 0) {
  5692. NtfsDeleteScb( IrpContext, &Scb );
  5693. ScbRemoved = TRUE;
  5694. }
  5695. }
  5696. }
  5697. }
  5698. }
  5699. DebugTrace( -1, Dbg, ("NtfsRemoveScb: Exit -> %04x\n", ScbRemoved) );
  5700. return ScbRemoved;
  5701. }
  5702. //
  5703. // Local support routine
  5704. //
  5705. BOOLEAN
  5706. NtfsPrepareFcbForRemoval (
  5707. IN PIRP_CONTEXT IrpContext,
  5708. IN PFCB Fcb,
  5709. IN PSCB StartingScb OPTIONAL,
  5710. IN BOOLEAN CheckForAttributeTable
  5711. )
  5712. /*++
  5713. Routine Description:
  5714. This routine will attempt to prepare the Fcb for removal from the Fcb/Scb
  5715. tree. It will try to remove all of the Scb's and test finally if
  5716. all of the close count has gone to zero. NOTE the close count is incremented
  5717. by routines to reference this Fcb to keep it from being torn down. An empty
  5718. Scb list isn't enough to insure that the Fcb can be removed.
  5719. Arguments:
  5720. Fcb - This is the Fcb to remove.
  5721. StartingScb - This is the Scb to remove first.
  5722. CheckForAttributeTable - Indicates that we should not teardown an
  5723. Scb which is in the attribute table. Instead we will attempt
  5724. to put an entry on the async close queue. This will be TRUE
  5725. if we may need the Scb to abort the current transaction.
  5726. Return Value:
  5727. BOOLEAN - TRUE if the Fcb can be removed, FALSE otherwise.
  5728. --*/
  5729. {
  5730. PSCB Scb;
  5731. PAGED_CODE();
  5732. //
  5733. // Try to remove each Scb in the Fcb queue.
  5734. //
  5735. while (TRUE) {
  5736. if (IsListEmpty( &Fcb->ScbQueue )) {
  5737. if (Fcb->CloseCount == 0) {
  5738. return TRUE;
  5739. } else {
  5740. return FALSE;
  5741. }
  5742. }
  5743. if (ARGUMENT_PRESENT( StartingScb )) {
  5744. Scb = StartingScb;
  5745. StartingScb = NULL;
  5746. } else {
  5747. Scb = CONTAINING_RECORD( Fcb->ScbQueue.Flink,
  5748. SCB,
  5749. FcbLinks );
  5750. }
  5751. //
  5752. // Another thread along the create path could be active on
  5753. // one of these Scbs. If we try to remove the Attribute List Scb and
  5754. // somebody else has an index pinned, we'll wait on an VacbActiveCount
  5755. // forever. So, we want to skip the AttributeList Scb,
  5756. // unless it's the only Scb around. (This'll get cleaned up, eventually).
  5757. //
  5758. if ((Scb->AttributeTypeCode == $ATTRIBUTE_LIST) &&
  5759. (Fcb->ScbQueue.Flink != Fcb->ScbQueue.Blink)) {
  5760. RemoveEntryList( &Scb->FcbLinks );
  5761. InsertTailList( &Fcb->ScbQueue, &Scb->FcbLinks );
  5762. continue;
  5763. }
  5764. //
  5765. // Try to remove this Scb. If the call to remove didn't succeed
  5766. // but the close count has gone to zero, it means that a recursive
  5767. // close was generated which removed a stream file. In that
  5768. // case we can delete the Scb now.
  5769. //
  5770. if (!NtfsRemoveScb( IrpContext, Scb, CheckForAttributeTable )) {
  5771. //
  5772. // Return FALSE to indicate the Fcb can't go away.
  5773. //
  5774. return FALSE;
  5775. }
  5776. }
  5777. }
  5778. //
  5779. // Local support routine
  5780. //
  5781. VOID
  5782. NtfsTeardownFromLcb (
  5783. IN PIRP_CONTEXT IrpContext,
  5784. IN PVCB Vcb,
  5785. IN PFCB StartingFcb,
  5786. IN PLCB StartingLcb,
  5787. IN BOOLEAN CheckForAttributeTable,
  5788. IN ULONG AcquireFlags,
  5789. OUT PBOOLEAN RemovedStartingLcb,
  5790. OUT PBOOLEAN RemovedStartingFcb
  5791. )
  5792. /*++
  5793. Routine Description:
  5794. This routine is called to remove a link and continue moving up the
  5795. tree looking for more elements to remove. We will check that the
  5796. link is unreferenced. NOTE this Lcb must point up to a directory
  5797. so that other than our starting Lcb no Lcb we encounter will
  5798. have multiple parents.
  5799. Arguments:
  5800. Vcb - Vcb for this volume.
  5801. StartingFcb - This is the Fcb whose link we are trying to remove.
  5802. StartingLcb - This is the Lcb to walk up through. Note that
  5803. this may be a bogus pointer. It is only valid if there
  5804. is at least one Fcb in the queue.
  5805. CheckForAttributeTable - Indicates that we should not teardown an
  5806. Scb which is in the attribute table. Instead we will attempt
  5807. to put an entry on the async close queue. This will be TRUE
  5808. if we may need the Scb to abort the current transaction.
  5809. AcquireFlags - Indicates whether we should abort the teardown when
  5810. we can't acquire a parent. When called from some path where we may
  5811. hold the MftScb or another resource in another path up the tree.
  5812. RemovedStartingLcb - Address to store TRUE if we remove the
  5813. starting Lcb.
  5814. RemovedStartingFcb - Address to store TRUE if we remove the
  5815. starting Fcb.
  5816. Return Value:
  5817. None
  5818. --*/
  5819. {
  5820. PSCB ParentScb;
  5821. BOOLEAN AcquiredParentScb = FALSE;
  5822. BOOLEAN AcquiredFcb = FALSE;
  5823. BOOLEAN UpdateStandardInfo;
  5824. BOOLEAN AcquiredFcbTable = FALSE;
  5825. BOOLEAN StandardInfoUpdateAllowed = FALSE;
  5826. BOOLEAN AcquiredParentExclusive;
  5827. BOOLEAN EmptyParentQueue;
  5828. PLCB Lcb;
  5829. PFCB Fcb = StartingFcb;
  5830. PAGED_CODE();
  5831. //
  5832. // Use a try-finally to free any resources held.
  5833. //
  5834. try {
  5835. if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  5836. (IrpContext->TopLevelIrpContext->ExceptionStatus == STATUS_SUCCESS)) {
  5837. StandardInfoUpdateAllowed = TRUE;
  5838. }
  5839. while (TRUE) {
  5840. ParentScb = NULL;
  5841. EmptyParentQueue = FALSE;
  5842. //
  5843. // Check if we need to update the standard information for this file.
  5844. //
  5845. if (StandardInfoUpdateAllowed &&
  5846. !FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED | FCB_STATE_SYSTEM_FILE )) {
  5847. UpdateStandardInfo = TRUE;
  5848. } else {
  5849. UpdateStandardInfo = FALSE;
  5850. }
  5851. //
  5852. // Look through all of the Lcb's for this Fcb.
  5853. //
  5854. while (!IsListEmpty( &Fcb->LcbQueue )) {
  5855. if (Fcb == StartingFcb) {
  5856. Lcb = StartingLcb;
  5857. } else {
  5858. Lcb = CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  5859. LCB,
  5860. FcbLinks );
  5861. }
  5862. //
  5863. // Get out if not the last handle on this Lcb.
  5864. //
  5865. if (Lcb->CleanupCount != 0) {
  5866. leave;
  5867. }
  5868. //
  5869. // Acquire the parent if not already acquired.
  5870. //
  5871. if (ParentScb == NULL) {
  5872. ParentScb = Lcb->Scb;
  5873. //
  5874. // Do an unsafe test to see if we want the parent
  5875. // shared or exclusive. We want it exclusive
  5876. // if we will be walking up the tree because we are at the last Lcb.
  5877. //
  5878. if (ParentScb->ScbType.Index.LcbQueue.Flink == ParentScb->ScbType.Index.LcbQueue.Blink) {
  5879. if (!NtfsAcquireExclusiveFcb( IrpContext,
  5880. ParentScb->Fcb,
  5881. ParentScb,
  5882. ACQUIRE_NO_DELETE_CHECK | AcquireFlags )) {
  5883. leave;
  5884. }
  5885. if (FlagOn( ParentScb->ScbState, SCB_STATE_FILE_SIZE_LOADED )) {
  5886. NtfsSnapshotScb( IrpContext, ParentScb );
  5887. }
  5888. AcquiredParentExclusive = TRUE;
  5889. } else {
  5890. //
  5891. // Try to acquire the parent but check whether we
  5892. // should wait.
  5893. //
  5894. if (!NtfsAcquireSharedFcbCheckWait( IrpContext,
  5895. ParentScb->Fcb,
  5896. AcquireFlags )) {
  5897. leave;
  5898. }
  5899. AcquiredParentExclusive = FALSE;
  5900. }
  5901. AcquiredParentScb = TRUE;
  5902. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  5903. } else {
  5904. //
  5905. // We better be looking at another Lcb to the same parent.
  5906. //
  5907. ASSERT( ParentScb == Lcb->Scb );
  5908. #endif
  5909. }
  5910. //
  5911. // Check if we collide with a create moving down the tree.
  5912. //
  5913. if (Lcb->ReferenceCount != 0) {
  5914. leave;
  5915. }
  5916. //
  5917. // Now remove the Lcb. Remember if this is our original
  5918. // Lcb.
  5919. //
  5920. if (Lcb == StartingLcb) {
  5921. *RemovedStartingLcb = TRUE;
  5922. }
  5923. //
  5924. // We may only have the parent shared at this point. We need
  5925. // to serialize using the parent shared plus the fast
  5926. // mutex to remove the Lcb. We could test whether we need
  5927. // to do this but hopefully the typical case is that we
  5928. // have it shared and it won't be very expensive to acquire
  5929. // it exclusively at this point.
  5930. //
  5931. NtfsAcquireFsrtlHeader( ParentScb );
  5932. NtfsDeleteLcb( IrpContext, &Lcb );
  5933. //
  5934. // Remember if the parent Lcb queue is now empty.
  5935. //
  5936. if (IsListEmpty( &ParentScb->ScbType.Index.LcbQueue )) {
  5937. EmptyParentQueue = TRUE;
  5938. }
  5939. NtfsReleaseFsrtlHeader( ParentScb );
  5940. //
  5941. // If this is the first Fcb then exit the loop.
  5942. //
  5943. if (Fcb == StartingFcb) {
  5944. break;
  5945. }
  5946. }
  5947. //
  5948. // If we get here it means we removed all of the Lcb's we
  5949. // could for the current Fcb. If the list is empty we
  5950. // can remove the Fcb itself.
  5951. //
  5952. if (IsListEmpty( &Fcb->LcbQueue )) {
  5953. //
  5954. // If this is a directory that was opened by Id it is
  5955. // possible that we still have an update to perform
  5956. // for the duplicate information and possibly for
  5957. // standard information.
  5958. //
  5959. if (UpdateStandardInfo &&
  5960. (FlagOn( Fcb->InfoFlags, FCB_INFO_UPDATE_LAST_ACCESS ) ||
  5961. FlagOn( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO ))) {
  5962. //
  5963. // Use a try-except, we ignore errors here.
  5964. //
  5965. try {
  5966. NtfsUpdateStandardInformation( IrpContext, Fcb );
  5967. ClearFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5968. } except( EXCEPTION_EXECUTE_HANDLER ) {
  5969. NtfsMinimumExceptionProcessing( IrpContext );
  5970. }
  5971. NtfsCheckpointCurrentTransaction( IrpContext );
  5972. }
  5973. //
  5974. // Our worst nightmare has come true. We had to create an Scb
  5975. // and a stream in order to write out the duplicate information.
  5976. // This will happen if we have a non-resident attribute list.
  5977. //
  5978. if (!IsListEmpty( &Fcb->ScbQueue)) {
  5979. //
  5980. // Dereference any file object and delete the Scb if possible.
  5981. //
  5982. NtfsRemoveScb( IrpContext,
  5983. CONTAINING_RECORD( Fcb->ScbQueue.Flink,
  5984. SCB,
  5985. FcbLinks ),
  5986. FALSE );
  5987. }
  5988. //
  5989. // If the list is now empty then check the reference count.
  5990. //
  5991. if (IsListEmpty( &Fcb->ScbQueue)) {
  5992. //
  5993. // Now we are ready to remove the current Fcb. We need to
  5994. // do a final check of the reference count to make sure
  5995. // it isn't being referenced in an open somewhere.
  5996. //
  5997. NtfsAcquireFcbTable( IrpContext, Vcb );
  5998. AcquiredFcbTable = TRUE;
  5999. if (Fcb->ReferenceCount == 0) {
  6000. if (Fcb == StartingFcb) {
  6001. *RemovedStartingFcb = TRUE;
  6002. }
  6003. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  6004. AcquiredFcb = FALSE;
  6005. } else {
  6006. NtfsReleaseFcbTable( IrpContext, Vcb );
  6007. AcquiredFcbTable = FALSE;
  6008. }
  6009. }
  6010. }
  6011. //
  6012. // Move to the Fcb for the ParentScb. Break out if no parent
  6013. // or there are no more entries on the parent.
  6014. //
  6015. if ((ParentScb == NULL) || !EmptyParentQueue) {
  6016. leave;
  6017. }
  6018. //
  6019. // If we have a parent Scb then we might have it
  6020. // either shared or exclusive. We can now do
  6021. // a thorough test to see if we need it exclusive.
  6022. //
  6023. if (!AcquiredParentExclusive) {
  6024. //
  6025. // We need to acquire the Fcb table, reference the
  6026. // parent, drop the parent and reacquire exclusively.
  6027. //
  6028. NtfsAcquireFcbTable( IrpContext, Vcb );
  6029. ParentScb->Fcb->ReferenceCount += 1;
  6030. NtfsReleaseFcbTable( IrpContext, Vcb );
  6031. NtfsReleaseFcb( IrpContext, ParentScb->Fcb );
  6032. if (!NtfsAcquireExclusiveFcb( IrpContext,
  6033. ParentScb->Fcb,
  6034. ParentScb,
  6035. ACQUIRE_NO_DELETE_CHECK | AcquireFlags )) {
  6036. //
  6037. // We couldn't get the parent. No problem, someone
  6038. // else will do any necessary teardown.
  6039. //
  6040. AcquiredParentScb = FALSE;
  6041. NtfsAcquireFcbTable( IrpContext, Vcb );
  6042. ParentScb->Fcb->ReferenceCount -= 1;
  6043. NtfsReleaseFcbTable( IrpContext, Vcb );
  6044. leave;
  6045. } else {
  6046. if (FlagOn( ParentScb->ScbState, SCB_STATE_FILE_SIZE_LOADED )) {
  6047. NtfsSnapshotScb( IrpContext, ParentScb );
  6048. }
  6049. AcquiredParentExclusive = TRUE;
  6050. }
  6051. //
  6052. // Now decrement the parent reference.
  6053. //
  6054. NtfsAcquireFcbTable( IrpContext, Vcb );
  6055. ParentScb->Fcb->ReferenceCount -= 1;
  6056. NtfsReleaseFcbTable( IrpContext, Vcb );
  6057. }
  6058. Fcb = ParentScb->Fcb;
  6059. AcquiredFcb = TRUE;
  6060. AcquiredParentScb = FALSE;
  6061. //
  6062. // Check if this Fcb can be removed.
  6063. //
  6064. if (!NtfsPrepareFcbForRemoval( IrpContext, Fcb, NULL, CheckForAttributeTable )) {
  6065. leave;
  6066. }
  6067. }
  6068. } finally {
  6069. DebugUnwind( NtfsTeardownFromLcb );
  6070. if (AcquiredFcbTable) {
  6071. NtfsReleaseFcbTable( IrpContext, Vcb );
  6072. }
  6073. if (AcquiredFcb) {
  6074. NtfsReleaseFcb( IrpContext, Fcb );
  6075. }
  6076. if (AcquiredParentScb) {
  6077. NtfsReleaseScb( IrpContext, ParentScb );
  6078. }
  6079. }
  6080. return;
  6081. }
  6082. //
  6083. // Local support routine
  6084. //
  6085. RTL_GENERIC_COMPARE_RESULTS
  6086. NtfsFcbTableCompare (
  6087. IN PRTL_GENERIC_TABLE FcbTable,
  6088. IN PVOID FirstStruct,
  6089. IN PVOID SecondStruct
  6090. )
  6091. /*++
  6092. Routine Description:
  6093. This is a generic table support routine to compare two fcb table elements
  6094. Arguments:
  6095. FcbTable - Supplies the generic table being queried
  6096. FirstStruct - Supplies the first fcb table element to compare
  6097. SecondStruct - Supplies the second fcb table element to compare
  6098. Return Value:
  6099. RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
  6100. input structures
  6101. --*/
  6102. {
  6103. FILE_REFERENCE FirstRef = *((PFILE_REFERENCE) FirstStruct);
  6104. FILE_REFERENCE SecondRef = *((PFILE_REFERENCE) SecondStruct);
  6105. PAGED_CODE();
  6106. //
  6107. // Use also the sequence number for all compares so file references in the
  6108. // fcb table are unique over time and space. If we want to ignore sequence
  6109. // numbers we can zero out the sequence number field, but then we will also
  6110. // need to delete the Fcbs from the table during cleanup and not when the
  6111. // fcb really gets deleted. Otherwise we cannot reuse file records.
  6112. //
  6113. if (NtfsFullSegmentNumber( &FirstRef ) < NtfsFullSegmentNumber( &SecondRef )) {
  6114. return GenericLessThan;
  6115. } else if (NtfsFullSegmentNumber( &FirstRef ) > NtfsFullSegmentNumber( &SecondRef )) {
  6116. return GenericGreaterThan;
  6117. } else {
  6118. //
  6119. // SequenceNumber comparison now
  6120. //
  6121. if (FirstRef.SequenceNumber < SecondRef.SequenceNumber) {
  6122. return GenericLessThan;
  6123. } else if (FirstRef.SequenceNumber > SecondRef.SequenceNumber) {
  6124. return GenericGreaterThan;
  6125. } else {
  6126. return GenericEqual;
  6127. }
  6128. }
  6129. UNREFERENCED_PARAMETER( FcbTable );
  6130. }
  6131. //
  6132. // Local support routine
  6133. //
  6134. VOID
  6135. NtfsReserveCcbNamesInLcb (
  6136. IN PIRP_CONTEXT IrpContext,
  6137. IN PLCB Lcb,
  6138. IN PULONG ParentNameLength OPTIONAL,
  6139. IN ULONG LastComponentNameLength
  6140. )
  6141. /*++
  6142. Routine Description:
  6143. This routine walks through a list of Ccbs and grows the name buffer as
  6144. necessary.
  6145. Arguments:
  6146. Lcb - Lcb with links of Ccbs to check.
  6147. ParentNameLength - If specified then this is the full length of the new name
  6148. to the parent directory. Otherwise we use the existing parent name in
  6149. each Ccb. The separator is implied.
  6150. LastComponentNameLength - Number of bytes needed for the last component of the name.
  6151. Return Value:
  6152. None - This routine will raise on an allocation failure.
  6153. --*/
  6154. {
  6155. PCCB Ccb;
  6156. PVOID NewAllocation;
  6157. ULONG BytesNeeded;
  6158. PAGED_CODE();
  6159. //
  6160. // Now for every ccb attached to us we need to check if we need a new
  6161. // filename buffer. Protect the Ccb with the Fcb mutex to serialize access to
  6162. // the flags field with close.
  6163. //
  6164. Ccb = NULL;
  6165. while ((Ccb = NtfsGetNextCcb( Lcb, Ccb )) != NULL) {
  6166. //
  6167. // If the Ccb last component length is zero, this Ccb is for a
  6168. // file object that was opened by File Id. We won't to any
  6169. // work for the name in the fileobject for this. Otherwise we
  6170. // compute the length of the new name and see if we have enough space
  6171. // The CLOSE flag indicates whether this had gone through the close path or not.
  6172. // We use the LockFcb command above to serialize with the setting of the close
  6173. // flag.
  6174. //
  6175. NtfsLockFcb( IrpContext, Ccb->Lcb->Fcb );
  6176. if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_FILE_ID | CCB_FLAG_CLOSE )) {
  6177. if (ARGUMENT_PRESENT( ParentNameLength )) {
  6178. BytesNeeded = *ParentNameLength + LastComponentNameLength;
  6179. } else {
  6180. BytesNeeded = Ccb->LastFileNameOffset + LastComponentNameLength;
  6181. }
  6182. if (Ccb->FullFileName.MaximumLength < BytesNeeded) {
  6183. //
  6184. // Allocate a new file name buffer and copy the existing data back into it.
  6185. //
  6186. NewAllocation = NtfsAllocatePoolNoRaise( PagedPool, BytesNeeded );
  6187. if (NewAllocation == NULL) {
  6188. NtfsUnlockFcb( IrpContext, Ccb->Lcb->Fcb );
  6189. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  6190. }
  6191. RtlCopyMemory( NewAllocation,
  6192. Ccb->FullFileName.Buffer,
  6193. Ccb->FullFileName.Length );
  6194. if (FlagOn( Ccb->Flags, CCB_FLAG_ALLOCATED_FILE_NAME )) {
  6195. NtfsFreePool( Ccb->FullFileName.Buffer );
  6196. }
  6197. Ccb->FullFileName.Buffer = NewAllocation;
  6198. Ccb->FullFileName.MaximumLength = (USHORT) BytesNeeded;
  6199. SetFlag( Ccb->Flags, CCB_FLAG_ALLOCATED_FILE_NAME );
  6200. }
  6201. }
  6202. NtfsUnlockFcb( IrpContext, Ccb->Lcb->Fcb );
  6203. }
  6204. return;
  6205. }
  6206. //
  6207. // Local support routine
  6208. //
  6209. VOID
  6210. NtfsClearRecursiveLcb (
  6211. IN PLCB Lcb
  6212. )
  6213. /*++
  6214. Routine Description:
  6215. This routine is called to clear all of the normalized names, prefix entries and hash entries in
  6216. a subtree starting from a given Lcb. Typically this is used as part of a rename when a parent rename
  6217. affects the full name of all of the children.
  6218. Arguments:
  6219. Lcb - Lcb which is root of rename.
  6220. Return Value:
  6221. None - This routine will raise on an allocation failure.
  6222. --*/
  6223. {
  6224. PSCB ChildScb;
  6225. PSCB NextScb;
  6226. PLCB NextLcb;
  6227. PAGED_CODE();
  6228. //
  6229. // Clear the index offset pointer so we will look this up again.
  6230. //
  6231. Lcb->QuickIndex.BufferOffset = 0;
  6232. //
  6233. // Get rid of any prefixes that might still be attached to us
  6234. //
  6235. ASSERT( NtfsIsExclusiveScb( Lcb->Scb ) );
  6236. NtfsRemovePrefix( Lcb );
  6237. //
  6238. // Remove any hash table entries for this Lcb.
  6239. //
  6240. NtfsRemoveHashEntriesForLcb( Lcb );
  6241. //
  6242. // And then traverse the graph underneath our fcb and remove all prefixes
  6243. // also used there. For each child scb under the fcb we will traverse all of
  6244. // its descendant Scb children and for each lcb we encounter we will remove its prefixes.
  6245. //
  6246. ChildScb = NULL;
  6247. while ((ChildScb = NtfsGetNextChildScb( Lcb->Fcb, ChildScb )) != NULL) {
  6248. //
  6249. // Now we have to descend into this Scb subtree, if it exists.
  6250. // Then remove the prefix entries on all of the links found.
  6251. // Do this as a do-while so we can use common code to handle the top-level
  6252. // Scb as well.
  6253. //
  6254. NextScb = ChildScb;
  6255. do {
  6256. //
  6257. // Walk through the Lcbs of any index Scb and remove the prefix and
  6258. // hash entries.
  6259. //
  6260. if (SafeNodeType( NextScb ) == NTFS_NTC_SCB_INDEX) {
  6261. //
  6262. // We better have the Vcb exclusive to descend down the tree.
  6263. //
  6264. ASSERT( NtfsIsExclusiveVcb( Lcb->Fcb->Vcb ));
  6265. NextLcb = NULL;
  6266. while ((NextLcb = NtfsGetNextChildLcb( NextScb, NextLcb )) != NULL) {
  6267. //
  6268. // Remove any hash table and prefix entries for this Lcb.
  6269. // We can be unsynchronized here because we own the Vcb
  6270. // exclusive and there are no open handles on either of these.
  6271. //
  6272. NtfsRemovePrefix( NextLcb );
  6273. NtfsRemoveHashEntriesForLcb( NextLcb );
  6274. }
  6275. //
  6276. // If this is an index Scb with a normalized name, then free
  6277. // the normalized name.
  6278. //
  6279. if ((NextScb != ChildScb) &&
  6280. (NextScb->ScbType.Index.NormalizedName.Buffer != NULL)) {
  6281. NtfsDeleteNormalizedName( NextScb );
  6282. }
  6283. }
  6284. } while ((NextScb = NtfsGetNextScb( NextScb, ChildScb )) != NULL);
  6285. }
  6286. return;
  6287. }
  6288. PDEALLOCATED_CLUSTERS
  6289. NtfsGetDeallocatedClusters (
  6290. IN PIRP_CONTEXT IrpContext,
  6291. IN PVCB Vcb
  6292. )
  6293. /*++
  6294. Routine Description:
  6295. Add an entry if possible and neccessary to recently deallocated list and return the head of the list.
  6296. If there isn't enough memory this routine just returns the old head
  6297. We determine whether to add the entry based on the threshold for the mapping size
  6298. Arguments:
  6299. Vcb - Vcb to add entry to
  6300. Return Value:
  6301. The new head of the list
  6302. --*/
  6303. {
  6304. PDEALLOCATED_CLUSTERS CurrentClusters;
  6305. PDEALLOCATED_CLUSTERS NewClusters;
  6306. UNREFERENCED_PARAMETER( IrpContext );
  6307. PAGED_CODE();
  6308. CurrentClusters = (PDEALLOCATED_CLUSTERS) Vcb->DeallocatedClusterListHead.Flink;
  6309. if (FsRtlNumberOfRunsInLargeMcb( &CurrentClusters->Mcb ) > NTFS_DEALLOCATED_MCB_LIMIT) {
  6310. //
  6311. // Find a new deallocated cluster. Use the preallocated ones if they
  6312. // are not in use. If we fail to allocate memory continue to use the old one
  6313. //
  6314. if (Vcb->DeallocatedClusters1.Link.Flink == NULL) {
  6315. NewClusters = &Vcb->DeallocatedClusters1;
  6316. NewClusters->Lsn.QuadPart = 0;
  6317. } else if (Vcb->DeallocatedClusters2.Link.Flink == NULL) {
  6318. NewClusters = &Vcb->DeallocatedClusters2;
  6319. NewClusters->Lsn.QuadPart = 0;
  6320. } else {
  6321. NewClusters = NtfsAllocatePoolNoRaise( PagedPool, sizeof( DEALLOCATED_CLUSTERS ) );
  6322. if (NewClusters != NULL) {
  6323. RtlZeroMemory( NewClusters, sizeof( DEALLOCATED_CLUSTERS ) );
  6324. FsRtlInitializeLargeMcb( &NewClusters->Mcb, PagedPool );
  6325. }
  6326. }
  6327. if (NewClusters != NULL) {
  6328. ASSERT( NewClusters->ClusterCount == 0 );
  6329. CurrentClusters->Lsn = LfsQueryLastLsn( Vcb->LogHandle );
  6330. InsertHeadList( &Vcb->DeallocatedClusterListHead, &NewClusters->Link );
  6331. CurrentClusters = NewClusters;
  6332. }
  6333. }
  6334. return CurrentClusters;
  6335. }
  6336. #ifdef SYSCACHE_DEBUG
  6337. #define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof( ON_DISK_SYSCACHE_LOG ))
  6338. ULONG
  6339. FsRtlLogSyscacheEvent (
  6340. IN PSCB Scb,
  6341. IN ULONG Event,
  6342. IN ULONG Flags,
  6343. IN LONGLONG Start,
  6344. IN LONGLONG Range,
  6345. IN LONGLONG Result
  6346. )
  6347. /*++
  6348. Routine Description:
  6349. Logging routine for syscache tracking
  6350. Arguments:
  6351. Scb - Scb being tracked
  6352. Event - SCE Event being record
  6353. Flags -Flag for the event
  6354. Start - starting offset
  6355. Range - range of the action
  6356. Result - result
  6357. Return Value:
  6358. Sequence number for this log entry
  6359. --*/
  6360. {
  6361. LONG TempEntry;
  6362. #ifdef SYSCACHE_DEBUG_ON_DISK
  6363. LONG TempDiskEntry;
  6364. LONGLONG Offset;
  6365. PON_DISK_SYSCACHE_LOG Entry;
  6366. PBCB Bcb;
  6367. #endif
  6368. TempEntry = InterlockedIncrement( &(Scb->CurrentSyscacheLogEntry) );
  6369. TempEntry = TempEntry % Scb->SyscacheLogEntryCount;
  6370. Scb->SyscacheLog[TempEntry].Event = Event;
  6371. Scb->SyscacheLog[TempEntry].Flags = Flags;
  6372. Scb->SyscacheLog[TempEntry].Start = Start;
  6373. Scb->SyscacheLog[TempEntry].Range = Range;
  6374. Scb->SyscacheLog[TempEntry].Result = Result;
  6375. #ifdef SYSCACHE_DEBUG_ON_DISK
  6376. if ((Scb->Vcb->SyscacheScb != NULL) &&
  6377. (Scb->Vcb->SyscacheScb->Header.FileSize.QuadPart > 0 )) {
  6378. TempDiskEntry = InterlockedIncrement( &NtfsCurrentSyscacheOnDiskEntry );
  6379. Offset = (((TempDiskEntry / ENTRIES_PER_PAGE) * PAGE_SIZE) +
  6380. ((TempDiskEntry % ENTRIES_PER_PAGE) * sizeof( ON_DISK_SYSCACHE_LOG )));
  6381. Offset = Offset % Scb->Vcb->SyscacheScb->Header.FileSize.QuadPart;
  6382. try {
  6383. CcPreparePinWrite( Scb->Vcb->SyscacheScb->FileObject,
  6384. (PLARGE_INTEGER)&Offset,
  6385. sizeof( ON_DISK_SYSCACHE_LOG ),
  6386. FALSE,
  6387. TRUE,
  6388. &Bcb,
  6389. &Entry );
  6390. Entry->SegmentNumberUnsafe = Scb->Fcb->FileReference.SegmentNumberLowPart;
  6391. Entry->Event = Event;
  6392. Entry->Flags = Flags;
  6393. Entry->Start = Start;
  6394. Entry->Range = Range;
  6395. Entry->Result = Result;
  6396. CcUnpinData( Bcb );
  6397. } except( EXCEPTION_EXECUTE_HANDLER ) {
  6398. ASSERT( FALSE );
  6399. }
  6400. }
  6401. #endif
  6402. return TempEntry;
  6403. }
  6404. VOID
  6405. FsRtlUpdateSyscacheEvent (
  6406. IN PSCB Scb,
  6407. IN ULONG EntryNumber,
  6408. IN LONGLONG Result,
  6409. IN ULONG NewFlag
  6410. )
  6411. /*++
  6412. Routine Description:
  6413. Logging routine for syscache tracking - updates a prev. written record
  6414. Arguments:
  6415. Scb -
  6416. EntryNumber -
  6417. Result -
  6418. NewFlag -
  6419. Return Value:
  6420. none
  6421. --*/
  6422. {
  6423. Scb->SyscacheLog[EntryNumber].Flags |= NewFlag;
  6424. Scb->SyscacheLog[EntryNumber].Result = Result;
  6425. }
  6426. #endif