[FASTFAT_NEW] Fix build with FASTFATDBG set
[reactos.git] / drivers / filesystems / fastfat_new / strucsup.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 StrucSup.c
8
9 Abstract:
10
11 This module implements the Fat in-memory data structure manipulation
12 routines
13
14
15 --*/
16
17 #include "fatprocs.h"
18
19 //
20 // The Bug check file id for this module
21 //
22
23 #define BugCheckFileId (FAT_BUG_CHECK_STRUCSUP)
24
25 //
26 // The debug trace level
27 //
28
29 #define Dbg (DEBUG_TRACE_STRUCSUP)
30
31 #define FillMemory(BUF,SIZ,MASK) { \
32 ULONG i; \
33 for (i = 0; i < (((SIZ)/4) - 1); i += 2) { \
34 ((PULONG)(BUF))[i] = (MASK); \
35 ((PULONG)(BUF))[i+1] = (ULONG)PsGetCurrentThread(); \
36 } \
37 }
38
39 #define IRP_CONTEXT_HEADER (sizeof( IRP_CONTEXT ) * 0x10000 + FAT_NTC_IRP_CONTEXT)
40
41 //
42 // Local macros.
43 //
44 // Define our lookaside list allocators. For the time being, and perhaps
45 // permanently, the paged structures don't come off of lookasides. This
46 // is due to complications with clean unload as FAT can be in the paging
47 // path, making it really hard to find the right time to empty them.
48 //
49 // Fortunately, the hit rates on the Fcb/Ccb lists weren't stunning.
50 //
51
52 #define FAT_FILL_FREE 0
53
54 INLINE
55 PCCB
56 FatAllocateCcb (
57 )
58 {
59 return (PCCB) FsRtlAllocatePoolWithTag( PagedPool, sizeof(CCB), TAG_CCB );
60 }
61
62 INLINE
63 VOID
64 FatFreeCcb (
65 IN PCCB Ccb
66 )
67 {
68 #if FAT_FILL_FREE
69 RtlFillMemoryUlong(Ccb, sizeof(CCB), FAT_FILL_FREE);
70 #endif
71
72 ExFreePool( Ccb );
73 }
74
75 INLINE
76 PFCB
77 FatAllocateFcb (
78 )
79 {
80 return (PFCB) FsRtlAllocatePoolWithTag( PagedPool, sizeof(FCB), TAG_FCB );
81 }
82
83 INLINE
84 VOID
85 FatFreeFcb (
86 IN PFCB Fcb
87 )
88 {
89 #if FAT_FILL_FREE
90 RtlFillMemoryUlong(Fcb, sizeof(FCB), FAT_FILL_FREE);
91 #endif
92
93 ExFreePool( Fcb );
94 }
95
96 INLINE
97 PNON_PAGED_FCB
98 FatAllocateNonPagedFcb (
99 )
100 {
101 return (PNON_PAGED_FCB) ExAllocateFromNPagedLookasideList( &FatNonPagedFcbLookasideList );
102 }
103
104 INLINE
105 VOID
106 FatFreeNonPagedFcb (
107 PNON_PAGED_FCB NonPagedFcb
108 )
109 {
110 #if FAT_FILL_FREE
111 RtlFillMemoryUlong(NonPagedFcb, sizeof(NON_PAGED_FCB), FAT_FILL_FREE);
112 #endif
113
114 ExFreeToNPagedLookasideList( &FatNonPagedFcbLookasideList, (PVOID) NonPagedFcb );
115 }
116
117 INLINE
118 PERESOURCE
119 FatAllocateResource (
120 )
121 {
122 PERESOURCE Resource;
123
124 Resource = (PERESOURCE) ExAllocateFromNPagedLookasideList( &FatEResourceLookasideList );
125
126 ExInitializeResourceLite( Resource );
127
128 return Resource;
129 }
130
131 INLINE
132 VOID
133 FatFreeResource (
134 IN PERESOURCE Resource
135 )
136 {
137 ExDeleteResourceLite( Resource );
138
139 #if FAT_FILL_FREE
140 RtlFillMemoryUlong(Resource, sizeof(ERESOURCE), FAT_FILL_FREE);
141 #endif
142
143 ExFreeToNPagedLookasideList( &FatEResourceLookasideList, (PVOID) Resource );
144 }
145
146 INLINE
147 PIRP_CONTEXT
148 FatAllocateIrpContext (
149 )
150 {
151 return (PIRP_CONTEXT) ExAllocateFromNPagedLookasideList( &FatIrpContextLookasideList );
152 }
153
154 INLINE
155 VOID
156 FatFreeIrpContext (
157 IN PIRP_CONTEXT IrpContext
158 )
159 {
160 #if FAT_FILL_FREE
161 RtlFillMemoryUlong(IrpContext, sizeof(IRP_CONTEXT), FAT_FILL_FREE);
162 #endif
163
164 ExFreeToNPagedLookasideList( &FatIrpContextLookasideList, (PVOID) IrpContext );
165 }
166
167 #ifdef ALLOC_PRAGMA
168 #pragma alloc_text(PAGE, FatInitializeVcb)
169 #pragma alloc_text(PAGE, FatTearDownVcb)
170 #pragma alloc_text(PAGE, FatDeleteVcb)
171 #pragma alloc_text(PAGE, FatCreateRootDcb)
172 #pragma alloc_text(PAGE, FatCreateFcb)
173 #pragma alloc_text(PAGE, FatCreateDcb)
174 #pragma alloc_text(PAGE, FatDeleteFcb_Real)
175 #pragma alloc_text(PAGE, FatCreateCcb)
176 #pragma alloc_text(PAGE, FatDeallocateCcbStrings)
177 #pragma alloc_text(PAGE, FatDeleteCcb_Real)
178 #pragma alloc_text(PAGE, FatGetNextFcbTopDown)
179 #pragma alloc_text(PAGE, FatGetNextFcbBottomUp)
180 #pragma alloc_text(PAGE, FatConstructNamesInFcb)
181 #pragma alloc_text(PAGE, FatCheckFreeDirentBitmap)
182 #pragma alloc_text(PAGE, FatCreateIrpContext)
183 #pragma alloc_text(PAGE, FatDeleteIrpContext_Real)
184 #pragma alloc_text(PAGE, FatIsHandleCountZero)
185 #pragma alloc_text(PAGE, FatPreallocateCloseContext)
186 #endif
187
188 \f
189 VOID
190 FatInitializeVcb (
191 IN PIRP_CONTEXT IrpContext,
192 IN OUT PVCB Vcb,
193 IN PDEVICE_OBJECT TargetDeviceObject,
194 IN PVPB Vpb,
195 IN PDEVICE_OBJECT FsDeviceObject
196 )
197
198 /*++
199
200 Routine Description:
201
202 This routine initializes and inserts a new Vcb record into the in-memory
203 data structure. The Vcb record "hangs" off the end of the Volume device
204 object and must be allocated by our caller.
205
206 Arguments:
207
208 Vcb - Supplies the address of the Vcb record being initialized.
209
210 TargetDeviceObject - Supplies the address of the target device object to
211 associate with the Vcb record.
212
213 Vpb - Supplies the address of the Vpb to associate with the Vcb record.
214
215 FsDeviceObject - The filesystem device object that the mount was directed
216 too.
217
218 Return Value:
219
220 None.
221
222 --*/
223
224 {
225 CC_FILE_SIZES FileSizes;
226 PDEVICE_OBJECT RealDevice;
227 LONG i;
228
229 STORAGE_HOTPLUG_INFO HotplugInfo;
230 NTSTATUS Status;
231
232 //
233 // The following variables are used for abnormal unwind
234 //
235
236 PLIST_ENTRY UnwindEntryList = NULL;
237 PERESOURCE UnwindResource = NULL;
238 PERESOURCE UnwindResource2 = NULL;
239 PFILE_OBJECT UnwindFileObject = NULL;
240 PFILE_OBJECT UnwindCacheMap = NULL;
241 BOOLEAN UnwindWeAllocatedMcb = FALSE;
242 PFILE_SYSTEM_STATISTICS UnwindStatistics = NULL;
243
244 DebugTrace(+1, Dbg, "FatInitializeVcb, Vcb = %08lx\n", Vcb);
245
246 _SEH2_TRY {
247
248 //
249 // We start by first zeroing out all of the VCB, this will guarantee
250 // that any stale data is wiped clean
251 //
252
253 RtlZeroMemory( Vcb, sizeof(VCB) );
254
255 //
256 // Set the proper node type code and node byte size
257 //
258
259 Vcb->VolumeFileHeader.NodeTypeCode = FAT_NTC_VCB;
260 Vcb->VolumeFileHeader.NodeByteSize = sizeof(VCB);
261
262 //
263 // Initialize the tunneling cache
264 //
265
266 FsRtlInitializeTunnelCache(&Vcb->Tunnel);
267
268 //
269 // Insert this Vcb record on the FatData.VcbQueue
270 //
271
272 ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
273
274 (VOID)FatAcquireExclusiveGlobal( IrpContext );
275 InsertTailList( &FatData.VcbQueue, &Vcb->VcbLinks );
276 FatReleaseGlobal( IrpContext );
277 UnwindEntryList = &Vcb->VcbLinks;
278
279 //
280 // Set the Target Device Object, Vpb, and Vcb State fields
281 //
282
283
284 ObReferenceObject( TargetDeviceObject );
285 Vcb->TargetDeviceObject = TargetDeviceObject;
286 Vcb->Vpb = Vpb;
287
288 Vcb->CurrentDevice = Vpb->RealDevice;
289
290 //
291 // Set the removable media and defflush flags based on the storage
292 // inquiry and the old characteristic bits.
293 //
294
295 Status = FatPerformDevIoCtrl( IrpContext,
296 IOCTL_STORAGE_GET_HOTPLUG_INFO,
297 TargetDeviceObject,
298 &HotplugInfo,
299 sizeof(HotplugInfo),
300 FALSE,
301 TRUE,
302 NULL );
303
304 if (NT_SUCCESS( Status )) {
305
306 if (HotplugInfo.MediaRemovable) {
307
308 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA );
309 }
310
311 if (!HotplugInfo.WriteCacheEnableOverride) {
312
313 //
314 // If the device or media is hotplug and the override is not
315 // set, force defflush behavior for the device.
316 //
317
318 if (HotplugInfo.MediaHotplug || HotplugInfo.DeviceHotplug) {
319
320 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH );
321
322 //
323 // Now, for removables that claim to be lockable, lob a lock
324 // request and see if it works. There can unfortunately be
325 // transient, media dependent reasons that it can fail. If
326 // it does not, we must force defflush on.
327 //
328
329 } else if (HotplugInfo.MediaRemovable &&
330 !HotplugInfo.MediaHotplug) {
331
332 Status = FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
333
334 if (!NT_SUCCESS( Status )) {
335
336 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH );
337
338 }
339
340 Status = FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
341 }
342 }
343 }
344
345 if (FlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
346
347 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA );
348 }
349
350 //
351 // Make sure we turn on deferred flushing for floppies like we always
352 // have.
353 //
354
355 if (FlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
356
357 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH );
358 }
359
360 Vcb->VcbCondition = VcbGood;
361
362 //
363 // Initialize the resource variable for the Vcb
364 //
365
366 ExInitializeResourceLite( &Vcb->Resource );
367 UnwindResource = &Vcb->Resource;
368
369 ExInitializeResourceLite( &Vcb->ChangeBitMapResource );
370 UnwindResource2 = &Vcb->ChangeBitMapResource;
371
372 //
373 // Initialize the free cluster bitmap mutex.
374 //
375
376 ExInitializeFastMutex( &Vcb->FreeClusterBitMapMutex );
377
378 //
379 // Create the special file object for the virtual volume file with a close
380 // context, its pointers back to the Vcb and the section object pointer.
381 //
382 // We don't have to unwind the close context. That will happen in the close
383 // path automatically.
384 //
385
386 RealDevice = Vcb->CurrentDevice;
387
388 Vcb->VirtualVolumeFile = UnwindFileObject = IoCreateStreamFileObject( NULL, RealDevice );
389 FatPreallocateCloseContext();
390
391 FatSetFileObject( Vcb->VirtualVolumeFile,
392 VirtualVolumeFile,
393 Vcb,
394 NULL );
395
396 //
397 // Remember this internal, residual open.
398 //
399
400 #ifndef __REACTOS__
401 InterlockedIncrement( &(Vcb->InternalOpenCount) );
402 InterlockedIncrement( &(Vcb->ResidualOpenCount) );
403 #else
404
405 InterlockedIncrement( (LONG*)&(Vcb->InternalOpenCount) );
406 InterlockedIncrement( (LONG*)&(Vcb->ResidualOpenCount) );
407 #endif
408
409 Vcb->VirtualVolumeFile->SectionObjectPointer = &Vcb->SectionObjectPointers;
410
411 Vcb->VirtualVolumeFile->ReadAccess = TRUE;
412 Vcb->VirtualVolumeFile->WriteAccess = TRUE;
413 Vcb->VirtualVolumeFile->DeleteAccess = TRUE;
414
415 //
416 // Initialize the notify structures.
417 //
418
419 InitializeListHead( &Vcb->DirNotifyList );
420
421 FsRtlNotifyInitializeSync( &Vcb->NotifySync );
422
423 //
424 // Initialize the Cache Map for the volume file. The size is
425 // initially set to that of our first read. It will be extended
426 // when we know how big the Fat is.
427 //
428
429 FileSizes.AllocationSize.QuadPart =
430 FileSizes.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
431 FileSizes.ValidDataLength = FatMaxLarge;
432
433 CcInitializeCacheMap( Vcb->VirtualVolumeFile,
434 &FileSizes,
435 TRUE,
436 &FatData.CacheManagerNoOpCallbacks,
437 Vcb );
438 UnwindCacheMap = Vcb->VirtualVolumeFile;
439
440 //
441 // Initialize the structure that will keep track of dirty fat sectors.
442 // The largest possible Mcb structures are less than 1K, so we use
443 // non paged pool.
444 //
445
446 FsRtlInitializeLargeMcb( &Vcb->DirtyFatMcb, PagedPool );
447
448 UnwindWeAllocatedMcb = TRUE;
449
450 //
451 // Set the cluster index hint to the first valid cluster of a fat: 2
452 //
453
454 Vcb->ClusterHint = 2;
455
456 //
457 // Initialize the directory stream file object creation event.
458 // This event is also "borrowed" for async non-cached writes.
459 //
460
461 ExInitializeFastMutex( &Vcb->DirectoryFileCreationMutex );
462
463 //
464 // Initialize the clean volume callback Timer and DPC.
465 //
466
467 KeInitializeTimer( &Vcb->CleanVolumeTimer );
468
469 KeInitializeDpc( &Vcb->CleanVolumeDpc, FatCleanVolumeDpc, Vcb );
470
471 //
472 // Initialize the performance counters.
473 //
474
475 Vcb->Statistics = FsRtlAllocatePoolWithTag( NonPagedPool,
476 sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors,
477 TAG_VCB_STATS );
478 UnwindStatistics = Vcb->Statistics;
479
480 RtlZeroMemory( Vcb->Statistics, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors );
481
482 for (i = 0; i < KeNumberProcessors; i += 1) {
483 Vcb->Statistics[i].Common.FileSystemType = FILESYSTEM_STATISTICS_TYPE_FAT;
484 Vcb->Statistics[i].Common.Version = 1;
485 Vcb->Statistics[i].Common.SizeOfCompleteStructure =
486 sizeof(FILE_SYSTEM_STATISTICS);
487 }
488
489 //
490 // Pick up a VPB right now so we know we can pull this filesystem stack off
491 // of the storage stack on demand.
492 //
493
494 Vcb->SwapVpb = FsRtlAllocatePoolWithTag( NonPagedPool,
495 sizeof( VPB ),
496 TAG_VPB );
497
498 RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) );
499
500 //
501 // Initialize the close queue listheads.
502 //
503
504 InitializeListHead( &Vcb->AsyncCloseList );
505 InitializeListHead( &Vcb->DelayedCloseList );
506
507 //
508 // Initialize the Advanced FCB Header
509 //
510
511 ExInitializeFastMutex( &Vcb->AdvancedFcbHeaderMutex );
512 FsRtlSetupAdvancedHeader( &Vcb->VolumeFileHeader,
513 &Vcb->AdvancedFcbHeaderMutex );
514
515 //
516 // With the Vcb now set up, set the IrpContext Vcb field.
517 //
518
519 IrpContext->Vcb = Vcb;
520
521 } _SEH2_FINALLY {
522
523 DebugUnwind( FatInitializeVcb );
524
525 //
526 // If this is an abnormal termination then undo our work
527 //
528
529 if (_SEH2_AbnormalTermination()) {
530
531 if (UnwindCacheMap != NULL) { FatSyncUninitializeCacheMap( IrpContext, UnwindCacheMap ); }
532 if (UnwindFileObject != NULL) { ObDereferenceObject( UnwindFileObject ); }
533 if (UnwindResource != NULL) { FatDeleteResource( UnwindResource ); }
534 if (UnwindResource2 != NULL) { FatDeleteResource( UnwindResource2 ); }
535 if (UnwindWeAllocatedMcb) { FsRtlUninitializeLargeMcb( &Vcb->DirtyFatMcb ); }
536 if (UnwindEntryList != NULL) {
537 (VOID)FatAcquireExclusiveGlobal( IrpContext );
538 RemoveEntryList( UnwindEntryList );
539 FatReleaseGlobal( IrpContext );
540 }
541 if (UnwindStatistics != NULL) { ExFreePool( UnwindStatistics ); }
542 }
543
544 DebugTrace(-1, Dbg, "FatInitializeVcb -> VOID\n", 0);
545 } _SEH2_END;
546
547 //
548 // and return to our caller
549 //
550
551 UNREFERENCED_PARAMETER( IrpContext );
552
553 return;
554 }
555
556 VOID
557 FatTearDownVcb (
558 IN PIRP_CONTEXT IrpContext,
559 IN PVCB Vcb
560 )
561
562 /*++
563
564 Routine Description:
565
566 This routine tries to remove all internal opens from the volume.
567
568 Arguments:
569
570 IrpContext - Supplies the context for the overall request.
571
572 Vcb - Supplies the Vcb to be torn down.
573
574 Return Value:
575
576 None
577
578 --*/
579
580 {
581 PFILE_OBJECT DirectoryFileObject;
582
583
584 PAGED_CODE();
585
586 //
587 // Get rid of the virtual volume file, if we need to.
588 //
589
590 if (Vcb->VirtualVolumeFile != NULL) {
591
592 //
593 // Uninitialize the cache
594 //
595
596 FatSyncUninitializeCacheMap( IrpContext, Vcb->VirtualVolumeFile );
597
598 //
599 // Dereference the virtual volume file. This will cause a close
600 // Irp to be processed, so we need to do this before we destory
601 // the Vcb
602 //
603
604 FsRtlTeardownPerStreamContexts( &Vcb->VolumeFileHeader );
605
606 ObDereferenceObject( Vcb->VirtualVolumeFile );
607
608 Vcb->VirtualVolumeFile = NULL;
609 }
610
611 //
612 // Close down the EA file.
613 //
614
615 FatCloseEaFile( IrpContext, Vcb, FALSE );
616
617 //
618 // Close down the root directory stream..
619 //
620
621 if (Vcb->RootDcb != NULL) {
622
623 DirectoryFileObject = Vcb->RootDcb->Specific.Dcb.DirectoryFile;
624
625 if (DirectoryFileObject != NULL) {
626
627 //
628 // Tear down this directory file.
629 //
630
631 FatSyncUninitializeCacheMap( IrpContext,
632 DirectoryFileObject );
633
634 Vcb->RootDcb->Specific.Dcb.DirectoryFile = NULL;
635 ObDereferenceObject( DirectoryFileObject );
636 }
637 }
638
639 //
640 // The VCB can no longer be used.
641 //
642
643 FatSetVcbCondition( Vcb, VcbBad );
644 }
645
646 \f
647 VOID
648 FatDeleteVcb (
649 IN PIRP_CONTEXT IrpContext,
650 IN PVCB Vcb
651 )
652
653 /*++
654
655 Routine Description:
656
657 This routine removes the Vcb record from Fat's in-memory data
658 structures. It also will remove all associated underlings
659 (i.e., FCB records).
660
661 Arguments:
662
663 Vcb - Supplies the Vcb to be removed
664
665 Return Value:
666
667 None
668
669 --*/
670
671 {
672 PFCB Fcb;
673
674 DebugTrace(+1, Dbg, "FatDeleteVcb, Vcb = %08lx\n", Vcb);
675
676 //
677 // If the IrpContext points to the VCB being deleted NULL out the stall
678 // pointer.
679 //
680
681 if (IrpContext->Vcb == Vcb) {
682
683 IrpContext->Vcb = NULL;
684
685 }
686
687
688 //
689 // Check the backpocket Vpb we kept just in case.
690 //
691
692 if (Vcb->SwapVpb) {
693
694 ExFreePool( Vcb->SwapVpb );
695 }
696
697 //
698 // Free the VPB, if we need to.
699 //
700
701 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED )) {
702
703 //
704 // We swapped the VPB, so we need to free the main one.
705 //
706
707 ExFreePool( Vcb->Vpb );
708 }
709
710 //
711 // Remove this record from the global list of all Vcb records.
712 // Note that the global lock must already be held when calling
713 // this function.
714 //
715
716 RemoveEntryList( &(Vcb->VcbLinks) );
717
718 //
719 // Make sure the direct access open count is zero, and the open file count
720 // is also zero.
721 //
722
723 if ((Vcb->DirectAccessOpenCount != 0) || (Vcb->OpenFileCount != 0)) {
724
725 FatBugCheck( 0, 0, 0 );
726 }
727
728 //
729 // Remove the EaFcb and dereference the Fcb for the Ea file if it
730 // exists.
731 //
732
733 if (Vcb->EaFcb != NULL) {
734
735 Vcb->EaFcb->OpenCount = 0;
736 FatDeleteFcb( IrpContext, Vcb->EaFcb );
737
738 Vcb->EaFcb = NULL;
739 }
740
741 //
742 // Remove the Root Dcb
743 //
744
745 if (Vcb->RootDcb != NULL) {
746
747 //
748 // Rundown stale child Fcbs that may be hanging around. Yes, this
749 // can happen. No, the create path isn't perfectly defensive about
750 // tearing down branches built up on creates that don't wind up
751 // succeeding. Normal system operation usually winds up having
752 // cleaned them out through re-visiting, but ...
753 //
754 // Just pick off Fcbs from the bottom of the tree until we run out.
755 // Then we delete the root Dcb.
756 //
757
758 while( (Fcb = FatGetNextFcbBottomUp( IrpContext, NULL, Vcb->RootDcb )) != Vcb->RootDcb ) {
759
760 FatDeleteFcb( IrpContext, Fcb );
761 }
762
763 FatDeleteFcb( IrpContext, Vcb->RootDcb );
764 }
765
766 //
767 // Uninitialize the notify sychronization object.
768 //
769
770 FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
771
772 //
773 // Uninitialize the resource variable for the Vcb
774 //
775
776 FatDeleteResource( &Vcb->Resource );
777 FatDeleteResource( &Vcb->ChangeBitMapResource );
778
779 //
780 // If allocation support has been setup, free it.
781 //
782
783 if (Vcb->FreeClusterBitMap.Buffer != NULL) {
784
785 FatTearDownAllocationSupport( IrpContext, Vcb );
786 }
787
788 //
789 // UnInitialize the Mcb structure that kept track of dirty fat sectors.
790 //
791
792 FsRtlUninitializeLargeMcb( &Vcb->DirtyFatMcb );
793
794 //
795 // Free the pool for the stached copy of the boot sector
796 //
797
798 if ( Vcb->First0x24BytesOfBootSector ) {
799
800 ExFreePool( Vcb->First0x24BytesOfBootSector );
801 }
802
803 //
804 // Cancel the CleanVolume Timer and Dpc
805 //
806
807 (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
808
809 (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
810
811 //
812 // Free the performance counters memory
813 //
814
815 ExFreePool( Vcb->Statistics );
816
817 //
818 // Clean out the tunneling cache
819 //
820
821 FsRtlDeleteTunnelCache(&Vcb->Tunnel);
822
823 //
824 // Dereference the target device object.
825 //
826
827 ObDereferenceObject( Vcb->TargetDeviceObject );
828
829 //
830 // And zero out the Vcb, this will help ensure that any stale data is
831 // wiped clean
832 //
833
834 RtlZeroMemory( Vcb, sizeof(VCB) );
835
836 //
837 // return and tell the caller
838 //
839
840 DebugTrace(-1, Dbg, "FatDeleteVcb -> VOID\n", 0);
841
842 return;
843 }
844
845 \f
846 VOID
847 FatCreateRootDcb (
848 IN PIRP_CONTEXT IrpContext,
849 IN PVCB Vcb
850 )
851
852 /*++
853
854 Routine Description:
855
856 This routine allocates, initializes, and inserts a new root DCB record
857 into the in memory data structure.
858
859 Arguments:
860
861 Vcb - Supplies the Vcb to associate the new DCB under
862
863 Return Value:
864
865 None. The Vcb is modified in-place.
866
867 --*/
868
869 {
870 PDCB Dcb;
871
872 //
873 // The following variables are used for abnormal unwind
874 //
875
876 PVOID UnwindStorage[2] = { NULL, NULL };
877 PERESOURCE UnwindResource = NULL;
878 PERESOURCE UnwindResource2 = NULL;
879 PLARGE_MCB UnwindMcb = NULL;
880 PFILE_OBJECT UnwindFileObject = NULL;
881
882 DebugTrace(+1, Dbg, "FatCreateRootDcb, Vcb = %08lx\n", Vcb);
883
884 _SEH2_TRY {
885
886 //
887 // Make sure we don't already have a root dcb for this vcb
888 //
889
890 if (Vcb->RootDcb != NULL) {
891
892 DebugDump("Error trying to create multiple root dcbs\n", 0, Vcb);
893 FatBugCheck( 0, 0, 0 );
894 }
895
896 //
897 // Allocate a new DCB and zero it out, we use Dcb locally so we don't
898 // have to continually reference through the Vcb
899 //
900
901 UnwindStorage[0] = Dcb = Vcb->RootDcb = FsRtlAllocatePoolWithTag( NonPagedPool,
902 sizeof(DCB),
903 TAG_FCB );
904
905 RtlZeroMemory( Dcb, sizeof(DCB));
906
907 UnwindStorage[1] =
908 Dcb->NonPaged = FatAllocateNonPagedFcb();
909
910 RtlZeroMemory( Dcb->NonPaged, sizeof( NON_PAGED_FCB ) );
911
912 //
913 // Set the proper node type code, node byte size, and call backs
914 //
915
916 Dcb->Header.NodeTypeCode = FAT_NTC_ROOT_DCB;
917 Dcb->Header.NodeByteSize = sizeof(DCB);
918
919 Dcb->FcbCondition = FcbGood;
920
921 //
922 // The parent Dcb, initial state, open count, dirent location
923 // information, and directory change count fields are already zero so
924 // we can skip setting them
925 //
926
927 //
928 // Initialize the resource variable
929 //
930
931 UnwindResource =
932 Dcb->Header.Resource = FatAllocateResource();
933
934 //
935 // Initialize the PagingIo Resource. We no longer use the FsRtl common
936 // shared pool because this led to a) deadlocks due to cases where files
937 // and their parent directories shared a resource and b) there is no way
938 // to anticipate inter-driver induced deadlock via recursive operation.
939 //
940
941 UnwindResource2 =
942 Dcb->Header.PagingIoResource = FatAllocateResource();
943
944 //
945 // The root Dcb has an empty parent dcb links field
946 //
947
948 InitializeListHead( &Dcb->ParentDcbLinks );
949
950 //
951 // Set the Vcb
952 //
953
954 Dcb->Vcb = Vcb;
955
956 //
957 // initialize the parent dcb queue.
958 //
959
960 InitializeListHead( &Dcb->Specific.Dcb.ParentDcbQueue );
961
962 //
963 // Set the full file name up.
964 //
965
966 Dcb->FullFileName.Buffer = L"\\";
967 Dcb->FullFileName.Length = (USHORT)2;
968 Dcb->FullFileName.MaximumLength = (USHORT)4;
969
970 Dcb->ShortName.Name.Oem.Buffer = "\\";
971 Dcb->ShortName.Name.Oem.Length = (USHORT)1;
972 Dcb->ShortName.Name.Oem.MaximumLength = (USHORT)2;
973
974 //
975 // Construct a lie about file properties since we don't
976 // have a proper "." entry to look at.
977 //
978
979 Dcb->DirentFatFlags = FILE_ATTRIBUTE_DIRECTORY;
980
981 //
982 // Initialize Advanced FCB Header fields
983 //
984
985 ExInitializeFastMutex( &Dcb->NonPaged->AdvancedFcbHeaderMutex );
986 FsRtlSetupAdvancedHeader( &Dcb->Header,
987 &Dcb->NonPaged->AdvancedFcbHeaderMutex );
988
989 //
990 // Initialize the Mcb, and setup its mapping. Note that the root
991 // directory is a fixed size so we can set it everything up now.
992 //
993
994 FsRtlInitializeLargeMcb( &Dcb->Mcb, NonPagedPool );
995 UnwindMcb = &Dcb->Mcb;
996
997 if (FatIsFat32(Vcb)) {
998
999 //
1000 // The first cluster of fat32 roots comes from the BPB
1001 //
1002
1003 Dcb->FirstClusterOfFile = Vcb->Bpb.RootDirFirstCluster;
1004
1005 } else {
1006
1007 FatAddMcbEntry( Vcb, &Dcb->Mcb,
1008 0,
1009 FatRootDirectoryLbo( &Vcb->Bpb ),
1010 FatRootDirectorySize( &Vcb->Bpb ));
1011 }
1012
1013 if (FatIsFat32(Vcb)) {
1014
1015 //
1016 // Find the size of the fat32 root. As a side-effect, this will create
1017 // MCBs for the entire root. In the process of doing this, we may
1018 // discover that the FAT chain is bogus and raise corruption.
1019 //
1020
1021 Dcb->Header.AllocationSize.LowPart = 0xFFFFFFFF;
1022 FatLookupFileAllocationSize( IrpContext, Dcb);
1023
1024 Dcb->Header.FileSize.QuadPart =
1025 Dcb->Header.AllocationSize.QuadPart;
1026 } else {
1027
1028 //
1029 // set the allocation size to real size of the root directory
1030 //
1031
1032 Dcb->Header.FileSize.QuadPart =
1033 Dcb->Header.AllocationSize.QuadPart = FatRootDirectorySize( &Vcb->Bpb );
1034
1035 }
1036
1037 //
1038 // Set our two create dirent aids to represent that we have yet to
1039 // enumerate the directory for never used or deleted dirents.
1040 //
1041
1042 Dcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
1043 Dcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
1044
1045 //
1046 // Setup the free dirent bitmap buffer.
1047 //
1048
1049 RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
1050 NULL,
1051 0 );
1052
1053 FatCheckFreeDirentBitmap( IrpContext, Dcb );
1054
1055 } _SEH2_FINALLY {
1056
1057 DebugUnwind( FatCreateRootDcb );
1058
1059 //
1060 // If this is an abnormal termination then undo our work
1061 //
1062
1063 if (_SEH2_AbnormalTermination()) {
1064
1065 ULONG i;
1066
1067 if (UnwindFileObject != NULL) { ObDereferenceObject( UnwindFileObject ); }
1068 if (UnwindMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindMcb ); }
1069 if (UnwindResource != NULL) { FatFreeResource( UnwindResource ); }
1070 if (UnwindResource2 != NULL) { FatFreeResource( UnwindResource2 ); }
1071
1072 for (i = 0; i < sizeof(UnwindStorage)/sizeof(PVOID); i += 1) {
1073 if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
1074 }
1075
1076 //
1077 // Re-zero the entry in the Vcb.
1078 //
1079
1080 Vcb->RootDcb = NULL;
1081 }
1082
1083 DebugTrace(-1, Dbg, "FatCreateRootDcb -> %8lx\n", Dcb);
1084 } _SEH2_END;
1085
1086 return;
1087 }
1088
1089 \f
1090 PFCB
1091 FatCreateFcb (
1092 IN PIRP_CONTEXT IrpContext,
1093 IN PVCB Vcb,
1094 IN PDCB ParentDcb,
1095 IN ULONG LfnOffsetWithinDirectory,
1096 IN ULONG DirentOffsetWithinDirectory,
1097 IN PDIRENT Dirent,
1098 IN PUNICODE_STRING Lfn OPTIONAL,
1099 IN BOOLEAN IsPagingFile,
1100 IN BOOLEAN SingleResource
1101 )
1102
1103 /*++
1104
1105 Routine Description:
1106
1107 This routine allocates, initializes, and inserts a new Fcb record into
1108 the in-memory data structures.
1109
1110 Arguments:
1111
1112 Vcb - Supplies the Vcb to associate the new FCB under.
1113
1114 ParentDcb - Supplies the parent dcb that the new FCB is under.
1115
1116 LfnOffsetWithinDirectory - Supplies the offset of the LFN. If there is
1117 no LFN associated with this file then this value is same as
1118 DirentOffsetWithinDirectory.
1119
1120 DirentOffsetWithinDirectory - Supplies the offset, in bytes from the
1121 start of the directory file where the dirent for the fcb is located
1122
1123 Dirent - Supplies the dirent for the fcb being created
1124
1125 Lfn - Supplies a long UNICODE name associated with this file.
1126
1127 IsPagingFile - Indicates if we are creating an FCB for a paging file
1128 or some other type of file.
1129
1130 SingleResource - Indicates if this Fcb should share a single resource
1131 as both main and paging.
1132
1133 Return Value:
1134
1135 PFCB - Returns a pointer to the newly allocated FCB
1136
1137 --*/
1138
1139 {
1140 PFCB Fcb;
1141 POOL_TYPE PoolType;
1142
1143 //
1144 // The following variables are used for abnormal unwind
1145 //
1146
1147 PVOID UnwindStorage[2] = { NULL, NULL };
1148 PERESOURCE UnwindResource = NULL;
1149 PERESOURCE UnwindResource2 = NULL;
1150 PLIST_ENTRY UnwindEntryList = NULL;
1151 PLARGE_MCB UnwindMcb = NULL;
1152 PFILE_LOCK UnwindFileLock = NULL;
1153 POPLOCK UnwindOplock = NULL;
1154
1155 DebugTrace(+1, Dbg, "FatCreateFcb\n", 0);
1156
1157 _SEH2_TRY {
1158
1159 //
1160 // Determine the pool type we should be using for the fcb and the
1161 // mcb structure
1162 //
1163
1164 if (IsPagingFile) {
1165
1166 PoolType = NonPagedPool;
1167 Fcb = UnwindStorage[0] = FsRtlAllocatePoolWithTag( NonPagedPool,
1168 sizeof(FCB),
1169 TAG_FCB );
1170 } else {
1171
1172 PoolType = PagedPool;
1173 Fcb = UnwindStorage[0] = FatAllocateFcb();
1174
1175 }
1176
1177 //
1178 // ... and zero it out
1179 //
1180
1181 RtlZeroMemory( Fcb, sizeof(FCB) );
1182
1183 UnwindStorage[1] =
1184 Fcb->NonPaged = FatAllocateNonPagedFcb();
1185
1186 RtlZeroMemory( Fcb->NonPaged, sizeof( NON_PAGED_FCB ) );
1187
1188 //
1189 // Set the proper node type code, node byte size, and call backs
1190 //
1191
1192 Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
1193 Fcb->Header.NodeByteSize = sizeof(FCB);
1194
1195 Fcb->FcbCondition = FcbGood;
1196
1197 //
1198 // Check to see if we need to set the Fcb state to indicate that this
1199 // is a paging/system file. This will prevent it from being opened
1200 // again.
1201 //
1202
1203 if (IsPagingFile) {
1204
1205 SetFlag( Fcb->FcbState, FCB_STATE_PAGING_FILE | FCB_STATE_SYSTEM_FILE );
1206 }
1207
1208 //
1209 // The initial state, open count, and segment objects fields are already
1210 // zero so we can skip setting them
1211 //
1212
1213 //
1214 // Initialize the resource variable
1215 //
1216
1217
1218 UnwindResource =
1219 Fcb->Header.Resource = FatAllocateResource();
1220
1221 //
1222 // Initialize the PagingIo Resource. We no longer use the FsRtl common
1223 // shared pool because this led to a) deadlocks due to cases where files
1224 // and their parent directories shared a resource and b) there is no way
1225 // to anticipate inter-driver induced deadlock via recursive operation.
1226 //
1227
1228 if (SingleResource) {
1229
1230 Fcb->Header.PagingIoResource = Fcb->Header.Resource;
1231
1232 } else {
1233
1234 UnwindResource2 =
1235 Fcb->Header.PagingIoResource = FatAllocateResource();
1236 }
1237
1238 //
1239 // Insert this fcb into our parent dcb's queue.
1240 //
1241 // There is a deep reason why this goes on the tail, to allow us
1242 // to easily enumerate all child directories before child files.
1243 // This is important to let us maintain whole-volume lockorder
1244 // via BottomUp enumeration.
1245 //
1246
1247 InsertTailList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
1248 &Fcb->ParentDcbLinks );
1249 UnwindEntryList = &Fcb->ParentDcbLinks;
1250
1251 //
1252 // Point back to our parent dcb
1253 //
1254
1255 Fcb->ParentDcb = ParentDcb;
1256
1257 //
1258 // Set the Vcb
1259 //
1260
1261 Fcb->Vcb = Vcb;
1262
1263 //
1264 // Set the dirent offset within the directory
1265 //
1266
1267 Fcb->LfnOffsetWithinDirectory = LfnOffsetWithinDirectory;
1268 Fcb->DirentOffsetWithinDirectory = DirentOffsetWithinDirectory;
1269
1270 //
1271 // Set the DirentFatFlags and LastWriteTime
1272 //
1273
1274 Fcb->DirentFatFlags = Dirent->Attributes;
1275
1276 Fcb->LastWriteTime = FatFatTimeToNtTime( IrpContext,
1277 Dirent->LastWriteTime,
1278 0 );
1279
1280 //
1281 // These fields are only non-zero when in Chicago mode.
1282 //
1283
1284 if (FatData.ChicagoMode) {
1285
1286 LARGE_INTEGER FatSystemJanOne1980;
1287
1288 //
1289 // If either date is possibly zero, get the system
1290 // version of 1/1/80.
1291 //
1292
1293 if ((((PUSHORT)Dirent)[9] & ((PUSHORT)Dirent)[8]) == 0) {
1294
1295 ExLocalTimeToSystemTime( &FatJanOne1980,
1296 &FatSystemJanOne1980 );
1297 }
1298
1299 //
1300 // Only do the really hard work if this field is non-zero.
1301 //
1302
1303 if (((PUSHORT)Dirent)[9] != 0) {
1304
1305 Fcb->LastAccessTime =
1306 FatFatDateToNtTime( IrpContext,
1307 Dirent->LastAccessDate );
1308
1309 } else {
1310
1311 Fcb->LastAccessTime = FatSystemJanOne1980;
1312 }
1313
1314 //
1315 // Only do the really hard work if this field is non-zero.
1316 //
1317
1318 if (((PUSHORT)Dirent)[8] != 0) {
1319
1320 Fcb->CreationTime =
1321 FatFatTimeToNtTime( IrpContext,
1322 Dirent->CreationTime,
1323 Dirent->CreationMSec );
1324
1325 } else {
1326
1327 Fcb->CreationTime = FatSystemJanOne1980;
1328 }
1329 }
1330
1331 //
1332 // Initialize Advanced FCB Header fields
1333 //
1334
1335 ExInitializeFastMutex( &Fcb->NonPaged->AdvancedFcbHeaderMutex );
1336 FsRtlSetupAdvancedHeader( &Fcb->Header,
1337 &Fcb->NonPaged->AdvancedFcbHeaderMutex );
1338
1339 //
1340 // To make FAT match the present functionality of NTFS, disable
1341 // stream contexts on paging files (nealch 7/2/01)
1342 //
1343
1344 if (IsPagingFile) {
1345
1346 ClearFlag( Fcb->Header.Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS );
1347 }
1348
1349 //
1350 // Initialize the Mcb
1351 //
1352
1353 FsRtlInitializeLargeMcb( &Fcb->Mcb, PoolType );
1354 UnwindMcb = &Fcb->Mcb;
1355
1356 //
1357 // Set the file size, valid data length, first cluster of file,
1358 // and allocation size based on the information stored in the dirent
1359 //
1360
1361 Fcb->Header.FileSize.LowPart = Dirent->FileSize;
1362
1363 Fcb->Header.ValidDataLength.LowPart = Dirent->FileSize;
1364
1365 Fcb->ValidDataToDisk = Dirent->FileSize;
1366
1367 Fcb->FirstClusterOfFile = (ULONG)Dirent->FirstClusterOfFile;
1368
1369 if ( FatIsFat32(Vcb) ) {
1370
1371 Fcb->FirstClusterOfFile += Dirent->FirstClusterOfFileHi << 16;
1372 }
1373
1374 if ( Fcb->FirstClusterOfFile == 0 ) {
1375
1376 Fcb->Header.AllocationSize.QuadPart = 0;
1377
1378 } else {
1379
1380 Fcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
1381 }
1382
1383 //
1384 // Initialize the Fcb's file lock record
1385 //
1386
1387 FsRtlInitializeFileLock( &Fcb->Specific.Fcb.FileLock, NULL, NULL );
1388 UnwindFileLock = &Fcb->Specific.Fcb.FileLock;
1389
1390 //
1391 // Initialize the oplock structure.
1392 //
1393
1394 FsRtlInitializeOplock( &Fcb->Specific.Fcb.Oplock );
1395 UnwindOplock = &Fcb->Specific.Fcb.Oplock;
1396
1397 //
1398 // Indicate that Fast I/O is possible
1399 //
1400
1401 Fcb->Header.IsFastIoPossible = TRUE;
1402
1403 //
1404 // Set the file names. This must be the last thing we do.
1405 //
1406
1407 FatConstructNamesInFcb( IrpContext,
1408 Fcb,
1409 Dirent,
1410 Lfn );
1411
1412 //
1413 // Drop the shortname hint so prefix searches can figure out
1414 // what they found
1415 //
1416
1417 Fcb->ShortName.FileNameDos = TRUE;
1418
1419 } _SEH2_FINALLY {
1420
1421 DebugUnwind( FatCreateFcb );
1422
1423 //
1424 // If this is an abnormal termination then undo our work
1425 //
1426
1427 if (_SEH2_AbnormalTermination()) {
1428
1429 ULONG i;
1430
1431 if (UnwindOplock != NULL) { FsRtlUninitializeOplock( UnwindOplock ); }
1432 if (UnwindFileLock != NULL) { FsRtlUninitializeFileLock( UnwindFileLock ); }
1433 if (UnwindMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindMcb ); }
1434 if (UnwindEntryList != NULL) { RemoveEntryList( UnwindEntryList ); }
1435 if (UnwindResource != NULL) { FatFreeResource( UnwindResource ); }
1436 if (UnwindResource2 != NULL) { FatFreeResource( UnwindResource2 ); }
1437
1438 for (i = 0; i < sizeof(UnwindStorage)/sizeof(PVOID); i += 1) {
1439 if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
1440 }
1441 }
1442
1443 DebugTrace(-1, Dbg, "FatCreateFcb -> %08lx\n", Fcb);
1444 } _SEH2_END;
1445
1446 //
1447 // return and tell the caller
1448 //
1449
1450 return Fcb;
1451 }
1452
1453 \f
1454 PDCB
1455 FatCreateDcb (
1456 IN PIRP_CONTEXT IrpContext,
1457 IN PVCB Vcb,
1458 IN PDCB ParentDcb,
1459 IN ULONG LfnOffsetWithinDirectory,
1460 IN ULONG DirentOffsetWithinDirectory,
1461 IN PDIRENT Dirent,
1462 IN PUNICODE_STRING Lfn OPTIONAL
1463 )
1464
1465 /*++
1466
1467 Routine Description:
1468
1469 This routine allocates, initializes, and inserts a new Dcb record into
1470 the in memory data structures.
1471
1472 Arguments:
1473
1474 Vcb - Supplies the Vcb to associate the new DCB under.
1475
1476 ParentDcb - Supplies the parent dcb that the new DCB is under.
1477
1478 LfnOffsetWithinDirectory - Supplies the offset of the LFN. If there is
1479 no LFN associated with this file then this value is same as
1480 DirentOffsetWithinDirectory.
1481
1482 DirentOffsetWithinDirectory - Supplies the offset, in bytes from the
1483 start of the directory file where the dirent for the fcb is located
1484
1485 Dirent - Supplies the dirent for the dcb being created
1486
1487 FileName - Supplies the file name of the file relative to the directory
1488 it's in (e.g., the file \config.sys is called "CONFIG.SYS" without
1489 the preceding backslash).
1490
1491 Lfn - Supplies a long UNICODE name associated with this directory.
1492
1493 Return Value:
1494
1495 PDCB - Returns a pointer to the newly allocated DCB
1496
1497 --*/
1498
1499 {
1500 PDCB Dcb;
1501
1502 //
1503 // The following variables are used for abnormal unwind
1504 //
1505
1506 PVOID UnwindStorage[2] = { NULL, NULL };
1507 PERESOURCE UnwindResource = NULL;
1508 PERESOURCE UnwindResource2 = NULL;
1509 PLIST_ENTRY UnwindEntryList = NULL;
1510 PLARGE_MCB UnwindMcb = NULL;
1511
1512 DebugTrace(+1, Dbg, "FatCreateDcb\n", 0);
1513
1514
1515 _SEH2_TRY {
1516
1517 //
1518 // assert that the only time we are called is if wait is true
1519 //
1520
1521 ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
1522
1523 //
1524 // Allocate a new DCB, and zero it out
1525 //
1526
1527 UnwindStorage[0] = Dcb = FatAllocateFcb();
1528
1529 RtlZeroMemory( Dcb, sizeof(DCB) );
1530
1531 UnwindStorage[1] =
1532 Dcb->NonPaged = FatAllocateNonPagedFcb();
1533
1534 RtlZeroMemory( Dcb->NonPaged, sizeof( NON_PAGED_FCB ) );
1535
1536 //
1537 // Set the proper node type code, node byte size and call backs
1538 //
1539
1540 Dcb->Header.NodeTypeCode = FAT_NTC_DCB;
1541 Dcb->Header.NodeByteSize = sizeof(DCB);
1542
1543 Dcb->FcbCondition = FcbGood;
1544
1545 //
1546 // The initial state, open count, and directory change count fields are
1547 // already zero so we can skip setting them
1548 //
1549
1550 //
1551 // Initialize the resource variable
1552 //
1553
1554
1555 UnwindResource =
1556 Dcb->Header.Resource = FatAllocateResource();
1557
1558 //
1559 // Initialize the PagingIo Resource. We no longer use the FsRtl common
1560 // shared pool because this led to a) deadlocks due to cases where files
1561 // and their parent directories shared a resource and b) there is no way
1562 // to anticipate inter-driver induced deadlock via recursive operation.
1563 //
1564
1565 UnwindResource2 =
1566 Dcb->Header.PagingIoResource = FatAllocateResource();
1567
1568 //
1569 // Insert this Dcb into our parent dcb's queue
1570 //
1571 // There is a deep reason why this goes on the head, to allow us
1572 // to easily enumerate all child directories before child files.
1573 // This is important to let us maintain whole-volume lockorder
1574 // via BottomUp enumeration.
1575 //
1576
1577 InsertHeadList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
1578 &Dcb->ParentDcbLinks );
1579 UnwindEntryList = &Dcb->ParentDcbLinks;
1580
1581 //
1582 // Point back to our parent dcb
1583 //
1584
1585 Dcb->ParentDcb = ParentDcb;
1586
1587 //
1588 // Set the Vcb
1589 //
1590
1591 Dcb->Vcb = Vcb;
1592
1593 //
1594 // Set the dirent offset within the directory
1595 //
1596
1597 Dcb->LfnOffsetWithinDirectory = LfnOffsetWithinDirectory;
1598 Dcb->DirentOffsetWithinDirectory = DirentOffsetWithinDirectory;
1599
1600 //
1601 // Set the DirentFatFlags and LastWriteTime
1602 //
1603
1604 Dcb->DirentFatFlags = Dirent->Attributes;
1605
1606 Dcb->LastWriteTime = FatFatTimeToNtTime( IrpContext,
1607 Dirent->LastWriteTime,
1608 0 );
1609
1610 //
1611 // These fields are only non-zero when in Chicago mode.
1612 //
1613
1614 if (FatData.ChicagoMode) {
1615
1616 LARGE_INTEGER FatSystemJanOne1980;
1617
1618 //
1619 // If either date is possibly zero, get the system
1620 // version of 1/1/80.
1621 //
1622
1623 if ((((PUSHORT)Dirent)[9] & ((PUSHORT)Dirent)[8]) == 0) {
1624
1625 ExLocalTimeToSystemTime( &FatJanOne1980,
1626 &FatSystemJanOne1980 );
1627 }
1628
1629 //
1630 // Only do the really hard work if this field is non-zero.
1631 //
1632
1633 if (((PUSHORT)Dirent)[9] != 0) {
1634
1635 Dcb->LastAccessTime =
1636 FatFatDateToNtTime( IrpContext,
1637 Dirent->LastAccessDate );
1638
1639 } else {
1640
1641 Dcb->LastAccessTime = FatSystemJanOne1980;
1642 }
1643
1644 //
1645 // Only do the really hard work if this field is non-zero.
1646 //
1647
1648 if (((PUSHORT)Dirent)[8] != 0) {
1649
1650 Dcb->CreationTime =
1651 FatFatTimeToNtTime( IrpContext,
1652 Dirent->CreationTime,
1653 Dirent->CreationMSec );
1654
1655 } else {
1656
1657 Dcb->CreationTime = FatSystemJanOne1980;
1658 }
1659 }
1660
1661 //
1662 // Initialize Advanced FCB Header fields
1663 //
1664
1665 ExInitializeFastMutex( &Dcb->NonPaged->AdvancedFcbHeaderMutex );
1666 FsRtlSetupAdvancedHeader( &Dcb->Header,
1667 &Dcb->NonPaged->AdvancedFcbHeaderMutex );
1668
1669 //
1670 // Initialize the Mcb
1671 //
1672
1673 FsRtlInitializeLargeMcb( &Dcb->Mcb, PagedPool );
1674 UnwindMcb = &Dcb->Mcb;
1675
1676 //
1677 // Set the file size, first cluster of file, and allocation size
1678 // based on the information stored in the dirent
1679 //
1680
1681 Dcb->FirstClusterOfFile = (ULONG)Dirent->FirstClusterOfFile;
1682
1683 if ( FatIsFat32(Dcb->Vcb) ) {
1684
1685 Dcb->FirstClusterOfFile += Dirent->FirstClusterOfFileHi << 16;
1686 }
1687
1688 if ( Dcb->FirstClusterOfFile == 0 ) {
1689
1690 Dcb->Header.AllocationSize.QuadPart = 0;
1691
1692 } else {
1693
1694 Dcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
1695 }
1696
1697 // initialize the notify queues, and the parent dcb queue.
1698 //
1699
1700 InitializeListHead( &Dcb->Specific.Dcb.ParentDcbQueue );
1701
1702 //
1703 // Setup the free dirent bitmap buffer. Since we don't know the
1704 // size of the directory, leave it zero for now.
1705 //
1706
1707 RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
1708 NULL,
1709 0 );
1710
1711 //
1712 // Set our two create dirent aids to represent that we have yet to
1713 // enumerate the directory for never used or deleted dirents.
1714 //
1715
1716 Dcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
1717 Dcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
1718
1719 //
1720 // Postpone initializing the cache map until we need to do a read/write
1721 // of the directory file.
1722
1723
1724 //
1725 // set the file names. This must be the last thing we do.
1726 //
1727
1728 FatConstructNamesInFcb( IrpContext,
1729 Dcb,
1730 Dirent,
1731 Lfn );
1732
1733 } _SEH2_FINALLY {
1734
1735 DebugUnwind( FatCreateDcb );
1736
1737 //
1738 // If this is an abnormal termination then undo our work
1739 //
1740
1741 if (_SEH2_AbnormalTermination()) {
1742
1743 ULONG i;
1744
1745 if (UnwindMcb != NULL) { FsRtlUninitializeLargeMcb( UnwindMcb ); }
1746 if (UnwindEntryList != NULL) { RemoveEntryList( UnwindEntryList ); }
1747 if (UnwindResource != NULL) { FatFreeResource( UnwindResource ); }
1748 if (UnwindResource2 != NULL) { FatFreeResource( UnwindResource2 ); }
1749
1750 for (i = 0; i < sizeof(UnwindStorage)/sizeof(PVOID); i += 1) {
1751 if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
1752 }
1753 }
1754
1755 DebugTrace(-1, Dbg, "FatCreateDcb -> %08lx\n", Dcb);
1756 } _SEH2_END;
1757
1758 //
1759 // return and tell the caller
1760 //
1761
1762 DebugTrace(-1, Dbg, "FatCreateDcb -> %08lx\n", Dcb);
1763
1764 return Dcb;
1765 }
1766
1767 \f
1768 VOID
1769 FatDeleteFcb_Real (
1770 IN PIRP_CONTEXT IrpContext,
1771 IN PFCB Fcb
1772 )
1773
1774 /*++
1775
1776 Routine Description:
1777
1778 This routine deallocates and removes an FCB, DCB, or ROOT DCB record
1779 from Fat's in-memory data structures. It also will remove all
1780 associated underlings (i.e., Notify irps, and child FCB/DCB records).
1781
1782 Arguments:
1783
1784 Fcb - Supplies the FCB/DCB/ROOT DCB to be removed
1785
1786 Return Value:
1787
1788 None
1789
1790 --*/
1791
1792 {
1793 DebugTrace(+1, Dbg, "FatDeleteFcb, Fcb = %08lx\n", Fcb);
1794
1795 //
1796 // We can only delete this record if the open count is zero.
1797 //
1798
1799 if (Fcb->OpenCount != 0) {
1800
1801 DebugDump("Error deleting Fcb, Still Open\n", 0, Fcb);
1802 FatBugCheck( 0, 0, 0 );
1803 }
1804
1805 //
1806 // If this is a DCB then remove every Notify record from the two
1807 // notify queues
1808 //
1809
1810 if ((Fcb->Header.NodeTypeCode == FAT_NTC_DCB) ||
1811 (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB)) {
1812
1813 //
1814 // If we allocated a free dirent bitmap buffer, free it.
1815 //
1816
1817 if ((Fcb->Specific.Dcb.FreeDirentBitmap.Buffer != NULL) &&
1818 (Fcb->Specific.Dcb.FreeDirentBitmap.Buffer !=
1819 &Fcb->Specific.Dcb.FreeDirentBitmapBuffer[0])) {
1820
1821 ExFreePool(Fcb->Specific.Dcb.FreeDirentBitmap.Buffer);
1822 }
1823
1824 ASSERT( Fcb->Specific.Dcb.DirectoryFileOpenCount == 0 );
1825 ASSERT( IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) );
1826
1827 } else {
1828
1829 //
1830 // Uninitialize the byte range file locks and opportunistic locks
1831 //
1832
1833 FsRtlUninitializeFileLock( &Fcb->Specific.Fcb.FileLock );
1834 FsRtlUninitializeOplock( &Fcb->Specific.Fcb.Oplock );
1835 }
1836
1837 //
1838 // Release any Filter Context structures associated with this FCB
1839 //
1840
1841 FsRtlTeardownPerStreamContexts( &Fcb->Header );
1842
1843 //
1844 // Uninitialize the Mcb
1845 //
1846
1847 FsRtlUninitializeLargeMcb( &Fcb->Mcb );
1848
1849 //
1850 // If this is not the root dcb then we need to remove ourselves from
1851 // our parents Dcb queue
1852 //
1853
1854 if (Fcb->Header.NodeTypeCode != FAT_NTC_ROOT_DCB) {
1855
1856 RemoveEntryList( &(Fcb->ParentDcbLinks) );
1857 }
1858
1859 //
1860 // Remove the entry from the splay table if there is still is one.
1861 //
1862
1863 if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) {
1864
1865 FatRemoveNames( IrpContext, Fcb );
1866 }
1867
1868 //
1869 // Free the file name pool if allocated.
1870 //
1871
1872 if (Fcb->Header.NodeTypeCode != FAT_NTC_ROOT_DCB) {
1873
1874 //
1875 // If we blew up at inconvenient times, the shortname
1876 // could be null even though you will *never* see this
1877 // normally. Rename is a good example of this case.
1878 //
1879
1880 if (Fcb->ShortName.Name.Oem.Buffer) {
1881
1882 ExFreePool( Fcb->ShortName.Name.Oem.Buffer );
1883 }
1884
1885 if (Fcb->FullFileName.Buffer) {
1886
1887 ExFreePool( Fcb->FullFileName.Buffer );
1888 }
1889 }
1890
1891 if (Fcb->ExactCaseLongName.Buffer) {
1892
1893 ExFreePool(Fcb->ExactCaseLongName.Buffer);
1894 }
1895
1896 #ifdef SYSCACHE_COMPILE
1897
1898 if (Fcb->WriteMask) {
1899
1900 ExFreePool( Fcb->WriteMask );
1901 }
1902
1903 #endif
1904
1905 //
1906 // Finally deallocate the Fcb and non-paged fcb records
1907 //
1908
1909 FatFreeResource( Fcb->Header.Resource );
1910
1911 if (Fcb->Header.PagingIoResource != Fcb->Header.Resource) {
1912
1913 FatFreeResource( Fcb->Header.PagingIoResource );
1914 }
1915
1916 //
1917 // If an Event was allocated, get rid of it.
1918 //
1919
1920 if (Fcb->NonPaged->OutstandingAsyncEvent) {
1921
1922 ExFreePool( Fcb->NonPaged->OutstandingAsyncEvent );
1923 }
1924
1925 FatFreeNonPagedFcb( Fcb->NonPaged );
1926 FatFreeFcb( Fcb );
1927
1928 //
1929 // and return to our caller
1930 //
1931
1932 DebugTrace(-1, Dbg, "FatDeleteFcb -> VOID\n", 0);
1933
1934 return;
1935 }
1936 \f
1937 PCCB
1938 FatCreateCcb (
1939 IN PIRP_CONTEXT IrpContext
1940 )
1941
1942 /*++
1943
1944 Routine Description:
1945
1946 This routine creates a new CCB record
1947
1948 Arguments:
1949
1950 Return Value:
1951
1952 CCB - returns a pointer to the newly allocate CCB
1953
1954 --*/
1955
1956 {
1957 PCCB Ccb;
1958
1959 DebugTrace(+1, Dbg, "FatCreateCcb\n", 0);
1960
1961 //
1962 // Allocate a new CCB Record
1963 //
1964
1965 Ccb = FatAllocateCcb();
1966
1967 RtlZeroMemory( Ccb, sizeof(CCB) );
1968
1969 //
1970 // Set the proper node type code and node byte size
1971 //
1972
1973 Ccb->NodeTypeCode = FAT_NTC_CCB;
1974 Ccb->NodeByteSize = sizeof(CCB);
1975
1976 //
1977 // return and tell the caller
1978 //
1979
1980 DebugTrace(-1, Dbg, "FatCreateCcb -> %08lx\n", Ccb);
1981
1982 UNREFERENCED_PARAMETER( IrpContext );
1983
1984 return Ccb;
1985 }
1986
1987
1988
1989 VOID
1990 FatDeallocateCcbStrings(
1991 IN PCCB Ccb
1992 )
1993 /*++
1994
1995 Routine Description:
1996
1997 This routine deallocates CCB query templates
1998
1999 Arguments:
2000
2001 Ccb - Supplies the CCB
2002
2003 Return Value:
2004
2005 None
2006
2007 --*/
2008 {
2009 //
2010 // If we allocated query template buffers, deallocate them now.
2011 //
2012
2013 if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_UNICODE)) {
2014
2015 ASSERT( Ccb->UnicodeQueryTemplate.Buffer);
2016 ASSERT( !FlagOn( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT));
2017 RtlFreeUnicodeString( &Ccb->UnicodeQueryTemplate );
2018 }
2019
2020 if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT)) {
2021
2022 ASSERT( Ccb->OemQueryTemplate.Wild.Buffer );
2023 ASSERT( !FlagOn( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT));
2024 RtlFreeOemString( &Ccb->OemQueryTemplate.Wild );
2025 }
2026
2027 ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT | CCB_FLAG_FREE_UNICODE);
2028 }
2029
2030
2031
2032 VOID
2033 FatDeleteCcb_Real (
2034 IN PIRP_CONTEXT IrpContext,
2035 IN PCCB Ccb
2036 )
2037
2038 /*++
2039
2040 Routine Description:
2041
2042 This routine deallocates and removes the specified CCB record
2043 from the Fat in memory data structures
2044
2045 Arguments:
2046
2047 Ccb - Supplies the CCB to remove
2048
2049 Return Value:
2050
2051 None
2052
2053 --*/
2054
2055 {
2056 DebugTrace(+1, Dbg, "FatDeleteCcb, Ccb = %08lx\n", Ccb);
2057
2058 FatDeallocateCcbStrings( Ccb);
2059
2060 //
2061 // Deallocate the Ccb record
2062 //
2063
2064 FatFreeCcb( Ccb );
2065
2066 //
2067 // return and tell the caller
2068 //
2069
2070 DebugTrace(-1, Dbg, "FatDeleteCcb -> VOID\n", 0);
2071
2072 UNREFERENCED_PARAMETER( IrpContext );
2073
2074 return;
2075 }
2076
2077 \f
2078 PIRP_CONTEXT
2079 FatCreateIrpContext (
2080 IN PIRP Irp,
2081 IN BOOLEAN Wait
2082 )
2083
2084 /*++
2085
2086 Routine Description:
2087
2088 This routine creates a new IRP_CONTEXT record
2089
2090 Arguments:
2091
2092 Irp - Supplies the originating Irp.
2093
2094 Wait - Supplies the wait value to store in the context
2095
2096 Return Value:
2097
2098 PIRP_CONTEXT - returns a pointer to the newly allocate IRP_CONTEXT Record
2099
2100 --*/
2101
2102 {
2103 PIRP_CONTEXT IrpContext;
2104 PIO_STACK_LOCATION IrpSp;
2105
2106 DebugTrace(+1, Dbg, "FatCreateIrpContext\n", 0);
2107
2108 IrpSp = IoGetCurrentIrpStackLocation( Irp );
2109
2110 //
2111 // The only operations a filesystem device object should ever receive
2112 // are create/teardown of fsdo handles and operations which do not
2113 // occur in the context of fileobjects (i.e., mount).
2114 //
2115
2116 if (FatDeviceIsFatFsdo( IrpSp->DeviceObject)) {
2117
2118 if (IrpSp->FileObject != NULL &&
2119 IrpSp->MajorFunction != IRP_MJ_CREATE &&
2120 IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
2121 IrpSp->MajorFunction != IRP_MJ_CLOSE) {
2122
2123 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
2124 }
2125
2126 ASSERT( IrpSp->FileObject != NULL ||
2127
2128 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
2129 IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
2130 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
2131
2132 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
2133 IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
2134
2135 IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
2136 }
2137
2138 //
2139 // Attemtp to allocate from the region first and failing that allocate
2140 // from pool.
2141 //
2142
2143 DebugDoit( FatFsdEntryCount += 1);
2144
2145 IrpContext = FatAllocateIrpContext();
2146
2147 //
2148 // Zero out the irp context.
2149 //
2150
2151 RtlZeroMemory( IrpContext, sizeof(IRP_CONTEXT) );
2152
2153 //
2154 // Set the proper node type code and node byte size
2155 //
2156
2157 IrpContext->NodeTypeCode = FAT_NTC_IRP_CONTEXT;
2158 IrpContext->NodeByteSize = sizeof(IRP_CONTEXT);
2159
2160 //
2161 // Set the originating Irp field
2162 //
2163
2164 IrpContext->OriginatingIrp = Irp;
2165
2166 //
2167 // Major/Minor Function codes
2168 //
2169
2170 IrpContext->MajorFunction = IrpSp->MajorFunction;
2171 IrpContext->MinorFunction = IrpSp->MinorFunction;
2172
2173 //
2174 // Copy RealDevice for workque algorithms, and also set Write Through
2175 // and Removable Media if there is a file object. Only file system
2176 // control Irps won't have a file object, and they should all have
2177 // a Vpb as the first IrpSp location.
2178 //
2179
2180 if (IrpSp->FileObject != NULL) {
2181
2182 #ifndef __REACTOS__
2183 PVCB Vcb;
2184 #endif
2185 PFILE_OBJECT FileObject = IrpSp->FileObject;
2186
2187 IrpContext->RealDevice = FileObject->DeviceObject;
2188 #ifndef __REACTOS__
2189 Vcb = IrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT)(IrpSp->DeviceObject))->Vcb;
2190 #else
2191 IrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT)(IrpSp->DeviceObject))->Vcb;
2192 #endif
2193
2194 //
2195 // See if the request is Write Through.
2196 //
2197
2198 if (IsFileWriteThrough( FileObject, Vcb )) {
2199
2200 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
2201 }
2202
2203 } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) {
2204
2205 IrpContext->RealDevice = IrpSp->Parameters.MountVolume.Vpb->RealDevice;
2206 }
2207
2208 //
2209 // Set the wait parameter
2210 //
2211
2212 if (Wait) { SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); }
2213
2214 //
2215 // Set the recursive file system call parameter. We set it true if
2216 // the TopLevelIrp field in the thread local storage is not the current
2217 // irp, otherwise we leave it as FALSE.
2218 //
2219
2220 if ( IoGetTopLevelIrp() != Irp) {
2221
2222 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL);
2223 }
2224
2225 //
2226 // return and tell the caller
2227 //
2228
2229 DebugTrace(-1, Dbg, "FatCreateIrpContext -> %08lx\n", IrpContext);
2230
2231 return IrpContext;
2232 }
2233
2234 \f
2235
2236 VOID
2237 FatDeleteIrpContext_Real (
2238 IN PIRP_CONTEXT IrpContext
2239 )
2240
2241 /*++
2242
2243 Routine Description:
2244
2245 This routine deallocates and removes the specified IRP_CONTEXT record
2246 from the Fat in memory data structures. It should only be called
2247 by FatCompleteRequest.
2248
2249 Arguments:
2250
2251 IrpContext - Supplies the IRP_CONTEXT to remove
2252
2253 Return Value:
2254
2255 None
2256
2257 --*/
2258
2259 {
2260 DebugTrace(+1, Dbg, "FatDeleteIrpContext, IrpContext = %08lx\n", IrpContext);
2261
2262 ASSERT( IrpContext->NodeTypeCode == FAT_NTC_IRP_CONTEXT );
2263 ASSERT( IrpContext->PinCount == 0 );
2264
2265 //
2266 // If there is a FatIoContext that was allocated, free it.
2267 //
2268
2269 if (IrpContext->FatIoContext != NULL) {
2270
2271 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
2272
2273 if (IrpContext->FatIoContext->ZeroMdl) {
2274 IoFreeMdl( IrpContext->FatIoContext->ZeroMdl );
2275 }
2276
2277 ExFreePool( IrpContext->FatIoContext );
2278 }
2279 }
2280
2281 //
2282 // Drop the IrpContext.
2283 //
2284
2285 FatFreeIrpContext( IrpContext );
2286
2287 //
2288 // return and tell the caller
2289 //
2290
2291 DebugTrace(-1, Dbg, "FatDeleteIrpContext -> VOID\n", 0);
2292
2293 return;
2294 }
2295
2296 \f
2297 PFCB
2298 FatGetNextFcbBottomUp (
2299 IN PIRP_CONTEXT IrpContext,
2300 IN PFCB Fcb OPTIONAL,
2301 IN PFCB TerminationFcb
2302 )
2303
2304 /*++
2305
2306 Routine Description:
2307
2308 This routine is used to iterate through Fcbs in a tree. In order to match
2309 the lockorder for getting multiple Fcbs (so this can be used for acquiring
2310 all Fcbs), this version does a bottom-up enumeration.
2311
2312 This is different than the old one, now called TopDown. The problem with
2313 lockorder was very well hidden.
2314
2315 The transition rule is still pretty simple:
2316
2317 A) If you have an adjacent sibling, go to it
2318 1) Descend to its leftmost child
2319 B) Else go to your parent
2320
2321 If this routine is called with in invalid TerminationFcb it will fail,
2322 badly.
2323
2324 The TerminationFcb is the last Fcb returned in the enumeration.
2325
2326 This method is incompatible with the possibility that ancestors may vanish
2327 based on operations done on the last returned node. For instance,
2328 FatPurgeReferencedFileObjects cannot use BottomUp enumeration.
2329
2330 Arguments:
2331
2332 Fcb - Supplies the current Fcb. This is NULL if enumeration is starting.
2333
2334 TerminationFcb - The root Fcb of the tree in which the enumeration starts
2335 and at which it inclusively stops.
2336
2337 Return Value:
2338
2339 The next Fcb in the enumeration, or NULL if Fcb was the final one.
2340
2341 --*/
2342
2343 {
2344 PFCB NextFcb;
2345
2346 ASSERT( FatVcbAcquiredExclusive( IrpContext, TerminationFcb->Vcb ) ||
2347 FlagOn( TerminationFcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
2348
2349 //
2350 // Do we need to begin the enumeration?
2351 //
2352
2353 if (Fcb != NULL) {
2354
2355 //
2356 // Did we complete?
2357 //
2358
2359 if (Fcb == TerminationFcb) {
2360
2361 return NULL;
2362 }
2363
2364 //
2365 // Do we have a sibling to return?
2366 //
2367
2368 NextFcb = FatGetNextSibling( Fcb );
2369
2370 //
2371 // If not, return our parent. We are done with this branch.
2372 //
2373
2374 if (NextFcb == NULL) {
2375
2376 return Fcb->ParentDcb;
2377 }
2378
2379 } else {
2380
2381 NextFcb = TerminationFcb;
2382 }
2383
2384 //
2385 // Decend to its furthest child (if it exists) and return it.
2386 //
2387
2388 for (;
2389 NodeType( NextFcb ) != FAT_NTC_FCB && FatGetFirstChild( NextFcb ) != NULL;
2390 NextFcb = FatGetFirstChild( NextFcb )) {
2391 }
2392
2393 return NextFcb;
2394 }
2395
2396 PFCB
2397 FatGetNextFcbTopDown (
2398 IN PIRP_CONTEXT IrpContext,
2399 IN PFCB Fcb,
2400 IN PFCB TerminationFcb
2401 )
2402
2403 /*++
2404
2405 Routine Description:
2406
2407 This routine is used to iterate through Fcbs in a tree, from the top down.
2408
2409 The rule is very simple:
2410
2411 A) If you have a child, go to it, else
2412 B) If you have an older sibling, go to it, else
2413 C) Go to your parent's older sibling.
2414
2415 If this routine is called with in invalid TerminationFcb it will fail,
2416 badly.
2417
2418 The Termination Fcb is never returned. If it is the root of the tree you
2419 are traversing, visit it first.
2420
2421 This routine never returns direct ancestors of Fcb, and thus is useful when
2422 making Fcb's go away (which may tear up the tree).
2423
2424 Arguments:
2425
2426 Fcb - Supplies the current Fcb
2427
2428 TerminationFcb - The Fcb at which the enumeration should (non-inclusivly)
2429 stop. Assumed to be a directory.
2430
2431 Return Value:
2432
2433 The next Fcb in the enumeration, or NULL if Fcb was the final one.
2434
2435 --*/
2436
2437 {
2438 PFCB Sibling;
2439
2440 ASSERT( FatVcbAcquiredExclusive( IrpContext, Fcb->Vcb ) ||
2441 FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
2442
2443 //
2444 // If this was a directory (ie. not a file), get the child. If
2445 // there aren't any children and this is our termination Fcb,
2446 // return NULL.
2447 //
2448
2449 if ( ((NodeType(Fcb) == FAT_NTC_DCB) ||
2450 (NodeType(Fcb) == FAT_NTC_ROOT_DCB)) &&
2451 !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) ) {
2452
2453 return FatGetFirstChild( Fcb );
2454 }
2455
2456 //
2457 // Were we only meant to do one iteration?
2458 //
2459
2460 if ( Fcb == TerminationFcb ) {
2461
2462 return NULL;
2463 }
2464
2465 Sibling = FatGetNextSibling(Fcb);
2466
2467 while (TRUE) {
2468
2469 //
2470 // Do we still have an "older" sibling in this directory who is
2471 // not the termination Fcb?
2472 //
2473
2474 if ( Sibling != NULL ) {
2475
2476 return (Sibling != TerminationFcb) ? Sibling : NULL;
2477 }
2478
2479 //
2480 // OK, let's move on to out parent and see if he is the termination
2481 // node or has any older siblings.
2482 //
2483
2484 if ( Fcb->ParentDcb == TerminationFcb ) {
2485
2486 return NULL;
2487 }
2488
2489 Fcb = Fcb->ParentDcb;
2490
2491 Sibling = FatGetNextSibling(Fcb);
2492 }
2493 }
2494
2495 BOOLEAN
2496 FatSwapVpb (
2497 IN PIRP_CONTEXT IrpContext,
2498 PVCB Vcb
2499 )
2500
2501 /*++
2502
2503 Routine Description:
2504
2505 This routine swaps the VPB for this VCB if it has not been done already.
2506 This means the device object will get our spare VPB and we will cleanup
2507 the one used while the volume was mounted.
2508
2509 Arguments:
2510
2511 IrpContext - Supplies the context for the overall request.
2512
2513 Vcb - Supplies the VCB to swap the VPB on.
2514
2515 Return Value:
2516
2517 TRUE - If the VPB was actually swapped.
2518
2519 FALSE - If the VPB was already swapped.
2520
2521 --*/
2522
2523 {
2524 BOOLEAN Result = FALSE;
2525 PVPB OldVpb;
2526 PIO_STACK_LOCATION IrpSp;
2527
2528
2529 //
2530 // Make sure we have not already swapped it.
2531 //
2532
2533 OldVpb = Vcb->Vpb;
2534
2535 if (OldVpb->RealDevice->Vpb == OldVpb) {
2536
2537 //
2538 // If not the final reference and we are forcing the disconnect,
2539 // then swap out the Vpb. We must preserve the REMOVE_PENDING flag
2540 // so that the device is not remounted in the middle of a PnP remove
2541 // operation.
2542 //
2543
2544 ASSERT( Vcb->SwapVpb != NULL );
2545
2546 Vcb->SwapVpb->Type = IO_TYPE_VPB;
2547 Vcb->SwapVpb->Size = sizeof( VPB );
2548 Vcb->SwapVpb->RealDevice = OldVpb->RealDevice;
2549
2550 Vcb->SwapVpb->RealDevice->Vpb = Vcb->SwapVpb;
2551
2552 Vcb->SwapVpb->Flags = FlagOn( OldVpb->Flags, VPB_REMOVE_PENDING );
2553
2554 //
2555 // If we are working on a mount request, we need to make sure we update
2556 // the VPB in the IRP, since the one it points to may no longer be valid.
2557 //
2558
2559 if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) {
2560
2561 //
2562 // Get the IRP stack.
2563 //
2564
2565 IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
2566
2567 ASSERT( IrpSp->FileObject == NULL );
2568
2569 //
2570 // Check the VPB in the IRP to see if it is the one we are swapping.
2571 //
2572
2573 if (IrpSp->Parameters.MountVolume.Vpb == OldVpb) {
2574
2575 //
2576 // Change the IRP to point to the swap VPB.
2577 //
2578
2579 IrpSp->Parameters.MountVolume.Vpb = Vcb->SwapVpb;
2580 }
2581 }
2582
2583 //
2584 // We place the volume in the Bad state (as opposed to NotMounted) so
2585 // that it is not eligible for a remount. Also indicate we used up
2586 // the swap.
2587 //
2588
2589 Vcb->SwapVpb = NULL;
2590 FatSetVcbCondition( Vcb, VcbBad);
2591 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED );
2592
2593 Result = TRUE;
2594 }
2595
2596 return Result;
2597 }
2598
2599 \f
2600 BOOLEAN
2601 FatCheckForDismount (
2602 IN PIRP_CONTEXT IrpContext,
2603 PVCB Vcb,
2604 IN BOOLEAN Force
2605 )
2606
2607 /*++
2608
2609 Routine Description:
2610
2611 This routine determines if a volume is ready for deletion. It
2612 correctly synchronizes with creates en-route to the file system.
2613
2614 Arguments:
2615
2616 Vcb - Supplies the volume to examine
2617
2618 Force - Specifies whether we want this Vcb forcibly disconnected
2619 from the driver stack if it will not be deleted (a new vpb will
2620 be installed if neccesary). Caller is responsible for making
2621 sure that the volume has been marked in such a way that attempts
2622 to operate through the realdevice are blocked (i.e., move the vcb
2623 out of the mounted state).
2624
2625 Return Value:
2626
2627 BOOLEAN - TRUE if the volume was deleted, FALSE otherwise.
2628
2629 --*/
2630
2631 {
2632 KIRQL SavedIrql;
2633 BOOLEAN VcbDeleted = FALSE;
2634
2635 //
2636 // If the VCB condition is good and we are not forcing, just return.
2637 //
2638
2639 if (Vcb->VcbCondition == VcbGood && !Force) {
2640
2641 return FALSE;
2642 }
2643
2644 //
2645 // Now check for a zero Vpb count on an unmounted volume. These
2646 // volumes will be deleted as they now have no file objects and
2647 // there are no creates en route to this volume.
2648 //
2649
2650 IoAcquireVpbSpinLock( &SavedIrql );
2651
2652 if (Vcb->Vpb->ReferenceCount == Vcb->ResidualOpenCount && Vcb->OpenFileCount == 0) {
2653
2654 PVPB Vpb = Vcb->Vpb;
2655
2656 #if DBG
2657 UNICODE_STRING VolumeLabel;
2658
2659 //
2660 // Setup the VolumeLabel string
2661 //
2662
2663 VolumeLabel.Length = Vcb->Vpb->VolumeLabelLength;
2664 VolumeLabel.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
2665 VolumeLabel.Buffer = &Vcb->Vpb->VolumeLabel[0];
2666
2667 KdPrintEx((DPFLTR_FASTFAT_ID,
2668 DPFLTR_INFO_LEVEL,
2669 "FASTFAT: Dismounting Volume %Z\n",
2670 &VolumeLabel));
2671 #endif // DBG
2672
2673 //
2674 // Swap this VCB's VPB.
2675 //
2676
2677 FatSwapVpb( IrpContext,
2678 Vcb );
2679
2680 //
2681 // Clear the VPB_MOUNTED bit. New opens should not come in due
2682 // to the swapped VPB, but having the flag cleared helps debugging.
2683 // Note that we must leave the Vpb->DeviceObject field set until
2684 // after the FatTearDownVcb call as closes will have to make their
2685 // way back to us.
2686 //
2687
2688 ClearFlag( Vpb->Flags, VPB_MOUNTED );
2689
2690 //
2691 // If this Vpb was locked, clear this flag now.
2692 //
2693
2694 ClearFlag( Vpb->Flags, VPB_LOCKED );
2695
2696 IoReleaseVpbSpinLock( SavedIrql );
2697
2698 //
2699 // We are going to attempt the dismount, so mark the VCB as having
2700 // a dismount in progress.
2701 //
2702
2703 ASSERT( !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) );
2704 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS );
2705
2706 //
2707 // Close down our internal opens.
2708 //
2709
2710 FatTearDownVcb( IrpContext,
2711 Vcb );
2712
2713 //
2714 // Process any delayed closes.
2715 //
2716
2717 FatFspClose( Vcb );
2718
2719 //
2720 // Grab the VPB lock again so that we can recheck our counts.
2721 //
2722
2723 IoAcquireVpbSpinLock( &SavedIrql );
2724
2725 //
2726 // See if we can delete this VCB.
2727 //
2728
2729 if (Vcb->Vpb->ReferenceCount == 0 && Vcb->InternalOpenCount == 0) {
2730
2731 Vpb->DeviceObject = NULL;
2732
2733 IoReleaseVpbSpinLock( SavedIrql );
2734
2735 FatDeleteVcb( IrpContext, Vcb );
2736
2737
2738 IoDeleteDevice( (PDEVICE_OBJECT)
2739 CONTAINING_RECORD( Vcb,
2740 VOLUME_DEVICE_OBJECT,
2741 Vcb ) );
2742
2743 VcbDeleted = TRUE;
2744
2745 } else {
2746
2747 IoReleaseVpbSpinLock( SavedIrql );
2748
2749 ASSERT( FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) );
2750 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS );
2751 }
2752
2753 } else if (Force) {
2754
2755 //
2756 // The requester is forcing the issue. We need to swap the VPB with our spare.
2757 //
2758
2759 FatSwapVpb( IrpContext,
2760 Vcb );
2761
2762 IoReleaseVpbSpinLock( SavedIrql );
2763
2764 } else {
2765
2766 //
2767 // Just drop the Vpb spinlock.
2768 //
2769
2770 IoReleaseVpbSpinLock( SavedIrql );
2771 }
2772
2773 return VcbDeleted;
2774 }
2775
2776 \f
2777 VOID
2778 FatConstructNamesInFcb (
2779 IN PIRP_CONTEXT IrpContext,
2780 PFCB Fcb,
2781 PDIRENT Dirent,
2782 PUNICODE_STRING Lfn OPTIONAL
2783 )
2784
2785 /*++
2786
2787 Routine Description:
2788
2789 This routine places the short name in the dirent in the first set of
2790 STRINGs in the Fcb. If a long file name (Lfn) was specified, then
2791 we must decide whether we will store its Oem equivolent in the same
2792 prefix table as the short name, or rather just save the upcased
2793 version of the UNICODE string in the FCB.
2794
2795 For looking up Fcbs, the first approach will be faster, so we want to
2796 do this as much as possible. Here are the rules that I have thought
2797 through extensively to determine when it is safe to store only Oem
2798 version of the UNICODE name.
2799
2800 - If the UNICODE name contains no extended characters (>0x80), use Oem.
2801
2802 - Let U be the upcased version of the UNICODE name.
2803 Let Up(x) be the function that upcases a UNICODE string.
2804 Let Down(x) be the function that upcases a UNICODE string.
2805 Let OemToUni(x) be the function that converts an Oem string to Unicode.
2806 Let UniToOem(x) be the function that converts a Unicode string to Oem.
2807 Let BestOemFit(x) be the function that creates the Best uppercase Oem
2808 fit for the UNICODE string x.
2809
2810 BestOemFit(x) = UniToOem(Up(OemToUni(UniToOem(x)))) <1>
2811
2812 if (BestOemFit(U) == BestOemFit(Down(U)) <2>
2813
2814 then I know that there exists no UNICODE string Y such that:
2815
2816 Up(Y) == Up(U) <3>
2817
2818 AND
2819
2820 BestOemFit(U) != BestOemFit(Y) <4>
2821
2822 Consider string U as a collection of one character strings. The
2823 conjecture is clearly true for each sub-string, thus it is true
2824 for the entire string.
2825
2826 Equation <1> is what we use to convert an incoming unicode name in
2827 FatCommonCreate() to Oem. The double conversion is done to provide
2828 better visual best fitting for characters in the Ansi code page but
2829 not in the Oem code page. A single Nls routine is provided to do
2830 this conversion efficiently.
2831
2832 The idea is that with U, I only have to worry about a case varient Y
2833 matching it in a unicode compare, and I have shown that any case varient
2834 of U (the set Y defined in equation <3>), when filtered through <1>
2835 (as in create), will match the Oem string defined in <1>.
2836
2837 Thus I do not have to worry about another UNICODE string missing in
2838 the prefix lookup, but matching when comparing LFNs in the directory.
2839
2840 Arguments:
2841
2842 Fcb - The Fcb we are supposed to fill in. Note that ParentDcb must
2843 already be filled in.
2844
2845 Dirent - The gives up the short name.
2846
2847 Lfn - If provided, this gives us the long name.
2848
2849 Return Value:
2850
2851 None
2852
2853 --*/
2854
2855 {
2856 #ifndef __REACTOS__
2857 NTSTATUS Status;
2858 #endif
2859 ULONG i;
2860
2861 #ifndef __REACTOS__
2862 OEM_STRING OemA;
2863 OEM_STRING OemB;
2864 #endif
2865 UNICODE_STRING Unicode;
2866 POEM_STRING ShortName;
2867 POEM_STRING LongOemName;
2868 PUNICODE_STRING LongUniName;
2869
2870 ShortName = &Fcb->ShortName.Name.Oem;
2871
2872 ASSERT( ShortName->Buffer == NULL );
2873
2874 _SEH2_TRY {
2875
2876 //
2877 // First do the short name.
2878 //
2879
2880 //
2881 // Copy over the case flags for the short name of the file
2882 //
2883
2884 if (FlagOn(Dirent->NtByte, FAT_DIRENT_NT_BYTE_8_LOWER_CASE)) {
2885
2886 SetFlag(Fcb->FcbState, FCB_STATE_8_LOWER_CASE);
2887
2888 } else {
2889
2890 ClearFlag(Fcb->FcbState, FCB_STATE_8_LOWER_CASE);
2891 }
2892
2893 if (FlagOn(Dirent->NtByte, FAT_DIRENT_NT_BYTE_3_LOWER_CASE)) {
2894
2895 SetFlag(Fcb->FcbState, FCB_STATE_3_LOWER_CASE);
2896
2897 } else {
2898
2899 ClearFlag(Fcb->FcbState, FCB_STATE_3_LOWER_CASE);
2900 }
2901
2902 ShortName->MaximumLength = 16;
2903 ShortName->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
2904 16,
2905 TAG_FILENAME_BUFFER );
2906
2907 Fat8dot3ToString( IrpContext, Dirent, FALSE, ShortName );
2908
2909 //
2910 // If no Lfn was specified, we are done. In either case, set the
2911 // final name length.
2912 //
2913
2914 ASSERT( Fcb->ExactCaseLongName.Buffer == NULL );
2915
2916 if (!ARGUMENT_PRESENT(Lfn) || (Lfn->Length == 0)) {
2917
2918 Fcb->FinalNameLength = (USHORT) RtlOemStringToCountedUnicodeSize( ShortName );
2919 Fcb->ExactCaseLongName.Length = Fcb->ExactCaseLongName.MaximumLength = 0;
2920
2921 try_return( NOTHING );
2922 }
2923
2924 //
2925 // If we already set up the full filename, we could be in trouble. If the fast
2926 // path for doing it already fired, FatSetFullFileNameInFcb, it will have missed
2927 // this and could have built the full filename out of the shortname of the file.
2928 //
2929 // At that point, disaster could be inevitable since the final name length will not
2930 // match. We use this to tell the notify package what to do - FatNotifyReportChange.
2931 //
2932
2933 ASSERT( Fcb->FullFileName.Buffer == NULL );
2934
2935 //
2936 // We know now we have an Lfn, save away a copy.
2937 //
2938
2939 Fcb->FinalNameLength = Lfn->Length;
2940
2941 Fcb->ExactCaseLongName.Length = Fcb->ExactCaseLongName.MaximumLength = Lfn->Length;
2942 Fcb->ExactCaseLongName.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
2943 Lfn->Length,
2944 TAG_FILENAME_BUFFER );
2945 RtlCopyMemory(Fcb->ExactCaseLongName.Buffer, Lfn->Buffer, Lfn->Length);
2946
2947 //
2948 // First check for no extended characters.
2949 //
2950
2951 for (i=0; i < Lfn->Length/sizeof(WCHAR); i++) {
2952
2953 if (Lfn->Buffer[i] >= 0x80) {
2954
2955 break;
2956 }
2957 }
2958
2959 if (i == Lfn->Length/sizeof(WCHAR)) {
2960
2961 //
2962 // Cool, I can go with the Oem, upcase it fast by hand.
2963 //
2964
2965 LongOemName = &Fcb->LongName.Oem.Name.Oem;
2966
2967
2968 LongOemName->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
2969 Lfn->Length/sizeof(WCHAR),
2970 TAG_FILENAME_BUFFER );
2971 LongOemName->Length =
2972 LongOemName->MaximumLength = Lfn->Length/sizeof(WCHAR);
2973
2974 for (i=0; i < Lfn->Length/sizeof(WCHAR); i++) {
2975
2976 WCHAR c;
2977
2978 c = Lfn->Buffer[i];
2979
2980 LongOemName->Buffer[i] = c < 'a' ?
2981 (UCHAR)c :
2982 c <= 'z' ?
2983 c - (UCHAR)('a'-'A') :
2984 (UCHAR) c;
2985 }
2986
2987 //
2988 // If this name happens to be exactly the same as the short
2989 // name, don't add it to the splay table.
2990 //
2991
2992 if (FatAreNamesEqual(IrpContext, *ShortName, *LongOemName) ||
2993 (FatFindFcb( IrpContext,
2994 &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
2995 LongOemName,
2996 NULL) != NULL)) {
2997
2998 ExFreePool( LongOemName->Buffer );
2999
3000 LongOemName->Buffer = NULL;
3001 LongOemName->Length =
3002 LongOemName->MaximumLength = 0;
3003
3004 } else {
3005
3006 SetFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
3007 }
3008
3009 try_return( NOTHING );
3010 }
3011
3012 //
3013 // Now we have the fun part. Make a copy of the Lfn.
3014 //
3015
3016 #ifndef __REACTOS__
3017 OemA.Buffer = NULL;
3018 OemB.Buffer = NULL;
3019 #endif
3020 Unicode.Buffer = NULL;
3021
3022 Unicode.Length =
3023 Unicode.MaximumLength = Lfn->Length;
3024 Unicode.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
3025 Lfn->Length,
3026 TAG_FILENAME_BUFFER );
3027
3028 RtlCopyMemory( Unicode.Buffer, Lfn->Buffer, Lfn->Length );
3029
3030 #ifndef __REACTOS__
3031 Status = STATUS_SUCCESS;
3032 #endif
3033
3034 #if TRUE
3035 //
3036 // Unfortunately, this next block of code breaks down when you have
3037 // two long Unicode filenames that both map to the same Oem (and are,
3038 // well, long, i.e. are not the short names). In this case, with one
3039 // in the prefix table first, the other will hit the common Oem
3040 // representation. This leads to several forms of user astonishment.
3041 //
3042 // It isn't worth it, or probably even possible, to try to figure out
3043 // when this is really safe to go through. Simply omit the attempt.
3044 //
3045 // Ex: ANSI 0x82 and 0x84 in the 1252 ANSI->UNI and 437 UNI->OEM codepages.
3046 //
3047 // 0x82 => 0x201a => 0x2c
3048 // 0x84 => 0x201e => 0x2c
3049 //
3050 // 0x2c is comma, so is FAT Oem illegal and forces shortname generation.
3051 // Since it is otherwise well-formed by the rules articulated previously,
3052 // we would have put 0x2c in the Oem prefix tree. In terms of the
3053 // argument given above, even though there exist no Y and U s.t.
3054 //
3055 // Up(Y) == Up(U) && BestOemFit(U) != BestOemFit(Y)
3056 //
3057 // there most certainly exist Y and U s.t.
3058 //
3059 // Up(Y) != Up(U) && BestOemFit(U) == BestOemFit(Y)
3060 //
3061 // and that is enough to keep us from doing this. Note that the < 0x80
3062 // case is OK since we know that the mapping in the OEM codepages are
3063 // the identity in that range.
3064 //
3065 // We still need to monocase it, though. Do this through a full down/up
3066 // transition.
3067 //
3068
3069 (VOID)RtlDowncaseUnicodeString( &Unicode, &Unicode, FALSE );
3070 (VOID)RtlUpcaseUnicodeString( &Unicode, &Unicode, FALSE );
3071 #else
3072 //
3073 // Downcase and convert to upcased Oem. Only continue if we can
3074 // convert without error. Any error other than UNMAPPABLE_CHAR
3075 // is a fatal error and we raise.
3076 //
3077 // Note that even if the conversion fails, we must leave Unicode
3078 // in an upcased state.
3079 //
3080 // NB: The Rtl doesn't NULL .Buffer on error.
3081 //
3082
3083 (VOID)RtlDowncaseUnicodeString( &Unicode, &Unicode, FALSE );
3084 Status = RtlUpcaseUnicodeStringToCountedOemString( &OemA, &Unicode, TRUE );
3085 (VOID)RtlUpcaseUnicodeString( &Unicode, &Unicode, FALSE );
3086
3087 if (!NT_SUCCESS(Status)) {
3088
3089 if (Status != STATUS_UNMAPPABLE_CHARACTER) {
3090
3091 ASSERT( Status == STATUS_NO_MEMORY );
3092 ExFreePool(Unicode.Buffer);
3093 FatNormalizeAndRaiseStatus( IrpContext, Status );
3094 }
3095
3096 } else {
3097
3098 //
3099 // The same as above except upcase.
3100 //
3101
3102 Status = RtlUpcaseUnicodeStringToCountedOemString( &OemB, &Unicode, TRUE );
3103
3104 if (!NT_SUCCESS(Status)) {
3105
3106 RtlFreeOemString( &OemA );
3107
3108 if (Status != STATUS_UNMAPPABLE_CHARACTER) {
3109
3110 ASSERT( Status == STATUS_NO_MEMORY );
3111 ExFreePool(Unicode.Buffer);
3112 FatNormalizeAndRaiseStatus( IrpContext, Status );
3113 }
3114 }
3115 }
3116
3117 //
3118 // If the final OemNames are equal, I can use save only the Oem
3119 // name. If the name did not map, then I have to go with the UNICODE
3120 // name because I could get a case varient that didn't convert
3121 // in create, but did match the LFN.
3122 //
3123
3124 if (NT_SUCCESS(Status) && FatAreNamesEqual( IrpContext, OemA, OemB )) {
3125
3126 //
3127 // Cool, I can go with the Oem. If we didn't convert correctly,
3128 // get a fresh convert from the original LFN.
3129 //
3130
3131 ExFreePool(Unicode.Buffer);
3132
3133 RtlFreeOemString( &OemB );
3134
3135 Fcb->LongName.Oem.Name.Oem = OemA;
3136
3137 //
3138 // If this name happens to be exactly the same as the short
3139 // name, or a similar short name already exists don't add it
3140 // to the splay table (note the final condition implies a
3141 // corrupt disk.
3142 //
3143
3144 if (FatAreNamesEqual(IrpContext, *ShortName, OemA) ||
3145 (FatFindFcb( IrpContext,
3146 &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
3147 &OemA,
3148 NULL) != NULL)) {
3149
3150 RtlFreeOemString( &OemA );
3151
3152 } else {
3153
3154 SetFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
3155 }
3156
3157 try_return( NOTHING );
3158 }
3159
3160 //
3161 // The long name must be left in UNICODE. Free the two Oem strings
3162 // if we got here just because they weren't equal.
3163 //
3164
3165 if (NT_SUCCESS(Status)) {
3166
3167 RtlFreeOemString( &OemA );
3168 RtlFreeOemString( &OemB );
3169 }
3170 #endif
3171
3172 LongUniName = &Fcb->LongName.Unicode.Name.Unicode;
3173
3174 LongUniName->Length =
3175 LongUniName->MaximumLength = Unicode.Length;
3176 LongUniName->Buffer = Unicode.Buffer;
3177
3178 SetFlag(Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME);
3179
3180 try_exit: NOTHING;
3181 } _SEH2_FINALLY {
3182
3183 if (_SEH2_AbnormalTermination()) {
3184
3185 if (ShortName->Buffer != NULL) {
3186
3187 ExFreePool( ShortName->Buffer );
3188 ShortName->Buffer = NULL;
3189 }
3190
3191 } else {
3192
3193 //
3194 // Creating all the names worked, so add all the names
3195 // to the splay tree.
3196 //
3197
3198 FatInsertName( IrpContext,
3199 &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
3200 &Fcb->ShortName );
3201
3202 Fcb->ShortName.Fcb = Fcb;
3203
3204 if (FlagOn(Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME)) {
3205
3206 FatInsertName( IrpContext,
3207 &Fcb->ParentDcb->Specific.Dcb.RootOemNode,
3208 &Fcb->LongName.Oem );
3209
3210 Fcb->LongName.Oem.Fcb = Fcb;
3211 }
3212
3213 if (FlagOn(Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME)) {
3214
3215 FatInsertName( IrpContext,
3216 &Fcb->ParentDcb->Specific.Dcb.RootUnicodeNode,
3217 &Fcb->LongName.Unicode );
3218
3219 Fcb->LongName.Unicode.Fcb = Fcb;
3220 }
3221
3222 SetFlag(Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE);
3223 }
3224 } _SEH2_END;
3225
3226 return;
3227 }
3228
3229 \f
3230 VOID
3231 FatCheckFreeDirentBitmap (
3232 IN PIRP_CONTEXT IrpContext,
3233 IN PDCB Dcb
3234 )
3235
3236 /*++
3237
3238 Routine Description:
3239
3240 This routine checks if the size of the free dirent bitmap is
3241 sufficient to for the current directory size. It is called
3242 whenever we grow a directory.
3243
3244 Arguments:
3245
3246 Dcb - Supplies the directory in question.
3247
3248 Return Value:
3249
3250 None
3251
3252 --*/
3253
3254 {
3255 ULONG OldNumberOfDirents;
3256 ULONG NewNumberOfDirents;
3257
3258 //
3259 // Setup the Bitmap buffer if it is not big enough already
3260 //
3261
3262 ASSERT( Dcb->Header.AllocationSize.QuadPart != FCB_LOOKUP_ALLOCATIONSIZE_HINT );
3263
3264 OldNumberOfDirents = Dcb->Specific.Dcb.FreeDirentBitmap.SizeOfBitMap;
3265 NewNumberOfDirents = Dcb->Header.AllocationSize.LowPart / sizeof(DIRENT);
3266
3267 //
3268 // Do the usual unsync/sync check.
3269 //
3270
3271 if (NewNumberOfDirents > OldNumberOfDirents) {
3272
3273 FatAcquireDirectoryFileMutex( Dcb->Vcb );
3274
3275 _SEH2_TRY {
3276
3277 PULONG OldBitmapBuffer;
3278 PULONG BitmapBuffer;
3279
3280 ULONG BytesInBitmapBuffer;
3281 ULONG BytesInOldBitmapBuffer;
3282
3283 OldNumberOfDirents = Dcb->Specific.Dcb.FreeDirentBitmap.SizeOfBitMap;
3284 NewNumberOfDirents = Dcb->Header.AllocationSize.LowPart / sizeof(DIRENT);
3285
3286 if (NewNumberOfDirents > OldNumberOfDirents) {
3287
3288 //
3289 // Remember the old bitmap
3290 //
3291
3292 OldBitmapBuffer = Dcb->Specific.Dcb.FreeDirentBitmap.Buffer;
3293
3294 //
3295 // Now make a new bitmap bufffer
3296 //
3297
3298 BytesInBitmapBuffer = NewNumberOfDirents / 8;
3299
3300 BytesInOldBitmapBuffer = OldNumberOfDirents / 8;
3301
3302 if (DCB_UNION_SLACK_SPACE >= BytesInBitmapBuffer) {
3303
3304 BitmapBuffer = &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0];
3305
3306 } else {
3307
3308 BitmapBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3309 BytesInBitmapBuffer,
3310 TAG_DIRENT_BITMAP );
3311 }
3312
3313 //
3314 // Copy the old buffer to the new buffer, free the old one, and zero
3315 // the rest of the new one. Only do the first two steps though if
3316 // we moved out of the initial buffer.
3317 //
3318
3319 if ((OldNumberOfDirents != 0) &&
3320 (BitmapBuffer != &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0])) {
3321
3322 RtlCopyMemory( BitmapBuffer,
3323 OldBitmapBuffer,
3324 BytesInOldBitmapBuffer );
3325
3326 if (OldBitmapBuffer != &Dcb->Specific.Dcb.FreeDirentBitmapBuffer[0]) {
3327
3328 ExFreePool( OldBitmapBuffer );
3329 }
3330 }
3331
3332 ASSERT( BytesInBitmapBuffer > BytesInOldBitmapBuffer );
3333
3334 RtlZeroMemory( (PUCHAR)BitmapBuffer + BytesInOldBitmapBuffer,
3335 BytesInBitmapBuffer - BytesInOldBitmapBuffer );
3336
3337 //
3338 // Now initialize the new bitmap.
3339 //
3340
3341 RtlInitializeBitMap( &Dcb->Specific.Dcb.FreeDirentBitmap,
3342 BitmapBuffer,
3343 NewNumberOfDirents );
3344 }
3345
3346 } _SEH2_FINALLY {
3347
3348 FatReleaseDirectoryFileMutex( Dcb->Vcb );
3349 } _SEH2_END;
3350 }
3351 }
3352
3353 \f
3354 BOOLEAN
3355 FatIsHandleCountZero (
3356 IN PIRP_CONTEXT IrpContext,
3357 IN PVCB Vcb
3358 )
3359
3360 /*++
3361
3362 Routine Description:
3363
3364 This routine decides if the handle count on the volume is zero.
3365
3366 Arguments:
3367
3368 Vcb - The volume in question
3369
3370 Return Value:
3371
3372 BOOLEAN - TRUE if there are no open handles on the volume, FALSE
3373 otherwise.
3374
3375 --*/
3376
3377 {
3378 PFCB Fcb;
3379
3380 Fcb = Vcb->RootDcb;
3381
3382 while (Fcb != NULL) {
3383
3384 if (Fcb->UncleanCount != 0) {
3385
3386 return FALSE;
3387 }
3388
3389 Fcb = FatGetNextFcbTopDown(IrpContext, Fcb, Vcb->RootDcb);
3390 }
3391
3392 return TRUE;
3393 }
3394
3395 \f
3396 VOID
3397 FatPreallocateCloseContext (
3398 )
3399
3400 /*++
3401
3402 Routine Description:
3403
3404 This routine preallocates a close context, presumeably on behalf
3405 of a fileobject which does not have a structure we can embed one
3406 in.
3407
3408 Arguments:
3409
3410 None.
3411
3412 Return Value:
3413
3414 None.
3415
3416 --*/
3417
3418 {
3419 PCLOSE_CONTEXT CloseContext = FsRtlAllocatePoolWithTag( PagedPool,
3420 sizeof(CLOSE_CONTEXT),
3421 TAG_FAT_CLOSE_CONTEXT );
3422
3423 ExInterlockedPushEntrySList( &FatCloseContextSList,
3424 (PSINGLE_LIST_ENTRY) CloseContext,
3425 &FatData.GeneralSpinLock );
3426 }
3427
3428
3429 VOID
3430 FatEnsureStringBufferEnough(
3431 IN OUT PVOID String,
3432 IN USHORT DesiredBufferSize
3433 )
3434 /*++
3435
3436 Routine Description:
3437
3438 Ensures that a string string (STRING, UNICODE_STRING, ANSI_STRING, OEM_STRING)
3439 has a buffer >= DesiredBufferSize, allocating from pool if neccessary. Any
3440 existing pool buffer will be freed if a new one is allocated.
3441
3442 NOTE: No copy of old buffer contents is performed on reallocation.
3443
3444 Will raise on allocation failure.
3445
3446 Arguments:
3447
3448 String - pointer to string structure
3449
3450 DesiredBufferSize - (bytes) minimum required buffer size
3451
3452 --*/
3453 {
3454 PSTRING LocalString = String;
3455
3456 if (LocalString->MaximumLength < DesiredBufferSize) {
3457
3458 FatFreeStringBuffer( LocalString);
3459
3460 LocalString->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
3461 DesiredBufferSize,
3462 TAG_DYNAMIC_NAME_BUFFER);
3463 ASSERT( LocalString->Buffer);
3464
3465 LocalString->MaximumLength = DesiredBufferSize;
3466 }
3467 }
3468
3469
3470 VOID
3471 FatFreeStringBuffer(
3472 IN PVOID String
3473 )
3474 /*++
3475
3476 Routine Description:
3477
3478 Frees the buffer of an string (STRING, UNICODE_STRING, ANSI_STRING, OEM_STRING)
3479 structure if it is not within the current thread's stack limits.
3480
3481 Regardless of action performed, on exit String->Buffer will be set to NULL and
3482 String->MaximumLength to zero.
3483
3484 Arguments:
3485
3486 String - pointer to string structure
3487
3488 --*/
3489 {
3490 ULONG_PTR High, Low;
3491 PSTRING LocalString = String;
3492
3493 if (NULL != LocalString->Buffer) {
3494
3495 IoGetStackLimits( &Low, &High );
3496
3497 if (((ULONG_PTR)(LocalString->Buffer) < Low) ||
3498 ((ULONG_PTR)(LocalString->Buffer) > High)) {
3499
3500 ExFreePool( LocalString->Buffer);
3501 }
3502
3503 LocalString->Buffer = NULL;
3504 }
3505
3506 LocalString->MaximumLength = LocalString->Length = 0;
3507 }
3508
3509
3510 BOOLEAN
3511 FatScanForDataTrack(
3512 IN PIRP_CONTEXT IrpContext,
3513 IN PDEVICE_OBJECT TargetDeviceObject
3514 )
3515
3516 /*++
3517
3518 Routine Description:
3519
3520 This routine is called to verify and process the TOC for this disk.
3521
3522 FAT queries for the TOC to avoid trying to mount on CD-DA/CD-E media, Doing data reads on
3523 audio/leadin of that media sends a lot of drives into what could charitably be called
3524 "conniptions" which take a couple seconds to clear and would also convince FAT that the
3525 device was busted, and fail the mount (not letting CDFS get its crack).
3526
3527 There is special handling of PD media. These things fail the TOC read, but return
3528 a special error code so FAT knows to continue to try the mount anyway.
3529
3530 Arguments:
3531
3532 TargetDeviceObject - Device object to send TOC request to.
3533
3534 Return Value:
3535
3536 BOOLEAN - TRUE if we found a TOC with a single data track.
3537
3538 --*/
3539
3540 {
3541 NTSTATUS Status;
3542 IO_STATUS_BLOCK Iosb;
3543
3544 ULONG LocalTrackCount;
3545 ULONG LocalTocLength;
3546
3547 PCDROM_TOC CdromToc;
3548 BOOLEAN Result = FALSE;
3549
3550 PAGED_CODE();
3551
3552 CdromToc = FsRtlAllocatePoolWithTag( PagedPool,
3553 sizeof( CDROM_TOC ),
3554 TAG_IO_BUFFER );
3555
3556 RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
3557
3558 _SEH2_TRY {
3559
3560 //
3561 // Go ahead and read the table of contents
3562 //
3563
3564 Status = FatPerformDevIoCtrl( IrpContext,
3565 IOCTL_CDROM_READ_TOC,
3566 TargetDeviceObject,
3567 CdromToc,
3568 sizeof( CDROM_TOC ),
3569 FALSE,
3570 TRUE,
3571 &Iosb );
3572
3573 //
3574 // Nothing to process if this request fails.
3575 //
3576
3577 if (Status != STATUS_SUCCESS) {
3578
3579 //
3580 // If we get the special error indicating a failed TOC read on PD media just
3581 // plow ahead with the mount (see comments above).
3582 //
3583
3584 if ((Status == STATUS_IO_DEVICE_ERROR) || (Status == STATUS_INVALID_DEVICE_REQUEST)) {
3585
3586 Result = TRUE;
3587
3588 }
3589
3590 try_leave( NOTHING );
3591 }
3592
3593 //
3594 // Get the number of tracks and stated size of this structure.
3595 //
3596
3597 LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1;
3598 LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] );
3599
3600 //
3601 // Get out if there is an immediate problem with the TOC, or more than
3602 // one track.
3603 //
3604
3605 if ((LocalTocLength > Iosb.Information) ||
3606 (CdromToc->FirstTrack > CdromToc->LastTrack) ||
3607 (LocalTrackCount != 1)) {
3608
3609 try_leave( NOTHING);
3610 }
3611
3612 //
3613 // Is it a data track? DVD-RAM reports single, data, track.
3614 //
3615
3616 Result = BooleanFlagOn( CdromToc->TrackData[ 0].Control, 0x04 );
3617 }
3618 _SEH2_FINALLY {
3619
3620 ExFreePool( CdromToc);
3621 } _SEH2_END;
3622
3623 return Result;
3624 }
3625
3626