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

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