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.

3485 lines
93 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. StrucSup.c
  5. Abstract:
  6. This module implements the Fat in-memory data structure manipulation
  7. routines
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 22-Jan-1990
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_STRUCSUP)
  19. //
  20. // The debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_STRUCSUP)
  23. #define FillMemory(BUF,SIZ,MASK) { \
  24. ULONG i; \
  25. for (i = 0; i < (((SIZ)/4) - 1); i += 2) { \
  26. ((PULONG)(BUF))[i] = (MASK); \
  27. ((PULONG)(BUF))[i+1] = (ULONG)PsGetCurrentThread(); \
  28. } \
  29. }
  30. #define IRP_CONTEXT_HEADER (sizeof( IRP_CONTEXT ) * 0x10000 + FAT_NTC_IRP_CONTEXT)
  31. //
  32. // Local macros.
  33. //
  34. // Define our lookaside list allocators. For the time being, and perhaps
  35. // permanently, the paged structures don't come off of lookasides. This
  36. // is due to complications with clean unload as FAT can be in the paging
  37. // path, making it really hard to find the right time to empty them.
  38. //
  39. // Fortunately, the hit rates on the Fcb/Ccb lists weren't stunning.
  40. //
  41. #define FAT_FILL_FREE 0
  42. INLINE
  43. PCCB
  44. FatAllocateCcb (
  45. )
  46. {
  47. return (PCCB) FsRtlAllocatePoolWithTag( PagedPool, sizeof(CCB), TAG_CCB );
  48. }
  49. INLINE
  50. VOID
  51. FatFreeCcb (
  52. IN PCCB Ccb
  53. )
  54. {
  55. #if FAT_FILL_FREE
  56. RtlFillMemoryUlong(Ccb, sizeof(CCB), FAT_FILL_FREE);
  57. #endif
  58. ExFreePool( Ccb );
  59. }
  60. INLINE
  61. PFCB
  62. FatAllocateFcb (
  63. )
  64. {
  65. return (PFCB) FsRtlAllocatePoolWithTag( PagedPool, sizeof(FCB), TAG_FCB );
  66. }
  67. INLINE
  68. VOID
  69. FatFreeFcb (
  70. IN PFCB Fcb
  71. )
  72. {
  73. #if FAT_FILL_FREE
  74. RtlFillMemoryUlong(Fcb, sizeof(FCB), FAT_FILL_FREE);
  75. #endif
  76. ExFreePool( Fcb );
  77. }
  78. INLINE
  79. PNON_PAGED_FCB
  80. FatAllocateNonPagedFcb (
  81. )
  82. {
  83. return (PNON_PAGED_FCB) ExAllocateFromNPagedLookasideList( &FatNonPagedFcbLookasideList );
  84. }
  85. INLINE
  86. VOID
  87. FatFreeNonPagedFcb (
  88. PNON_PAGED_FCB NonPagedFcb
  89. )
  90. {
  91. #if FAT_FILL_FREE
  92. RtlFillMemoryUlong(NonPagedFcb, sizeof(NON_PAGED_FCB), FAT_FILL_FREE);
  93. #endif
  94. ExFreeToNPagedLookasideList( &FatNonPagedFcbLookasideList, (PVOID) NonPagedFcb );
  95. }
  96. INLINE
  97. PERESOURCE
  98. FatAllocateResource (
  99. )
  100. {
  101. PERESOURCE Resource;
  102. Resource = (PERESOURCE) ExAllocateFromNPagedLookasideList( &FatEResourceLookasideList );
  103. ExInitializeResourceLite( Resource );
  104. return Resource;
  105. }
  106. INLINE
  107. VOID
  108. FatFreeResource (
  109. IN PERESOURCE Resource
  110. )
  111. {
  112. ExDeleteResourceLite( Resource );
  113. #if FAT_FILL_FREE
  114. RtlFillMemoryUlong(Resource, sizeof(ERESOURCE), FAT_FILL_FREE);
  115. #endif
  116. ExFreeToNPagedLookasideList( &FatEResourceLookasideList, (PVOID) Resource );
  117. }
  118. INLINE
  119. PIRP_CONTEXT
  120. FatAllocateIrpContext (
  121. )
  122. {
  123. return (PIRP_CONTEXT) ExAllocateFromNPagedLookasideList( &FatIrpContextLookasideList );
  124. }
  125. INLINE
  126. VOID
  127. FatFreeIrpContext (
  128. IN PIRP_CONTEXT IrpContext
  129. )
  130. {
  131. #if FAT_FILL_FREE
  132. RtlFillMemoryUlong(IrpContext, sizeof(IRP_CONTEXT), FAT_FILL_FREE);
  133. #endif
  134. ExFreeToNPagedLookasideList( &FatIrpContextLookasideList, (PVOID) IrpContext );
  135. }
  136. #ifdef ALLOC_PRAGMA
  137. #pragma alloc_text(PAGE, FatInitializeVcb)
  138. #pragma alloc_text(PAGE, FatDeleteVcb)
  139. #pragma alloc_text(PAGE, FatCreateRootDcb)
  140. #pragma alloc_text(PAGE, FatCreateFcb)
  141. #pragma alloc_text(PAGE, FatCreateDcb)
  142. #pragma alloc_text(PAGE, FatDeleteFcb_Real)
  143. #pragma alloc_text(PAGE, FatCreateCcb)
  144. #pragma alloc_text(PAGE, FatDeallocateCcbStrings)
  145. #pragma alloc_text(PAGE, FatDeleteCcb_Real)
  146. #pragma alloc_text(PAGE, FatGetNextFcbTopDown)
  147. #pragma alloc_text(PAGE, FatGetNextFcbBottomUp)
  148. #pragma alloc_text(PAGE, FatConstructNamesInFcb)
  149. #pragma alloc_text(PAGE, FatCheckFreeDirentBitmap)
  150. #pragma alloc_text(PAGE, FatCreateIrpContext)
  151. #pragma alloc_text(PAGE, FatDeleteIrpContext_Real)
  152. #pragma alloc_text(PAGE, FatIsHandleCountZero)
  153. #pragma alloc_text(PAGE, FatPreallocateCloseContext)
  154. #endif
  155. VOID
  156. FatInitializeVcb (
  157. IN PIRP_CONTEXT IrpContext,
  158. IN OUT PVCB Vcb,
  159. IN PDEVICE_OBJECT TargetDeviceObject,
  160. IN PVPB Vpb,
  161. IN PDEVICE_OBJECT FsDeviceObject
  162. )
  163. /*++
  164. Routine Description:
  165. This routine initializes and inserts a new Vcb record into the in-memory
  166. data structure. The Vcb record "hangs" off the end of the Volume device
  167. object and must be allocated by our caller.
  168. Arguments:
  169. Vcb - Supplies the address of the Vcb record being initialized.
  170. TargetDeviceObject - Supplies the address of the target device object to
  171. associate with the Vcb record.
  172. Vpb - Supplies the address of the Vpb to associate with the Vcb record.
  173. FsDeviceObject - The filesystem device object that the mount was directed
  174. too.
  175. Return Value:
  176. None.
  177. --*/
  178. {
  179. CC_FILE_SIZES FileSizes;
  180. PDEVICE_OBJECT RealDevice;
  181. LONG i;
  182. STORAGE_HOTPLUG_INFO HotplugInfo;
  183. NTSTATUS Status;
  184. //
  185. // The following variables are used for abnormal unwind
  186. //
  187. PLIST_ENTRY UnwindEntryList = NULL;
  188. PERESOURCE UnwindResource = NULL;
  189. PERESOURCE UnwindResource2 = NULL;
  190. PFILE_OBJECT UnwindFileObject = NULL;
  191. PFILE_OBJECT UnwindCacheMap = NULL;
  192. BOOLEAN UnwindWeAllocatedMcb = FALSE;
  193. PFILE_SYSTEM_STATISTICS UnwindStatistics = NULL;
  194. DebugTrace(+1, Dbg, "FatInitializeVcb, Vcb = %08lx\n", Vcb);
  195. try {
  196. //
  197. // We start by first zeroing out all of the VCB, this will guarantee
  198. // that any stale data is wiped clean
  199. //
  200. RtlZeroMemory( Vcb, sizeof(VCB) );
  201. //
  202. // Set the proper node type code and node byte size
  203. //
  204. Vcb->VolumeFileHeader.NodeTypeCode = FAT_NTC_VCB;
  205. Vcb->VolumeFileHeader.NodeByteSize = sizeof(VCB);
  206. //
  207. // Initialize the tunneling cache
  208. //
  209. FsRtlInitializeTunnelCache(&Vcb->Tunnel);
  210. //
  211. // Insert this Vcb record on the FatData.VcbQueue
  212. //
  213. ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  214. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  215. InsertTailList( &FatData.VcbQueue, &Vcb->VcbLinks );
  216. FatReleaseGlobal( IrpContext );
  217. UnwindEntryList = &Vcb->VcbLinks;
  218. //
  219. // Set the Target Device Object, Vpb, and Vcb State fields
  220. //
  221. ObReferenceObject( TargetDeviceObject );
  222. Vcb->TargetDeviceObject = TargetDeviceObject;
  223. Vcb->Vpb = Vpb;
  224. Vcb->CurrentDevice = Vpb->RealDevice;
  225. //
  226. // Set the removable media and defflush flags based on the storage
  227. // inquiry and the old characteristic bits.
  228. //
  229. Status = FatPerformDevIoCtrl( IrpContext,
  230. IOCTL_STORAGE_GET_HOTPLUG_INFO,
  231. TargetDeviceObject,
  232. &HotplugInfo,
  233. sizeof(HotplugInfo),
  234. FALSE,
  235. TRUE,
  236. NULL );
  237. if (NT_SUCCESS( Status )) {
  238. if (HotplugInfo.MediaRemovable) {
  239. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA );
  240. }
  241. if (!HotplugInfo.WriteCacheEnableOverride) {
  242. //
  243. // If the device or media is hotplug and the override is not
  244. // set, force defflush behavior for the device.
  245. //
  246. if (HotplugInfo.MediaHotplug || HotplugInfo.DeviceHotplug) {
  247. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH );
  248. //
  249. // Now, for removables that claim to be lockable, lob a lock
  250. // request and see if it works. There can unfortunately be
  251. // transient, media dependent reasons that it can fail. If
  252. // it does not, we must force defflush on.
  253. //
  254. } else if (HotplugInfo.MediaRemovable &&
  255. !HotplugInfo.MediaHotplug) {
  256. Status = FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
  257. if (!NT_SUCCESS( Status )) {
  258. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH );
  259. }
  260. Status = FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
  261. }
  262. }
  263. }
  264. if (FlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
  265. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA );
  266. }
  267. //
  268. // Make sure we turn on deferred flushing for floppies like we always
  269. // have.
  270. //
  271. if (FlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
  272. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH );
  273. }
  274. FatSetVcbCondition( Vcb, VcbGood);
  275. //
  276. // Initialize the resource variable for the Vcb
  277. //
  278. ExInitializeResourceLite( &Vcb->Resource );
  279. UnwindResource = &Vcb->Resource;
  280. ExInitializeResourceLite( &Vcb->ChangeBitMapResource );
  281. UnwindResource2 = &Vcb->ChangeBitMapResource;
  282. //
  283. // Initialize the free cluster bitmap mutex.
  284. //
  285. ExInitializeFastMutex( &Vcb->FreeClusterBitMapMutex );
  286. //
  287. // Create the special file object for the virtual volume file with a close
  288. // context, its pointers back to the Vcb and the section object pointer.
  289. //
  290. // We don't have to unwind the close context. That will happen in the close
  291. // path automatically.
  292. //
  293. RealDevice = Vcb->CurrentDevice;
  294. Vcb->VirtualVolumeFile = UnwindFileObject = IoCreateStreamFileObject( NULL, RealDevice );
  295. Vcb->CloseContext = FsRtlAllocatePoolWithTag( PagedPool,
  296. sizeof(CLOSE_CONTEXT),
  297. TAG_FAT_CLOSE_CONTEXT );
  298. FatSetFileObject( Vcb->VirtualVolumeFile,
  299. VirtualVolumeFile,
  300. Vcb,
  301. NULL );
  302. Vcb->VirtualVolumeFile->SectionObjectPointer = &Vcb->SectionObjectPointers;
  303. Vcb->VirtualVolumeFile->ReadAccess = TRUE;
  304. Vcb->VirtualVolumeFile->WriteAccess = TRUE;
  305. Vcb->VirtualVolumeFile->DeleteAccess = TRUE;
  306. //
  307. // Initialize the notify structures.
  308. //
  309. InitializeListHead( &Vcb->DirNotifyList );
  310. FsRtlNotifyInitializeSync( &Vcb->NotifySync );
  311. //
  312. // Initialize the Cache Map for the volume file. The size is
  313. // initially set to that of our first read. It will be extended
  314. // when we know how big the Fat is.
  315. //
  316. FileSizes.AllocationSize.QuadPart =
  317. FileSizes.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
  318. FileSizes.ValidDataLength = FatMaxLarge;
  319. CcInitializeCacheMap( Vcb->VirtualVolumeFile,
  320. &FileSizes,
  321. TRUE,
  322. &FatData.CacheManagerNoOpCallbacks,
  323. Vcb );
  324. UnwindCacheMap = Vcb->VirtualVolumeFile;
  325. //
  326. // Initialize the structure that will keep track of dirty fat sectors.
  327. // The largest possible Mcb structures are less than 1K, so we use
  328. // non paged pool.
  329. //
  330. FsRtlInitializeLargeMcb( &Vcb->DirtyFatMcb, PagedPool );
  331. UnwindWeAllocatedMcb = TRUE;
  332. //
  333. // Set the cluster index hint to the first valid cluster of a fat: 2
  334. //
  335. Vcb->ClusterHint = 2;
  336. //
  337. // Initialize the directory stream file object creation event.
  338. // This event is also "borrowed" for async non-cached writes.
  339. //
  340. ExInitializeFastMutex( &Vcb->DirectoryFileCreationMutex );
  341. //
  342. // Initialize the clean volume callback Timer and DPC.
  343. //
  344. KeInitializeTimer( &Vcb->CleanVolumeTimer );
  345. KeInitializeDpc( &Vcb->CleanVolumeDpc, FatCleanVolumeDpc, Vcb );
  346. //
  347. // Initialize the performance counters.
  348. //
  349. Vcb->Statistics = FsRtlAllocatePoolWithTag( NonPagedPool,
  350. sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors,
  351. TAG_VCB_STATS );
  352. UnwindStatistics = Vcb->Statistics;
  353. RtlZeroMemory( Vcb->Statistics, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors );
  354. for (i = 0; i < KeNumberProcessors; i += 1) {
  355. Vcb->Statistics[i].Common.FileSystemType = FILESYSTEM_STATISTICS_TYPE_FAT;
  356. Vcb->Statistics[i].Common.Version = 1;
  357. Vcb->Statistics[i].Common.SizeOfCompleteStructure =
  358. sizeof(FILE_SYSTEM_STATISTICS);
  359. }
  360. //
  361. // Pick up a VPB right now so we know we can pull this filesystem stack off
  362. // of the storage stack on demand.
  363. //
  364. Vcb->SwapVpb = FsRtlAllocatePoolWithTag( NonPagedPool,
  365. sizeof( VPB ),
  366. TAG_VPB );
  367. RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) );
  368. //
  369. // Initialize the close queue listheads.
  370. //
  371. InitializeListHead( &Vcb->AsyncCloseList );
  372. InitializeListHead( &Vcb->DelayedCloseList );
  373. //
  374. // Initialize the Advanced FCB Header
  375. //
  376. ExInitializeFastMutex( &Vcb->AdvancedFcbHeaderMutex );
  377. FsRtlSetupAdvancedHeader( &Vcb->VolumeFileHeader,
  378. &Vcb->AdvancedFcbHeaderMutex );
  379. //
  380. // With the Vcb now set up, set the IrpContext Vcb field.
  381. //
  382. IrpContext->Vcb = Vcb;
  383. } finally {
  384. DebugUnwind( FatInitializeVcb );
  385. //
  386. // If this is an abnormal termination then undo our work
  387. //
  388. if (AbnormalTermination()) {
  389. if (UnwindCacheMap != NULL) { FatSyncUninitializeCacheMap( IrpContext, UnwindCacheMap ); }
  390. if (UnwindFileObject != NULL) { ObDereferenceObject( UnwindFileObject ); }
  391. if (UnwindResource != NULL) { FatDeleteResource( UnwindResource ); }
  392. if (UnwindResource2 != NULL) { FatDeleteResource( UnwindResource2 ); }
  393. if (UnwindWeAllocatedMcb) { FsRtlUninitializeLargeMcb( &Vcb->DirtyFatMcb ); }
  394. if (UnwindEntryList != NULL) {
  395. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  396. RemoveEntryList( UnwindEntryList );
  397. FatReleaseGlobal( IrpContext );
  398. }
  399. if (UnwindStatistics != NULL) { ExFreePool( UnwindStatistics ); }
  400. if (Vcb->CloseContext != NULL) {
  401. ExFreePool( Vcb->CloseContext );
  402. Vcb->CloseContext = NULL;
  403. }
  404. }
  405. DebugTrace(-1, Dbg, "FatInitializeVcb -> VOID\n", 0);
  406. }
  407. //
  408. // and return to our caller
  409. //
  410. UNREFERENCED_PARAMETER( IrpContext );
  411. return;
  412. }
  413. VOID
  414. FatDeleteVcb (
  415. IN PIRP_CONTEXT IrpContext,
  416. IN PVCB Vcb
  417. )
  418. /*++
  419. Routine Description:
  420. This routine removes the Vcb record from Fat's in-memory data
  421. structures. It also will remove all associated underlings
  422. (i.e., FCB records).
  423. Arguments:
  424. Vcb - Supplies the Vcb to be removed
  425. Return Value:
  426. None
  427. --*/
  428. {
  429. PFCB Fcb;
  430. DebugTrace(+1, Dbg, "FatDeleteVcb, Vcb = %08lx\n", Vcb);
  431. //
  432. // If the IrpContext points to the VCB being deleted NULL out the stail
  433. // pointer.
  434. //
  435. if (IrpContext->Vcb == Vcb) {
  436. IrpContext->Vcb = NULL;
  437. }
  438. //
  439. // Chuck the backpocket Vpb we kept just in case.
  440. //
  441. if (Vcb->SwapVpb) {
  442. ExFreePool( Vcb->SwapVpb );
  443. }
  444. //
  445. // Uninitialize the cache
  446. //
  447. FatSyncUninitializeCacheMap( IrpContext, Vcb->VirtualVolumeFile );
  448. //
  449. // Dereference the virtual volume file. This will cause a close
  450. // Irp to be processed, so we need to do this before we destory
  451. // the Vcb
  452. //
  453. FsRtlTeardownPerStreamContexts( &Vcb->VolumeFileHeader );
  454. FatSetFileObject( Vcb->VirtualVolumeFile, UnopenedFileObject, NULL, NULL );
  455. if (Vcb->CloseContext != NULL) {
  456. ExFreePool( Vcb->CloseContext );
  457. Vcb->CloseContext = NULL;
  458. }
  459. ObDereferenceObject( Vcb->VirtualVolumeFile );
  460. //
  461. // Remove this record from the global list of all Vcb records
  462. //
  463. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  464. RemoveEntryList( &(Vcb->VcbLinks) );
  465. FatReleaseGlobal( IrpContext );
  466. //
  467. // Make sure the direct access open count is zero, and the open file count
  468. // is also zero.
  469. //
  470. if ((Vcb->DirectAccessOpenCount != 0) || (Vcb->OpenFileCount != 0)) {
  471. FatBugCheck( 0, 0, 0 );
  472. }
  473. //
  474. // Remove the EaFcb and dereference the Fcb for the Ea file if it
  475. // exists.
  476. //
  477. FatCloseEaFile( IrpContext, Vcb, FALSE );
  478. if (Vcb->EaFcb != NULL) {
  479. Vcb->EaFcb->OpenCount = 0;
  480. FatDeleteFcb( IrpContext, Vcb->EaFcb );
  481. Vcb->EaFcb = NULL;
  482. }
  483. //
  484. // Remove the Root Dcb
  485. //
  486. if (Vcb->RootDcb != NULL) {
  487. PFILE_OBJECT DirectoryFileObject = Vcb->RootDcb->Specific.Dcb.DirectoryFile;
  488. if (DirectoryFileObject != NULL) {
  489. FatSyncUninitializeCacheMap( IrpContext, DirectoryFileObject );
  490. //
  491. // Dereference the directory file. This will cause a close
  492. // Irp to be processed, so we need to do this before we destory
  493. // the Fcb
  494. //
  495. InterlockedDecrement( &Vcb->RootDcb->Specific.Dcb.DirectoryFileOpenCount );
  496. Vcb->RootDcb->Specific.Dcb.DirectoryFile = NULL;
  497. FatSetFileObject( DirectoryFileObject, UnopenedFileObject, NULL, NULL );
  498. ObDereferenceObject( DirectoryFileObject );
  499. ExFreePool( FatAllocateCloseContext( Vcb));
  500. }
  501. //
  502. // Rundown stale child Fcbs that may be hanging around. Yes, this
  503. // can happen. No, the create path isn't perfectly defensive about
  504. // tearing down branches built up on creates that don't wind up
  505. // succeeding. Normal system operation usually winds up having
  506. // cleaned them out through re-visiting, but ...
  507. //
  508. // Just pick off Fcbs from the bottom of the tree until we run out.
  509. // Then we delete the root Dcb.
  510. //
  511. while( (Fcb = FatGetNextFcbBottomUp( IrpContext, NULL, Vcb->RootDcb )) != Vcb->RootDcb ) {
  512. FatDeleteFcb( IrpContext, Fcb );
  513. }
  514. FatDeleteFcb( IrpContext, Vcb->RootDcb );
  515. Vcb->RootDcb = NULL;
  516. }
  517. //
  518. // Uninitialize the notify sychronization object.
  519. //
  520. FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
  521. //
  522. // Uninitialize the resource variable for the Vcb
  523. //
  524. FatDeleteResource( &Vcb->Resource );
  525. FatDeleteResource( &Vcb->ChangeBitMapResource );
  526. //
  527. // If allocation support has been setup, free it.
  528. //
  529. if (Vcb->FreeClusterBitMap.Buffer != NULL) {
  530. FatTearDownAllocationSupport( IrpContext, Vcb );
  531. }
  532. //
  533. // UnInitialize the Mcb structure that kept track of dirty fat sectors.
  534. //
  535. FsRtlUninitializeLargeMcb( &Vcb->DirtyFatMcb );
  536. //
  537. // Free the pool for the stached copy of the boot sector
  538. //
  539. if ( Vcb->First0x24BytesOfBootSector ) {
  540. ExFreePool( Vcb->First0x24BytesOfBootSector );
  541. Vcb->First0x24BytesOfBootSector = NULL;
  542. }
  543. //
  544. // Cancel the CleanVolume Timer and Dpc
  545. //
  546. (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
  547. (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
  548. //
  549. // Free the performance counters memory
  550. //
  551. ExFreePool( Vcb->Statistics );
  552. //
  553. // Clean out the tunneling cache
  554. //
  555. FsRtlDeleteTunnelCache(&Vcb->Tunnel);
  556. //
  557. // Dereference the target device object.
  558. //
  559. ObDereferenceObject( Vcb->TargetDeviceObject );
  560. //
  561. // We better have used all the close contexts we allocated. There could be
  562. // one remaining if we're doing teardown due to a final close coming in on
  563. // a directory file stream object. It will be freed on the way back up.
  564. //
  565. ASSERT( Vcb->CloseContextCount <= 1);
  566. //
  567. // And zero out the Vcb, this will help ensure that any stale data is
  568. // wiped clean
  569. //
  570. RtlZeroMemory( Vcb, sizeof(VCB) );
  571. //
  572. // return and tell the caller
  573. //
  574. DebugTrace(-1, Dbg, "FatDeleteVcb -> VOID\n", 0);
  575. return;
  576. }
  577. VOID
  578. FatCreateRootDcb (
  579. IN PIRP_CONTEXT IrpContext,
  580. IN PVCB Vcb
  581. )
  582. /*++
  583. Routine Description:
  584. This routine allocates, initializes, and inserts a new root DCB record
  585. into the in memory data structure.
  586. Arguments:
  587. Vcb - Supplies the Vcb to associate the new DCB under
  588. Return Value:
  589. None. The Vcb is modified in-place.
  590. --*/
  591. {
  592. PDCB Dcb;
  593. //
  594. // The following variables are used for abnormal unwind
  595. //
  596. PVOID UnwindStorage[2] = { NULL, NULL };
  597. PERESOURCE UnwindResource = NULL;
  598. PERESOURCE UnwindResource2 = NULL;
  599. PLARGE_MCB UnwindMcb = NULL;
  600. PFILE_OBJECT UnwindFileObject = NULL;
  601. DebugTrace(+1, Dbg, "FatCreateRootDcb, Vcb = %08lx\n", Vcb);
  602. try {
  603. //
  604. // Make sure we don't already have a root dcb for this vcb
  605. //
  606. if (Vcb->RootDcb != NULL) {
  607. DebugDump("Error trying to create multiple root dcbs\n", 0, Vcb);
  608. FatBugCheck( 0, 0, 0 );
  609. }
  610. //
  611. // Allocate a new DCB and zero it out, we use Dcb locally so we don't
  612. // have to continually reference through the Vcb
  613. //
  614. UnwindStorage[0] = Dcb = Vcb->RootDcb = FsRtlAllocatePoolWithTag( NonPagedPool,
  615. sizeof(DCB),
  616. TAG_FCB );
  617. RtlZeroMemory( Dcb, sizeof(DCB));
  618. UnwindStorage[1] =
  619. Dcb->NonPaged = FatAllocateNonPagedFcb();
  620. RtlZeroMemory( Dcb->NonPaged, sizeof( NON_PAGED_FCB ) );
  621. //
  622. // Set the proper node type code, node byte size, and call backs
  623. //
  624. Dcb->Header.NodeTypeCode = FAT_NTC_ROOT_DCB;
  625. Dcb->Header.NodeByteSize = sizeof(DCB);
  626. Dcb->FcbCondition = FcbGood;
  627. //
  628. // The parent Dcb, initial state, open count, dirent location
  629. // information, and directory change count fields are already zero so
  630. // we can skip setting them
  631. //
  632. //
  633. // Initialize the resource variable
  634. //
  635. UnwindResource =
  636. Dcb->Header.Resource = FatAllocateResource();
  637. //
  638. // Initialize the PagingIo Resource. We no longer use the FsRtl common
  639. // shared pool because this led to a) deadlocks due to cases where files
  640. // and their parent directories shared a resource and b) there is no way
  641. // to anticipate inter-driver induced deadlock via recursive operation.
  642. //
  643. UnwindResource2 =
  644. Dcb->Header.PagingIoResource = FatAllocateResource();
  645. //
  646. // The root Dcb has an empty parent dcb links field
  647. //
  648. InitializeListHead( &Dcb->ParentDcbLinks );
  649. //
  650. // Set the Vcb
  651. //
  652. Dcb->Vcb = Vcb;
  653. //
  654. // initialize the parent dcb queue.
  655. //
  656. InitializeListHead( &Dcb->Specific.Dcb.ParentDcbQueue );
  657. //
  658. // Set the full file name up.
  659. //
  660. Dcb->FullFileName.Buffer = L"\\";
  661. Dcb->FullFileName.Length = (USHORT)2;
  662. Dcb->FullFileName.MaximumLength = (USHORT)4;
  663. Dcb->ShortName.Name.Oem.Buffer = "\\";
  664. Dcb->ShortName.Name.Oem.Length = (USHORT)1;
  665. Dcb->ShortName.Name.Oem.MaximumLength = (USHORT)2;
  666. //
  667. // Construct a lie about file properties since we don't
  668. // have a proper "." entry to look at.
  669. //
  670. Dcb->DirentFatFlags = FILE_ATTRIBUTE_DIRECTORY;
  671. //
  672. // Initialize Advanced FCB Header fields
  673. //
  674. ExInitializeFastMutex( &Dcb->NonPaged->AdvancedFcbHeaderMutex );
  675. FsRtlSetupAdvancedHeader( &Dcb->Header,
  676. &Dcb->NonPaged->AdvancedFcbHeaderMutex );
  677. //
  678. // Initialize the Mcb, and setup its mapping. Note that the root
  679. // directory is a fixed size so we can set it everything up now.
  680. //
  681. FsRtlInitializeLargeMcb( &Dcb->Mcb, NonPagedPool );
  682. UnwindMcb = &Dcb->Mcb;
  683. if (FatIsFat32(Vcb)) {
  684. //
  685. // The first cluster of fat32 roots comes from the BPB
  686. //
  687. Dcb->FirstClusterOfFile = Vcb->Bpb.RootDirFirstCluster;
  688. } else {
  689. FatAddMcbEntry( Vcb, &Dcb->Mcb,
  690. 0,
  691. FatRootDirectoryLbo( &Vcb->Bpb ),
  692. FatRootDirectorySize( &Vcb->Bpb ));
  693. }
  694. if (FatIsFat32(Vcb)) {
  695. //
  696. // Find the size of the fat32 root. As a side-effect, this will create
  697. // MCBs for the entire root. In the process of doing this, we may
  698. // discover that the FAT chain is bogus and raise corruption.
  699. //
  700. Dcb->Header.AllocationSize.LowPart = 0xFFFFFFFF;
  701. FatLookupFileAllocationSize( IrpContext, Dcb);
  702. Dcb->Header.FileSize.QuadPart =
  703. Dcb->Header.AllocationSize.QuadPart;
  704. } else {
  705. //
  706. // set the allocation size to real size of the root directory
  707. //
  708. Dcb->Header.FileSize.QuadPart =
  709. Dcb->Header.AllocationSize.QuadPart = FatRootDirectorySize( &Vcb->Bpb );
  710. }
  711. //
  712. // Set our two create dirent aids to represent that we have yet to
  713. // enumerate the directory for never used or deleted dirents.
  714. //
  715. Dcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
  716. Dcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
  717. //
  718. // Setup the free dirent bitmap buffer.
  719. //
  720. RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
  721. NULL,
  722. 0 );
  723. FatCheckFreeDirentBitmap( IrpContext, Dcb );
  724. } finally {
  725. DebugUnwind( FatCreateRootDcb );
  726. //
  727. // If this is an abnormal termination then undo our work
  728. //
  729. if (AbnormalTermination()) {
  730. ULONG i;
  731. if (UnwindFileObject != NULL) { ObDereferenceObject( UnwindFileObject ); }
  732. if (UnwindMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindMcb ); }
  733. if (UnwindResource != NULL) { FatFreeResource( UnwindResource ); }
  734. if (UnwindResource2 != NULL) { FatFreeResource( UnwindResource2 ); }
  735. for (i = 0; i < sizeof(UnwindStorage)/sizeof(PVOID); i += 1) {
  736. if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
  737. }
  738. //
  739. // Re-zero the entry in the Vcb.
  740. //
  741. Vcb->RootDcb = NULL;
  742. }
  743. DebugTrace(-1, Dbg, "FatCreateRootDcb -> %8lx\n", Dcb);
  744. }
  745. return;
  746. }
  747. PFCB
  748. FatCreateFcb (
  749. IN PIRP_CONTEXT IrpContext,
  750. IN PVCB Vcb,
  751. IN PDCB ParentDcb,
  752. IN ULONG LfnOffsetWithinDirectory,
  753. IN ULONG DirentOffsetWithinDirectory,
  754. IN PDIRENT Dirent,
  755. IN PUNICODE_STRING Lfn OPTIONAL,
  756. IN BOOLEAN IsPagingFile,
  757. IN BOOLEAN SingleResource
  758. )
  759. /*++
  760. Routine Description:
  761. This routine allocates, initializes, and inserts a new Fcb record into
  762. the in-memory data structures.
  763. Arguments:
  764. Vcb - Supplies the Vcb to associate the new FCB under.
  765. ParentDcb - Supplies the parent dcb that the new FCB is under.
  766. LfnOffsetWithinDirectory - Supplies the offset of the LFN. If there is
  767. no LFN associated with this file then this value is same as
  768. DirentOffsetWithinDirectory.
  769. DirentOffsetWithinDirectory - Supplies the offset, in bytes from the
  770. start of the directory file where the dirent for the fcb is located
  771. Dirent - Supplies the dirent for the fcb being created
  772. Lfn - Supplies a long UNICODE name associated with this file.
  773. IsPagingFile - Indicates if we are creating an FCB for a paging file
  774. or some other type of file.
  775. SingleResource - Indicates if this Fcb should share a single resource
  776. as both main and paging.
  777. Return Value:
  778. PFCB - Returns a pointer to the newly allocated FCB
  779. --*/
  780. {
  781. PFCB Fcb;
  782. POOL_TYPE PoolType;
  783. //
  784. // The following variables are used for abnormal unwind
  785. //
  786. PVOID UnwindStorage[2] = { NULL, NULL };
  787. PERESOURCE UnwindResource = NULL;
  788. PERESOURCE UnwindResource2 = NULL;
  789. PLIST_ENTRY UnwindEntryList = NULL;
  790. PLARGE_MCB UnwindMcb = NULL;
  791. PFILE_LOCK UnwindFileLock = NULL;
  792. POPLOCK UnwindOplock = NULL;
  793. DebugTrace(+1, Dbg, "FatCreateFcb\n", 0);
  794. try {
  795. //
  796. // Determine the pool type we should be using for the fcb and the
  797. // mcb structure
  798. //
  799. if (IsPagingFile) {
  800. PoolType = NonPagedPool;
  801. Fcb = UnwindStorage[0] = FsRtlAllocatePoolWithTag( NonPagedPool,
  802. sizeof(FCB),
  803. TAG_FCB );
  804. } else {
  805. PoolType = PagedPool;
  806. Fcb = UnwindStorage[0] = FatAllocateFcb();
  807. }
  808. //
  809. // ... and zero it out
  810. //
  811. RtlZeroMemory( Fcb, sizeof(FCB) );
  812. UnwindStorage[1] =
  813. Fcb->NonPaged = FatAllocateNonPagedFcb();
  814. RtlZeroMemory( Fcb->NonPaged, sizeof( NON_PAGED_FCB ) );
  815. //
  816. // Set the proper node type code, node byte size, and call backs
  817. //
  818. Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
  819. Fcb->Header.NodeByteSize = sizeof(FCB);
  820. Fcb->FcbCondition = FcbGood;
  821. //
  822. // Check to see if we need to set the Fcb state to indicate that this
  823. // is a paging/system file. This will prevent it from being opened
  824. // again.
  825. //
  826. if (IsPagingFile) {
  827. SetFlag( Fcb->FcbState, FCB_STATE_PAGING_FILE | FCB_STATE_SYSTEM_FILE );
  828. }
  829. //
  830. // The initial state, open count, and segment objects fields are already
  831. // zero so we can skip setting them
  832. //
  833. //
  834. // Initialize the resource variable
  835. //
  836. UnwindResource =
  837. Fcb->Header.Resource = FatAllocateResource();
  838. //
  839. // Initialize the PagingIo Resource. We no longer use the FsRtl common
  840. // shared pool because this led to a) deadlocks due to cases where files
  841. // and their parent directories shared a resource and b) there is no way
  842. // to anticipate inter-driver induced deadlock via recursive operation.
  843. //
  844. if (SingleResource) {
  845. Fcb->Header.PagingIoResource = Fcb->Header.Resource;
  846. } else {
  847. UnwindResource2 =
  848. Fcb->Header.PagingIoResource = FatAllocateResource();
  849. }
  850. //
  851. // Insert this fcb into our parent dcb's queue.
  852. //
  853. // There is a deep reason why this goes on the tail, to allow us
  854. // to easily enumerate all child directories before child files.
  855. // This is important to let us maintain whole-volume lockorder
  856. // via BottomUp enumeration.
  857. //
  858. InsertTailList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
  859. &Fcb->ParentDcbLinks );
  860. UnwindEntryList = &Fcb->ParentDcbLinks;
  861. //
  862. // Point back to our parent dcb
  863. //
  864. Fcb->ParentDcb = ParentDcb;
  865. //
  866. // Set the Vcb
  867. //
  868. Fcb->Vcb = Vcb;
  869. //
  870. // Set the dirent offset within the directory
  871. //
  872. Fcb->LfnOffsetWithinDirectory = LfnOffsetWithinDirectory;
  873. Fcb->DirentOffsetWithinDirectory = DirentOffsetWithinDirectory;
  874. //
  875. // Set the DirentFatFlags and LastWriteTime
  876. //
  877. Fcb->DirentFatFlags = Dirent->Attributes;
  878. Fcb->LastWriteTime = FatFatTimeToNtTime( IrpContext,
  879. Dirent->LastWriteTime,
  880. 0 );
  881. //
  882. // These fields are only non-zero when in Chicago mode.
  883. //
  884. if (FatData.ChicagoMode) {
  885. LARGE_INTEGER FatSystemJanOne1980;
  886. //
  887. // If either date is possibly zero, get the system
  888. // version of 1/1/80.
  889. //
  890. if ((((PUSHORT)Dirent)[9] & ((PUSHORT)Dirent)[8]) == 0) {
  891. ExLocalTimeToSystemTime( &FatJanOne1980,
  892. &FatSystemJanOne1980 );
  893. }
  894. //
  895. // Only do the really hard work if this field is non-zero.
  896. //
  897. if (((PUSHORT)Dirent)[9] != 0) {
  898. Fcb->LastAccessTime =
  899. FatFatDateToNtTime( IrpContext,
  900. Dirent->LastAccessDate );
  901. } else {
  902. Fcb->LastAccessTime = FatSystemJanOne1980;
  903. }
  904. //
  905. // Only do the really hard work if this field is non-zero.
  906. //
  907. if (((PUSHORT)Dirent)[8] != 0) {
  908. Fcb->CreationTime =
  909. FatFatTimeToNtTime( IrpContext,
  910. Dirent->CreationTime,
  911. Dirent->CreationMSec );
  912. } else {
  913. Fcb->CreationTime = FatSystemJanOne1980;
  914. }
  915. }
  916. //
  917. // Initialize Advanced FCB Header fields
  918. //
  919. ExInitializeFastMutex( &Fcb->NonPaged->AdvancedFcbHeaderMutex );
  920. FsRtlSetupAdvancedHeader( &Fcb->Header,
  921. &Fcb->NonPaged->AdvancedFcbHeaderMutex );
  922. //
  923. // To make FAT match the present functionality of NTFS, disable
  924. // stream contexts on paging files (nealch 7/2/01)
  925. //
  926. if (IsPagingFile) {
  927. ClearFlag( Fcb->Header.Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS );
  928. }
  929. //
  930. // Initialize the Mcb
  931. //
  932. FsRtlInitializeLargeMcb( &Fcb->Mcb, PoolType );
  933. UnwindMcb = &Fcb->Mcb;
  934. //
  935. // Set the file size, valid data length, first cluster of file,
  936. // and allocation size based on the information stored in the dirent
  937. //
  938. Fcb->Header.FileSize.LowPart = Dirent->FileSize;
  939. Fcb->Header.ValidDataLength.LowPart = Dirent->FileSize;
  940. Fcb->ValidDataToDisk = Dirent->FileSize;
  941. Fcb->FirstClusterOfFile = (ULONG)Dirent->FirstClusterOfFile;
  942. if ( FatIsFat32(Vcb) ) {
  943. Fcb->FirstClusterOfFile += Dirent->FirstClusterOfFileHi << 16;
  944. }
  945. if ( Fcb->FirstClusterOfFile == 0 ) {
  946. Fcb->Header.AllocationSize.QuadPart = 0;
  947. } else {
  948. Fcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
  949. }
  950. //
  951. // Initialize the Fcb's file lock record
  952. //
  953. FsRtlInitializeFileLock( &Fcb->Specific.Fcb.FileLock, NULL, NULL );
  954. UnwindFileLock = &Fcb->Specific.Fcb.FileLock;
  955. //
  956. // Initialize the oplock structure.
  957. //
  958. FsRtlInitializeOplock( &Fcb->Specific.Fcb.Oplock );
  959. UnwindOplock = &Fcb->Specific.Fcb.Oplock;
  960. //
  961. // Indicate that Fast I/O is possible
  962. //
  963. Fcb->Header.IsFastIoPossible = TRUE;
  964. //
  965. // Set the file names. This must be the last thing we do.
  966. //
  967. FatConstructNamesInFcb( IrpContext,
  968. Fcb,
  969. Dirent,
  970. Lfn );
  971. //
  972. // Drop the shortname hint so prefix searches can figure out
  973. // what they found
  974. //
  975. Fcb->ShortName.FileNameDos = TRUE;
  976. } finally {
  977. DebugUnwind( FatCreateFcb );
  978. //
  979. // If this is an abnormal termination then undo our work
  980. //
  981. if (AbnormalTermination()) {
  982. ULONG i;
  983. if (UnwindOplock != NULL) { FsRtlUninitializeOplock( UnwindOplock ); }
  984. if (UnwindFileLock != NULL) { FsRtlUninitializeFileLock( UnwindFileLock ); }
  985. if (UnwindMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindMcb ); }
  986. if (UnwindEntryList != NULL) { RemoveEntryList( UnwindEntryList ); }
  987. if (UnwindResource != NULL) { FatFreeResource( UnwindResource ); }
  988. if (UnwindResource2 != NULL) { FatFreeResource( UnwindResource2 ); }
  989. for (i = 0; i < sizeof(UnwindStorage)/sizeof(PVOID); i += 1) {
  990. if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
  991. }
  992. }
  993. DebugTrace(-1, Dbg, "FatCreateFcb -> %08lx\n", Fcb);
  994. }
  995. //
  996. // return and tell the caller
  997. //
  998. return Fcb;
  999. }
  1000. PDCB
  1001. FatCreateDcb (
  1002. IN PIRP_CONTEXT IrpContext,
  1003. IN PVCB Vcb,
  1004. IN PDCB ParentDcb,
  1005. IN ULONG LfnOffsetWithinDirectory,
  1006. IN ULONG DirentOffsetWithinDirectory,
  1007. IN PDIRENT Dirent,
  1008. IN PUNICODE_STRING Lfn OPTIONAL
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This routine allocates, initializes, and inserts a new Dcb record into
  1013. the in memory data structures.
  1014. Arguments:
  1015. Vcb - Supplies the Vcb to associate the new DCB under.
  1016. ParentDcb - Supplies the parent dcb that the new DCB is under.
  1017. LfnOffsetWithinDirectory - Supplies the offset of the LFN. If there is
  1018. no LFN associated with this file then this value is same as
  1019. DirentOffsetWithinDirectory.
  1020. DirentOffsetWithinDirectory - Supplies the offset, in bytes from the
  1021. start of the directory file where the dirent for the fcb is located
  1022. Dirent - Supplies the dirent for the dcb being created
  1023. FileName - Supplies the file name of the file relative to the directory
  1024. it's in (e.g., the file \config.sys is called "CONFIG.SYS" without
  1025. the preceding backslash).
  1026. Lfn - Supplies a long UNICODE name associated with this directory.
  1027. Return Value:
  1028. PDCB - Returns a pointer to the newly allocated DCB
  1029. --*/
  1030. {
  1031. PDCB Dcb;
  1032. //
  1033. // The following variables are used for abnormal unwind
  1034. //
  1035. PVOID UnwindStorage[2] = { NULL, NULL };
  1036. PERESOURCE UnwindResource = NULL;
  1037. PERESOURCE UnwindResource2 = NULL;
  1038. PLIST_ENTRY UnwindEntryList = NULL;
  1039. PLARGE_MCB UnwindMcb = NULL;
  1040. DebugTrace(+1, Dbg, "FatCreateDcb\n", 0);
  1041. try {
  1042. //
  1043. // assert that the only time we are called is if wait is true
  1044. //
  1045. ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  1046. //
  1047. // Allocate a new DCB, and zero it out
  1048. //
  1049. UnwindStorage[0] = Dcb = FatAllocateFcb();
  1050. RtlZeroMemory( Dcb, sizeof(DCB) );
  1051. UnwindStorage[1] =
  1052. Dcb->NonPaged = FatAllocateNonPagedFcb();
  1053. RtlZeroMemory( Dcb->NonPaged, sizeof( NON_PAGED_FCB ) );
  1054. //
  1055. // Set the proper node type code, node byte size and call backs
  1056. //
  1057. Dcb->Header.NodeTypeCode = FAT_NTC_DCB;
  1058. Dcb->Header.NodeByteSize = sizeof(DCB);
  1059. Dcb->FcbCondition = FcbGood;
  1060. //
  1061. // The initial state, open count, and directory change count fields are
  1062. // already zero so we can skip setting them
  1063. //
  1064. //
  1065. // Initialize the resource variable
  1066. //
  1067. UnwindResource =
  1068. Dcb->Header.Resource = FatAllocateResource();
  1069. //
  1070. // Initialize the PagingIo Resource. We no longer use the FsRtl common
  1071. // shared pool because this led to a) deadlocks due to cases where files
  1072. // and their parent directories shared a resource and b) there is no way
  1073. // to anticipate inter-driver induced deadlock via recursive operation.
  1074. //
  1075. UnwindResource2 =
  1076. Dcb->Header.PagingIoResource = FatAllocateResource();
  1077. //
  1078. // Insert this Dcb into our parent dcb's queue
  1079. //
  1080. // There is a deep reason why this goes on the head, to allow us
  1081. // to easily enumerate all child directories before child files.
  1082. // This is important to let us maintain whole-volume lockorder
  1083. // via BottomUp enumeration.
  1084. //
  1085. InsertHeadList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
  1086. &Dcb->ParentDcbLinks );
  1087. UnwindEntryList = &Dcb->ParentDcbLinks;
  1088. //
  1089. // Point back to our parent dcb
  1090. //
  1091. Dcb->ParentDcb = ParentDcb;
  1092. //
  1093. // Set the Vcb
  1094. //
  1095. Dcb->Vcb = Vcb;
  1096. //
  1097. // Set the dirent offset within the directory
  1098. //
  1099. Dcb->LfnOffsetWithinDirectory = LfnOffsetWithinDirectory;
  1100. Dcb->DirentOffsetWithinDirectory = DirentOffsetWithinDirectory;
  1101. //
  1102. // Set the DirentFatFlags and LastWriteTime
  1103. //
  1104. Dcb->DirentFatFlags = Dirent->Attributes;
  1105. Dcb->LastWriteTime = FatFatTimeToNtTime( IrpContext,
  1106. Dirent->LastWriteTime,
  1107. 0 );
  1108. //
  1109. // These fields are only non-zero when in Chicago mode.
  1110. //
  1111. if (FatData.ChicagoMode) {
  1112. LARGE_INTEGER FatSystemJanOne1980;
  1113. //
  1114. // If either date is possibly zero, get the system
  1115. // version of 1/1/80.
  1116. //
  1117. if ((((PUSHORT)Dirent)[9] & ((PUSHORT)Dirent)[8]) == 0) {
  1118. ExLocalTimeToSystemTime( &FatJanOne1980,
  1119. &FatSystemJanOne1980 );
  1120. }
  1121. //
  1122. // Only do the really hard work if this field is non-zero.
  1123. //
  1124. if (((PUSHORT)Dirent)[9] != 0) {
  1125. Dcb->LastAccessTime =
  1126. FatFatDateToNtTime( IrpContext,
  1127. Dirent->LastAccessDate );
  1128. } else {
  1129. Dcb->LastAccessTime = FatSystemJanOne1980;
  1130. }
  1131. //
  1132. // Only do the really hard work if this field is non-zero.
  1133. //
  1134. if (((PUSHORT)Dirent)[8] != 0) {
  1135. Dcb->CreationTime =
  1136. FatFatTimeToNtTime( IrpContext,
  1137. Dirent->CreationTime,
  1138. Dirent->CreationMSec );
  1139. } else {
  1140. Dcb->CreationTime = FatSystemJanOne1980;
  1141. }
  1142. }
  1143. //
  1144. // Initialize Advanced FCB Header fields
  1145. //
  1146. ExInitializeFastMutex( &Dcb->NonPaged->AdvancedFcbHeaderMutex );
  1147. FsRtlSetupAdvancedHeader( &Dcb->Header,
  1148. &Dcb->NonPaged->AdvancedFcbHeaderMutex );
  1149. //
  1150. // Initialize the Mcb
  1151. //
  1152. FsRtlInitializeLargeMcb( &Dcb->Mcb, PagedPool );
  1153. UnwindMcb = &Dcb->Mcb;
  1154. //
  1155. // Set the file size, first cluster of file, and allocation size
  1156. // based on the information stored in the dirent
  1157. //
  1158. Dcb->FirstClusterOfFile = (ULONG)Dirent->FirstClusterOfFile;
  1159. if ( FatIsFat32(Dcb->Vcb) ) {
  1160. Dcb->FirstClusterOfFile += Dirent->FirstClusterOfFileHi << 16;
  1161. }
  1162. if ( Dcb->FirstClusterOfFile == 0 ) {
  1163. Dcb->Header.AllocationSize.QuadPart = 0;
  1164. } else {
  1165. Dcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
  1166. }
  1167. // initialize the notify queues, and the parent dcb queue.
  1168. //
  1169. InitializeListHead( &Dcb->Specific.Dcb.ParentDcbQueue );
  1170. //
  1171. // Setup the free dirent bitmap buffer. Since we don't know the
  1172. // size of the directory, leave it zero for now.
  1173. //
  1174. RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
  1175. NULL,
  1176. 0 );
  1177. //
  1178. // Set our two create dirent aids to represent that we have yet to
  1179. // enumerate the directory for never used or deleted dirents.
  1180. //
  1181. Dcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
  1182. Dcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
  1183. //
  1184. // Postpone initializing the cache map until we need to do a read/write
  1185. // of the directory file.
  1186. //
  1187. // set the file names. This must be the last thing we do.
  1188. //
  1189. FatConstructNamesInFcb( IrpContext,
  1190. Dcb,
  1191. Dirent,
  1192. Lfn );
  1193. } finally {
  1194. DebugUnwind( FatCreateDcb );
  1195. //
  1196. // If this is an abnormal termination then undo our work
  1197. //
  1198. if (AbnormalTermination()) {
  1199. ULONG i;
  1200. if (UnwindMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindMcb ); }
  1201. if (UnwindEntryList != NULL) { RemoveEntryList( UnwindEntryList ); }
  1202. if (UnwindResource != NULL) { FatFreeResource( UnwindResource ); }
  1203. if (UnwindResource2 != NULL) { FatFreeResource( UnwindResource2 ); }
  1204. for (i = 0; i < sizeof(UnwindStorage)/sizeof(PVOID); i += 1) {
  1205. if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
  1206. }
  1207. }
  1208. DebugTrace(-1, Dbg, "FatCreateDcb -> %08lx\n", Dcb);
  1209. }
  1210. //
  1211. // return and tell the caller
  1212. //
  1213. DebugTrace(-1, Dbg, "FatCreateDcb -> %08lx\n", Dcb);
  1214. return Dcb;
  1215. }
  1216. VOID
  1217. FatDeleteFcb_Real (
  1218. IN PIRP_CONTEXT IrpContext,
  1219. IN PFCB Fcb
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. This routine deallocates and removes an FCB, DCB, or ROOT DCB record
  1224. from Fat's in-memory data structures. It also will remove all
  1225. associated underlings (i.e., Notify irps, and child FCB/DCB records).
  1226. Arguments:
  1227. Fcb - Supplies the FCB/DCB/ROOT DCB to be removed
  1228. Return Value:
  1229. None
  1230. --*/
  1231. {
  1232. DebugTrace(+1, Dbg, "FatDeleteFcb, Fcb = %08lx\n", Fcb);
  1233. //
  1234. // We can only delete this record if the open count is zero.
  1235. //
  1236. if (Fcb->OpenCount != 0) {
  1237. DebugDump("Error deleting Fcb, Still Open\n", 0, Fcb);
  1238. FatBugCheck( 0, 0, 0 );
  1239. }
  1240. //
  1241. // If this is a DCB then remove every Notify record from the two
  1242. // notify queues
  1243. //
  1244. if ((Fcb->Header.NodeTypeCode == FAT_NTC_DCB) ||
  1245. (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB)) {
  1246. //
  1247. // If we allocated a free dirent bitmap buffer, free it.
  1248. //
  1249. if ((Fcb->Specific.Dcb.FreeDirentBitmap.Buffer != NULL) &&
  1250. (Fcb->Specific.Dcb.FreeDirentBitmap.Buffer !=
  1251. &Fcb->Specific.Dcb.FreeDirentBitmapBuffer[0])) {
  1252. ExFreePool(Fcb->Specific.Dcb.FreeDirentBitmap.Buffer);
  1253. }
  1254. ASSERT( Fcb->Specific.Dcb.DirectoryFileOpenCount == 0 );
  1255. ASSERT( IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) );
  1256. ASSERT( NULL == Fcb->Specific.Dcb.DirectoryFile);
  1257. } else {
  1258. //
  1259. // Uninitialize the byte range file locks and opportunistic locks
  1260. //
  1261. FsRtlUninitializeFileLock( &Fcb->Specific.Fcb.FileLock );
  1262. FsRtlUninitializeOplock( &Fcb->Specific.Fcb.Oplock );
  1263. }
  1264. //
  1265. // Release any Filter Context structures associated with this FCB
  1266. //
  1267. FsRtlTeardownPerStreamContexts( &Fcb->Header );
  1268. //
  1269. // Uninitialize the Mcb
  1270. //
  1271. FsRtlUninitializeLargeMcb( &Fcb->Mcb );
  1272. //
  1273. // If this is not the root dcb then we need to remove ourselves from
  1274. // our parents Dcb queue
  1275. //
  1276. if (Fcb->Header.NodeTypeCode != FAT_NTC_ROOT_DCB) {
  1277. RemoveEntryList( &(Fcb->ParentDcbLinks) );
  1278. }
  1279. //
  1280. // Remove the entry from the splay table if there is still is one.
  1281. //
  1282. if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) {
  1283. FatRemoveNames( IrpContext, Fcb );
  1284. }
  1285. //
  1286. // Free the file name pool if allocated.
  1287. //
  1288. if (Fcb->Header.NodeTypeCode != FAT_NTC_ROOT_DCB) {
  1289. //
  1290. // If we blew up at inconvenient times, the shortname
  1291. // could be null even though you will *never* see this
  1292. // normally. Rename is a good example of this case.
  1293. //
  1294. if (Fcb->ShortName.Name.Oem.Buffer) {
  1295. ExFreePool( Fcb->ShortName.Name.Oem.Buffer );
  1296. }
  1297. if (Fcb->FullFileName.Buffer) {
  1298. ExFreePool( Fcb->FullFileName.Buffer );
  1299. }
  1300. }
  1301. if (Fcb->ExactCaseLongName.Buffer) {
  1302. ExFreePool(Fcb->ExactCaseLongName.Buffer);
  1303. }
  1304. #ifdef SYSCACHE_COMPILE
  1305. if (Fcb->WriteMask) {
  1306. ExFreePool( Fcb->WriteMask );
  1307. }
  1308. #endif
  1309. //
  1310. // Finally deallocate the Fcb and non-paged fcb records
  1311. //
  1312. FatFreeResource( Fcb->Header.Resource );
  1313. if (Fcb->Header.PagingIoResource != Fcb->Header.Resource) {
  1314. FatFreeResource( Fcb->Header.PagingIoResource );
  1315. }
  1316. //
  1317. // If an Event was allocated, get rid of it.
  1318. //
  1319. if (Fcb->NonPaged->OutstandingAsyncEvent) {
  1320. ExFreePool( Fcb->NonPaged->OutstandingAsyncEvent );
  1321. }
  1322. FatFreeNonPagedFcb( Fcb->NonPaged );
  1323. FatFreeFcb( Fcb );
  1324. //
  1325. // and return to our caller
  1326. //
  1327. DebugTrace(-1, Dbg, "FatDeleteFcb -> VOID\n", 0);
  1328. }
  1329. PCCB
  1330. FatCreateCcb (
  1331. IN PIRP_CONTEXT IrpContext
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. This routine creates a new CCB record
  1336. Arguments:
  1337. Return Value:
  1338. CCB - returns a pointer to the newly allocate CCB
  1339. --*/
  1340. {
  1341. PCCB Ccb;
  1342. DebugTrace(+1, Dbg, "FatCreateCcb\n", 0);
  1343. //
  1344. // Allocate a new CCB Record
  1345. //
  1346. Ccb = FatAllocateCcb();
  1347. RtlZeroMemory( Ccb, sizeof(CCB) );
  1348. //
  1349. // Set the proper node type code and node byte size
  1350. //
  1351. Ccb->NodeTypeCode = FAT_NTC_CCB;
  1352. Ccb->NodeByteSize = sizeof(CCB);
  1353. //
  1354. // return and tell the caller
  1355. //
  1356. DebugTrace(-1, Dbg, "FatCreateCcb -> %08lx\n", Ccb);
  1357. UNREFERENCED_PARAMETER( IrpContext );
  1358. return Ccb;
  1359. }
  1360. VOID
  1361. FatDeallocateCcbStrings(
  1362. IN PCCB Ccb
  1363. )
  1364. /*++
  1365. Routine Description:
  1366. This routine deallocates CCB query templates
  1367. Arguments:
  1368. Ccb - Supplies the CCB
  1369. Return Value:
  1370. None
  1371. --*/
  1372. {
  1373. //
  1374. // If we allocated query template buffers, deallocate them now.
  1375. //
  1376. if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_UNICODE)) {
  1377. ASSERT( Ccb->UnicodeQueryTemplate.Buffer);
  1378. ASSERT( !FlagOn( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT));
  1379. RtlFreeUnicodeString( &Ccb->UnicodeQueryTemplate );
  1380. }
  1381. if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT)) {
  1382. ASSERT( Ccb->OemQueryTemplate.Wild.Buffer );
  1383. ASSERT( !FlagOn( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT));
  1384. RtlFreeOemString( &Ccb->OemQueryTemplate.Wild );
  1385. }
  1386. ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT | CCB_FLAG_FREE_UNICODE);
  1387. }
  1388. VOID
  1389. FatDeleteCcb_Real (
  1390. IN PIRP_CONTEXT IrpContext,
  1391. IN PCCB Ccb
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. This routine deallocates and removes the specified CCB record
  1396. from the Fat in memory data structures
  1397. Arguments:
  1398. Ccb - Supplies the CCB to remove
  1399. Return Value:
  1400. None
  1401. --*/
  1402. {
  1403. DebugTrace(+1, Dbg, "FatDeleteCcb, Ccb = %08lx\n", Ccb);
  1404. FatDeallocateCcbStrings( Ccb);
  1405. //
  1406. // Deallocate the Ccb record
  1407. //
  1408. FatFreeCcb( Ccb );
  1409. //
  1410. // return and tell the caller
  1411. //
  1412. DebugTrace(-1, Dbg, "FatDeleteCcb -> VOID\n", 0);
  1413. UNREFERENCED_PARAMETER( IrpContext );
  1414. return;
  1415. }
  1416. PIRP_CONTEXT
  1417. FatCreateIrpContext (
  1418. IN PIRP Irp,
  1419. IN BOOLEAN Wait
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This routine creates a new IRP_CONTEXT record
  1424. Arguments:
  1425. Irp - Supplies the originating Irp.
  1426. Wait - Supplies the wait value to store in the context
  1427. Return Value:
  1428. PIRP_CONTEXT - returns a pointer to the newly allocate IRP_CONTEXT Record
  1429. --*/
  1430. {
  1431. PIRP_CONTEXT IrpContext;
  1432. PIO_STACK_LOCATION IrpSp;
  1433. DebugTrace(+1, Dbg, "FatCreateIrpContext\n", 0);
  1434. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1435. //
  1436. // The only operations a filesystem device object should ever receive
  1437. // are create/teardown of fsdo handles and operations which do not
  1438. // occur in the context of fileobjects (i.e., mount).
  1439. //
  1440. if (FatDeviceIsFatFsdo( IrpSp->DeviceObject)) {
  1441. if (IrpSp->FileObject != NULL &&
  1442. IrpSp->MajorFunction != IRP_MJ_CREATE &&
  1443. IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
  1444. IrpSp->MajorFunction != IRP_MJ_CLOSE) {
  1445. ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
  1446. }
  1447. ASSERT( IrpSp->FileObject != NULL ||
  1448. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1449. IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
  1450. IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
  1451. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1452. IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
  1453. IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
  1454. }
  1455. //
  1456. // Attemtp to allocate from the region first and failing that allocate
  1457. // from pool.
  1458. //
  1459. DebugDoit( FatFsdEntryCount += 1);
  1460. IrpContext = FatAllocateIrpContext();
  1461. //
  1462. // Zero out the irp context.
  1463. //
  1464. RtlZeroMemory( IrpContext, sizeof(IRP_CONTEXT) );
  1465. //
  1466. // Set the proper node type code and node byte size
  1467. //
  1468. IrpContext->NodeTypeCode = FAT_NTC_IRP_CONTEXT;
  1469. IrpContext->NodeByteSize = sizeof(IRP_CONTEXT);
  1470. //
  1471. // Set the originating Irp field
  1472. //
  1473. IrpContext->OriginatingIrp = Irp;
  1474. //
  1475. // Major/Minor Function codes
  1476. //
  1477. IrpContext->MajorFunction = IrpSp->MajorFunction;
  1478. IrpContext->MinorFunction = IrpSp->MinorFunction;
  1479. //
  1480. // Copy RealDevice for workque algorithms, and also set Write Through
  1481. // and Removable Media if there is a file object. Only file system
  1482. // control Irps won't have a file object, and they should all have
  1483. // a Vpb as the first IrpSp location.
  1484. //
  1485. if (IrpSp->FileObject != NULL) {
  1486. PVCB Vcb;
  1487. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1488. IrpContext->RealDevice = FileObject->DeviceObject;
  1489. Vcb = IrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT)(IrpSp->DeviceObject))->Vcb;
  1490. //
  1491. // See if the request is Write Through.
  1492. //
  1493. if (IsFileWriteThrough( FileObject, Vcb )) {
  1494. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
  1495. }
  1496. } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) {
  1497. IrpContext->RealDevice = IrpSp->Parameters.MountVolume.Vpb->RealDevice;
  1498. }
  1499. //
  1500. // Set the wait parameter
  1501. //
  1502. if (Wait) { SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); }
  1503. //
  1504. // Set the recursive file system call parameter. We set it true if
  1505. // the TopLevelIrp field in the thread local storage is not the current
  1506. // irp, otherwise we leave it as FALSE.
  1507. //
  1508. if ( IoGetTopLevelIrp() != Irp) {
  1509. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL);
  1510. }
  1511. //
  1512. // return and tell the caller
  1513. //
  1514. DebugTrace(-1, Dbg, "FatCreateIrpContext -> %08lx\n", IrpContext);
  1515. return IrpContext;
  1516. }
  1517. VOID
  1518. FatDeleteIrpContext_Real (
  1519. IN PIRP_CONTEXT IrpContext
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. This routine deallocates and removes the specified IRP_CONTEXT record
  1524. from the Fat in memory data structures. It should only be called
  1525. by FatCompleteRequest.
  1526. Arguments:
  1527. IrpContext - Supplies the IRP_CONTEXT to remove
  1528. Return Value:
  1529. None
  1530. --*/
  1531. {
  1532. DebugTrace(+1, Dbg, "FatDeleteIrpContext, IrpContext = %08lx\n", IrpContext);
  1533. ASSERT( IrpContext->NodeTypeCode == FAT_NTC_IRP_CONTEXT );
  1534. ASSERT( IrpContext->PinCount == 0 );
  1535. //
  1536. // If there is a FatIoContext that was allocated, free it.
  1537. //
  1538. if (IrpContext->FatIoContext != NULL) {
  1539. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
  1540. if (IrpContext->FatIoContext->ZeroMdl) {
  1541. IoFreeMdl( IrpContext->FatIoContext->ZeroMdl );
  1542. }
  1543. ExFreePool( IrpContext->FatIoContext );
  1544. }
  1545. }
  1546. //
  1547. // Drop the IrpContext.
  1548. //
  1549. FatFreeIrpContext( IrpContext );
  1550. //
  1551. // return and tell the caller
  1552. //
  1553. DebugTrace(-1, Dbg, "FatDeleteIrpContext -> VOID\n", 0);
  1554. return;
  1555. }
  1556. PFCB
  1557. FatGetNextFcbBottomUp (
  1558. IN PIRP_CONTEXT IrpContext,
  1559. IN PFCB Fcb OPTIONAL,
  1560. IN PFCB TerminationFcb
  1561. )
  1562. /*++
  1563. Routine Description:
  1564. This routine is used to iterate through Fcbs in a tree. In order to match
  1565. the lockorder for getting multiple Fcbs (so this can be used for acquiring
  1566. all Fcbs), this version does a bottom-up enumeration.
  1567. This is different than the old one, now called TopDown. The problem with
  1568. lockorder was very well hidden.
  1569. The transition rule is still pretty simple:
  1570. A) If you have an adjacent sibling, go to it
  1571. 1) Descend to its leftmost child
  1572. B) Else go to your parent
  1573. If this routine is called with in invalid TerminationFcb it will fail,
  1574. badly.
  1575. The TerminationFcb is the last Fcb returned in the enumeration.
  1576. This method is incompatible with the possibility that ancestors may vanish
  1577. based on operations done on the last returned node. For instance,
  1578. FatPurgeReferencedFileObjects cannot use BottomUp enumeration.
  1579. Arguments:
  1580. Fcb - Supplies the current Fcb. This is NULL if enumeration is starting.
  1581. TerminationFcb - The root Fcb of the tree in which the enumeration starts
  1582. and at which it inclusively stops.
  1583. Return Value:
  1584. The next Fcb in the enumeration, or NULL if Fcb was the final one.
  1585. --*/
  1586. {
  1587. PFCB NextFcb;
  1588. ASSERT( FatVcbAcquiredExclusive( IrpContext, TerminationFcb->Vcb ) ||
  1589. FlagOn( TerminationFcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
  1590. //
  1591. // Do we need to begin the enumeration?
  1592. //
  1593. if (Fcb != NULL) {
  1594. //
  1595. // Did we complete?
  1596. //
  1597. if (Fcb == TerminationFcb) {
  1598. return NULL;
  1599. }
  1600. //
  1601. // Do we have a sibling to return?
  1602. //
  1603. NextFcb = FatGetNextSibling( Fcb );
  1604. //
  1605. // If not, return our parent. We are done with this branch.
  1606. //
  1607. if (NextFcb == NULL) {
  1608. return Fcb->ParentDcb;
  1609. }
  1610. } else {
  1611. NextFcb = TerminationFcb;
  1612. }
  1613. //
  1614. // Decend to its furthest child (if it exists) and return it.
  1615. //
  1616. for (;
  1617. NodeType( NextFcb ) != FAT_NTC_FCB && FatGetFirstChild( NextFcb ) != NULL;
  1618. NextFcb = FatGetFirstChild( NextFcb )) {
  1619. }
  1620. return NextFcb;
  1621. }
  1622. PFCB
  1623. FatGetNextFcbTopDown (
  1624. IN PIRP_CONTEXT IrpContext,
  1625. IN PFCB Fcb,
  1626. IN PFCB TerminationFcb
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine is used to iterate through Fcbs in a tree, from the top down.
  1631. The rule is very simple:
  1632. A) If you have a child, go to it, else
  1633. B) If you have an older sibling, go to it, else
  1634. C) Go to your parent's older sibling.
  1635. If this routine is called with in invalid TerminationFcb it will fail,
  1636. badly.
  1637. The Termination Fcb is never returned. If it is the root of the tree you
  1638. are traversing, visit it first.
  1639. This routine never returns direct ancestors of Fcb, and thus is useful when
  1640. making Fcb's go away (which may tear up the tree).
  1641. Arguments:
  1642. Fcb - Supplies the current Fcb
  1643. TerminationFcb - The Fcb at which the enumeration should (non-inclusivly)
  1644. stop. Assumed to be a directory.
  1645. Return Value:
  1646. The next Fcb in the enumeration, or NULL if Fcb was the final one.
  1647. --*/
  1648. {
  1649. PFCB Sibling;
  1650. ASSERT( FatVcbAcquiredExclusive( IrpContext, Fcb->Vcb ) ||
  1651. FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
  1652. //
  1653. // If this was a directory (ie. not a file), get the child. If
  1654. // there aren't any children and this is our termination Fcb,
  1655. // return NULL.
  1656. //
  1657. if ( ((NodeType(Fcb) == FAT_NTC_DCB) ||
  1658. (NodeType(Fcb) == FAT_NTC_ROOT_DCB)) &&
  1659. !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) ) {
  1660. return FatGetFirstChild( Fcb );
  1661. }
  1662. //
  1663. // Were we only meant to do one iteration?
  1664. //
  1665. if ( Fcb == TerminationFcb ) {
  1666. return NULL;
  1667. }
  1668. Sibling = FatGetNextSibling(Fcb);
  1669. while (TRUE) {
  1670. //
  1671. // Do we still have an "older" sibling in this directory who is
  1672. // not the termination Fcb?
  1673. //
  1674. if ( Sibling != NULL ) {
  1675. return (Sibling != TerminationFcb) ? Sibling : NULL;
  1676. }
  1677. //
  1678. // OK, let's move on to out parent and see if he is the termination
  1679. // node or has any older siblings.
  1680. //
  1681. if ( Fcb->ParentDcb == TerminationFcb ) {
  1682. return NULL;
  1683. }
  1684. Fcb = Fcb->ParentDcb;
  1685. Sibling = FatGetNextSibling(Fcb);
  1686. }
  1687. }
  1688. BOOLEAN
  1689. FatCheckForDismount (
  1690. IN PIRP_CONTEXT IrpContext,
  1691. PVCB Vcb,
  1692. IN BOOLEAN Force
  1693. )
  1694. /*++
  1695. Routine Description:
  1696. This routine determines if a volume is ready for deletion. It
  1697. correctly synchronizes with creates en-route to the file system.
  1698. Arguments:
  1699. Vcb - Supplies the volume to examine
  1700. Force - Specifies whether we want this Vcb forcibly disconnected
  1701. from the driver stack if it will not be deleted (a new vpb will
  1702. be installed if neccesary). Caller is responsible for making
  1703. sure that the volume has been marked in such a way that attempts
  1704. to operate through the realdevice are blocked (i.e., move the vcb
  1705. out of the mounted state).
  1706. Return Value:
  1707. BOOLEAN - TRUE if the volume was deleted, FALSE otherwise.
  1708. --*/
  1709. {
  1710. KIRQL SavedIrql;
  1711. ULONG ResidualReferenceCount;
  1712. PVPB OldVpb;
  1713. BOOLEAN VcbDeleted = FALSE;
  1714. OldVpb = Vcb->Vpb;
  1715. //
  1716. // Now check for a zero Vpb count on an unmounted volume. These
  1717. // volumes will be deleted as they now have no file objects and
  1718. // there are no creates en route to this volume.
  1719. //
  1720. IoAcquireVpbSpinLock( &SavedIrql );
  1721. if (Vcb->Vpb->ReferenceCount == FAT_RESIDUAL_USER_REFERENCE && Vcb->OpenFileCount == 0) {
  1722. PVPB Vpb = Vcb->Vpb;
  1723. #if DBG
  1724. UNICODE_STRING VolumeLabel;
  1725. //
  1726. // Setup the VolumeLabel string
  1727. //
  1728. VolumeLabel.Length = Vcb->Vpb->VolumeLabelLength;
  1729. VolumeLabel.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  1730. VolumeLabel.Buffer = &Vcb->Vpb->VolumeLabel[0];
  1731. KdPrintEx((DPFLTR_FASTFAT_ID,
  1732. DPFLTR_INFO_LEVEL,
  1733. "FASTFAT: Dismounting Volume %Z\n",
  1734. &VolumeLabel));
  1735. #endif // DBG
  1736. //
  1737. // Clear the VPB_MOUNTED bit so that new creates will not come
  1738. // to this volume. We must leave the Vpb->DeviceObject field
  1739. // set until after the DeleteVcb call as two closes will
  1740. // have to make their way back to us.
  1741. //
  1742. // Note also that if we were called from close, it will take care
  1743. // of freeing the Vpb if it is not the primary one, otherwise
  1744. // if we were called from Create->Verify, IopParseDevice will
  1745. // take care of freeing the Vpb in its Reparse path.
  1746. //
  1747. ClearFlag( Vpb->Flags, VPB_MOUNTED );
  1748. //
  1749. // If this Vpb was locked, clear this flag now.
  1750. //
  1751. ClearFlag( Vpb->Flags, VPB_LOCKED );
  1752. //
  1753. // This will prevent anybody else from attempting to mount this
  1754. // volume. Also if this volume was mounted on a "wanna-be" real
  1755. // device object, keep anybody from following the link, and the Io
  1756. // system from deleting the Vpb.
  1757. //
  1758. if ((Vcb->CurrentDevice != Vpb->RealDevice) &&
  1759. (Vcb->CurrentDevice->Vpb == Vpb)) {
  1760. SetFlag( Vcb->CurrentDevice->Flags, DO_DEVICE_INITIALIZING );
  1761. SetFlag( Vpb->Flags, VPB_PERSISTENT );
  1762. }
  1763. IoReleaseVpbSpinLock( SavedIrql );
  1764. FatDeleteVcb( IrpContext, Vcb );
  1765. //
  1766. // Note, after deleting the Vcb per the comment above.
  1767. //
  1768. Vpb->DeviceObject = NULL;
  1769. IoDeleteDevice( (PDEVICE_OBJECT)
  1770. CONTAINING_RECORD( Vcb,
  1771. VOLUME_DEVICE_OBJECT,
  1772. Vcb ) );
  1773. VcbDeleted = TRUE;
  1774. } else if (OldVpb->RealDevice->Vpb == OldVpb && Force) {
  1775. //
  1776. // If not the final reference and we are forcing the disconnect,
  1777. // then swap out the Vpb. We must preserve the REMOVE_PENDING flag
  1778. // so that the device is not remounted in the middle of a PnP remove
  1779. // operation.
  1780. //
  1781. ASSERT( Vcb->SwapVpb != NULL );
  1782. Vcb->SwapVpb->Type = IO_TYPE_VPB;
  1783. Vcb->SwapVpb->Size = sizeof( VPB );
  1784. Vcb->SwapVpb->RealDevice = OldVpb->RealDevice;
  1785. Vcb->SwapVpb->RealDevice->Vpb = Vcb->SwapVpb;
  1786. Vcb->SwapVpb->Flags = FlagOn( OldVpb->Flags, VPB_REMOVE_PENDING );
  1787. IoReleaseVpbSpinLock( SavedIrql );
  1788. //
  1789. // We place the volume in the Bad state (as opposed to NotMounted) so
  1790. // that it is not eligible for a remount. Also indicate we used up
  1791. // the swap.
  1792. //
  1793. Vcb->SwapVpb = NULL;
  1794. FatSetVcbCondition( Vcb, VcbBad);
  1795. } else {
  1796. //
  1797. // Just drop the Vpb spinlock.
  1798. //
  1799. IoReleaseVpbSpinLock( SavedIrql );
  1800. }
  1801. return VcbDeleted;
  1802. }
  1803. VOID
  1804. FatConstructNamesInFcb (
  1805. IN PIRP_CONTEXT IrpContext,
  1806. PFCB Fcb,
  1807. PDIRENT Dirent,
  1808. PUNICODE_STRING Lfn OPTIONAL
  1809. )
  1810. /*++
  1811. Routine Description:
  1812. This routine places the short name in the dirent in the first set of
  1813. STRINGs in the Fcb. If a long file name (Lfn) was specified, then
  1814. we must decide whether we will store its Oem equivolent in the same
  1815. prefix table as the short name, or rather just save the upcased
  1816. version of the UNICODE string in the FCB.
  1817. For looking up Fcbs, the first approach will be faster, so we want to
  1818. do this as much as possible. Here are the rules that I have thought
  1819. through extensively to determine when it is safe to store only Oem
  1820. version of the UNICODE name.
  1821. - If the UNICODE name contains no extended characters (>0x80), use Oem.
  1822. - Let U be the upcased version of the UNICODE name.
  1823. Let Up(x) be the function that upcases a UNICODE string.
  1824. Let Down(x) be the function that upcases a UNICODE string.
  1825. Let OemToUni(x) be the function that converts an Oem string to Unicode.
  1826. Let UniToOem(x) be the function that converts a Unicode string to Oem.
  1827. Let BestOemFit(x) be the function that creates the Best uppercase Oem
  1828. fit for the UNICODE string x.
  1829. BestOemFit(x) = UniToOem(Up(OemToUni(UniToOem(x)))) <1>
  1830. if (BestOemFit(U) == BestOemFit(Down(U)) <2>
  1831. then I know that there exists no UNICODE string Y such that:
  1832. Up(Y) == Up(U) <3>
  1833. AND
  1834. BestOemFit(U) != BestOemFit(Y) <4>
  1835. Consider string U as a collection of one character strings. The
  1836. conjecture is clearly true for each sub-string, thus it is true
  1837. for the entire string.
  1838. Equation <1> is what we use to convert an incoming unicode name in
  1839. FatCommonCreate() to Oem. The double conversion is done to provide
  1840. better visual best fitting for characters in the Ansi code page but
  1841. not in the Oem code page. A single Nls routine is provided to do
  1842. this conversion efficiently.
  1843. The idea is that with U, I only have to worry about a case varient Y
  1844. matching it in a unicode compare, and I have shown that any case varient
  1845. of U (the set Y defined in equation <3>), when filtered through <1>
  1846. (as in create), will match the Oem string defined in <1>.
  1847. Thus I do not have to worry about another UNICODE string missing in
  1848. the prefix lookup, but matching when comparing LFNs in the directory.
  1849. Arguments:
  1850. Fcb - The Fcb we are supposed to fill in. Note that ParentDcb must
  1851. already be filled in.
  1852. Dirent - The gives up the short name.
  1853. Lfn - If provided, this gives us the long name.
  1854. Return Value:
  1855. None
  1856. --*/
  1857. {
  1858. NTSTATUS Status;
  1859. ULONG i;
  1860. OEM_STRING OemA;
  1861. OEM_STRING OemB;
  1862. UNICODE_STRING Unicode;
  1863. POEM_STRING ShortName;
  1864. POEM_STRING LongOemName;
  1865. PUNICODE_STRING LongUniName;
  1866. ShortName = &Fcb->ShortName.Name.Oem;
  1867. ASSERT( ShortName->Buffer == NULL );
  1868. try {
  1869. //
  1870. // First do the short name.
  1871. //
  1872. //
  1873. // Copy over the case flags for the short name of the file
  1874. //
  1875. if (FlagOn(Dirent->NtByte, FAT_DIRENT_NT_BYTE_8_LOWER_CASE)) {
  1876. SetFlag(Fcb->FcbState, FCB_STATE_8_LOWER_CASE);
  1877. } else {
  1878. ClearFlag(Fcb->FcbState, FCB_STATE_8_LOWER_CASE);
  1879. }
  1880. if (FlagOn(Dirent->NtByte, FAT_DIRENT_NT_BYTE_3_LOWER_CASE)) {
  1881. SetFlag(Fcb->FcbState, FCB_STATE_3_LOWER_CASE);
  1882. } else {
  1883. ClearFlag(Fcb->FcbState, FCB_STATE_3_LOWER_CASE);
  1884. }
  1885. ShortName->MaximumLength = 16;
  1886. ShortName->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  1887. 16,
  1888. TAG_FILENAME_BUFFER );
  1889. Fat8dot3ToString( IrpContext, Dirent, FALSE, ShortName );
  1890. //
  1891. // If no Lfn was specified, we are done. In either case, set the
  1892. // final name length.
  1893. //
  1894. ASSERT( Fcb->ExactCaseLongName.Buffer == NULL );
  1895. if (!ARGUMENT_PRESENT(Lfn) || (Lfn->Length == 0)) {
  1896. Fcb->FinalNameLength = (USHORT) RtlOemStringToCountedUnicodeSize( ShortName );
  1897. Fcb->ExactCaseLongName.Length = Fcb->ExactCaseLongName.MaximumLength = 0;
  1898. try_return( NOTHING );
  1899. }
  1900. //
  1901. // If we already set up the full filename, we could be in trouble. If the fast
  1902. // path for doing it already fired, FatSetFullFileNameInFcb, it will have missed
  1903. // this and could have built the full filename out of the shortname of the file.
  1904. //
  1905. // At that point, disaster could be inevitable since the final name length will not
  1906. // match. We use this to tell the notify package what to do - FatNotifyReportChange.
  1907. //
  1908. ASSERT( Fcb->FullFileName.Buffer == NULL );
  1909. //
  1910. // We know now we have an Lfn, save away a copy.
  1911. //
  1912. Fcb->FinalNameLength = Lfn->Length;
  1913. Fcb->ExactCaseLongName.Length = Fcb->ExactCaseLongName.MaximumLength = Lfn->Length;
  1914. Fcb->ExactCaseLongName.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  1915. Lfn->Length,
  1916. TAG_FILENAME_BUFFER );
  1917. RtlCopyMemory(Fcb->ExactCaseLongName.Buffer, Lfn->Buffer, Lfn->Length);
  1918. //
  1919. // First check for no extended characters.
  1920. //
  1921. for (i=0; i < Lfn->Length/sizeof(WCHAR); i++) {
  1922. if (Lfn->Buffer[i] >= 0x80) {
  1923. break;
  1924. }
  1925. }
  1926. if (i == Lfn->Length/sizeof(WCHAR)) {
  1927. //
  1928. // Cool, I can go with the Oem, upcase it fast by hand.
  1929. //
  1930. LongOemName = &Fcb->LongName.Oem.Name.Oem;
  1931. LongOemName->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  1932. Lfn->Length/sizeof(WCHAR),
  1933. TAG_FILENAME_BUFFER );
  1934. LongOemName->Length =
  1935. LongOemName->MaximumLength = Lfn->Length/sizeof(WCHAR);
  1936. for (i=0; i < Lfn->Length/sizeof(WCHAR); i++) {
  1937. WCHAR c;
  1938. c = Lfn->Buffer[i];
  1939. LongOemName->Buffer[i] = c < 'a' ?
  1940. (UCHAR)c :
  1941. c <= 'z' ?
  1942. c - (UCHAR)('a'-'A') :
  1943. (UCHAR) c;
  1944. }
  1945. //
  1946. // If this name happens to be exactly the same as the short
  1947. // name, don't add it to the splay table.
  1948. //
  1949. if (FatAreNamesEqual(IrpContext, *ShortName, *LongOemName) ||
  1950. (FatFindFcb( IrpContext,
  1951. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  1952. LongOemName,
  1953. NULL) != NULL)) {
  1954. ExFreePool( LongOemName->Buffer );
  1955. LongOemName->Buffer = NULL;
  1956. LongOemName->Length =
  1957. LongOemName->MaximumLength = 0;
  1958. } else {
  1959. SetFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
  1960. }
  1961. try_return( NOTHING );
  1962. }
  1963. //
  1964. // Now we have the fun part. Make a copy of the Lfn.
  1965. //
  1966. OemA.Buffer = NULL;
  1967. OemB.Buffer = NULL;
  1968. Unicode.Buffer = NULL;
  1969. Unicode.Length =
  1970. Unicode.MaximumLength = Lfn->Length;
  1971. Unicode.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  1972. Lfn->Length,
  1973. TAG_FILENAME_BUFFER );
  1974. RtlCopyMemory( Unicode.Buffer, Lfn->Buffer, Lfn->Length );
  1975. Status = STATUS_SUCCESS;
  1976. #if TRUE
  1977. //
  1978. // Unfortunately, this next block of code breaks down when you have
  1979. // two long Unicode filenames that both map to the same Oem (and are,
  1980. // well, long, i.e. are not the short names). In this case, with one
  1981. // in the prefix table first, the other will hit the common Oem
  1982. // representation. This leads to several forms of user astonishment.
  1983. //
  1984. // It isn't worth it, or probably even possible, to try to figure out
  1985. // when this is really safe to go through. Simply omit the attempt.
  1986. //
  1987. // Ex: ANSI 0x82 and 0x84 in the 1252 ANSI->UNI and 437 UNI->OEM codepages.
  1988. //
  1989. // 0x82 => 0x201a => 0x2c
  1990. // 0x84 => 0x201e => 0x2c
  1991. //
  1992. // 0x2c is comma, so is FAT Oem illegal and forces shortname generation.
  1993. // Since it is otherwise well-formed by the rules articulated previously,
  1994. // we would have put 0x2c in the Oem prefix tree. In terms of the
  1995. // argument given above, even though there exist no Y and U s.t.
  1996. //
  1997. // Up(Y) == Up(U) && BestOemFit(U) != BestOemFit(Y)
  1998. //
  1999. // there most certainly exist Y and U s.t.
  2000. //
  2001. // Up(Y) != Up(U) && BestOemFit(U) == BestOemFit(Y)
  2002. //
  2003. // and that is enough to keep us from doing this. Note that the < 0x80
  2004. // case is OK since we know that the mapping in the OEM codepages are
  2005. // the identity in that range.
  2006. //
  2007. // We still need to monocase it, though. Do this through a full down/up
  2008. // transition.
  2009. //
  2010. (VOID)RtlDowncaseUnicodeString( &Unicode, &Unicode, FALSE );
  2011. (VOID)RtlUpcaseUnicodeString( &Unicode, &Unicode, FALSE );
  2012. #else
  2013. //
  2014. // Downcase and convert to upcased Oem. Only continue if we can
  2015. // convert without error. Any error other than UNMAPPABLE_CHAR
  2016. // is a fatal error and we raise.
  2017. //
  2018. // Note that even if the conversion fails, we must leave Unicode
  2019. // in an upcased state.
  2020. //
  2021. // NB: The Rtl doesn't NULL .Buffer on error.
  2022. //
  2023. (VOID)RtlDowncaseUnicodeString( &Unicode, &Unicode, FALSE );
  2024. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemA, &Unicode, TRUE );
  2025. (VOID)RtlUpcaseUnicodeString( &Unicode, &Unicode, FALSE );
  2026. if (!NT_SUCCESS(Status)) {
  2027. if (Status != STATUS_UNMAPPABLE_CHARACTER) {
  2028. ASSERT( Status == STATUS_NO_MEMORY );
  2029. ExFreePool(Unicode.Buffer);
  2030. FatNormalizeAndRaiseStatus( IrpContext, Status );
  2031. }
  2032. } else {
  2033. //
  2034. // The same as above except upcase.
  2035. //
  2036. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemB, &Unicode, TRUE );
  2037. if (!NT_SUCCESS(Status)) {
  2038. RtlFreeOemString( &OemA );
  2039. if (Status != STATUS_UNMAPPABLE_CHARACTER) {
  2040. ASSERT( Status == STATUS_NO_MEMORY );
  2041. ExFreePool(Unicode.Buffer);
  2042. FatNormalizeAndRaiseStatus( IrpContext, Status );
  2043. }
  2044. }
  2045. }
  2046. //
  2047. // If the final OemNames are equal, I can use save only the Oem
  2048. // name. If the name did not map, then I have to go with the UNICODE
  2049. // name because I could get a case varient that didn't convert
  2050. // in create, but did match the LFN.
  2051. //
  2052. if (NT_SUCCESS(Status) && FatAreNamesEqual( IrpContext, OemA, OemB )) {
  2053. //
  2054. // Cool, I can go with the Oem. If we didn't convert correctly,
  2055. // get a fresh convert from the original LFN.
  2056. //
  2057. ExFreePool(Unicode.Buffer);
  2058. RtlFreeOemString( &OemB );
  2059. Fcb->LongName.Oem.Name.Oem = OemA;
  2060. //
  2061. // If this name happens to be exactly the same as the short
  2062. // name, or a similar short name already exists don't add it
  2063. // to the splay table (note the final condition implies a
  2064. // corrupt disk.
  2065. //
  2066. if (FatAreNamesEqual(IrpContext, *ShortName, OemA) ||
  2067. (FatFindFcb( IrpContext,
  2068. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  2069. &OemA,
  2070. NULL) != NULL)) {
  2071. RtlFreeOemString( &OemA );
  2072. } else {
  2073. SetFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
  2074. }
  2075. try_return( NOTHING );
  2076. }
  2077. //
  2078. // The long name must be left in UNICODE. Free the two Oem strings
  2079. // if we got here just because they weren't equal.
  2080. //
  2081. if (NT_SUCCESS(Status)) {
  2082. RtlFreeOemString( &OemA );
  2083. RtlFreeOemString( &OemB );
  2084. }
  2085. #endif
  2086. LongUniName = &Fcb->LongName.Unicode.Name.Unicode;
  2087. LongUniName->Length =
  2088. LongUniName->MaximumLength = Unicode.Length;
  2089. LongUniName->Buffer = Unicode.Buffer;
  2090. SetFlag(Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME);
  2091. try_exit: NOTHING;
  2092. } finally {
  2093. if (AbnormalTermination()) {
  2094. if (ShortName->Buffer != NULL) {
  2095. ExFreePool( ShortName->Buffer );
  2096. ShortName->Buffer = NULL;
  2097. }
  2098. } else {
  2099. //
  2100. // Creating all the names worked, so add all the names
  2101. // to the splay tree.
  2102. //
  2103. FatInsertName( IrpContext,
  2104. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  2105. &Fcb->ShortName );
  2106. Fcb->ShortName.Fcb = Fcb;
  2107. if (FlagOn(Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME)) {
  2108. FatInsertName( IrpContext,
  2109. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  2110. &Fcb->LongName.Oem );
  2111. Fcb->LongName.Oem.Fcb = Fcb;
  2112. }
  2113. if (FlagOn(Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME)) {
  2114. FatInsertName( IrpContext,
  2115. &Fcb->ParentDcb->Specific.Dcb.RootUnicodeNode,
  2116. &Fcb->LongName.Unicode );
  2117. Fcb->LongName.Unicode.Fcb = Fcb;
  2118. }
  2119. SetFlag(Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE);
  2120. }
  2121. }
  2122. return;
  2123. }
  2124. VOID
  2125. FatCheckFreeDirentBitmap (
  2126. IN PIRP_CONTEXT IrpContext,
  2127. IN PDCB Dcb
  2128. )
  2129. /*++
  2130. Routine Description:
  2131. This routine checks if the size of the free dirent bitmap is
  2132. sufficient to for the current directory size. It is called
  2133. whenever we grow a directory.
  2134. Arguments:
  2135. Dcb - Supplies the directory in question.
  2136. Return Value:
  2137. None
  2138. --*/
  2139. {
  2140. ULONG OldNumberOfDirents;
  2141. ULONG NewNumberOfDirents;
  2142. //
  2143. // Setup the Bitmap buffer if it is not big enough already
  2144. //
  2145. ASSERT( Dcb->Header.AllocationSize.QuadPart != FCB_LOOKUP_ALLOCATIONSIZE_HINT );
  2146. OldNumberOfDirents = Dcb->Specific.Dcb.FreeDirentBitmap.SizeOfBitMap;
  2147. NewNumberOfDirents = Dcb->Header.AllocationSize.LowPart / sizeof(DIRENT);
  2148. //
  2149. // Do the usual unsync/sync check.
  2150. //
  2151. if (NewNumberOfDirents > OldNumberOfDirents) {
  2152. FatAcquireDirectoryFileMutex( Dcb->Vcb );
  2153. try {
  2154. PULONG OldBitmapBuffer;
  2155. PULONG BitmapBuffer;
  2156. ULONG BytesInBitmapBuffer;
  2157. ULONG BytesInOldBitmapBuffer;
  2158. OldNumberOfDirents = Dcb->Specific.Dcb.FreeDirentBitmap.SizeOfBitMap;
  2159. NewNumberOfDirents = Dcb->Header.AllocationSize.LowPart / sizeof(DIRENT);
  2160. if (NewNumberOfDirents > OldNumberOfDirents) {
  2161. //
  2162. // Remember the old bitmap
  2163. //
  2164. OldBitmapBuffer = Dcb->Specific.Dcb.FreeDirentBitmap.Buffer;
  2165. //
  2166. // Now make a new bitmap bufffer
  2167. //
  2168. BytesInBitmapBuffer = NewNumberOfDirents / 8;
  2169. BytesInOldBitmapBuffer = OldNumberOfDirents / 8;
  2170. if (DCB_UNION_SLACK_SPACE >= BytesInBitmapBuffer) {
  2171. BitmapBuffer = &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0];
  2172. } else {
  2173. BitmapBuffer = FsRtlAllocatePoolWithTag( PagedPool,
  2174. BytesInBitmapBuffer,
  2175. TAG_DIRENT_BITMAP );
  2176. }
  2177. //
  2178. // Copy the old buffer to the new buffer, free the old one, and zero
  2179. // the rest of the new one. Only do the first two steps though if
  2180. // we moved out of the initial buffer.
  2181. //
  2182. if ((OldNumberOfDirents != 0) &&
  2183. (BitmapBuffer != &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0])) {
  2184. RtlCopyMemory( BitmapBuffer,
  2185. OldBitmapBuffer,
  2186. BytesInOldBitmapBuffer );
  2187. if (OldBitmapBuffer != &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0]) {
  2188. ExFreePool( OldBitmapBuffer );
  2189. }
  2190. }
  2191. ASSERT( BytesInBitmapBuffer > BytesInOldBitmapBuffer );
  2192. RtlZeroMemory( (PUCHAR)BitmapBuffer + BytesInOldBitmapBuffer,
  2193. BytesInBitmapBuffer - BytesInOldBitmapBuffer );
  2194. //
  2195. // Now initialize the new bitmap.
  2196. //
  2197. RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
  2198. BitmapBuffer,
  2199. NewNumberOfDirents );
  2200. }
  2201. } finally {
  2202. FatReleaseDirectoryFileMutex( Dcb->Vcb );
  2203. }
  2204. }
  2205. }
  2206. BOOLEAN
  2207. FatIsHandleCountZero (
  2208. IN PIRP_CONTEXT IrpContext,
  2209. IN PVCB Vcb
  2210. )
  2211. /*++
  2212. Routine Description:
  2213. This routine decides if the handle count on the volume is zero.
  2214. Arguments:
  2215. Vcb - The volume in question
  2216. Return Value:
  2217. BOOLEAN - TRUE if there are no open handles on the volume, FALSE
  2218. otherwise.
  2219. --*/
  2220. {
  2221. PFCB Fcb;
  2222. Fcb = Vcb->RootDcb;
  2223. while (Fcb != NULL) {
  2224. if (Fcb->UncleanCount != 0) {
  2225. return FALSE;
  2226. }
  2227. Fcb = FatGetNextFcbTopDown(IrpContext, Fcb, Vcb->RootDcb);
  2228. }
  2229. return TRUE;
  2230. }
  2231. PCLOSE_CONTEXT
  2232. FatAllocateCloseContext(
  2233. OPTIONAL PVCB Vcb
  2234. )
  2235. /*++
  2236. Routine Description:
  2237. This routine preallocates a close context, presumeably on behalf
  2238. of a fileobject which does not have a structure we can embed one
  2239. in.
  2240. Arguments:
  2241. None.
  2242. Return Value:
  2243. None.
  2244. --*/
  2245. {
  2246. #if DBG
  2247. if (ARGUMENT_PRESENT(Vcb)) {
  2248. ASSERT( 0 != Vcb->CloseContextCount);
  2249. InterlockedDecrement( &Vcb->CloseContextCount);
  2250. }
  2251. #endif
  2252. return (PCLOSE_CONTEXT)ExInterlockedPopEntrySList( &FatCloseContextSList,
  2253. &FatData.GeneralSpinLock );
  2254. }
  2255. VOID
  2256. FatPreallocateCloseContext (
  2257. PVCB Vcb
  2258. )
  2259. /*++
  2260. Routine Description:
  2261. This routine preallocates a close context, presumeably on behalf
  2262. of a fileobject which does not have a structure we can embed one
  2263. in.
  2264. Arguments:
  2265. None.
  2266. Return Value:
  2267. None.
  2268. --*/
  2269. {
  2270. PCLOSE_CONTEXT CloseContext = FsRtlAllocatePoolWithTag( PagedPool,
  2271. sizeof(CLOSE_CONTEXT),
  2272. TAG_FAT_CLOSE_CONTEXT );
  2273. ExInterlockedPushEntrySList( &FatCloseContextSList,
  2274. (PSLIST_ENTRY) CloseContext,
  2275. &FatData.GeneralSpinLock );
  2276. DbgDoit( InterlockedIncrement( &Vcb->CloseContextCount));
  2277. }
  2278. VOID
  2279. FatEnsureStringBufferEnough(
  2280. IN OUT PVOID String,
  2281. IN USHORT DesiredBufferSize
  2282. )
  2283. /*++
  2284. Routine Description:
  2285. Ensures that a string string (STRING, UNICODE_STRING, ANSI_STRING, OEM_STRING)
  2286. has a buffer >= DesiredBufferSize, allocating from pool if neccessary. Any
  2287. existing pool buffer will be freed if a new one is allocated.
  2288. NOTE: No copy of old buffer contents is performed on reallocation.
  2289. Will raise on allocation failure.
  2290. Arguments:
  2291. String - pointer to string structure
  2292. DesiredBufferSize - (bytes) minimum required buffer size
  2293. --*/
  2294. {
  2295. PSTRING LocalString = String;
  2296. if (LocalString->MaximumLength < DesiredBufferSize) {
  2297. FatFreeStringBuffer( LocalString);
  2298. LocalString->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  2299. DesiredBufferSize,
  2300. TAG_DYNAMIC_NAME_BUFFER);
  2301. ASSERT( LocalString->Buffer);
  2302. LocalString->MaximumLength = DesiredBufferSize;
  2303. }
  2304. }
  2305. VOID
  2306. FatFreeStringBuffer(
  2307. IN PVOID String
  2308. )
  2309. /*++
  2310. Routine Description:
  2311. Frees the buffer of an string (STRING, UNICODE_STRING, ANSI_STRING, OEM_STRING)
  2312. structure if it is not within the current thread's stack limits.
  2313. Regardless of action performed, on exit String->Buffer will be set to NULL and
  2314. String->MaximumLength to zero.
  2315. Arguments:
  2316. String - pointer to string structure
  2317. --*/
  2318. {
  2319. ULONG_PTR High, Low;
  2320. PSTRING LocalString = String;
  2321. if (NULL != LocalString->Buffer) {
  2322. IoGetStackLimits( &Low, &High );
  2323. if (((ULONG_PTR)(LocalString->Buffer) < Low) ||
  2324. ((ULONG_PTR)(LocalString->Buffer) > High)) {
  2325. ExFreePool( LocalString->Buffer);
  2326. }
  2327. LocalString->Buffer = NULL;
  2328. }
  2329. LocalString->MaximumLength = LocalString->Length = 0;
  2330. }
  2331. BOOLEAN
  2332. FatScanForDataTrack(
  2333. IN PIRP_CONTEXT IrpContext,
  2334. IN PDEVICE_OBJECT TargetDeviceObject
  2335. )
  2336. /*++
  2337. Routine Description:
  2338. This routine is called to verify and process the TOC for this disk.
  2339. FAT queries for the TOC to avoid trying to mount on CD-DA/CD-E media, Doing data reads on
  2340. audio/leadin of that media sends a lot of drives into what could charitably be called
  2341. "conniptions" which take a couple seconds to clear and would also convince FAT that the
  2342. device was busted, and fail the mount (not letting CDFS get its crack).
  2343. There is special handling of PD media. These things fail the TOC read, but return
  2344. a special error code so FAT knows to continue to try the mount anyway.
  2345. Arguments:
  2346. TargetDeviceObject - Device object to send TOC request to.
  2347. Return Value:
  2348. BOOLEAN - TRUE if we found a TOC with a single data track.
  2349. --*/
  2350. {
  2351. NTSTATUS Status;
  2352. IO_STATUS_BLOCK Iosb;
  2353. ULONG LocalTrackCount;
  2354. ULONG LocalTocLength;
  2355. PCDROM_TOC CdromToc;
  2356. BOOLEAN Result = FALSE;
  2357. PAGED_CODE();
  2358. CdromToc = FsRtlAllocatePoolWithTag( PagedPool,
  2359. sizeof( CDROM_TOC ),
  2360. TAG_IO_BUFFER );
  2361. RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
  2362. try {
  2363. //
  2364. // Go ahead and read the table of contents
  2365. //
  2366. Status = FatPerformDevIoCtrl( IrpContext,
  2367. IOCTL_CDROM_READ_TOC,
  2368. TargetDeviceObject,
  2369. CdromToc,
  2370. sizeof( CDROM_TOC ),
  2371. FALSE,
  2372. TRUE,
  2373. &Iosb );
  2374. //
  2375. // Nothing to process if this request fails.
  2376. //
  2377. if (Status != STATUS_SUCCESS) {
  2378. //
  2379. // If we get the special error indicating a failed TOC read on PD media just
  2380. // plow ahead with the mount (see comments above).
  2381. //
  2382. if ((Status == STATUS_IO_DEVICE_ERROR) || (Status == STATUS_INVALID_DEVICE_REQUEST)) {
  2383. Result = TRUE;
  2384. }
  2385. try_leave( NOTHING );
  2386. }
  2387. //
  2388. // Get the number of tracks and stated size of this structure.
  2389. //
  2390. LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1;
  2391. LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] );
  2392. //
  2393. // Get out if there is an immediate problem with the TOC, or more than
  2394. // one track.
  2395. //
  2396. if ((LocalTocLength > Iosb.Information) ||
  2397. (CdromToc->FirstTrack > CdromToc->LastTrack) ||
  2398. (LocalTrackCount != 1)) {
  2399. try_leave( NOTHING);
  2400. }
  2401. //
  2402. // Is it a data track? DVD-RAM reports single, data, track.
  2403. //
  2404. Result = BooleanFlagOn( CdromToc->TrackData[ 0].Control, 0x04 );
  2405. }
  2406. finally {
  2407. ExFreePool( CdromToc);
  2408. }
  2409. return Result;
  2410. }