Leaked source code of windows server 2003
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.

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