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.

2265 lines
55 KiB

  1. /*++
  2. DANGER DANGER DANGER
  3. ALL THE STUFF IN THIS FILE IS OBSOLETE BUT IS BEING TEMPORARILY MAINTAINED
  4. IN CASE WE WANT TO GRAP SOMETHING. THE CODE IS BEING SYSTEMATICALLY IFDEF'D OUT.
  5. Copyright (c) 1989 Microsoft Corporation
  6. Module Name:
  7. StrucSup.c
  8. Abstract:
  9. This module implements the Rx in-memory data structure manipulation
  10. routines
  11. Author:
  12. Gary Kimura [GaryKi] 22-Jan-1990
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #define RxFindFcb( __x, __y, __z) ((PFCB)( (RtlAssert("dont call rxfindfcb", __FILE__, __LINE__, NULL),0)))
  18. #define RxInsertName( __x, __y, __z) ((PFCB)( (RtlAssert("dont call rxfindfcb", __FILE__, __LINE__, NULL),0)))
  19. #define RxRemoveNames( __x, __z) ((PFCB)( (RtlAssert("dont call rxfindfcb", __FILE__, __LINE__, NULL),0)))
  20. //
  21. //**** include this file for our quick hacked quota check in NtfsFreePagedPool
  22. //
  23. // #include <pool.h>
  24. //
  25. // The Bug check file id for this module
  26. //
  27. #define BugCheckFileId (RDBSS_BUG_CHECK_STRUCSUP)
  28. //
  29. // The debug trace level
  30. //
  31. #define Dbg (DEBUG_TRACE_STRUCSUP)
  32. #define FillMemory(BUF,SIZ,MASK) { \
  33. ULONG i; \
  34. for (i = 0; i < (((SIZ)/4) - 1); i += 2) { \
  35. ((PULONG)(BUF))[i] = (MASK); \
  36. ((PULONG)(BUF))[i+1] = (ULONG)PsGetCurrentThread(); \
  37. } \
  38. }
  39. #define RX_CONTEXT_HEADER (sizeof( RX_CONTEXT ) * 0x10000 + RDBSS_NTC_RX_CONTEXT)
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text(PAGE, RxInitializeVcb)
  42. #pragma alloc_text(PAGE, RxDeleteVcb_Real)
  43. #pragma alloc_text(PAGE, RxCreateRootDcb)
  44. #pragma alloc_text(PAGE, RxCreateFcb)
  45. #pragma alloc_text(PAGE, RxCreateDcb)
  46. #pragma alloc_text(PAGE, RxDeleteFcb_Real)
  47. #pragma alloc_text(PAGE, RxCreateFobx)
  48. #pragma alloc_text(PAGE, RxDeleteFobx_Real)
  49. #pragma alloc_text(PAGE, RxGetNextFcb)
  50. #pragma alloc_text(PAGE, RxConstructNamesInFcb)
  51. #pragma alloc_text(PAGE, RxCheckFreeDirentBitmap)
  52. #endif
  53. VOID
  54. RxInitializeVcb (
  55. IN PRX_CONTEXT RxContext,
  56. IN OUT PVCB Vcb,
  57. IN PDEVICE_OBJECT TargetDeviceObject,
  58. IN PVPB Vpb,
  59. IN PDSCB Dscb OPTIONAL
  60. )
  61. /*++
  62. Routine Description:
  63. This routine initializes and inserts a new Vcb record into the in-memory
  64. data structure. The Vcb record "hangs" off the end of the Volume device
  65. object and must be allocated by our caller.
  66. Arguments:
  67. Vcb - Supplies the address of the Vcb record being initialized.
  68. TargetDeviceObject - Supplies the address of the target device object to
  69. associate with the Vcb record.
  70. Vpb - Supplies the address of the Vpb to associate with the Vcb record.
  71. Dscb - If present supplies the associated Double Space control block
  72. Return Value:
  73. None.
  74. --*/
  75. {
  76. CC_FILE_SIZES FileSizes;
  77. PDEVICE_OBJECT RealDevice;
  78. //
  79. // The following variables are used for abnormal unwind
  80. //
  81. PLIST_ENTRY UnwindEntryList = NULL;
  82. PERESOURCE UnwindResource = NULL;
  83. PERESOURCE UnwindVolFileResource = NULL;
  84. PFILE_OBJECT UnwindFileObject = NULL;
  85. PFILE_OBJECT UnwindCacheMap = NULL;
  86. BOOLEAN UnwindWeAllocatedMcb = FALSE;
  87. DebugTrace(+1, Dbg, "RxInitializeVcb, Vcb = %08lx\n", Vcb);
  88. ASSERT(FALSE);
  89. try {
  90. //
  91. // We start by first zeroing out all of the VCB, this will guarantee
  92. // that any stale data is wiped clean
  93. //
  94. RtlZeroMemory( Vcb, sizeof(VCB) );
  95. //
  96. // Set the proper node type code and node byte size
  97. //
  98. Vcb->NodeTypeCode = RDBSS_NTC_VCB;
  99. Vcb->NodeByteSize = sizeof(VCB);
  100. //
  101. // Insert this Vcb record on the RxData.VcbQueue
  102. //
  103. ASSERT( FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) );
  104. (VOID)RxAcquireExclusiveGlobal( RxContext );
  105. InsertTailList( &RxData.VcbQueue, &Vcb->VcbLinks );
  106. RxReleaseGlobal( RxContext );
  107. UnwindEntryList = &Vcb->VcbLinks;
  108. //
  109. // Set the Target Device Object, Vpb, and Vcb State fields
  110. //
  111. Vcb->TargetDeviceObject = TargetDeviceObject;
  112. Vcb->Vpb = Vpb;
  113. //
  114. // If this is a DoubleSpace volume note our "special" device.
  115. //
  116. Vcb->CurrentDevice = ARGUMENT_PRESENT(Dscb) ?
  117. Dscb->NewDevice : Vpb->RealDevice;
  118. //
  119. // Set the removable media and floppy flag based on the real device's
  120. // characteristics.
  121. //
  122. if (FlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
  123. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA );
  124. }
  125. if (FlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
  126. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_FLOPPY );
  127. }
  128. Vcb->VcbCondition = VcbGood;
  129. //
  130. // Initialize the resource variable for the Vcb
  131. //
  132. ExInitializeResource( &Vcb->Resource );
  133. UnwindResource = &Vcb->Resource;
  134. //
  135. // Initialize the free cluster bitmap event.
  136. //
  137. KeInitializeEvent( &Vcb->FreeClusterBitMapEvent,
  138. SynchronizationEvent,
  139. TRUE );
  140. //
  141. // Now, put the Dscb parameter in the Vcb. If NULL, this is a normal
  142. // mount and non-cached IO will go directly to the target device
  143. // object. If non-NULL, the DSCB structure contains all the
  144. // information needed to do the redirected reads and writes.
  145. //
  146. InitializeListHead(&Vcb->ParentDscbLinks);
  147. if (ARGUMENT_PRESENT(Dscb)) {
  148. Vcb->Dscb = Dscb;
  149. Dscb->Vcb = Vcb;
  150. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_COMPRESSED_VOLUME );
  151. }
  152. //
  153. // Create the special file object for the virtual volume file, and set
  154. // up its pointers back to the Vcb and the section object pointer
  155. //
  156. RealDevice = Vcb->CurrentDevice;
  157. Vcb->VirtualVolumeFile = UnwindFileObject = IoCreateStreamFileObject( NULL, RealDevice );
  158. RxSetFileObject( Vcb->VirtualVolumeFile,
  159. VirtualVolumeFile,
  160. Vcb,
  161. NULL );
  162. Vcb->VirtualVolumeFile->SectionObjectPointer = &Vcb->SectionObjectPointers;
  163. Vcb->VirtualVolumeFile->ReadAccess = TRUE;
  164. Vcb->VirtualVolumeFile->WriteAccess = TRUE;
  165. Vcb->VirtualVolumeFile->DeleteAccess = TRUE;
  166. //
  167. // Initialize the notify structures.
  168. //
  169. InitializeListHead( &Vcb->DirNotifyList );
  170. FsRtlNotifyInitializeSync( &Vcb->NotifySync );
  171. //
  172. // Initialize the Cache Map for the volume file. The size is
  173. // initially set to that of our first read. It will be extended
  174. // when we know how big the Rx is.
  175. //
  176. FileSizes.AllocationSize.QuadPart =
  177. FileSizes.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
  178. FileSizes.ValidDataLength = RxMaxLarge;
  179. CcInitializeCacheMap( Vcb->VirtualVolumeFile,
  180. &FileSizes,
  181. TRUE,
  182. &RxData.CacheManagerNoOpCallbacks,
  183. Vcb );
  184. UnwindCacheMap = Vcb->VirtualVolumeFile;
  185. //
  186. // Initialize the structure that will keep track of dirty rx sectors.
  187. // The largest possible Mcb structures are less than 1K, so we use
  188. // non paged pool.
  189. //
  190. FsRtlInitializeMcb( &Vcb->DirtyRxMcb, PagedPool );
  191. UnwindWeAllocatedMcb = TRUE;
  192. //
  193. // Set the cluster index hint to the first valid cluster of a rx: 2
  194. //
  195. Vcb->ClusterHint = 2;
  196. //
  197. // Initialize the directory stream file object creation event.
  198. // This event is also "borrowed" for async non-cached writes.
  199. //
  200. KeInitializeEvent( &Vcb->DirectoryFileCreationEvent,
  201. SynchronizationEvent,
  202. TRUE );
  203. //
  204. // Initialize the clean volume callback Timer and DPC.
  205. //
  206. KeInitializeTimer( &Vcb->CleanVolumeTimer );
  207. KeInitializeDpc( &Vcb->CleanVolumeDpc, RxCleanVolumeDpc, Vcb );
  208. } finally {
  209. DebugUnwind( RxInitializeVcb );
  210. //
  211. // If this is an abnormal termination then undo our work
  212. //
  213. if (AbnormalTermination()) {
  214. if (UnwindCacheMap != NULL) { RxSyncUninitializeCacheMap( RxContext, UnwindCacheMap ); }
  215. if (UnwindFileObject != NULL) { ObDereferenceObject( UnwindFileObject ); }
  216. if (UnwindVolFileResource != NULL) { RxDeleteResource( UnwindVolFileResource ); }
  217. if (UnwindResource != NULL) { RxDeleteResource( UnwindResource ); }
  218. if (UnwindWeAllocatedMcb) { FsRtlUninitializeMcb( &Vcb->DirtyRxMcb ); }
  219. if (UnwindEntryList != NULL) {
  220. (VOID)RxAcquireExclusiveGlobal( RxContext );
  221. RemoveEntryList( UnwindEntryList );
  222. RxReleaseGlobal( RxContext );
  223. }
  224. }
  225. DebugTrace(-1, Dbg, "RxInitializeVcb -> VOID\n", 0);
  226. }
  227. //
  228. // and return to our caller
  229. //
  230. UNREFERENCED_PARAMETER( RxContext );
  231. return;
  232. }
  233. VOID
  234. RxDeleteVcb_Real (
  235. IN PRX_CONTEXT RxContext,
  236. IN PVCB Vcb
  237. )
  238. /*++
  239. Routine Description:
  240. This routine removes the Vcb record from Rx's in-memory data
  241. structures. It also will remove all associated underlings
  242. (i.e., FCB records).
  243. Arguments:
  244. Vcb - Supplies the Vcb to be removed
  245. Return Value:
  246. None
  247. --*/
  248. {
  249. DebugTrace(+1, Dbg, "RxDeleteVcb, Vcb = %08lx\n", Vcb);
  250. ASSERT(FALSE);
  251. //
  252. // Uninitialize the cache
  253. //
  254. RxSyncUninitializeCacheMap( RxContext, Vcb->VirtualVolumeFile );
  255. //
  256. // Dereference the virtual volume file. This will cause a close
  257. // Irp to be processed, so we need to do this before we destory
  258. // the Vcb
  259. //
  260. RxSetFileObject( Vcb->VirtualVolumeFile, UnopenedFileObject, NULL, NULL );
  261. ObDereferenceObject( Vcb->VirtualVolumeFile );
  262. //
  263. // Remove this record from the global list of all Vcb records
  264. //
  265. (VOID)RxAcquireExclusiveGlobal( RxContext );
  266. RemoveEntryList( &(Vcb->VcbLinks) );
  267. RxReleaseGlobal( RxContext );
  268. //
  269. // Make sure the direct access open count is zero, and the open file count
  270. // is also zero.
  271. //
  272. if ((Vcb->DirectAccessOpenCount != 0) || (Vcb->OpenFileCount != 0)) {
  273. RxBugCheck( 0, 0, 0 );
  274. }
  275. ASSERT( IsListEmpty( &Vcb->ParentDscbLinks ) );
  276. //
  277. // Remove the EaFcb and dereference the Fcb for the Ea file if it
  278. // exists.
  279. //
  280. if (Vcb->VirtualEaFile != NULL) {
  281. RxSetFileObject( Vcb->VirtualEaFile, UnopenedFileObject, NULL, NULL );
  282. RxSyncUninitializeCacheMap( RxContext, Vcb->VirtualEaFile );
  283. ObDereferenceObject( Vcb->VirtualEaFile );
  284. }
  285. if (Vcb->EaFcb != NULL) {
  286. Vcb->EaFcb->OpenCount = 0;
  287. RxDeleteFcb( RxContext, Vcb->EaFcb );
  288. Vcb->EaFcb = NULL;
  289. }
  290. //
  291. // Remove the Root Dcb
  292. //
  293. if (Vcb->RootDcb != NULL) {
  294. PFILE_OBJECT DirectoryFileObject = Vcb->RootDcb->Specific.Dcb.DirectoryFile;
  295. if (DirectoryFileObject != NULL) {
  296. RxSyncUninitializeCacheMap( RxContext, DirectoryFileObject );
  297. //
  298. // Dereference the directory file. This will cause a close
  299. // Irp to be processed, so we need to do this before we destory
  300. // the Fcb
  301. //
  302. Vcb->RootDcb->Specific.Dcb.DirectoryFile = NULL;
  303. Vcb->RootDcb->Specific.Dcb.DirectoryFileOpenCount -= 1;
  304. RxSetFileObject( DirectoryFileObject, UnopenedFileObject, NULL, NULL );
  305. ObDereferenceObject( DirectoryFileObject );
  306. }
  307. RxDeleteFcb( RxContext, Vcb->RootDcb );
  308. }
  309. //
  310. // Uninitialize the notify sychronization object.
  311. //
  312. FsRtlNotifyInitializeSync( &Vcb->NotifySync );
  313. //
  314. // Uninitialize the resource variable for the Vcb
  315. //
  316. RxDeleteResource( &Vcb->Resource );
  317. //
  318. // If allocation support has been setup, free it.
  319. //
  320. if (Vcb->FreeClusterBitMap.Buffer != NULL) {
  321. RxTearDownAllocationSupport( RxContext, Vcb );
  322. }
  323. //
  324. // UnInitialize the Mcb structure that kept track of dirty rx sectors.
  325. //
  326. FsRtlUninitializeMcb( &Vcb->DirtyRxMcb );
  327. //
  328. // Cancel the CleanVolume Timer and Dpc
  329. //
  330. (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
  331. (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
  332. #ifdef WE_WON_ON_APPEAL
  333. //
  334. // If there is a Dscb, dismount and delete it.
  335. //
  336. if (Vcb->Dscb) {
  337. RxDblsDismount( RxContext, &Vcb->Dscb );
  338. }
  339. #endif // WE_WON_ON_APPEAL
  340. //
  341. // And zero out the Vcb, this will help ensure that any stale data is
  342. // wiped clean
  343. //
  344. RtlZeroMemory( Vcb, sizeof(VCB) );
  345. //
  346. // return and tell the caller
  347. //
  348. DebugTrace(-1, Dbg, "RxDeleteVcb -> VOID\n", 0);
  349. return;
  350. }
  351. PDCB
  352. RxCreateRootDcb (
  353. IN PRX_CONTEXT RxContext,
  354. IN PVCB Vcb
  355. )
  356. /*++
  357. Routine Description:
  358. This routine allocates, initializes, and inserts a new root DCB record
  359. into the in memory data structure.
  360. Arguments:
  361. Vcb - Supplies the Vcb to associate the new DCB under
  362. Return Value:
  363. PDCB - returns pointer to the newly allocated root DCB.
  364. --*/
  365. {
  366. PDCB Dcb;
  367. //
  368. // The following variables are used for abnormal unwind
  369. //
  370. PVOID UnwindStorage[5] = { NULL, NULL, NULL, NULL, NULL };
  371. PERESOURCE UnwindResource = NULL;
  372. PMCB UnwindMcb = NULL;
  373. PFILE_OBJECT UnwindFileObject = NULL;
  374. DebugTrace(+1, Dbg, "RxCreateRootDcb, Vcb = %08lx\n", Vcb);
  375. ASSERT(FALSE);
  376. try {
  377. //
  378. // Make sure we don't already have a root dcb for this vcb
  379. //
  380. if (Vcb->RootDcb != NULL) {
  381. DebugDump("Error trying to create multiple root dcbs\n", 0, Vcb);
  382. RxBugCheck( 0, 0, 0 );
  383. }
  384. //
  385. // Allocate a new DCB and zero it out, we use Dcb locally so we don't
  386. // have to continually reference through the Vcb
  387. //
  388. UnwindStorage[0] = Dcb = Vcb->RootDcb = FsRtlAllocatePool(NonPagedPool, sizeof(DCB));
  389. RtlZeroMemory( Dcb, sizeof(DCB));
  390. UnwindStorage[1] =
  391. Dcb->NonPaged = RxAllocateNonPagedFcb();
  392. RtlZeroMemory( Dcb->NonPaged, sizeof( NON_PAGED_FCB ) );
  393. //
  394. // Set the proper node type code, node byte size, and call backs
  395. //
  396. Dcb->Header.NodeTypeCode = (NODE_TYPE_CODE)RDBSS_NTC_ROOT_DCB;
  397. Dcb->Header.NodeByteSize = sizeof(DCB);
  398. Dcb->FcbCondition = FcbGood;
  399. //
  400. // The parent Dcb, initial state, open count, dirent location
  401. // information, and directory change count fields are already zero so
  402. // we can skip setting them
  403. //
  404. // do this later since the space is now already allocated
  405. // //
  406. // // Initialize the resource variable
  407. // //
  408. //
  409. // UnwindStorage[2] =
  410. // Dcb->Header.Resource = RxAllocateResource();
  411. //
  412. // UnwindResource = Dcb->Header.Resource;
  413. //
  414. // Initialize the PagingIo Resource
  415. //
  416. Dcb->Header.PagingIoResource = FsRtlAllocateResource();
  417. //
  418. // The root Dcb has an empty parent dcb links field
  419. //
  420. InitializeListHead( &Dcb->ParentDcbLinks );
  421. //
  422. // Set the Vcb
  423. //
  424. Dcb->Vcb = Vcb;
  425. //
  426. // Initialize the Mcb, and setup its mapping. Note that the root
  427. // directory is a fixed size so we can set it everything up now.
  428. //
  429. FsRtlInitializeMcb( &Dcb->Mcb, NonPagedPool );
  430. UnwindMcb = &Dcb->Mcb;
  431. FsRtlAddMcbEntry( &Dcb->Mcb,
  432. 0,
  433. RxRootDirectoryLbo( &Vcb->Bpb ),
  434. RxRootDirectorySize( &Vcb->Bpb ));
  435. //
  436. // set the allocation size to real size of the root directory
  437. //
  438. Dcb->Header.FileSize.QuadPart =
  439. Dcb->Header.AllocationSize.QuadPart = RxRootDirectorySize( &Vcb->Bpb );
  440. //
  441. // initialize the notify queues, and the parent dcb queue.
  442. //
  443. InitializeListHead( &Dcb->Specific.Dcb.ParentDcbQueue );
  444. //
  445. // set the full file name. We actually allocate pool here to spare
  446. // a compare and jump.
  447. //
  448. Dcb->FullFileName.Buffer = L"\\";
  449. Dcb->FullFileName.Length = (USHORT)2;
  450. Dcb->FullFileName.MaximumLength = (USHORT)4;
  451. Dcb->ShortName.Name.Oem.Buffer = "\\";
  452. Dcb->ShortName.Name.Oem.Length = (USHORT)1;
  453. Dcb->ShortName.Name.Oem.MaximumLength = (USHORT)2;
  454. //
  455. // Set our two create dirent aids to represent that we have yet to
  456. // enumerate the directory for never used or deleted dirents.
  457. //
  458. Dcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
  459. Dcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
  460. //
  461. // Setup the free dirent bitmap buffer.
  462. //
  463. RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
  464. NULL,
  465. 0 );
  466. RxCheckFreeDirentBitmap( RxContext, Dcb );
  467. } finally {
  468. DebugUnwind( RxCreateRootDcb );
  469. //
  470. // If this is an abnormal termination then undo our work
  471. //
  472. if (AbnormalTermination()) {
  473. ULONG i;
  474. if (UnwindFileObject != NULL) { ObDereferenceObject( UnwindFileObject ); }
  475. if (UnwindMcb != NULL) { FsRtlUninitializeMcb( UnwindMcb ); }
  476. if (UnwindResource != NULL) { RxDeleteResource( UnwindResource ); }
  477. for (i = 0; i < 4; i += 1) {
  478. if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
  479. }
  480. } else {
  481. Dcb->Header.Resource = &Dcb->NonPaged->HeaderResource;
  482. ExInitializeResource(Dcb->Header.Resource);
  483. }
  484. DebugTrace(-1, Dbg, "RxCreateRootDcb -> %8lx\n", Dcb);
  485. }
  486. //
  487. // return and tell the caller
  488. //
  489. return Dcb;
  490. }
  491. PFCB
  492. RxCreateFcb (
  493. IN PRX_CONTEXT RxContext,
  494. IN PVCB Vcb,
  495. IN PDCB ParentDcb,
  496. IN ULONG LfnOffsetWithinDirectory,
  497. IN ULONG DirentOffsetWithinDirectory,
  498. IN PDIRENT Dirent,
  499. IN PUNICODE_STRING Lfn OPTIONAL,
  500. IN BOOLEAN IsPagingFile
  501. )
  502. /*++
  503. Routine Description:
  504. This routine allocates, initializes, and inserts a new Fcb record into
  505. the in memory data structures.
  506. Arguments:
  507. Vcb - Supplies the Vcb to associate the new FCB under.
  508. ParentDcb - Supplies the parent dcb that the new FCB is under.
  509. LfnOffsetWithinDirectory - Supplies the offset of the LFN. If there is
  510. no LFN associated with this file then this value is same as
  511. DirentOffsetWithinDirectory.
  512. DirentOffsetWithinDirectory - Supplies the offset, in bytes from the
  513. start of the directory file where the dirent for the fcb is located
  514. Dirent - Supplies the dirent for the fcb being created
  515. Lfn - Supplies a long UNICODE name associated with this file.
  516. IsPagingFile - Indicates if we are creating an FCB for a paging file
  517. or some other type of file.
  518. Return Value:
  519. PFCB - Returns a pointer to the newly allocated FCB
  520. --*/
  521. {
  522. PFCB Fcb;
  523. POOL_TYPE PoolType;
  524. //
  525. // The following variables are used for abnormal unwind
  526. //
  527. PVOID UnwindStorage[3] = { NULL, NULL, NULL };
  528. PERESOURCE UnwindResource = NULL;
  529. PLIST_ENTRY UnwindEntryList = NULL;
  530. PMCB UnwindMcb = NULL;
  531. PFILE_LOCK UnwindFileLock = NULL;
  532. POPLOCK UnwindOplock = NULL;
  533. DebugTrace(+1, Dbg, "RxCreateFcb\n", 0);
  534. ASSERT(FALSE);
  535. try {
  536. //
  537. // Determine the pool type we should be using for the fcb and the
  538. // mcb structure
  539. //
  540. if (IsPagingFile) {
  541. PoolType = NonPagedPool;
  542. Fcb = UnwindStorage[0] = FsRtlAllocatePool( NonPagedPool, sizeof(FCB) );
  543. } else {
  544. PoolType = PagedPool;
  545. Fcb = UnwindStorage[0] = RxAllocateFcb();
  546. }
  547. //
  548. // Allocate a new FCB, and zero it out
  549. //
  550. RtlZeroMemory( Fcb, sizeof(FCB) );
  551. UnwindStorage[1] =
  552. Fcb->NonPaged = RxAllocateNonPagedFcb();
  553. RtlZeroMemory( Fcb->NonPaged, sizeof( NON_PAGED_FCB ) );
  554. //
  555. // Set the proper node type code, node byte size, and call backs
  556. //
  557. Fcb->Header.NodeTypeCode = (NODE_TYPE_CODE)RDBSS_NTC_FCB;
  558. Fcb->Header.NodeByteSize = sizeof(FCB);
  559. Fcb->FcbCondition = FcbGood;
  560. //
  561. // Check to see if we need to set the Fcb state to indicate that this
  562. // is a paging file
  563. //
  564. if (IsPagingFile) {
  565. Fcb->FcbState |= FCB_STATE_PAGING_FILE;
  566. }
  567. //
  568. // The initial state, open count, and segment objects fields are already
  569. // zero so we can skip setting them
  570. //
  571. // space has already been allocatd in nonpaged part don't do this
  572. // //
  573. // // Initialize the resource variable
  574. // //
  575. //
  576. // UnwindStorage[2] =
  577. // Fcb->Header.Resource = RxAllocateResource();
  578. //
  579. // UnwindResource = Fcb->Header.Resource;
  580. //
  581. // Initialize the PagingIo Resource
  582. //
  583. Fcb->Header.PagingIoResource = FsRtlAllocateResource();
  584. //
  585. // Insert this fcb into our parent dcb's queue
  586. //
  587. InsertTailList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
  588. &Fcb->ParentDcbLinks );
  589. UnwindEntryList = &Fcb->ParentDcbLinks;
  590. //
  591. // Point back to our parent dcb
  592. //
  593. Fcb->ParentDcb = ParentDcb;
  594. //
  595. // Set the Vcb
  596. //
  597. Fcb->Vcb = Vcb;
  598. //
  599. // Set the dirent offset within the directory
  600. //
  601. Fcb->LfnOffsetWithinDirectory = LfnOffsetWithinDirectory;
  602. Fcb->DirentOffsetWithinDirectory = DirentOffsetWithinDirectory;
  603. //
  604. // Set the DirentRxFlags and LastWriteTime
  605. //
  606. Fcb->DirentRxFlags = Dirent->Attributes;
  607. Fcb->LastWriteTime = RxRxTimeToNtTime( RxContext,
  608. Dirent->LastWriteTime,
  609. 0 );
  610. //
  611. // These fields are only non-zero when in Chicago mode.
  612. //
  613. if (RxData.ChicagoMode) {
  614. LARGE_INTEGER RxSystemJanOne1980;
  615. //
  616. // If either date is possibly zero, get the system
  617. // version of 1/1/80.
  618. //
  619. if ((((PUSHORT)Dirent)[9] & ((PUSHORT)Dirent)[8]) == 0) {
  620. ExLocalTimeToSystemTime( &RxJanOne1980,
  621. &RxSystemJanOne1980 );
  622. }
  623. //
  624. // Only do the really hard work if this field is non-zero.
  625. //
  626. if (((PUSHORT)Dirent)[9] != 0) {
  627. Fcb->LastAccessTime =
  628. RxRxDateToNtTime( RxContext,
  629. Dirent->LastAccessDate );
  630. } else {
  631. Fcb->LastAccessTime = RxSystemJanOne1980;
  632. }
  633. //
  634. // Only do the really hard work if this field is non-zero.
  635. //
  636. if (((PUSHORT)Dirent)[8] != 0) {
  637. Fcb->CreationTime =
  638. RxRxTimeToNtTime( RxContext,
  639. Dirent->CreationTime,
  640. Dirent->CreationMSec );
  641. } else {
  642. Fcb->CreationTime = RxSystemJanOne1980;
  643. }
  644. }
  645. //
  646. // Initialize the Mcb
  647. //
  648. FsRtlInitializeMcb( &Fcb->Mcb, PoolType );
  649. UnwindMcb = &Fcb->Mcb;
  650. //
  651. // Set the file size, valid data length, first cluster of file,
  652. // and allocation size based on the information stored in the dirent
  653. //
  654. Fcb->Header.FileSize.LowPart = Dirent->FileSize;
  655. Fcb->Header.ValidDataLength.LowPart = Dirent->FileSize;
  656. Fcb->FirstClusterOfFile = (ULONG)Dirent->FirstClusterOfFile;
  657. if ( Fcb->FirstClusterOfFile == 0 ) {
  658. Fcb->Header.AllocationSize = RxLargeZero;
  659. } else {
  660. Fcb->Header.AllocationSize.QuadPart = -1;
  661. }
  662. //
  663. // Initialize the Fcb's file lock record
  664. //
  665. FsRtlInitializeFileLock( &Fcb->Specific.Fcb.FileLock, NULL, NULL );
  666. UnwindFileLock = &Fcb->Specific.Fcb.FileLock;
  667. //
  668. // Initialize the oplock structure.
  669. //
  670. FsRtlInitializeOplock( &Fcb->Specific.Fcb.Oplock );
  671. UnwindOplock = &Fcb->Specific.Fcb.Oplock;
  672. //
  673. // Indicate that Fast I/O is possible
  674. //
  675. Fcb->Header.IsFastIoPossible = TRUE;
  676. //
  677. // Set the file names. This must be the last thing we do.
  678. //
  679. RxConstructNamesInFcb( RxContext,
  680. Fcb,
  681. Dirent,
  682. Lfn );
  683. } finally {
  684. DebugUnwind( RxCreateFcb );
  685. //
  686. // If this is an abnormal termination then undo our work
  687. //
  688. if (AbnormalTermination()) {
  689. ULONG i;
  690. if (UnwindOplock != NULL) { FsRtlUninitializeOplock( UnwindOplock ); }
  691. if (UnwindFileLock != NULL) { FsRtlUninitializeFileLock( UnwindFileLock ); }
  692. if (UnwindMcb != NULL) { FsRtlUninitializeMcb( UnwindMcb ); }
  693. if (UnwindEntryList != NULL) { RemoveEntryList( UnwindEntryList ); }
  694. if (UnwindResource != NULL) { RxDeleteResource( UnwindResource ); }
  695. for (i = 0; i < 3; i += 1) {
  696. if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
  697. }
  698. } else {
  699. Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
  700. ExInitializeResource(Fcb->Header.Resource);
  701. }
  702. DebugTrace(-1, Dbg, "RxCreateFcb -> %08lx\n", Fcb);
  703. }
  704. //
  705. // return and tell the caller
  706. //
  707. return Fcb;
  708. }
  709. PDCB
  710. RxCreateDcb (
  711. IN PRX_CONTEXT RxContext,
  712. IN PVCB Vcb,
  713. IN PDCB ParentDcb,
  714. IN ULONG LfnOffsetWithinDirectory,
  715. IN ULONG DirentOffsetWithinDirectory,
  716. IN PDIRENT Dirent,
  717. IN PUNICODE_STRING Lfn OPTIONAL
  718. )
  719. /*++
  720. Routine Description:
  721. This routine allocates, initializes, and inserts a new Dcb record into
  722. the in memory data structures.
  723. Arguments:
  724. Vcb - Supplies the Vcb to associate the new DCB under.
  725. ParentDcb - Supplies the parent dcb that the new DCB is under.
  726. LfnOffsetWithinDirectory - Supplies the offset of the LFN. If there is
  727. no LFN associated with this file then this value is same as
  728. DirentOffsetWithinDirectory.
  729. DirentOffsetWithinDirectory - Supplies the offset, in bytes from the
  730. start of the directory file where the dirent for the fcb is located
  731. Dirent - Supplies the dirent for the dcb being created
  732. FileName - Supplies the file name of the file relative to the directory
  733. it's in (e.g., the file \config.sys is called "CONFIG.SYS" without
  734. the preceding backslash).
  735. Lfn - Supplies a long UNICODE name associated with this directory.
  736. Return Value:
  737. PDCB - Returns a pointer to the newly allocated DCB
  738. --*/
  739. {
  740. PDCB Dcb;
  741. //
  742. // The following variables are used for abnormal unwind
  743. //
  744. PVOID UnwindStorage[4] = { NULL, NULL, NULL, NULL };
  745. PERESOURCE UnwindResource = NULL;
  746. PLIST_ENTRY UnwindEntryList = NULL;
  747. PMCB UnwindMcb = NULL;
  748. DebugTrace(+1, Dbg, "RxCreateDcb\n", 0);
  749. ASSERT(FALSE);
  750. try {
  751. //
  752. // assert that the only time we are called is if wait is true
  753. //
  754. ASSERT( FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) );
  755. //
  756. // Allocate a new DCB, and zero it out
  757. //
  758. UnwindStorage[0] = Dcb = RxAllocateFcb();
  759. RtlZeroMemory( Dcb, sizeof(DCB) );
  760. UnwindStorage[1] =
  761. Dcb->NonPaged = RxAllocateNonPagedFcb();
  762. RtlZeroMemory( Dcb->NonPaged, sizeof( NON_PAGED_FCB ) );
  763. //
  764. // Set the proper node type code, node byte size and call backs
  765. //
  766. Dcb->Header.NodeTypeCode = (NODE_TYPE_CODE)RDBSS_NTC_DCB;
  767. Dcb->Header.NodeByteSize = sizeof(DCB);
  768. Dcb->FcbCondition = FcbGood;
  769. //
  770. // The initial state, open count, and directory change count fields are
  771. // already zero so we can skip setting them
  772. //
  773. //space allready allocated in nonpaged part
  774. // //
  775. // // Initialize the resource variable
  776. // //
  777. //
  778. // UnwindStorage[2] =
  779. // Dcb->Header.Resource = RxAllocateResource();
  780. UnwindResource = Dcb->Header.Resource;
  781. //
  782. // Initialize the PagingIo Resource
  783. //
  784. Dcb->Header.PagingIoResource = FsRtlAllocateResource();
  785. //
  786. // Insert this Dcb into our parent dcb's queue
  787. //
  788. InsertTailList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
  789. &Dcb->ParentDcbLinks );
  790. UnwindEntryList = &Dcb->ParentDcbLinks;
  791. //
  792. // Point back to our parent dcb
  793. //
  794. Dcb->ParentDcb = ParentDcb;
  795. //
  796. // Set the Vcb
  797. //
  798. Dcb->Vcb = Vcb;
  799. //
  800. // Set the dirent offset within the directory
  801. //
  802. Dcb->LfnOffsetWithinDirectory = LfnOffsetWithinDirectory;
  803. Dcb->DirentOffsetWithinDirectory = DirentOffsetWithinDirectory;
  804. //
  805. // Set the DirentRxFlags and LastWriteTime
  806. //
  807. Dcb->DirentRxFlags = Dirent->Attributes;
  808. Dcb->LastWriteTime = RxRxTimeToNtTime( RxContext,
  809. Dirent->LastWriteTime,
  810. 0 );
  811. //
  812. // These fields are only non-zero when in Chicago mode.
  813. //
  814. if (RxData.ChicagoMode) {
  815. LARGE_INTEGER RxSystemJanOne1980;
  816. //
  817. // If either date is possibly zero, get the system
  818. // version of 1/1/80.
  819. //
  820. if ((((PUSHORT)Dirent)[9] & ((PUSHORT)Dirent)[8]) == 0) {
  821. ExLocalTimeToSystemTime( &RxJanOne1980,
  822. &RxSystemJanOne1980 );
  823. }
  824. //
  825. // Only do the really hard work if this field is non-zero.
  826. //
  827. if (((PUSHORT)Dirent)[9] != 0) {
  828. Dcb->LastAccessTime =
  829. RxRxDateToNtTime( RxContext,
  830. Dirent->LastAccessDate );
  831. } else {
  832. Dcb->LastAccessTime = RxSystemJanOne1980;
  833. }
  834. //
  835. // Only do the really hard work if this field is non-zero.
  836. //
  837. if (((PUSHORT)Dirent)[8] != 0) {
  838. Dcb->CreationTime =
  839. RxRxTimeToNtTime( RxContext,
  840. Dirent->CreationTime,
  841. Dirent->CreationMSec );
  842. } else {
  843. Dcb->CreationTime = RxSystemJanOne1980;
  844. }
  845. }
  846. //
  847. // Initialize the Mcb
  848. //
  849. FsRtlInitializeMcb( &Dcb->Mcb, PagedPool );
  850. UnwindMcb = &Dcb->Mcb;
  851. //
  852. // Set the file size, first cluster of file, and allocation size
  853. // based on the information stored in the dirent
  854. //
  855. Dcb->FirstClusterOfFile = (ULONG)Dirent->FirstClusterOfFile;
  856. if ( Dcb->FirstClusterOfFile == 0 ) {
  857. Dcb->Header.AllocationSize.QuadPart = 0;
  858. } else {
  859. Dcb->Header.AllocationSize.QuadPart = -1;
  860. }
  861. // initialize the notify queues, and the parent dcb queue.
  862. //
  863. InitializeListHead( &Dcb->Specific.Dcb.ParentDcbQueue );
  864. //
  865. // Setup the free dirent bitmap buffer. Since we don't know the
  866. // size of the directory, leave it zero for now.
  867. //
  868. RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
  869. NULL,
  870. 0 );
  871. //
  872. // Set our two create dirent aids to represent that we have yet to
  873. // enumerate the directory for never used or deleted dirents.
  874. //
  875. Dcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
  876. Dcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
  877. //
  878. // Postpone initializing the cache map until we need to do a read/write
  879. // of the directory file.
  880. //
  881. // set the file names. This must be the last thing we do.
  882. //
  883. RxConstructNamesInFcb( RxContext,
  884. Dcb,
  885. Dirent,
  886. Lfn );
  887. } finally {
  888. DebugUnwind( RxCreateDcb );
  889. //
  890. // If this is an abnormal termination then undo our work
  891. //
  892. if (AbnormalTermination()) {
  893. ULONG i;
  894. if (UnwindMcb != NULL) { FsRtlUninitializeMcb( UnwindMcb ); }
  895. if (UnwindEntryList != NULL) { RemoveEntryList( UnwindEntryList ); }
  896. if (UnwindResource != NULL) { RxDeleteResource( UnwindResource ); }
  897. for (i = 0; i < 4; i += 1) {
  898. if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
  899. }
  900. } else {
  901. Dcb->Header.Resource = &Dcb->NonPaged->HeaderResource;
  902. ExInitializeResource(Dcb->Header.Resource);
  903. }
  904. DebugTrace(-1, Dbg, "RxCreateDcb -> %08lx\n", Dcb);
  905. }
  906. //
  907. // return and tell the caller
  908. //
  909. DebugTrace(-1, Dbg, "RxCreateDcb -> %08lx\n", Dcb);
  910. return Dcb;
  911. }
  912. VOID
  913. RxDeleteFcb_Real (
  914. IN PRX_CONTEXT RxContext,
  915. IN PFCB Fcb
  916. )
  917. /*++
  918. Routine Description:
  919. This routine deallocates and removes an FCB, DCB, or ROOT DCB record
  920. from Rx's in-memory data structures. It also will remove all
  921. associated underlings (i.e., Notify irps, and child FCB/DCB records).
  922. Arguments:
  923. Fcb - Supplies the FCB/DCB/ROOT DCB to be removed
  924. Return Value:
  925. None
  926. --*/
  927. {
  928. DebugTrace(+1, Dbg, "RxDeleteFcb, Fcb = %08lx\n", Fcb);
  929. ASSERT(FALSE);
  930. //
  931. // We can only delete this record if the open count is zero.
  932. //
  933. if (Fcb->OpenCount != 0) {
  934. DebugDump("Error deleting Fcb, Still Open\n", 0, Fcb);
  935. RxBugCheck( 0, 0, 0 );
  936. }
  937. //
  938. // If this is a DCB then remove every Notify record from the two
  939. // notify queues
  940. //
  941. if ((Fcb->Header.NodeTypeCode == RDBSS_NTC_DCB) ||
  942. (Fcb->Header.NodeTypeCode == RDBSS_NTC_ROOT_DCB)) {
  943. //
  944. // If we allocated a free dirent bitmap buffer, free it.
  945. //
  946. if ((Fcb->Specific.Dcb.FreeDirentBitmap.Buffer != NULL) &&
  947. (Fcb->Specific.Dcb.FreeDirentBitmap.Buffer !=
  948. &Fcb->Specific.Dcb.FreeDirentBitmapBuffer[0])) {
  949. ExFreePool(Fcb->Specific.Dcb.FreeDirentBitmap.Buffer);
  950. }
  951. ASSERT( Fcb->Specific.Dcb.DirectoryFileOpenCount == 0 );
  952. ASSERT( IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) );
  953. } else {
  954. //
  955. // Uninitialize the byte range file locks and opportunistic locks
  956. //
  957. FsRtlUninitializeFileLock( &Fcb->Specific.Fcb.FileLock );
  958. FsRtlUninitializeOplock( &Fcb->Specific.Fcb.Oplock );
  959. }
  960. //
  961. // Uninitialize the Mcb
  962. //
  963. FsRtlUninitializeMcb( &Fcb->Mcb );
  964. //
  965. // If this is not the root dcb then we need to remove ourselves from
  966. // our parents Dcb queue
  967. //
  968. if (Fcb->Header.NodeTypeCode != RDBSS_NTC_ROOT_DCB) {
  969. RemoveEntryList( &(Fcb->ParentDcbLinks) );
  970. }
  971. //
  972. // Remove the entry from the splay table if there is still is one.
  973. //
  974. if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) {
  975. RxRemoveNames( RxContext, Fcb );
  976. }
  977. //
  978. // Free the file name pool if allocated.
  979. //
  980. if (Fcb->Header.NodeTypeCode != RDBSS_NTC_ROOT_DCB) {
  981. ExFreePool( Fcb->ShortName.Name.Oem.Buffer );
  982. if (Fcb->FullFileName.Buffer) {
  983. ExFreePool( Fcb->FullFileName.Buffer );
  984. }
  985. }
  986. //
  987. // Free up the resource variable. If we are below RxForceCacheMiss(),
  988. // release the resource here.
  989. //
  990. if (FlagOn( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS) ) {
  991. // RxReleaseFcb( RxContext, Fcb );
  992. // DavidGoe 5/26/94 - No reason to release the resource here.
  993. }
  994. //
  995. // Finally deallocate the Fcb and non-paged fcb records
  996. //
  997. //joejoe i put these tests here so that i could use these routines with some fields NULL
  998. if ( Fcb->Header.Resource != NULL )ExDeleteResource( Fcb->Header.Resource );
  999. if ( Fcb->NonPaged != NULL ) RxFreeNonPagedFcb( Fcb->NonPaged );
  1000. RxFreeFcb( Fcb );
  1001. //
  1002. // and return to our caller
  1003. //
  1004. DebugTrace(-1, Dbg, "RxDeleteFcb -> VOID\n", 0);
  1005. return;
  1006. }
  1007. PFOBX
  1008. RxCreateFobx (
  1009. IN PRX_CONTEXT RxContext
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. This routine creates a new FOBX record
  1014. Arguments:
  1015. Return Value:
  1016. FOBX - returns a pointer to the newly allocate FOBX
  1017. --*/
  1018. {
  1019. PFOBX Fobx;
  1020. DebugTrace(+1, Dbg, "RxCreateFobx\n", 0);
  1021. ASSERT(FALSE);
  1022. //
  1023. // Allocate a new FOBX Record
  1024. //
  1025. Fobx = RxAllocateFobx();
  1026. RtlZeroMemory( Fobx, sizeof(FOBX) );
  1027. //
  1028. // Set the proper node type code and node byte size
  1029. //
  1030. Fobx->NodeTypeCode = RDBSS_NTC_FOBX;
  1031. Fobx->NodeByteSize = sizeof(FOBX);
  1032. //
  1033. // return and tell the caller
  1034. //
  1035. DebugTrace(-1, Dbg, "RxCreateFobx -> %08lx\n", Fobx);
  1036. UNREFERENCED_PARAMETER( RxContext );
  1037. return Fobx;
  1038. }
  1039. VOID
  1040. RxDeleteFobx_Real (
  1041. IN PRX_CONTEXT RxContext,
  1042. IN PFOBX Fobx
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. This routine deallocates and removes the specified FOBX record
  1047. from the Rx in memory data structures
  1048. Arguments:
  1049. Fobx - Supplies the FOBX to remove
  1050. Return Value:
  1051. None
  1052. --*/
  1053. {
  1054. DebugTrace(+1, Dbg, "RxDeleteFobx, Fobx = %08lx\n", Fobx);
  1055. ASSERT(FALSE);
  1056. //
  1057. // If we allocated query template buffers, deallocate them now.
  1058. //
  1059. if (FlagOn(Fobx->Flags, FOBX_FLAG_FREE_UNICODE)) {
  1060. ASSERT( Fobx->UnicodeQueryTemplate.Buffer );
  1061. RtlFreeUnicodeString( &Fobx->UnicodeQueryTemplate );
  1062. }
  1063. // if (FlagOn(Fobx->Flags, FOBX_FLAG_FREE_OEM_BEST_FIT)) {
  1064. //
  1065. // ASSERT( Fobx->OemQueryTemplate.Wild.Buffer );
  1066. // RtlFreeOemString( &Fobx->OemQueryTemplate.Wild );
  1067. // }
  1068. //
  1069. // Deallocate the Fobx record
  1070. //
  1071. RxFreeFobx( Fobx );
  1072. //
  1073. // return and tell the caller
  1074. //
  1075. DebugTrace(-1, Dbg, "RxDeleteFobx -> VOID\n", 0);
  1076. UNREFERENCED_PARAMETER( RxContext );
  1077. return;
  1078. }
  1079. PFCB
  1080. RxGetNextFcb (
  1081. IN PRX_CONTEXT RxContext,
  1082. IN PFCB Fcb,
  1083. IN PFCB TerminationFcb
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. This routine is used to itterate through Fcbs in a tree.
  1088. The rule is very simple:
  1089. A) If you have a child, go to it, else
  1090. B) If you have an older sibling, go to it, else
  1091. C) Go to your parent's older sibling.
  1092. If this routine is called with in invalid TerminationFcb it will fail,
  1093. badly.
  1094. Arguments:
  1095. Fcb - Supplies the current Fcb
  1096. TerminationFcb - The Fcb at which the enumeration should (non-inclusivly)
  1097. stop. Assumed to be a directory.
  1098. Return Value:
  1099. The next Fcb in the enumeration, or NULL if Fcb was the final one.
  1100. --*/
  1101. {
  1102. PFCB Sibling;
  1103. ASSERT(FALSE);
  1104. ASSERT( RxVcbAcquiredExclusive( RxContext, Fcb->Vcb ) ||
  1105. FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
  1106. //
  1107. // If this was a directory (ie. not a file), get the child. If
  1108. // there aren't any children and this is our termination Fcb,
  1109. // return NULL.
  1110. //
  1111. if ( ((NodeType(Fcb) == RDBSS_NTC_DCB) ||
  1112. (NodeType(Fcb) == RDBSS_NTC_ROOT_DCB)) &&
  1113. !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) ) {
  1114. return RxGetFirstChild( Fcb );
  1115. }
  1116. //
  1117. // Were we only meant to do one itteration?
  1118. //
  1119. if ( Fcb == TerminationFcb ) {
  1120. return NULL;
  1121. }
  1122. Sibling = RxGetNextSibling(Fcb);
  1123. while (TRUE) {
  1124. //
  1125. // Do we still have an "older" sibling in this directory who is
  1126. // not the termination Fcb?
  1127. //
  1128. if ( Sibling != NULL ) {
  1129. return (Sibling != TerminationFcb) ? Sibling : NULL;
  1130. }
  1131. //
  1132. // OK, let's move on to out parent and see if he is the termination
  1133. // node or has any older siblings.
  1134. //
  1135. if ( Fcb->ParentDcb == TerminationFcb ) {
  1136. return NULL;
  1137. }
  1138. Fcb = Fcb->ParentDcb;
  1139. Sibling = RxGetNextSibling(Fcb);
  1140. }
  1141. }
  1142. BOOLEAN
  1143. RxCheckForDismount (
  1144. IN PRX_CONTEXT RxContext,
  1145. PVCB Vcb
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. This routine determines if a volume is ready for deletion. It
  1150. correctly synchronizes with creates en-route to the file system.
  1151. Arguments:
  1152. Vcb - Supplies the volue to examine
  1153. Return Value:
  1154. BOOLEAN - TRUE if the volume was deleted, FALSE otherwise.
  1155. --*/
  1156. {
  1157. KIRQL SavedIrql;
  1158. ULONG ResidualReferenceCount;
  1159. //
  1160. // Compute if the volume is OK to tear down. There should only be two
  1161. // residual file objects, one for the volume file and one for the root
  1162. // directory. If we are in the midst of a create (of an unmounted
  1163. // volume that has failed verify) then there will be an additional
  1164. // reference.
  1165. //
  1166. if ((RxContext->MajorFunction == IRP_MJ_CREATE) &&
  1167. (RxContext->RealDevice == Vcb->CurrentDevice)) {
  1168. ResidualReferenceCount = 3;
  1169. } else {
  1170. ResidualReferenceCount = 2;
  1171. }
  1172. //
  1173. // Now check for a zero Vpb count on an unmounted volume. These
  1174. // volumes will be deleted as they now have no file objects and
  1175. // there are no creates en route to this volume.
  1176. //
  1177. IoAcquireVpbSpinLock( &SavedIrql );
  1178. if (Vcb->Vpb->ReferenceCount == ResidualReferenceCount) {
  1179. PVPB Vpb = Vcb->Vpb;
  1180. #if DBG
  1181. UNICODE_STRING VolumeLabel;
  1182. //
  1183. // Setup the VolumeLabel string
  1184. //
  1185. VolumeLabel.Length = Vcb->Vpb->VolumeLabelLength;
  1186. VolumeLabel.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  1187. VolumeLabel.Buffer = &Vcb->Vpb->VolumeLabel[0];
  1188. KdPrint(("FASTRDBSS: Dismounting Volume %wZ\n", &VolumeLabel));
  1189. #endif // DBG
  1190. //
  1191. // Clear the VPB_MOUNTED bit so that new creates will not come
  1192. // to this volume. We must leave the Vpb->DeviceObject field
  1193. // set until after the DeleteVcb call as two closes will
  1194. // have to make their back to us.
  1195. //
  1196. // Note also that if we were called from close, it will take care
  1197. // of freeing the Vpb if it is not the primary one, otherwise
  1198. // if we were called from Create->Verify, IopParseDevice will
  1199. // take care of freeing the Vpb in its Reparse path.
  1200. //
  1201. ClearFlag( Vpb->Flags, VPB_MOUNTED );
  1202. //
  1203. // If this Vpb was locked, clear this flag now.
  1204. //
  1205. ClearFlag( Vpb->Flags, VPB_LOCKED );
  1206. //
  1207. // This will prevent anybody else from attempting to mount this
  1208. // volume. Also if this volume was mounted on a "wanna-be" real
  1209. // device object, keep anybody from following the link, and the Io
  1210. // system from deleting the Vpb.
  1211. //
  1212. if ((Vcb->CurrentDevice != Vpb->RealDevice) &&
  1213. (Vcb->CurrentDevice->Vpb == Vpb)) {
  1214. SetFlag( Vcb->CurrentDevice->Flags, DO_DEVICE_INITIALIZING );
  1215. SetFlag( Vpb->Flags, VPB_PERSISTENT );
  1216. }
  1217. IoReleaseVpbSpinLock( SavedIrql );
  1218. RxDeleteVcb( RxContext, Vcb );
  1219. Vpb->DeviceObject = NULL;
  1220. IoDeleteDevice( (PDEVICE_OBJECT)
  1221. CONTAINING_RECORD( Vcb,
  1222. RDBSS_DEVICE_OBJECT,
  1223. Vcb ) );
  1224. return TRUE;
  1225. } else {
  1226. IoReleaseVpbSpinLock( SavedIrql );
  1227. return FALSE;
  1228. }
  1229. }
  1230. VOID
  1231. RxConstructNamesInFcb (
  1232. IN PRX_CONTEXT RxContext,
  1233. PFCB Fcb,
  1234. PDIRENT Dirent,
  1235. PUNICODE_STRING Lfn OPTIONAL
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. This routine places the short name in the dirent in the first set of
  1240. STRINGs in the Fcb. If a long file name (Lfn) was specified, then
  1241. we must decide whether we will store its Oem equivolent in the same
  1242. prefix table as the short name, or rather just save the upcased
  1243. version of the UNICODE string in the FCB.
  1244. For looking up Fcbs, the first approach will be faster, so we want to
  1245. do this as much as possible. Here are the rules that I have thought
  1246. through extensively to determine when it is safe to store only Oem
  1247. version of the UNICODE name.
  1248. - If the UNICODE name contains no extended characters (>0x80), use Oem.
  1249. - Let U be the upcased version of the UNICODE name.
  1250. Let Up(x) be the function that upcases a UNICODE string.
  1251. Let Down(x) be the function that upcases a UNICODE string.
  1252. Let OemToUni(x) be the function that converts an Oem string to Unicode.
  1253. Let UniToOem(x) be the function that converts a Unicode string to Oem.
  1254. Let BestOemFit(x) be the function that creates the Best uppercase Oem
  1255. fit for the UNICODE string x.
  1256. BestOemFit(x) = UniToOem(Up(OemToUni(UniToOem(x)))) <1>
  1257. if (BestOemFit(U) == BestOemFit(Down(U)) <2>
  1258. then I know that there exists no UNICODE string Y such that:
  1259. Up(Y) == Up(U) <3>
  1260. AND
  1261. BestOemFit(U) != BestOemFit(Y) <4>
  1262. Consider string U as a collection of one character strings. The
  1263. conjecture is clearly true for each sub-string, thus it is true
  1264. for the entire string.
  1265. Equation <1> is what we use to convert an incoming unicode name in
  1266. RxCommonCreate() to Oem. The double conversion is done to provide
  1267. better visual best fitting for characters in the Ansi code page but
  1268. not in the Oem code page. A single Nls routine is provided to do
  1269. this conversion efficiently.
  1270. The idea is that with U, I only have to worry about a case varient Y
  1271. matching it in a unicode compare, and I have shown that any case varient
  1272. of U (the set Y defined in equation <3>), when filtered through <1>
  1273. (as in create), will match the Oem string defined in <1>.
  1274. Thus I do not have to worry about another UNICODE string missing in
  1275. the prefix lookup, but matching when comparing LFNs in the directory.
  1276. Arguments:
  1277. Fcb - The Fcb we are supposed to fill in. Note that ParentDcb must
  1278. already be filled in.
  1279. Dirent - The gives up the short name.
  1280. Lfn - If provided, this gives us the long name.
  1281. Return Value:
  1282. None
  1283. --*/
  1284. {
  1285. RXSTATUS Status;
  1286. ULONG i;
  1287. OEM_STRING OemA;
  1288. OEM_STRING OemB;
  1289. POEM_STRING ShortName;
  1290. POEM_STRING LongOemName;
  1291. PUNICODE_STRING LongUniName;
  1292. ShortName = &Fcb->ShortName.Name.Oem;
  1293. try {
  1294. //
  1295. // First do the short name.
  1296. //
  1297. ShortName->MaximumLength = 16;
  1298. ShortName->Buffer = FsRtlAllocatePool( PagedPool, 16);
  1299. Rx8dot3ToString( RxContext, Dirent, FALSE, ShortName );
  1300. //
  1301. // If no Lfn was specified, we are done. In either case, set the
  1302. // final name length.
  1303. //
  1304. if (!ARGUMENT_PRESENT(Lfn) || (Lfn->Length == 0)) {
  1305. Fcb->FinalNameLength = (USHORT)
  1306. RtlOemStringToCountedUnicodeSize( ShortName );
  1307. try_return( NOTHING );
  1308. } else {
  1309. Fcb->FinalNameLength = Lfn->Length;
  1310. }
  1311. //
  1312. // First check for no extended characters.
  1313. //
  1314. for (i=0; i < Lfn->Length/sizeof(WCHAR); i++) {
  1315. if (Lfn->Buffer[i] >= 0x80) {
  1316. break;
  1317. }
  1318. }
  1319. if (i == Lfn->Length/sizeof(WCHAR)) {
  1320. //
  1321. // Cool, I can go with the Oem, upcase it fast by hand.
  1322. //
  1323. LongOemName = &Fcb->LongName.Oem.Name.Oem;
  1324. LongOemName->Buffer = FsRtlAllocatePool( PagedPool,
  1325. Lfn->Length/sizeof(WCHAR) );
  1326. LongOemName->Length =
  1327. LongOemName->MaximumLength = Lfn->Length/sizeof(WCHAR);
  1328. for (i=0; i < Lfn->Length/sizeof(WCHAR); i++) {
  1329. WCHAR c;
  1330. c = Lfn->Buffer[i];
  1331. LongOemName->Buffer[i] = c < 'a' ?
  1332. (UCHAR)c :
  1333. c <= 'z' ?
  1334. c - (UCHAR)('a'-'A') :
  1335. (UCHAR) c;
  1336. }
  1337. //
  1338. // If this name happens to be exactly the same as the short
  1339. // name, don't add it to the splay table.
  1340. //
  1341. if (RxAreNamesEqual(RxContext, *ShortName, *LongOemName) ||
  1342. (RxFindFcb( RxContext,
  1343. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  1344. LongOemName) != NULL)) {
  1345. ExFreePool( LongOemName->Buffer );
  1346. LongOemName->Buffer = NULL;
  1347. LongOemName->Length =
  1348. LongOemName->MaximumLength = 0;
  1349. } else {
  1350. SetFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
  1351. }
  1352. try_return( NOTHING );
  1353. }
  1354. //
  1355. // Now we have the fun part.
  1356. // I am free to play with the Lfn since nobody above me needs it anymore.
  1357. //
  1358. (VOID)RtlDowncaseUnicodeString( Lfn, Lfn, FALSE );
  1359. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemA, Lfn, TRUE );
  1360. if (!NT_SUCCESS(Status)) {
  1361. RxNormalizeAndRaiseStatus( RxContext, Status );
  1362. }
  1363. (VOID)RtlUpcaseUnicodeString( Lfn, Lfn, FALSE );
  1364. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemB, Lfn, TRUE );
  1365. if (!NT_SUCCESS(Status)) {
  1366. RtlFreeOemString( &OemA );
  1367. RxNormalizeAndRaiseStatus( RxContext, Status );
  1368. }
  1369. if (RxAreNamesEqual( RxContext, OemA, OemB )) {
  1370. //
  1371. // Cool, I can go with the Oem
  1372. //
  1373. Fcb->LongName.Oem.Name.Oem = OemA;
  1374. RtlFreeOemString( &OemB );
  1375. //
  1376. // If this name happens to be exactly the same as the short
  1377. // name, or a similar short name already exists don't add it
  1378. // to the splay table (note the final condition implies a
  1379. // currupt disk.
  1380. //
  1381. if (RxAreNamesEqual(RxContext, *ShortName, OemA) ||
  1382. (RxFindFcb( RxContext,
  1383. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  1384. &OemA) != NULL)) {
  1385. RtlFreeOemString( &OemA );
  1386. } else {
  1387. SetFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
  1388. }
  1389. try_return( NOTHING );
  1390. }
  1391. //
  1392. // The long name must be left in UNICODE.
  1393. //
  1394. LongUniName = &Fcb->LongName.Unicode.Name.Unicode;
  1395. LongUniName->Length =
  1396. LongUniName->MaximumLength = Lfn->Length;
  1397. LongUniName->Buffer = FsRtlAllocatePool( PagedPool, Lfn->Length );
  1398. RtlCopyMemory( LongUniName->Buffer, Lfn->Buffer, Lfn->Length );
  1399. SetFlag(Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME);
  1400. try_exit: NOTHING;
  1401. } finally {
  1402. if (AbnormalTermination()) {
  1403. if (ShortName->Buffer != NULL) {
  1404. ExFreePool( ShortName->Buffer );
  1405. }
  1406. } else {
  1407. //
  1408. // Creating all the names worked, so add all the names
  1409. // to the splay tree.
  1410. //
  1411. RxInsertName( RxContext,
  1412. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  1413. &Fcb->ShortName );
  1414. Fcb->ShortName.Fcb = Fcb;
  1415. if (FlagOn(Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME)) {
  1416. RxInsertName( RxContext,
  1417. &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
  1418. &Fcb->LongName.Oem );
  1419. Fcb->LongName.Oem.Fcb = Fcb;
  1420. }
  1421. if (FlagOn(Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME)) {
  1422. RxInsertName( RxContext,
  1423. &Fcb->ParentDcb->Specific.Dcb.RootUnicodeNode,
  1424. &Fcb->LongName.Unicode );
  1425. Fcb->LongName.Unicode.Fcb = Fcb;
  1426. }
  1427. SetFlag(Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE)
  1428. }
  1429. }
  1430. return;
  1431. }
  1432. VOID
  1433. RxCheckFreeDirentBitmap (
  1434. IN PRX_CONTEXT RxContext,
  1435. IN PDCB Dcb
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. This routine checks if the size of the free dirent bitmap is
  1440. sufficient to for the current directory size. It is called
  1441. whenever we grow a directory.
  1442. Arguments:
  1443. Dcb - Supplies the directory in question.
  1444. Return Value:
  1445. None
  1446. --*/
  1447. {
  1448. ULONG OldNumberOfDirents;
  1449. ULONG NewNumberOfDirents;
  1450. //
  1451. // Setup the Bitmap buffer if it is not big enough already
  1452. //
  1453. OldNumberOfDirents = Dcb->Specific.Dcb.FreeDirentBitmap.SizeOfBitMap;
  1454. NewNumberOfDirents = Dcb->Header.AllocationSize.LowPart / sizeof(DIRENT);
  1455. ASSERT( Dcb->Header.AllocationSize.LowPart != 0xffffffff );
  1456. if (NewNumberOfDirents > OldNumberOfDirents) {
  1457. PULONG OldBitmapBuffer;
  1458. PULONG BitmapBuffer;
  1459. ULONG BytesInBitmapBuffer;
  1460. ULONG BytesInOldBitmapBuffer;
  1461. //
  1462. // Remember the old bitmap
  1463. //
  1464. OldBitmapBuffer = Dcb->Specific.Dcb.FreeDirentBitmap.Buffer;
  1465. //
  1466. // Now make a new bitmap bufffer
  1467. //
  1468. BytesInBitmapBuffer = NewNumberOfDirents / 8;
  1469. BytesInOldBitmapBuffer = OldNumberOfDirents / 8;
  1470. if (DCB_UNION_SLACK_SPACE >= BytesInBitmapBuffer) {
  1471. BitmapBuffer = &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0];
  1472. } else {
  1473. BitmapBuffer = FsRtlAllocatePool( PagedPool,
  1474. BytesInBitmapBuffer );
  1475. }
  1476. //
  1477. // Copy the old buffer to the new buffer, free the old one, and zero
  1478. // the rest of the new one. Only do the first two steps though if
  1479. // we moved out of the initial buffer.
  1480. //
  1481. if ((OldNumberOfDirents != 0) &&
  1482. (BitmapBuffer != &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0])) {
  1483. RtlCopyMemory( BitmapBuffer,
  1484. OldBitmapBuffer,
  1485. BytesInOldBitmapBuffer );
  1486. if (OldBitmapBuffer != &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0]) {
  1487. ExFreePool( OldBitmapBuffer );
  1488. }
  1489. }
  1490. ASSERT( BytesInBitmapBuffer > BytesInOldBitmapBuffer );
  1491. RtlZeroMemory( (PUCHAR)BitmapBuffer + BytesInOldBitmapBuffer,
  1492. BytesInBitmapBuffer - BytesInOldBitmapBuffer );
  1493. //
  1494. // Now initialize the new bitmap.
  1495. //
  1496. RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
  1497. BitmapBuffer,
  1498. NewNumberOfDirents );
  1499. }
  1500. }
  1501. BOOLEAN
  1502. RxIsHandleCountZero (
  1503. IN PRX_CONTEXT RxContext,
  1504. IN PVCB Vcb
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. This routine decides if the handle count on the volume is zero.
  1509. Arguments:
  1510. Vcb - The volume in question
  1511. Return Value:
  1512. BOOLEAN - TRUE if there are no open handles on the volume, FALSE
  1513. otherwise.
  1514. --*/
  1515. {
  1516. PFCB Fcb;
  1517. ASSERT(FALSE);
  1518. Fcb = Vcb->RootDcb;
  1519. while (Fcb != NULL) {
  1520. if (Fcb->UncleanCount != 0) {
  1521. return FALSE;
  1522. }
  1523. Fcb = RxGetNextFcb(RxContext, Fcb, Vcb->RootDcb);
  1524. }
  1525. return TRUE;
  1526. }