1 /*++
2
3
4 Copyright (c) 1989-2000 Microsoft Corporation
5
6 Module Name:
7
8 FsCtrl.c
9
10 Abstract:
11
12 This module implements the File System Control routines for Fat called
13 by the dispatch driver.
14
15
16 --*/
17
18 #include "fatprocs.h"
19
20 //
21 // The Bug check file id for this module
22 //
23
24 #define BugCheckFileId (FAT_BUG_CHECK_FSCTRL)
25
26 //
27 // The local debug trace level
28 //
29
30 #define Dbg (DEBUG_TRACE_FSCTRL)
31
32 //
33 // Local procedure prototypes
34 //
35
36 _Requires_lock_held_(_Global_critical_region_)
37 NTSTATUS
38 FatMountVolume (
39 IN PIRP_CONTEXT IrpContext,
40 IN PDEVICE_OBJECT TargetDeviceObject,
41 IN PVPB Vpb,
42 IN PDEVICE_OBJECT FsDeviceObject
43 );
44
45 _Requires_lock_held_(_Global_critical_region_)
46 NTSTATUS
47 FatVerifyVolume (
48 IN PIRP_CONTEXT IrpContext,
49 IN PIRP Irp
50 );
51
52 BOOLEAN
53 FatIsMediaWriteProtected (
54 IN PIRP_CONTEXT IrpContext,
55 IN PDEVICE_OBJECT TargetDeviceObject
56 );
57
58 _Requires_lock_held_(_Global_critical_region_)
59 NTSTATUS
60 FatUserFsCtrl (
61 IN PIRP_CONTEXT IrpContext,
62 IN PIRP Irp
63 );
64
65 _Requires_lock_held_(_Global_critical_region_)
66 NTSTATUS
67 FatOplockRequest (
68 _In_ PIRP_CONTEXT IrpContext,
69 _In_ PIRP Irp
70 );
71
72 _Requires_lock_held_(_Global_critical_region_)
73 NTSTATUS
74 FatLockVolume (
75 IN PIRP_CONTEXT IrpContext,
76 IN PIRP Irp
77 );
78
79 NTSTATUS
80 FatUnlockVolume (
81 IN PIRP_CONTEXT IrpContext,
82 IN PIRP Irp
83 );
84
85 _Requires_lock_held_(_Global_critical_region_)
86 NTSTATUS
87 FatDismountVolume (
88 IN PIRP_CONTEXT IrpContext,
89 IN PIRP Irp
90 );
91
92 _Requires_lock_held_(_Global_critical_region_)
93 NTSTATUS
94 FatDirtyVolume (
95 IN PIRP_CONTEXT IrpContext,
96 IN PIRP Irp
97 );
98
99 NTSTATUS
100 FatIsVolumeDirty (
101 IN PIRP_CONTEXT IrpContext,
102 IN PIRP Irp
103 );
104
105 NTSTATUS
106 FatIsVolumeMounted (
107 IN PIRP_CONTEXT IrpContext,
108 IN PIRP Irp
109 );
110
111 NTSTATUS
112 FatIsPathnameValid (
113 IN PIRP_CONTEXT IrpContext,
114 IN PIRP Irp
115 );
116
117 _Requires_lock_held_(_Global_critical_region_)
118 NTSTATUS
119 FatInvalidateVolumes (
120 IN PIRP Irp
121 );
122
123 _Requires_lock_held_(_Global_critical_region_)
124 VOID
125 FatScanForDismountedVcb (
126 IN PIRP_CONTEXT IrpContext
127 );
128
129 BOOLEAN
130 FatPerformVerifyDiskRead (
131 IN PIRP_CONTEXT IrpContext,
132 IN PVCB Vcb,
133 IN PVOID Buffer,
134 IN LBO Lbo,
135 IN ULONG NumberOfBytesToRead,
136 IN BOOLEAN ReturnOnError
137 );
138
139 _Requires_lock_held_(_Global_critical_region_)
140 NTSTATUS
141 FatQueryRetrievalPointers (
142 IN PIRP_CONTEXT IrpContext,
143 IN PIRP Irp
144 );
145
146 NTSTATUS
147 FatQueryBpb (
148 IN PIRP_CONTEXT IrpContext,
149 IN PIRP Irp
150 );
151
152 NTSTATUS
153 FatGetStatistics (
154 IN PIRP_CONTEXT IrpContext,
155 IN PIRP Irp
156 );
157
158 NTSTATUS
159 FatAllowExtendedDasdIo (
160 IN PIRP_CONTEXT IrpContext,
161 IN PIRP Irp
162 );
163
164 _Requires_lock_held_(_Global_critical_region_)
165 NTSTATUS
166 FatGetBootAreaInfo (
167 _In_ PIRP_CONTEXT IrpContext,
168 _In_ PIRP Irp
169 );
170
171 _Requires_lock_held_(_Global_critical_region_)
172 NTSTATUS
173 FatGetRetrievalPointerBase (
174 _In_ PIRP_CONTEXT IrpContext,
175 _In_ PIRP Irp
176 );
177
178 _Requires_lock_held_(_Global_critical_region_)
179 NTSTATUS
180 FatMarkHandle(
181 _In_ PIRP_CONTEXT IrpContext,
182 _In_ PIRP Irp
183 );
184
185 NTSTATUS
186 FatSetZeroOnDeallocate (
187 __in PIRP_CONTEXT IrpContext,
188 __in PIRP Irp
189 );
190
191 _Requires_lock_held_(_Global_critical_region_)
192 NTSTATUS
193 FatSetPurgeFailureMode (
194 _In_ PIRP_CONTEXT IrpContext,
195 _In_ PIRP Irp
196 );
197
198 //
199 // Local support routine prototypes
200 //
201
202 _Requires_lock_held_(_Global_critical_region_)
203 NTSTATUS
204 FatGetVolumeBitmap (
205 IN PIRP_CONTEXT IrpContext,
206 IN PIRP Irp
207 );
208
209 _Requires_lock_held_(_Global_critical_region_)
210 NTSTATUS
211 FatGetRetrievalPointers (
212 IN PIRP_CONTEXT IrpContext,
213 IN PIRP Irp
214 );
215
216 _Requires_lock_held_(_Global_critical_region_)
217 VOID
218 FatMoveFileNeedsWriteThrough (
219 _In_ PIRP_CONTEXT IrpContext,
220 _In_ PFCB FcbOrDcb,
221 _In_ ULONG OldWriteThroughFlags
222 );
223
224 _Requires_lock_held_(_Global_critical_region_)
225 NTSTATUS
226 FatMoveFile (
227 IN PIRP_CONTEXT IrpContext,
228 IN PIRP Irp
229 );
230
231 VOID
232 FatComputeMoveFileSplicePoints (
233 PIRP_CONTEXT IrpContext,
234 PFCB FcbOrDcb,
235 ULONG FileOffset,
236 ULONG TargetCluster,
237 ULONG BytesToReallocate,
238 PULONG FirstSpliceSourceCluster,
239 PULONG FirstSpliceTargetCluster,
240 PULONG SecondSpliceSourceCluster,
241 PULONG SecondSpliceTargetCluster,
242 PLARGE_MCB SourceMcb
243 );
244
245 _Requires_lock_held_(_Global_critical_region_)
246 VOID
247 FatComputeMoveFileParameter (
248 IN PIRP_CONTEXT IrpContext,
249 IN PFCB FcbOrDcb,
250 IN ULONG BufferSize,
251 IN ULONG FileOffset,
252 IN OUT PULONG ByteCount,
253 OUT PULONG BytesToReallocate,
254 OUT PULONG BytesToWrite,
255 OUT PLARGE_INTEGER SourceLbo
256 );
257
258 NTSTATUS
259 FatSearchBufferForLabel(
260 IN PIRP_CONTEXT IrpContext,
261 IN PVPB Vpb,
262 IN PVOID Buffer,
263 IN ULONG Size,
264 OUT PBOOLEAN LabelFound
265 );
266
267 VOID
268 FatVerifyLookupFatEntry (
269 IN PIRP_CONTEXT IrpContext,
270 IN PVCB Vcb,
271 IN ULONG FatIndex,
272 IN OUT PULONG FatEntry
273 );
274
275 #ifdef ALLOC_PRAGMA
276 #pragma alloc_text(PAGE, FatAddMcbEntry)
277 #pragma alloc_text(PAGE, FatAllowExtendedDasdIo)
278 #pragma alloc_text(PAGE, FatCommonFileSystemControl)
279 #pragma alloc_text(PAGE, FatComputeMoveFileParameter)
280 #pragma alloc_text(PAGE, FatComputeMoveFileSplicePoints)
281 #pragma alloc_text(PAGE, FatDirtyVolume)
282 #pragma alloc_text(PAGE, FatFsdFileSystemControl)
283 #pragma alloc_text(PAGE, FatGetRetrievalPointerBase)
284 #pragma alloc_text(PAGE, FatGetBootAreaInfo)
285 #pragma alloc_text(PAGE, FatMarkHandle)
286 #pragma alloc_text(PAGE, FatGetRetrievalPointers)
287 #pragma alloc_text(PAGE, FatGetStatistics)
288 #pragma alloc_text(PAGE, FatGetVolumeBitmap)
289 #pragma alloc_text(PAGE, FatIsMediaWriteProtected)
290 #pragma alloc_text(PAGE, FatIsPathnameValid)
291 #pragma alloc_text(PAGE, FatIsVolumeDirty)
292 #pragma alloc_text(PAGE, FatIsVolumeMounted)
293 #pragma alloc_text(PAGE, FatLockVolume)
294 #pragma alloc_text(PAGE, FatLookupLastMcbEntry)
295 #pragma alloc_text(PAGE, FatGetNextMcbEntry)
296 #pragma alloc_text(PAGE, FatMountVolume)
297 #pragma alloc_text(PAGE, FatMoveFileNeedsWriteThrough)
298 #pragma alloc_text(PAGE, FatMoveFile)
299 #pragma alloc_text(PAGE, FatOplockRequest)
300 #pragma alloc_text(PAGE, FatPerformVerifyDiskRead)
301 #pragma alloc_text(PAGE, FatQueryBpb)
302 #pragma alloc_text(PAGE, FatQueryRetrievalPointers)
303 #pragma alloc_text(PAGE, FatRemoveMcbEntry)
304 #pragma alloc_text(PAGE, FatScanForDismountedVcb)
305 #pragma alloc_text(PAGE, FatFlushAndCleanVolume)
306 #pragma alloc_text(PAGE, FatSearchBufferForLabel)
307 #pragma alloc_text(PAGE, FatSetPurgeFailureMode)
308 #pragma alloc_text(PAGE, FatUnlockVolume)
309 #pragma alloc_text(PAGE, FatUserFsCtrl)
310 #pragma alloc_text(PAGE, FatVerifyLookupFatEntry)
311 #pragma alloc_text(PAGE, FatVerifyVolume)
312 #endif
313
314 #if DBG
315
316 BOOLEAN FatMoveFileDebug = 0;
317
318 #endif
319
320 //
321 // These wrappers go around the MCB package; we scale the LBO's passed
322 // in (which can be bigger than 32 bits on fat32) by the volume's sector
323 // size.
324 //
325 // Note we now use the real large mcb package. This means these shims
326 // now also convert the -1 unused LBN number to the 0 of the original
327 // mcb package.
328 //
329
330 #define MCB_SCALE_LOG2 (Vcb->AllocationSupport.LogOfBytesPerSector)
331 #define MCB_SCALE (1 << MCB_SCALE_LOG2)
332 #define MCB_SCALE_MODULO (MCB_SCALE - 1)
333
334 BOOLEAN
FatNonSparseMcb(_In_ PVCB Vcb,_In_ PLARGE_MCB Mcb,_Out_ PVBO Vbo,_Out_ PLONGLONG ByteCount)335 FatNonSparseMcb(
336 _In_ PVCB Vcb,
337 _In_ PLARGE_MCB Mcb,
338 _Out_ PVBO Vbo,
339 _Out_ PLONGLONG ByteCount
340 )
341 {
342 LBO Lbo;
343 ULONG Index = 0;
344 LONGLONG llVbo = 0;
345
346 UNREFERENCED_PARAMETER(Vcb);
347
348 while (FsRtlGetNextLargeMcbEntry(Mcb, Index, &llVbo, &Lbo, ByteCount)) {
349 *Vbo = (VBO)llVbo;
350 if (((ULONG)Lbo) == -1) {
351 return FALSE;
352 }
353
354 Index++;
355 }
356
357 *Vbo = (VBO)llVbo;
358
359 return TRUE;
360 }
361
362
363 BOOLEAN
FatAddMcbEntry(IN PVCB Vcb,IN PLARGE_MCB Mcb,IN VBO Vbo,IN LBO Lbo,IN ULONG SectorCount)364 FatAddMcbEntry (
365 IN PVCB Vcb,
366 IN PLARGE_MCB Mcb,
367 IN VBO Vbo,
368 IN LBO Lbo,
369 IN ULONG SectorCount
370 )
371
372 {
373 BOOLEAN Result;
374 #if DBG
375 VBO SparseVbo;
376 LONGLONG SparseByteCount;
377 #endif
378
379 PAGED_CODE();
380
381 if (SectorCount) {
382
383 //
384 // Round up sectors, but be careful as SectorCount approaches 4Gb.
385 // Note that for x>0, (x+m-1)/m = ((x-1)/m)+(m/m) = ((x-1)/m)+1
386 //
387
388 SectorCount--;
389 SectorCount >>= MCB_SCALE_LOG2;
390 SectorCount++;
391 }
392
393 Vbo >>= MCB_SCALE_LOG2;
394 Lbo >>= MCB_SCALE_LOG2;
395
396 NT_ASSERT( SectorCount != 0 );
397
398 if (Mcb != &Vcb->DirtyFatMcb) {
399 NT_ASSERT( FatNonSparseMcb( Vcb, Mcb, &SparseVbo, &SparseByteCount ) ||
400 ((SparseVbo == Vbo) && (SparseByteCount == SectorCount )) );
401 }
402
403 Result = FsRtlAddLargeMcbEntry( Mcb,
404 ((LONGLONG) Vbo),
405 ((LONGLONG) Lbo),
406 ((LONGLONG) SectorCount) );
407
408 if (Mcb != &Vcb->DirtyFatMcb) {
409 NT_ASSERT( FatNonSparseMcb( Vcb, Mcb, &SparseVbo, &SparseByteCount ) ||
410 ((SparseVbo == Vbo) && (SparseByteCount == SectorCount )) );
411 }
412
413 return Result;
414 }
415
416
417 BOOLEAN
FatLookupMcbEntry(IN PVCB Vcb,IN PLARGE_MCB Mcb,IN VBO Vbo,OUT PLBO Lbo,OUT PULONG ByteCount OPTIONAL,OUT PULONG Index OPTIONAL)418 FatLookupMcbEntry (
419 IN PVCB Vcb,
420 IN PLARGE_MCB Mcb,
421 IN VBO Vbo,
422 OUT PLBO Lbo,
423 OUT PULONG ByteCount OPTIONAL,
424 OUT PULONG Index OPTIONAL
425 )
426 {
427 BOOLEAN Results;
428 LONGLONG LiLbo;
429 LONGLONG LiSectorCount;
430 ULONG Remainder;
431
432 LiLbo = 0;
433 LiSectorCount = 0;
434
435 Remainder = Vbo & MCB_SCALE_MODULO;
436
437 Results = FsRtlLookupLargeMcbEntry( Mcb,
438 (Vbo >> MCB_SCALE_LOG2),
439 &LiLbo,
440 ARGUMENT_PRESENT(ByteCount) ? &LiSectorCount : NULL,
441 NULL,
442 NULL,
443 Index );
444
445 if ((ULONG) LiLbo != -1) {
446
447 *Lbo = (((LBO) LiLbo) << MCB_SCALE_LOG2);
448
449 if (Results) {
450
451 *Lbo += Remainder;
452 }
453
454 } else {
455
456 *Lbo = 0;
457 }
458
459 if (ARGUMENT_PRESENT(ByteCount)) {
460
461 *ByteCount = (ULONG) LiSectorCount;
462
463 if (*ByteCount) {
464
465 *ByteCount <<= MCB_SCALE_LOG2;
466
467 //
468 // If ByteCount overflows, then this is likely the case of
469 // a file of max-supported size (4GiB - 1), allocated in a
470 // single continuous run.
471 //
472
473 if (*ByteCount == 0) {
474
475 *ByteCount = 0xFFFFFFFF;
476 }
477
478 if (Results) {
479
480 *ByteCount -= Remainder;
481 }
482 }
483
484 }
485
486 return Results;
487 }
488
489 //
490 // NOTE: Vbo/Lbn undefined if MCB is empty & return code false.
491 //
492
493 BOOLEAN
FatLookupLastMcbEntry(IN PVCB Vcb,IN PLARGE_MCB Mcb,OUT PVBO Vbo,OUT PLBO Lbo,OUT PULONG Index)494 FatLookupLastMcbEntry (
495 IN PVCB Vcb,
496 IN PLARGE_MCB Mcb,
497 OUT PVBO Vbo,
498 OUT PLBO Lbo,
499 OUT PULONG Index
500 )
501
502 {
503 BOOLEAN Results;
504 LONGLONG LiVbo;
505 LONGLONG LiLbo;
506 ULONG LocalIndex;
507
508 PAGED_CODE();
509
510 LiVbo = LiLbo = 0;
511 LocalIndex = 0;
512
513 Results = FsRtlLookupLastLargeMcbEntryAndIndex( Mcb,
514 &LiVbo,
515 &LiLbo,
516 &LocalIndex );
517
518 *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2;
519
520 if (((ULONG) LiLbo) != -1) {
521
522 *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2;
523
524 *Lbo += (MCB_SCALE - 1);
525 *Vbo += (MCB_SCALE - 1);
526
527 } else {
528
529 *Lbo = 0;
530 }
531
532 if (Index) {
533 *Index = LocalIndex;
534 }
535
536 return Results;
537 }
538
539
540 BOOLEAN
FatGetNextMcbEntry(IN PVCB Vcb,IN PLARGE_MCB Mcb,IN ULONG RunIndex,OUT PVBO Vbo,OUT PLBO Lbo,OUT PULONG ByteCount)541 FatGetNextMcbEntry (
542 IN PVCB Vcb,
543 IN PLARGE_MCB Mcb,
544 IN ULONG RunIndex,
545 OUT PVBO Vbo,
546 OUT PLBO Lbo,
547 OUT PULONG ByteCount
548 )
549
550 {
551 BOOLEAN Results;
552 LONGLONG LiVbo;
553 LONGLONG LiLbo;
554 LONGLONG LiSectorCount;
555
556 PAGED_CODE();
557
558 LiVbo = LiLbo = 0;
559
560 Results = FsRtlGetNextLargeMcbEntry( Mcb,
561 RunIndex,
562 &LiVbo,
563 &LiLbo,
564 &LiSectorCount );
565
566 if (Results) {
567
568 *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2;
569
570 if (((ULONG) LiLbo) != -1) {
571
572 *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2;
573
574 } else {
575
576 *Lbo = 0;
577 }
578
579 *ByteCount = ((ULONG) LiSectorCount) << MCB_SCALE_LOG2;
580
581 if ((*ByteCount == 0) && (LiSectorCount != 0)) {
582
583 //
584 // If 'ByteCount' overflows, then this is likely a file of
585 // max supported size (2^32 - 1) in one contiguous run.
586 //
587
588 NT_ASSERT( RunIndex == 0 );
589
590 *ByteCount = 0xFFFFFFFF;
591 }
592 }
593
594 return Results;
595 }
596
597
598 VOID
FatRemoveMcbEntry(IN PVCB Vcb,IN PLARGE_MCB Mcb,IN VBO Vbo,IN ULONG SectorCount)599 FatRemoveMcbEntry (
600 IN PVCB Vcb,
601 IN PLARGE_MCB Mcb,
602 IN VBO Vbo,
603 IN ULONG SectorCount
604 )
605 {
606 PAGED_CODE();
607
608 if ((SectorCount) && (SectorCount != 0xFFFFFFFF)) {
609
610 SectorCount--;
611 SectorCount >>= MCB_SCALE_LOG2;
612 SectorCount++;
613 }
614
615 Vbo >>= MCB_SCALE_LOG2;
616
617 #if DBG
618 _SEH2_TRY {
619 #endif
620
621 FsRtlRemoveLargeMcbEntry( Mcb,
622 (LONGLONG) Vbo,
623 (LONGLONG) SectorCount);
624
625 #if DBG
626 } _SEH2_EXCEPT(FatBugCheckExceptionFilter( _SEH2_GetExceptionInformation() )) {
627
628 NOTHING;
629 } _SEH2_END;
630 #endif
631
632 }
633
634
635 _Function_class_(IRP_MJ_FILE_SYSTEM_CONTROL)
_Function_class_(DRIVER_DISPATCH)636 _Function_class_(DRIVER_DISPATCH)
637 NTSTATUS
638 NTAPI
639 FatFsdFileSystemControl (
640 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
641 _Inout_ PIRP Irp
642 )
643
644 /*++
645
646 Routine Description:
647
648 This routine implements the FSD part of FileSystem control operations
649
650 Arguments:
651
652 VolumeDeviceObject - Supplies the volume device object where the
653 file exists
654
655 Irp - Supplies the Irp being processed
656
657 Return Value:
658
659 NTSTATUS - The FSD status for the IRP
660
661 --*/
662
663 {
664 BOOLEAN Wait;
665 NTSTATUS Status;
666 PIRP_CONTEXT IrpContext = NULL;
667
668 BOOLEAN TopLevel;
669
670 PAGED_CODE();
671 UNREFERENCED_PARAMETER( VolumeDeviceObject );
672
673 DebugTrace(+1, Dbg,"FatFsdFileSystemControl\n", 0);
674
675 //
676 // Call the common FileSystem Control routine, with blocking allowed if
677 // synchronous. This opeation needs to special case the mount
678 // and verify suboperations because we know they are allowed to block.
679 // We identify these suboperations by looking at the file object field
680 // and seeing if its null.
681 //
682
683 if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) {
684
685 Wait = TRUE;
686
687 } else {
688
689 Wait = CanFsdWait( Irp );
690 }
691
692 FsRtlEnterFileSystem();
693
694 TopLevel = FatIsIrpTopLevel( Irp );
695
696 _SEH2_TRY {
697
698 PIO_STACK_LOCATION IrpSp;
699
700 IrpSp = IoGetCurrentIrpStackLocation( Irp );
701
702 //
703 // We need to made a special check here for the InvalidateVolumes
704 // FSCTL as that comes in with a FileSystem device object instead
705 // of a volume device object.
706 //
707
708 if (FatDeviceIsFatFsdo( IrpSp->DeviceObject) &&
709 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
710 (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
711 (IrpSp->Parameters.FileSystemControl.FsControlCode ==
712 FSCTL_INVALIDATE_VOLUMES)) {
713
714 Status = FatInvalidateVolumes( Irp );
715
716 } else {
717
718 IrpContext = FatCreateIrpContext( Irp, Wait );
719
720 Status = FatCommonFileSystemControl( IrpContext, Irp );
721 }
722
723 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
724
725 //
726 // We had some trouble trying to perform the requested
727 // operation, so we'll abort the I/O request with
728 // the error status that we get back from the
729 // execption code
730 //
731
732 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
733 } _SEH2_END;
734
735 if (TopLevel) { IoSetTopLevelIrp( NULL ); }
736
737 FsRtlExitFileSystem();
738
739 //
740 // And return to our caller
741 //
742
743 DebugTrace(-1, Dbg, "FatFsdFileSystemControl -> %08lx\n", Status);
744
745 return Status;
746 }
747
748
_Requires_lock_held_(_Global_critical_region_)749 _Requires_lock_held_(_Global_critical_region_)
750 NTSTATUS
751 FatCommonFileSystemControl (
752 IN PIRP_CONTEXT IrpContext,
753 IN PIRP Irp
754 )
755
756 /*++
757
758 Routine Description:
759
760 This is the common routine for doing FileSystem control operations called
761 by both the fsd and fsp threads
762
763 Arguments:
764
765 Irp - Supplies the Irp to process
766
767 Return Value:
768
769 NTSTATUS - The return status for the operation
770
771 --*/
772
773 {
774 NTSTATUS Status;
775 PIO_STACK_LOCATION IrpSp;
776
777 PAGED_CODE();
778
779 //
780 // Get a pointer to the current Irp stack location
781 //
782
783 IrpSp = IoGetCurrentIrpStackLocation( Irp );
784
785 DebugTrace(+1, Dbg,"FatCommonFileSystemControl\n", 0);
786 DebugTrace( 0, Dbg,"Irp = %p\n", Irp);
787 DebugTrace( 0, Dbg,"MinorFunction = %08lx\n", IrpSp->MinorFunction);
788
789 //
790 // We know this is a file system control so we'll case on the
791 // minor function, and call a internal worker routine to complete
792 // the irp.
793 //
794
795 switch (IrpSp->MinorFunction) {
796
797 case IRP_MN_USER_FS_REQUEST:
798
799 Status = FatUserFsCtrl( IrpContext, Irp );
800 break;
801
802 case IRP_MN_MOUNT_VOLUME:
803
804 Status = FatMountVolume( IrpContext,
805 IrpSp->Parameters.MountVolume.DeviceObject,
806 IrpSp->Parameters.MountVolume.Vpb,
807 IrpSp->DeviceObject );
808
809 //
810 // Complete the request.
811 //
812 // We do this here because FatMountVolume can be called recursively,
813 // but the Irp is only to be completed once.
814 //
815 // NOTE: I don't think this is true anymore (danlo 3/15/1999). Probably
816 // an artifact of the old doublespace attempt.
817 //
818
819 FatCompleteRequest( IrpContext, Irp, Status );
820 break;
821
822 case IRP_MN_VERIFY_VOLUME:
823
824 Status = FatVerifyVolume( IrpContext, Irp );
825 break;
826
827 default:
828
829 DebugTrace( 0, Dbg, "Invalid FS Control Minor Function %08lx\n", IrpSp->MinorFunction);
830
831 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
832 Status = STATUS_INVALID_DEVICE_REQUEST;
833 break;
834 }
835
836 DebugTrace(-1, Dbg, "FatCommonFileSystemControl -> %08lx\n", Status);
837
838 return Status;
839 }
840
841
842 //
843 // Local Support Routine
844 //
845
_Requires_lock_held_(_Global_critical_region_)846 _Requires_lock_held_(_Global_critical_region_)
847 NTSTATUS
848 FatMountVolume (
849 IN PIRP_CONTEXT IrpContext,
850 IN PDEVICE_OBJECT TargetDeviceObject,
851 IN PVPB Vpb,
852 IN PDEVICE_OBJECT FsDeviceObject
853 )
854
855 /*++
856
857 Routine Description:
858
859 This routine performs the mount volume operation. It is responsible for
860 either completing of enqueuing the input Irp.
861
862 Its job is to verify that the volume denoted in the IRP is a Fat volume,
863 and create the VCB and root DCB structures. The algorithm it uses is
864 essentially as follows:
865
866 1. Create a new Vcb Structure, and initialize it enough to do cached
867 volume file I/O.
868
869 2. Read the disk and check if it is a Fat volume.
870
871 3. If it is not a Fat volume then free the cached volume file, delete
872 the VCB, and complete the IRP with STATUS_UNRECOGNIZED_VOLUME
873
874 4. Check if the volume was previously mounted and if it was then do a
875 remount operation. This involves reinitializing the cached volume
876 file, checking the dirty bit, resetting up the allocation support,
877 deleting the VCB, hooking in the old VCB, and completing the IRP.
878
879 5. Otherwise create a root DCB, create Fsp threads as necessary, and
880 complete the IRP.
881
882 Arguments:
883
884 TargetDeviceObject - This is where we send all of our requests.
885
886 Vpb - This gives us additional information needed to complete the mount.
887
888 Return Value:
889
890 NTSTATUS - The return status for the operation
891
892 --*/
893
894 {
895 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
896 NTSTATUS Status = STATUS_INVALID_PARAMETER;
897
898 PBCB BootBcb;
899 PPACKED_BOOT_SECTOR BootSector = NULL;
900
901 PBCB DirentBcb;
902 PDIRENT Dirent;
903 ULONG ByteOffset;
904
905 BOOLEAN MountNewVolume = FALSE;
906 BOOLEAN WeClearedVerifyRequiredBit = FALSE;
907 BOOLEAN DoARemount = FALSE;
908
909 PVCB OldVcb = NULL;
910 PVPB OldVpb = NULL;
911
912 PDEVICE_OBJECT RealDevice = NULL;
913 PVOLUME_DEVICE_OBJECT VolDo = NULL;
914 PVCB Vcb = NULL;
915 PFILE_OBJECT RootDirectoryFile = NULL;
916
917 PLIST_ENTRY Links;
918
919 IO_STATUS_BLOCK Iosb = {0};
920 ULONG ChangeCount = 0;
921
922 DISK_GEOMETRY Geometry;
923
924 PARTITION_INFORMATION_EX PartitionInformation;
925 NTSTATUS StatusPartInfo;
926
927 #if (NTDDI_VERSION > NTDDI_WIN8)
928 GUID VolumeGuid = {0};
929 #endif
930
931
932 PAGED_CODE();
933
934 DebugTrace(+1, Dbg, "FatMountVolume\n", 0);
935 DebugTrace( 0, Dbg, "TargetDeviceObject = %p\n", TargetDeviceObject);
936 DebugTrace( 0, Dbg, "Vpb = %p\n", Vpb);
937
938 NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
939 NT_ASSERT( FatDeviceIsFatFsdo( FsDeviceObject));
940
941 //
942 // Only send down IOCTL_DISK_CHECK_VERIFY if it is removable media.
943 //
944
945 if (FlagOn(TargetDeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
946
947 //
948 // Verify that there is a disk here and pick up the change count.
949 //
950
951 Status = FatPerformDevIoCtrl( IrpContext,
952 IOCTL_DISK_CHECK_VERIFY,
953 TargetDeviceObject,
954 NULL,
955 0,
956 &ChangeCount,
957 sizeof(ULONG),
958 FALSE,
959 TRUE,
960 &Iosb );
961
962 if (!NT_SUCCESS( Status )) {
963
964 //
965 // If we will allow a raw mount then avoid sending the popup.
966 //
967 // Only send this on "true" disk devices to handle the accidental
968 // legacy of FAT. No other FS will throw a harderror on empty
969 // drives.
970 //
971 // Cmd should really handle this per 9x.
972 //
973
974 if (!FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT ) &&
975 Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK) {
976
977 FatNormalizeAndRaiseStatus( IrpContext, Status );
978 }
979
980 return Status;
981 }
982
983 }
984
985 if (Iosb.Information != sizeof(ULONG)) {
986
987 //
988 // Be safe about the count in case the driver didn't fill it in
989 //
990
991 ChangeCount = 0;
992 }
993
994 //
995 // If this is a CD class device, then check to see if there is a
996 // 'data track' or not. This is to avoid issuing paging reads which will
997 // fail later in the mount process (e.g. CD-DA or blank CD media)
998 //
999
1000 if ((TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) &&
1001 !FatScanForDataTrack( IrpContext, TargetDeviceObject)) {
1002
1003 return STATUS_UNRECOGNIZED_VOLUME;
1004 }
1005
1006 //
1007 // Ping the volume with a partition query and pick up the partition
1008 // type. We'll check this later to avoid some scurrilous volumes.
1009 //
1010
1011 StatusPartInfo = FatPerformDevIoCtrl( IrpContext,
1012 IOCTL_DISK_GET_PARTITION_INFO_EX,
1013 TargetDeviceObject,
1014 NULL,
1015 0,
1016 &PartitionInformation,
1017 sizeof(PARTITION_INFORMATION_EX),
1018 FALSE,
1019 TRUE,
1020 &Iosb );
1021
1022 //
1023 // Make sure we can wait.
1024 //
1025
1026 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1027
1028 //
1029 // Do a quick check to see if there any Vcb's which can be removed.
1030 //
1031
1032 FatScanForDismountedVcb( IrpContext );
1033
1034 //
1035 // Initialize the Bcbs and our final state so that the termination
1036 // handlers will know what to free or unpin
1037 //
1038
1039 BootBcb = NULL;
1040 DirentBcb = NULL;
1041
1042 Vcb = NULL;
1043 VolDo = NULL;
1044 MountNewVolume = FALSE;
1045
1046 _SEH2_TRY {
1047
1048 //
1049 // Synchronize with FatCheckForDismount(), which modifies the vpb.
1050 //
1051
1052 #ifdef _MSC_VER
1053 #pragma prefast( push )
1054 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
1055 #pragma prefast( disable: 28193, "this will always wait" )
1056 #endif
1057
1058 (VOID)FatAcquireExclusiveGlobal( IrpContext );
1059
1060 #ifdef _MSC_VER
1061 #pragma prefast( pop )
1062 #endif
1063
1064 //
1065 // Create a new volume device object. This will have the Vcb
1066 // hanging off of its end, and set its alignment requirement
1067 // from the device we talk to.
1068 //
1069
1070 if (!NT_SUCCESS(Status = IoCreateDevice( FatData.DriverObject,
1071 sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
1072 NULL,
1073 FILE_DEVICE_DISK_FILE_SYSTEM,
1074 0,
1075 FALSE,
1076 (PDEVICE_OBJECT *)&VolDo))) {
1077
1078 try_return( Status );
1079 }
1080
1081 //
1082 // Our alignment requirement is the larger of the processor alignment requirement
1083 // already in the volume device object and that in the TargetDeviceObject
1084 //
1085
1086 if (TargetDeviceObject->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
1087
1088 VolDo->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
1089 }
1090
1091 //
1092 // Initialize the overflow queue for the volume
1093 //
1094
1095 VolDo->OverflowQueueCount = 0;
1096 InitializeListHead( &VolDo->OverflowQueue );
1097
1098 VolDo->PostedRequestCount = 0;
1099 KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
1100
1101 //
1102 // We must initialize the stack size in our device object before
1103 // the following reads, because the I/O system has not done it yet.
1104 // This must be done before we clear the device initializing flag
1105 // otherwise a filter could attach and copy the wrong stack size into
1106 // it's device object.
1107 //
1108
1109 VolDo->DeviceObject.StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
1110
1111 //
1112 // We must also set the sector size correctly in our device object
1113 // before clearing the device initializing flag.
1114 //
1115
1116 Status = FatPerformDevIoCtrl( IrpContext,
1117 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1118 TargetDeviceObject,
1119 NULL,
1120 0,
1121 &Geometry,
1122 sizeof( DISK_GEOMETRY ),
1123 FALSE,
1124 TRUE,
1125 NULL );
1126
1127 if (!NT_SUCCESS( Status )) {
1128
1129 try_return( Status );
1130 }
1131
1132 #ifdef _MSC_VER
1133 #pragma prefast( suppress: 28175, "this is a filesystem driver, touching SectorSize is fine" )
1134 #endif
1135 VolDo->DeviceObject.SectorSize = (USHORT)Geometry.BytesPerSector;
1136
1137 //
1138 // Indicate that this device object is now completely initialized
1139 //
1140
1141 ClearFlag(VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING);
1142
1143 //
1144 // Now Before we can initialize the Vcb we need to set up the device
1145 // object field in the Vpb to point to our new volume device object.
1146 // This is needed when we create the virtual volume file's file object
1147 // in initialize vcb.
1148 //
1149
1150 Vpb->DeviceObject = (PDEVICE_OBJECT)VolDo;
1151
1152 //
1153 // If the real device needs verification, temporarily clear the
1154 // field.
1155 //
1156
1157 RealDevice = Vpb->RealDevice;
1158
1159 if ( FlagOn(RealDevice->Flags, DO_VERIFY_VOLUME) ) {
1160
1161 ClearFlag(RealDevice->Flags, DO_VERIFY_VOLUME);
1162
1163 WeClearedVerifyRequiredBit = TRUE;
1164 }
1165
1166 //
1167 // Initialize the new vcb
1168 //
1169
1170 FatInitializeVcb( IrpContext,
1171 &VolDo->Vcb,
1172 TargetDeviceObject,
1173 Vpb,
1174 FsDeviceObject);
1175 //
1176 // Get a reference to the Vcb hanging off the end of the device object
1177 //
1178
1179 Vcb = &VolDo->Vcb;
1180
1181 //
1182 // Read in the boot sector, and have the read be the minumum size
1183 // needed. We know we can wait.
1184 //
1185
1186 //
1187 // We need to commute errors on CD so that CDFS will get its crack. Audio
1188 // and even data media may not be universally readable on sector zero.
1189 //
1190
1191 _SEH2_TRY {
1192
1193 FatReadVolumeFile( IrpContext,
1194 Vcb,
1195 0, // Starting Byte
1196 sizeof(PACKED_BOOT_SECTOR),
1197 &BootBcb,
1198 (PVOID *)&BootSector );
1199
1200 } _SEH2_EXCEPT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
1201 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
1202
1203 NOTHING;
1204 } _SEH2_END;
1205
1206 //
1207 // Call a routine to check the boot sector to see if it is fat
1208 //
1209
1210 if (BootBcb == NULL || !FatIsBootSectorFat( BootSector)) {
1211
1212 DebugTrace(0, Dbg, "Not a Fat Volume\n", 0);
1213
1214 //
1215 // Complete the request and return to our caller
1216 //
1217
1218 try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
1219 }
1220
1221 #if (NTDDI_VERSION > NTDDI_WIN8)
1222 //
1223 // Initialize the volume guid.
1224 //
1225
1226 if (NT_SUCCESS( IoVolumeDeviceToGuid( Vcb->TargetDeviceObject, &VolumeGuid ))) {
1227
1228
1229 //
1230 // Stash a copy away in the VCB.
1231 //
1232
1233 RtlCopyMemory( &Vcb->VolumeGuid, &VolumeGuid, sizeof(GUID));
1234
1235 }
1236
1237
1238 //
1239 // Stash away a copy of the volume GUID path in our VCB.
1240 //
1241
1242 if (Vcb->VolumeGuidPath.Buffer) {
1243 ExFreePool( Vcb->VolumeGuidPath.Buffer );
1244 Vcb->VolumeGuidPath.Buffer = NULL;
1245 Vcb->VolumeGuidPath.Length = Vcb->VolumeGuidPath.MaximumLength = 0;
1246 }
1247
1248 IoVolumeDeviceToGuidPath( Vcb->TargetDeviceObject, &Vcb->VolumeGuidPath );
1249 #endif
1250
1251 //
1252 // Unpack the BPB. We used to do some sanity checking of the FATs at
1253 // this point, but authoring errors on third-party devices prevent
1254 // us from continuing to safeguard ourselves. We can only hope the
1255 // boot sector check is good enough.
1256 //
1257 // (read: digital cameras)
1258 //
1259 // Win9x does the same.
1260 //
1261
1262 FatUnpackBios( &Vcb->Bpb, &BootSector->PackedBpb );
1263
1264 //
1265 // Check if we have an OS/2 Boot Manager partition and treat it as an
1266 // unknown file system. We'll check the partition type in from the
1267 // partition table and we ensure that it has less than 0x80 sectors,
1268 // which is just a heuristic that will capture all real OS/2 BM partitions
1269 // and avoid the chance we'll discover partitions which erroneously
1270 // (but to this point, harmlessly) put down the OS/2 BM type.
1271 //
1272 // Note that this is only conceivable on good old MBR media.
1273 //
1274 // The OS/2 Boot Manager boot format mimics a FAT16 partition in sector
1275 // zero but does is not a real FAT16 file system. For example, the boot
1276 // sector indicates it has 2 FATs but only really has one, with the boot
1277 // manager code overlaying the second FAT. If we then set clean bits in
1278 // FAT[0] we'll corrupt that code.
1279 //
1280
1281 if (NT_SUCCESS( StatusPartInfo ) &&
1282 (PartitionInformation.PartitionStyle == PARTITION_STYLE_MBR &&
1283 PartitionInformation.Mbr.PartitionType == PARTITION_OS2BOOTMGR) &&
1284 (Vcb->Bpb.Sectors != 0 &&
1285 Vcb->Bpb.Sectors < 0x80)) {
1286
1287 DebugTrace( 0, Dbg, "OS/2 Boot Manager volume detected, volume not mounted. \n", 0 );
1288
1289 //
1290 // Complete the request and return to our caller
1291 //
1292
1293 try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
1294 }
1295
1296 //
1297 // Verify that the sector size recorded in the Bpb matches what the
1298 // device currently reports it's sector size to be.
1299 //
1300
1301 if ( !NT_SUCCESS( Status) ||
1302 (Geometry.BytesPerSector != Vcb->Bpb.BytesPerSector)) {
1303
1304 try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
1305 }
1306
1307 //
1308 // This is a fat volume, so extract the bpb, serial number. The
1309 // label we'll get later after we've created the root dcb.
1310 //
1311 // Note that the way data caching is done, we set neither the
1312 // direct I/O or Buffered I/O bit in the device object flags.
1313 //
1314
1315 if (Vcb->Bpb.Sectors != 0) { Vcb->Bpb.LargeSectors = 0; }
1316
1317 if (IsBpbFat32(&BootSector->PackedBpb)) {
1318
1319 CopyUchar4( &Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id );
1320
1321 } else {
1322
1323 CopyUchar4( &Vpb->SerialNumber, BootSector->Id );
1324
1325 //
1326 // Allocate space for the stashed boot sector chunk. This only has meaning on
1327 // FAT12/16 volumes since this only is kept for the FSCTL_QUERY_FAT_BPB and it and
1328 // its users are a bit wierd, thinking that a BPB exists wholly in the first 0x24
1329 // bytes.
1330 //
1331
1332 Vcb->First0x24BytesOfBootSector =
1333 FsRtlAllocatePoolWithTag( PagedPool,
1334 0x24,
1335 TAG_STASHED_BPB );
1336
1337 //
1338 // Stash a copy of the first 0x24 bytes
1339 //
1340
1341 RtlCopyMemory( Vcb->First0x24BytesOfBootSector,
1342 BootSector,
1343 0x24 );
1344 }
1345
1346 //
1347 // Now unpin the boot sector, so when we set up allocation eveything
1348 // works.
1349 //
1350
1351 FatUnpinBcb( IrpContext, BootBcb );
1352
1353 //
1354 // Compute a number of fields for Vcb.AllocationSupport
1355 //
1356
1357 FatSetupAllocationSupport( IrpContext, Vcb );
1358
1359 //
1360 // Sanity check the FsInfo information for FAT32 volumes. Silently deal
1361 // with messed up information by effectively disabling FsInfo updates.
1362 //
1363
1364 if (FatIsFat32( Vcb )) {
1365
1366 if (Vcb->Bpb.FsInfoSector >= Vcb->Bpb.ReservedSectors) {
1367
1368 Vcb->Bpb.FsInfoSector = 0;
1369 }
1370 }
1371
1372
1373 //
1374 // Create a root Dcb so we can read in the volume label. If this is FAT32, we can
1375 // discover corruption in the FAT chain.
1376 //
1377 // NOTE: this exception handler presumes that this is the only spot where we can
1378 // discover corruption in the mount process. If this ever changes, this handler
1379 // MUST be expanded. The reason we have this guy here is because we have to rip
1380 // the structures down now (in the finally below) and can't wait for the outer
1381 // exception handling to do it for us, at which point everything will have vanished.
1382 //
1383
1384 _SEH2_TRY {
1385
1386 FatCreateRootDcb( IrpContext, Vcb );
1387
1388 } _SEH2_EXCEPT (_SEH2_GetExceptionCode() == STATUS_FILE_CORRUPT_ERROR ? EXCEPTION_EXECUTE_HANDLER :
1389 EXCEPTION_CONTINUE_SEARCH) {
1390
1391 //
1392 // The volume needs to be dirtied, do it now. Note that at this point we have built
1393 // enough of the Vcb to pull this off.
1394 //
1395
1396 FatCheckDirtyBit( IrpContext,
1397 Vcb );
1398
1399 //
1400 // Set the dirty bit if it is not set already
1401 //
1402
1403 if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
1404
1405 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNT_IN_PROGRESS );
1406 FatMarkVolume( IrpContext, Vcb, VolumeDirty );
1407 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNT_IN_PROGRESS );
1408 }
1409
1410 //
1411 // Now keep bailing out ...
1412 //
1413
1414 FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1415 } _SEH2_END;
1416
1417 FatLocateVolumeLabel( IrpContext,
1418 Vcb,
1419 &Dirent,
1420 &DirentBcb,
1421 (PVBO)&ByteOffset );
1422
1423 if (Dirent != NULL) {
1424
1425 UCHAR OemBuffer[11];
1426 OEM_STRING OemString;
1427 UNICODE_STRING UnicodeString;
1428
1429 OemString.Buffer = (PCHAR)&OemBuffer[0];
1430 OemString.MaximumLength = 11;
1431
1432 RtlCopyMemory( OemString.Buffer, Dirent->FileName, 11 );
1433
1434 //
1435 // Translate the first character from 0x5 to 0xe5.
1436 //
1437
1438 if (OemString.Buffer[0] == FAT_DIRENT_REALLY_0E5) {
1439
1440 OemString.Buffer[0] = 0xe5;
1441 }
1442
1443 //
1444 // Compute the length of the volume name
1445 //
1446
1447 for ( OemString.Length = 11;
1448 OemString.Length > 0;
1449 OemString.Length -= 1) {
1450
1451 if ( (OemString.Buffer[OemString.Length-1] != 0x00) &&
1452 (OemString.Buffer[OemString.Length-1] != 0x20) ) { break; }
1453 }
1454
1455 UnicodeString.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
1456 UnicodeString.Buffer = &Vcb->Vpb->VolumeLabel[0];
1457
1458 Status = RtlOemStringToCountedUnicodeString( &UnicodeString,
1459 &OemString,
1460 FALSE );
1461
1462 if ( !NT_SUCCESS( Status ) ) {
1463
1464 try_return( Status );
1465 }
1466
1467 Vpb->VolumeLabelLength = UnicodeString.Length;
1468
1469 } else {
1470
1471 Vpb->VolumeLabelLength = 0;
1472 }
1473
1474 //
1475 // Use the change count we noted initially *before* doing any work.
1476 // If something came along in the midst of this operation, we'll
1477 // verify and discover the problem.
1478 //
1479
1480 Vcb->ChangeCount = ChangeCount;
1481
1482 //
1483 // Now scan the list of previously mounted volumes and compare
1484 // serial numbers and volume labels off not currently mounted
1485 // volumes to see if we have a match.
1486 //
1487
1488 for (Links = FatData.VcbQueue.Flink;
1489 Links != &FatData.VcbQueue;
1490 Links = Links->Flink) {
1491
1492 OldVcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
1493 OldVpb = OldVcb->Vpb;
1494
1495 //
1496 // Skip over ourselves since we're already in the VcbQueue
1497 //
1498
1499 if (OldVpb == Vpb) { continue; }
1500
1501 //
1502 // Check for a match:
1503 //
1504 // Serial Number, VolumeLabel and Bpb must all be the same.
1505 // Also the volume must have failed a verify before (ie.
1506 // VolumeNotMounted), and it must be in the same physical
1507 // drive than it was mounted in before.
1508 //
1509
1510 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
1511 (OldVcb->VcbCondition == VcbNotMounted) &&
1512 (OldVpb->RealDevice == RealDevice) &&
1513 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
1514 (RtlEqualMemory(&OldVpb->VolumeLabel[0],
1515 &Vpb->VolumeLabel[0],
1516 Vpb->VolumeLabelLength)) &&
1517 (RtlEqualMemory(&OldVcb->Bpb,
1518 &Vcb->Bpb,
1519 IsBpbFat32(&Vcb->Bpb) ?
1520 sizeof(BIOS_PARAMETER_BLOCK) :
1521 FIELD_OFFSET(BIOS_PARAMETER_BLOCK,
1522 LargeSectorsPerFat) ))) {
1523
1524 DoARemount = TRUE;
1525
1526 break;
1527 }
1528 }
1529
1530 if ( DoARemount ) {
1531
1532 PVPB *IrpVpb;
1533
1534 DebugTrace(0, Dbg, "Doing a remount\n", 0);
1535 DebugTrace(0, Dbg, "Vcb = %p\n", Vcb);
1536 DebugTrace(0, Dbg, "Vpb = %p\n", Vpb);
1537 DebugTrace(0, Dbg, "OldVcb = %p\n", OldVcb);
1538 DebugTrace(0, Dbg, "OldVpb = %p\n", OldVpb);
1539
1540 //
1541 // Swap target device objects between the VCBs. That way
1542 // the old VCB will start using the new target device object,
1543 // and the new VCB will be torn down and deference the old
1544 // target device object.
1545 //
1546
1547 Vcb->TargetDeviceObject = OldVcb->TargetDeviceObject;
1548 OldVcb->TargetDeviceObject = TargetDeviceObject;
1549
1550 //
1551 // This is a remount, so link the old vpb in place
1552 // of the new vpb.
1553 //
1554
1555 NT_ASSERT( !FlagOn( OldVcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED ) );
1556
1557 FatSetVcbCondition( OldVcb, VcbGood);
1558 OldVpb->RealDevice = Vpb->RealDevice;
1559 ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
1560
1561 #ifdef _MSC_VER
1562 #pragma prefast( suppress: 28175, "touching Vpb is ok for a filesystem" )
1563 #endif
1564 OldVpb->RealDevice->Vpb = OldVpb;
1565
1566 //
1567 // Use the new changecount.
1568 //
1569
1570 OldVcb->ChangeCount = Vcb->ChangeCount;
1571
1572 //
1573 // If the new VPB is the VPB referenced in the original Irp, set
1574 // that reference back to the old VPB.
1575 //
1576
1577 IrpVpb = &IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->Parameters.MountVolume.Vpb;
1578
1579 if (*IrpVpb == Vpb) {
1580
1581 *IrpVpb = OldVpb;
1582 }
1583
1584 //
1585 // We do not want to touch this VPB again. It will get cleaned up when
1586 // the new VCB is cleaned up.
1587 //
1588
1589 NT_ASSERT( Vcb->Vpb == Vpb );
1590
1591 Vpb = NULL;
1592 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED );
1593 FatSetVcbCondition( Vcb, VcbBad );
1594
1595 //
1596 // Reinitialize the volume file cache and allocation support.
1597 //
1598
1599 {
1600 CC_FILE_SIZES FileSizes;
1601
1602 FileSizes.AllocationSize.QuadPart =
1603 FileSizes.FileSize.QuadPart = ( 0x40000 + 0x1000 );
1604 FileSizes.ValidDataLength = FatMaxLarge;
1605
1606 DebugTrace(0, Dbg, "Truncate and reinitialize the volume file\n", 0);
1607
1608 FatInitializeCacheMap( OldVcb->VirtualVolumeFile,
1609 &FileSizes,
1610 TRUE,
1611 &FatData.CacheManagerNoOpCallbacks,
1612 Vcb );
1613
1614 //
1615 // Redo the allocation support
1616 //
1617
1618 FatSetupAllocationSupport( IrpContext, OldVcb );
1619
1620 //
1621 // Get the state of the dirty bit.
1622 //
1623
1624 FatCheckDirtyBit( IrpContext, OldVcb );
1625
1626 //
1627 // Check for write protected media.
1628 //
1629
1630 if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
1631
1632 SetFlag( OldVcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
1633
1634 } else {
1635
1636 ClearFlag( OldVcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
1637 }
1638 }
1639
1640 //
1641 // Complete the request and return to our caller
1642 //
1643
1644 try_return( Status = STATUS_SUCCESS );
1645 }
1646
1647 DebugTrace(0, Dbg, "Mount a new volume\n", 0);
1648
1649 //
1650 // This is a new mount
1651 //
1652 // Create a blank ea data file fcb, just not for Fat32.
1653 //
1654
1655 if (!FatIsFat32(Vcb)) {
1656
1657 DIRENT TempDirent;
1658 PFCB EaFcb;
1659
1660 RtlZeroMemory( &TempDirent, sizeof(DIRENT) );
1661 RtlCopyMemory( &TempDirent.FileName[0], "EA DATA SF", 11 );
1662
1663 EaFcb = FatCreateFcb( IrpContext,
1664 Vcb,
1665 Vcb->RootDcb,
1666 0,
1667 0,
1668 &TempDirent,
1669 NULL,
1670 NULL,
1671 FALSE,
1672 TRUE );
1673
1674 //
1675 // Deny anybody who trys to open the file.
1676 //
1677
1678 SetFlag( EaFcb->FcbState, FCB_STATE_SYSTEM_FILE );
1679
1680 Vcb->EaFcb = EaFcb;
1681 }
1682
1683 //
1684 // Get the state of the dirty bit.
1685 //
1686
1687 FatCheckDirtyBit( IrpContext, Vcb );
1688
1689
1690 //
1691 // Check for write protected media.
1692 //
1693
1694 if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
1695
1696 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
1697
1698 } else {
1699
1700 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
1701 }
1702
1703
1704 //
1705 // Lock volume in drive if we just mounted the boot drive.
1706 //
1707
1708 if (FlagOn(RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION)) {
1709
1710 SetFlag(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE);
1711
1712 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
1713
1714 FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
1715 }
1716 }
1717
1718
1719 //
1720 // Indicate to our termination handler that we have mounted
1721 // a new volume.
1722 //
1723
1724 MountNewVolume = TRUE;
1725
1726 //
1727 // Complete the request
1728 //
1729
1730 Status = STATUS_SUCCESS;
1731
1732 //
1733 // Ref the root dir stream object so we can send mount notification.
1734 //
1735
1736 RootDirectoryFile = Vcb->RootDcb->Specific.Dcb.DirectoryFile;
1737 ObReferenceObject( RootDirectoryFile );
1738
1739 //
1740 // Remove the extra reference to this target DO made on behalf of us
1741 // by the IO system. In the remount case, we permit regular Vcb
1742 // deletion to do this work.
1743 //
1744
1745 ObDereferenceObject( TargetDeviceObject );
1746
1747
1748 try_exit: NOTHING;
1749
1750 } _SEH2_FINALLY {
1751
1752 DebugUnwind( FatMountVolume );
1753
1754 FatUnpinBcb( IrpContext, BootBcb );
1755 FatUnpinBcb( IrpContext, DirentBcb );
1756
1757 //
1758 // Check if a volume was mounted. If not then we need to
1759 // mark the Vpb not mounted again.
1760 //
1761
1762 if ( !MountNewVolume ) {
1763
1764 if ( Vcb != NULL ) {
1765
1766 //
1767 // A VCB was created and initialized. We need to try to tear it down.
1768 //
1769
1770 FatCheckForDismount( IrpContext,
1771 Vcb,
1772 TRUE );
1773
1774 IrpContext->Vcb = NULL;
1775
1776 } else if (VolDo != NULL) {
1777
1778 //
1779 // The VCB was never initialized, so we need to delete the
1780 // device right here.
1781 //
1782
1783 IoDeleteDevice( &VolDo->DeviceObject );
1784 }
1785
1786 //
1787 // See if a remount failed.
1788 //
1789
1790 if (DoARemount && _SEH2_AbnormalTermination()) {
1791
1792 //
1793 // The remount failed. Try to tear down the old VCB as well.
1794 //
1795
1796 FatCheckForDismount( IrpContext,
1797 OldVcb,
1798 TRUE );
1799 }
1800 }
1801
1802 if ( WeClearedVerifyRequiredBit == TRUE ) {
1803
1804 SetFlag(RealDevice->Flags, DO_VERIFY_VOLUME);
1805 }
1806
1807 FatReleaseGlobal( IrpContext );
1808
1809 DebugTrace(-1, Dbg, "FatMountVolume -> %08lx\n", Status);
1810 } _SEH2_END;
1811
1812 //
1813 // Now send mount notification. Note that since this is outside of any
1814 // synchronization since the synchronous delivery of this may go to
1815 // folks that provoke re-entrance to the FS.
1816 //
1817
1818 if (RootDirectoryFile != NULL) {
1819
1820 #if (NTDDI_VERSION >= NTDDI_WIN8)
1821 if (FatDiskAccountingEnabled) {
1822
1823 CcSetAdditionalCacheAttributesEx( RootDirectoryFile, CC_ENABLE_DISK_IO_ACCOUNTING );
1824 }
1825 #endif
1826
1827 FsRtlNotifyVolumeEvent( RootDirectoryFile, FSRTL_VOLUME_MOUNT );
1828 ObDereferenceObject( RootDirectoryFile );
1829 }
1830
1831 return Status;
1832 }
1833
1834
1835 //
1836 // Local Support Routine
1837 //
1838
_Requires_lock_held_(_Global_critical_region_)1839 _Requires_lock_held_(_Global_critical_region_)
1840 NTSTATUS
1841 FatVerifyVolume (
1842 IN PIRP_CONTEXT IrpContext,
1843 IN PIRP Irp
1844 )
1845
1846 /*++
1847
1848 Routine Description:
1849
1850 This routine performs the verify volume operation by checking the volume
1851 label and serial number physically on the media with the the Vcb
1852 currently claiming to have the volume mounted. It is responsible for
1853 either completing or enqueuing the input Irp.
1854
1855 Regardless of whether the verify operation succeeds, the following
1856 operations are performed:
1857
1858 - Set Vcb->VirtualEaFile back to its initial state.
1859 - Purge all cached data (flushing first if verify succeeds)
1860 - Mark all Fcbs as needing verification
1861
1862 If the volumes verifies correctly we also must:
1863
1864 - Check the volume dirty bit.
1865 - Reinitialize the allocation support
1866 - Flush any dirty data
1867
1868 If the volume verify fails, it may never be mounted again. If it is
1869 mounted again, it will happen as a remount operation. In preparation
1870 for that, and to leave the volume in a state that can be "lazy deleted"
1871 the following operations are performed:
1872
1873 - Set the Vcb condition to VcbNotMounted
1874 - Uninitialize the volume file cachemap
1875 - Tear down the allocation support
1876
1877 In the case of an abnormal termination we haven't determined the state
1878 of the volume, so we set the Device Object as needing verification again.
1879
1880 Arguments:
1881
1882 Irp - Supplies the Irp to process
1883
1884 Return Value:
1885
1886 NTSTATUS - If the verify operation completes, it will return either
1887 STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. If an IO or
1888 other error is encountered, that status will be returned.
1889
1890 --*/
1891
1892 {
1893 NTSTATUS Status = STATUS_SUCCESS;
1894
1895 PIO_STACK_LOCATION IrpSp;
1896
1897 PDIRENT RootDirectory = NULL;
1898 PPACKED_BOOT_SECTOR BootSector = NULL;
1899
1900 BIOS_PARAMETER_BLOCK Bpb;
1901
1902 PVOLUME_DEVICE_OBJECT VolDo;
1903 PVCB Vcb;
1904 PVPB Vpb;
1905
1906 ULONG SectorSize;
1907 BOOLEAN ClearVerify = FALSE;
1908 BOOLEAN ReleaseEntireVolume = FALSE;
1909 BOOLEAN VerifyAlreadyDone = FALSE;
1910
1911 DISK_GEOMETRY DiskGeometry;
1912
1913 LBO RootDirectoryLbo;
1914 ULONG RootDirectorySize;
1915 BOOLEAN LabelFound;
1916
1917 ULONG ChangeCount = 0;
1918 IO_STATUS_BLOCK Iosb = {0};
1919
1920 PAGED_CODE();
1921
1922 //
1923 // Get the current Irp stack location
1924 //
1925
1926 IrpSp = IoGetCurrentIrpStackLocation( Irp );
1927
1928 DebugTrace(+1, Dbg, "FatVerifyVolume\n", 0);
1929 DebugTrace( 0, Dbg, "DeviceObject = %p\n", IrpSp->Parameters.VerifyVolume.DeviceObject);
1930 DebugTrace( 0, Dbg, "Vpb = %p\n", IrpSp->Parameters.VerifyVolume.Vpb);
1931
1932 //
1933 // Save some references to make our life a little easier. Note the Vcb for the purposes
1934 // of exception handling.
1935 //
1936
1937 VolDo = (PVOLUME_DEVICE_OBJECT)IrpSp->Parameters.VerifyVolume.DeviceObject;
1938
1939 Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
1940 IrpContext->Vcb = Vcb = &VolDo->Vcb;
1941
1942 //
1943 // If we cannot wait then enqueue the irp to the fsp and
1944 // return the status to our caller.
1945 //
1946
1947 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
1948
1949 DebugTrace(0, Dbg, "Cannot wait for verify.\n", 0);
1950
1951 Status = FatFsdPostRequest( IrpContext, Irp );
1952
1953 DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status );
1954 return Status;
1955 }
1956
1957 //
1958 // We are serialized at this point allowing only one thread to
1959 // actually perform the verify operation. Any others will just
1960 // wait and then no-op when checking if the volume still needs
1961 // verification.
1962 //
1963
1964 #ifdef _MSC_VER
1965 #pragma prefast( push )
1966 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
1967 #pragma prefast( disable: 28193, "this will always wait" )
1968 #endif
1969
1970 (VOID)FatAcquireExclusiveGlobal( IrpContext );
1971
1972 #ifdef _MSC_VER
1973 #pragma prefast( pop )
1974 #endif
1975
1976 (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
1977
1978 _SEH2_TRY {
1979
1980 BOOLEAN AllowRawMount = BooleanFlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT );
1981
1982 //
1983 // Mark ourselves as verifying this volume so that recursive I/Os
1984 // will be able to complete.
1985 //
1986
1987 NT_ASSERT( Vcb->VerifyThread == NULL );
1988 Vcb->VerifyThread = KeGetCurrentThread();
1989
1990 //
1991 // Check if the real device still needs to be verified. If it doesn't
1992 // then obviously someone beat us here and already did the work
1993 // so complete the verify irp with success. Otherwise reenable
1994 // the real device and get to work.
1995 //
1996
1997 if (!FlagOn(Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
1998
1999 DebugTrace(0, Dbg, "RealDevice has already been verified\n", 0);
2000
2001 VerifyAlreadyDone = TRUE;
2002 try_return( Status = STATUS_SUCCESS );
2003 }
2004
2005 //
2006 // Ping the volume with a partition query to make Jeff happy.
2007 //
2008
2009 {
2010 PARTITION_INFORMATION_EX PartitionInformation;
2011
2012 (VOID) FatPerformDevIoCtrl( IrpContext,
2013 IOCTL_DISK_GET_PARTITION_INFO_EX,
2014 Vcb->TargetDeviceObject,
2015 NULL,
2016 0,
2017 &PartitionInformation,
2018 sizeof(PARTITION_INFORMATION_EX),
2019 FALSE,
2020 TRUE,
2021 &Iosb );
2022 }
2023
2024 //
2025 // Only send down IOCTL_DISK_CHECK_VERIFY if it is removable media.
2026 //
2027
2028 if (FlagOn(Vcb->TargetDeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
2029
2030 //
2031 // Verify that there is a disk here and pick up the change count.
2032 //
2033
2034 Status = FatPerformDevIoCtrl( IrpContext,
2035 IOCTL_DISK_CHECK_VERIFY,
2036 Vcb->TargetDeviceObject,
2037 NULL,
2038 0,
2039 &ChangeCount,
2040 sizeof(ULONG),
2041 FALSE,
2042 TRUE,
2043 &Iosb );
2044
2045 if (!NT_SUCCESS( Status )) {
2046
2047 //
2048 // If we will allow a raw mount then return WRONG_VOLUME to
2049 // allow the volume to be mounted by raw.
2050 //
2051
2052 if (AllowRawMount) {
2053
2054 try_return( Status = STATUS_WRONG_VOLUME );
2055 }
2056
2057 FatNormalizeAndRaiseStatus( IrpContext, Status );
2058 }
2059
2060 }
2061
2062 if (Iosb.Information != sizeof(ULONG)) {
2063
2064 //
2065 // Be safe about the count in case the driver didn't fill it in
2066 //
2067
2068 ChangeCount = 0;
2069 }
2070
2071 //
2072 // Whatever happens we will have verified this volume at this change
2073 // count, so record that fact.
2074 //
2075
2076 Vcb->ChangeCount = ChangeCount;
2077
2078 //
2079 // If this is a CD class device, then check to see if there is a
2080 // 'data track' or not. This is to avoid issuing paging reads which will
2081 // fail later in the mount process (e.g. CD-DA or blank CD media)
2082 //
2083
2084 if ((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) &&
2085 !FatScanForDataTrack( IrpContext, Vcb->TargetDeviceObject)) {
2086
2087 try_return( Status = STATUS_WRONG_VOLUME);
2088 }
2089
2090 //
2091 // Some devices can change sector sizes on the fly. Obviously, it
2092 // isn't the same volume if that happens.
2093 //
2094
2095 Status = FatPerformDevIoCtrl( IrpContext,
2096 IOCTL_DISK_GET_DRIVE_GEOMETRY,
2097 Vcb->TargetDeviceObject,
2098 NULL,
2099 0,
2100 &DiskGeometry,
2101 sizeof( DISK_GEOMETRY ),
2102 FALSE,
2103 TRUE,
2104 NULL );
2105
2106 if (!NT_SUCCESS( Status )) {
2107
2108 //
2109 // If we will allow a raw mount then return WRONG_VOLUME to
2110 // allow the volume to be mounted by raw.
2111 //
2112
2113 if (AllowRawMount) {
2114
2115 try_return( Status = STATUS_WRONG_VOLUME );
2116 }
2117
2118 FatNormalizeAndRaiseStatus( IrpContext, Status );
2119 }
2120
2121 //
2122 // Read in the boot sector
2123 //
2124
2125 SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
2126
2127 if (SectorSize != DiskGeometry.BytesPerSector) {
2128
2129 try_return( Status = STATUS_WRONG_VOLUME );
2130 }
2131
2132 BootSector = FsRtlAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
2133 (ULONG) ROUND_TO_PAGES( SectorSize ),
2134 TAG_VERIFY_BOOTSECTOR);
2135
2136 //
2137 // If this verify is on behalf of a DASD open, allow a RAW mount.
2138 //
2139
2140 if (!FatPerformVerifyDiskRead( IrpContext,
2141 Vcb,
2142 BootSector,
2143 0,
2144 SectorSize,
2145 AllowRawMount )) {
2146
2147 try_return( Status = STATUS_WRONG_VOLUME );
2148 }
2149
2150 //
2151 // Call a routine to check the boot sector to see if it is fat.
2152 // If it is not fat then mark the vcb as not mounted tell our
2153 // caller its the wrong volume
2154 //
2155
2156 if (!FatIsBootSectorFat( BootSector )) {
2157
2158 DebugTrace(0, Dbg, "Not a Fat Volume\n", 0);
2159
2160 try_return( Status = STATUS_WRONG_VOLUME );
2161 }
2162
2163 //
2164 // This is a fat volume, so extract serial number and see if it is
2165 // ours.
2166 //
2167
2168 {
2169 ULONG SerialNumber;
2170
2171 if (IsBpbFat32(&BootSector->PackedBpb)) {
2172 CopyUchar4( &SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id );
2173 } else {
2174 CopyUchar4( &SerialNumber, BootSector->Id );
2175 }
2176
2177 if (SerialNumber != Vpb->SerialNumber) {
2178
2179 DebugTrace(0, Dbg, "Not our serial number\n", 0);
2180
2181 try_return( Status = STATUS_WRONG_VOLUME );
2182 }
2183 }
2184
2185 //
2186 // Make sure the Bpbs are not different. We have to zero out our
2187 // stack version of the Bpb since unpacking leaves holes.
2188 //
2189
2190 RtlZeroMemory( &Bpb, sizeof(BIOS_PARAMETER_BLOCK) );
2191
2192 FatUnpackBios( &Bpb, &BootSector->PackedBpb );
2193 if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; }
2194
2195 if ( !RtlEqualMemory( &Bpb,
2196 &Vcb->Bpb,
2197 IsBpbFat32(&Bpb) ?
2198 sizeof(BIOS_PARAMETER_BLOCK) :
2199 FIELD_OFFSET(BIOS_PARAMETER_BLOCK,
2200 LargeSectorsPerFat) )) {
2201
2202 DebugTrace(0, Dbg, "Bpb is different\n", 0);
2203
2204 try_return( Status = STATUS_WRONG_VOLUME );
2205 }
2206
2207 //
2208 // Check the volume label. We do this by trying to locate the
2209 // volume label, making two strings one for the saved volume label
2210 // and the other for the new volume label and then we compare the
2211 // two labels.
2212 //
2213
2214 if (FatRootDirectorySize(&Bpb) > 0) {
2215
2216 RootDirectorySize = FatRootDirectorySize(&Bpb);
2217
2218 } else {
2219
2220 RootDirectorySize = FatBytesPerCluster(&Bpb);
2221 }
2222
2223 RootDirectory = FsRtlAllocatePoolWithTag( NonPagedPoolNxCacheAligned,
2224 (ULONG) ROUND_TO_PAGES( RootDirectorySize ),
2225 TAG_VERIFY_ROOTDIR);
2226
2227 if (!IsBpbFat32(&BootSector->PackedBpb)) {
2228
2229 //
2230 // The Fat12/16 case is simple -- read the root directory in and
2231 // search it.
2232 //
2233
2234 RootDirectoryLbo = FatRootDirectoryLbo(&Bpb);
2235
2236 if (!FatPerformVerifyDiskRead( IrpContext,
2237 Vcb,
2238 RootDirectory,
2239 RootDirectoryLbo,
2240 RootDirectorySize,
2241 AllowRawMount )) {
2242
2243 try_return( Status = STATUS_WRONG_VOLUME );
2244 }
2245
2246 Status = FatSearchBufferForLabel(IrpContext, Vpb,
2247 RootDirectory, RootDirectorySize,
2248 &LabelFound);
2249
2250 if (!NT_SUCCESS(Status)) {
2251
2252 try_return( Status );
2253 }
2254
2255 if (!LabelFound && Vpb->VolumeLabelLength > 0) {
2256
2257 try_return( Status = STATUS_WRONG_VOLUME );
2258 }
2259
2260 } else {
2261
2262 ULONG RootDirectoryCluster;
2263
2264 RootDirectoryCluster = Bpb.RootDirFirstCluster;
2265
2266 while (RootDirectoryCluster != FAT_CLUSTER_LAST) {
2267
2268 RootDirectoryLbo = FatGetLboFromIndex(Vcb, RootDirectoryCluster);
2269
2270 if (!FatPerformVerifyDiskRead( IrpContext,
2271 Vcb,
2272 RootDirectory,
2273 RootDirectoryLbo,
2274 RootDirectorySize,
2275 AllowRawMount )) {
2276
2277 try_return( Status = STATUS_WRONG_VOLUME );
2278 }
2279
2280 Status = FatSearchBufferForLabel(IrpContext, Vpb,
2281 RootDirectory, RootDirectorySize,
2282 &LabelFound);
2283
2284 if (!NT_SUCCESS(Status)) {
2285
2286 try_return( Status );
2287 }
2288
2289 if (LabelFound) {
2290
2291 //
2292 // Found a matching label.
2293 //
2294
2295 break;
2296 }
2297
2298 //
2299 // Set ourselves up for the next loop iteration.
2300 //
2301
2302 FatVerifyLookupFatEntry( IrpContext, Vcb,
2303 RootDirectoryCluster,
2304 &RootDirectoryCluster );
2305
2306 switch (FatInterpretClusterType(Vcb, RootDirectoryCluster)) {
2307
2308 case FatClusterAvailable:
2309 case FatClusterReserved:
2310 case FatClusterBad:
2311
2312 //
2313 // Bail all the way out if we have a bad root.
2314 //
2315
2316 FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
2317 break;
2318
2319 default:
2320
2321 break;
2322 }
2323
2324 }
2325
2326 if (RootDirectoryCluster == FAT_CLUSTER_LAST &&
2327 Vpb->VolumeLabelLength > 0) {
2328
2329 //
2330 // Should have found a label, didn't find any.
2331 //
2332
2333 try_return( Status = STATUS_WRONG_VOLUME );
2334 }
2335 }
2336
2337
2338 try_exit: NOTHING;
2339
2340 //
2341 // Note that we have previously acquired the Vcb to serialize
2342 // the EA file stuff the marking all the Fcbs as NeedToBeVerified.
2343 //
2344 // Put the Ea file back in a initial state.
2345 //
2346
2347 FatCloseEaFile( IrpContext, Vcb, (BOOLEAN)(Status == STATUS_SUCCESS) );
2348
2349 //
2350 // Mark all Fcbs as needing verification, but only if we really have
2351 // to do it.
2352 //
2353
2354 if (!VerifyAlreadyDone) {
2355
2356 FatAcquireExclusiveVolume( IrpContext, Vcb );
2357 ReleaseEntireVolume = TRUE;
2358
2359 FatMarkFcbCondition( IrpContext, Vcb->RootDcb, FcbNeedsToBeVerified, TRUE );
2360 }
2361
2362 //
2363 // If the verify didn't succeed, get the volume ready for a
2364 // remount or eventual deletion.
2365 //
2366
2367 if (Vcb->VcbCondition == VcbNotMounted) {
2368
2369 //
2370 // If the volume was already in an unmounted state, just bail
2371 // and make sure we return STATUS_WRONG_VOLUME.
2372 //
2373
2374 Status = STATUS_WRONG_VOLUME;
2375
2376 } else if ( Status == STATUS_WRONG_VOLUME ) {
2377
2378 //
2379 // Grab everything so we can safely transition the volume state without
2380 // having a thread stumble into the torn-down allocation engine.
2381 //
2382
2383 if (!ReleaseEntireVolume) {
2384 FatAcquireExclusiveVolume( IrpContext, Vcb );
2385 ReleaseEntireVolume = TRUE;
2386 }
2387
2388 //
2389 // Get rid of any cached data, without flushing
2390 //
2391
2392 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush );
2393
2394 //
2395 // Uninitialize the volume file cache map. Note that we cannot
2396 // do a "FatSyncUninit" because of deadlock problems. However,
2397 // since this FileObject is referenced by us, and thus included
2398 // in the Vpb residual count, it is OK to do a normal CcUninit.
2399 //
2400
2401 CcUninitializeCacheMap( Vcb->VirtualVolumeFile,
2402 &FatLargeZero,
2403 NULL );
2404
2405 FatTearDownAllocationSupport( IrpContext, Vcb );
2406
2407 FatSetVcbCondition( Vcb, VcbNotMounted);
2408
2409 ClearVerify = TRUE;
2410
2411 } else if (!VerifyAlreadyDone) {
2412
2413 //
2414 // Grab everything so we can safely transition the volume state without
2415 // having a thread stumble into the torn-down allocation engine.
2416 //
2417
2418 if (!ReleaseEntireVolume) {
2419 FatAcquireExclusiveVolume( IrpContext, Vcb );
2420 ReleaseEntireVolume = TRUE;
2421 }
2422
2423 //
2424 // Get rid of any cached data, flushing first.
2425 //
2426 // Future work (and for bonus points, around the other flush points)
2427 // could address the possibility that the dirent filesize hasn't been
2428 // updated yet, causing us to fail the re-verification of a file in
2429 // DetermineAndMark. This is pretty subtle and very very uncommon.
2430 //
2431
2432 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
2433
2434 //
2435 // Flush and Purge the volume file.
2436 //
2437
2438 (VOID)FatFlushFat( IrpContext, Vcb );
2439 CcPurgeCacheSection( &Vcb->SectionObjectPointers, NULL, 0, FALSE );
2440
2441 //
2442 // Redo the allocation support with newly paged stuff.
2443 //
2444
2445 FatTearDownAllocationSupport( IrpContext, Vcb );
2446 FatSetupAllocationSupport( IrpContext, Vcb );
2447
2448 FatCheckDirtyBit( IrpContext, Vcb );
2449
2450 //
2451 // Check for write protected media.
2452 //
2453
2454 if (FatIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
2455
2456 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
2457
2458 } else {
2459
2460 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
2461 }
2462
2463 ClearVerify = TRUE;
2464 }
2465
2466 if (ClearVerify) {
2467
2468 //
2469 // Mark the device as no longer needing verification.
2470 //
2471
2472 ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
2473 }
2474
2475 } _SEH2_FINALLY {
2476
2477 DebugUnwind( FatVerifyVolume );
2478
2479 //
2480 // Free any buffer we may have allocated
2481 //
2482
2483 if ( BootSector != NULL ) { ExFreePool( BootSector ); }
2484 if ( RootDirectory != NULL ) { ExFreePool( RootDirectory ); }
2485
2486 //
2487 // Show that we are done with this volume.
2488 //
2489
2490 NT_ASSERT( Vcb->VerifyThread == KeGetCurrentThread() );
2491 Vcb->VerifyThread = NULL;
2492
2493 if (ReleaseEntireVolume) {
2494
2495 FatReleaseVolume( IrpContext, Vcb );
2496 }
2497
2498 FatReleaseVcb( IrpContext, Vcb );
2499 FatReleaseGlobal( IrpContext );
2500
2501 //
2502 // If this was not an abnormal termination, complete the irp.
2503 //
2504
2505 if (!_SEH2_AbnormalTermination()) {
2506
2507 FatCompleteRequest( IrpContext, Irp, Status );
2508 }
2509
2510 DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status);
2511 } _SEH2_END;
2512
2513 return Status;
2514 }
2515
2516
2517 //
2518 // Local Support Routine
2519 //
2520
2521 BOOLEAN
FatIsBootSectorFat(IN PPACKED_BOOT_SECTOR BootSector)2522 FatIsBootSectorFat (
2523 IN PPACKED_BOOT_SECTOR BootSector
2524 )
2525
2526 /*++
2527
2528 Routine Description:
2529
2530 This routine checks if the boot sector is for a fat file volume.
2531
2532 Arguments:
2533
2534 BootSector - Supplies the packed boot sector to check
2535
2536 Return Value:
2537
2538 BOOLEAN - TRUE if the volume is Fat and FALSE otherwise.
2539
2540 --*/
2541
2542 {
2543 BOOLEAN Result;
2544 BIOS_PARAMETER_BLOCK Bpb = {0};
2545
2546 DebugTrace(+1, Dbg, "FatIsBootSectorFat, BootSector = %p\n", BootSector);
2547
2548 //
2549 // The result is true unless we decide that it should be false
2550 //
2551
2552 Result = TRUE;
2553
2554 //
2555 // Unpack the bios and then test everything
2556 //
2557
2558 FatUnpackBios( &Bpb, &BootSector->PackedBpb );
2559 if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; }
2560
2561 if ((BootSector->Jump[0] != 0xe9) &&
2562 (BootSector->Jump[0] != 0xeb) &&
2563 (BootSector->Jump[0] != 0x49)) {
2564
2565 Result = FALSE;
2566
2567 //
2568 // Enforce some sanity on the sector size (easy check)
2569 //
2570
2571 } else if ((Bpb.BytesPerSector != 128) &&
2572 (Bpb.BytesPerSector != 256) &&
2573 (Bpb.BytesPerSector != 512) &&
2574 (Bpb.BytesPerSector != 1024) &&
2575 (Bpb.BytesPerSector != 2048) &&
2576 (Bpb.BytesPerSector != 4096)) {
2577
2578 Result = FALSE;
2579
2580 //
2581 // Likewise on the clustering.
2582 //
2583
2584 } else if ((Bpb.SectorsPerCluster != 1) &&
2585 (Bpb.SectorsPerCluster != 2) &&
2586 (Bpb.SectorsPerCluster != 4) &&
2587 (Bpb.SectorsPerCluster != 8) &&
2588 (Bpb.SectorsPerCluster != 16) &&
2589 (Bpb.SectorsPerCluster != 32) &&
2590 (Bpb.SectorsPerCluster != 64) &&
2591 (Bpb.SectorsPerCluster != 128)) {
2592
2593 Result = FALSE;
2594
2595 //
2596 // Likewise on the reserved sectors (must reflect at least the boot sector!)
2597 //
2598
2599 } else if (Bpb.ReservedSectors == 0) {
2600
2601 Result = FALSE;
2602
2603 //
2604 // No FATs? Wrong ...
2605 //
2606
2607 } else if (Bpb.Fats == 0) {
2608
2609 Result = FALSE;
2610
2611 //
2612 // Prior to DOS 3.2 might contains value in both of Sectors and
2613 // Sectors Large.
2614 //
2615
2616 } else if ((Bpb.Sectors == 0) && (Bpb.LargeSectors == 0)) {
2617
2618 Result = FALSE;
2619
2620 //
2621 // Check that FAT32 (SectorsPerFat == 0) claims some FAT space and
2622 // is of a version we recognize, currently Version 0.0.
2623 //
2624
2625 } else if (Bpb.SectorsPerFat == 0 && ( Bpb.LargeSectorsPerFat == 0 ||
2626 Bpb.FsVersion != 0 )) {
2627
2628 Result = FALSE;
2629
2630 } else if ((Bpb.Media != 0xf0) &&
2631 (Bpb.Media != 0xf8) &&
2632 (Bpb.Media != 0xf9) &&
2633 (Bpb.Media != 0xfb) &&
2634 (Bpb.Media != 0xfc) &&
2635 (Bpb.Media != 0xfd) &&
2636 (Bpb.Media != 0xfe) &&
2637 (Bpb.Media != 0xff) &&
2638 (!FatData.FujitsuFMR || ((Bpb.Media != 0x00) &&
2639 (Bpb.Media != 0x01) &&
2640 (Bpb.Media != 0xfa)))) {
2641
2642 Result = FALSE;
2643
2644 //
2645 // If this isn't FAT32, then there better be a claimed root directory
2646 // size here ...
2647 //
2648
2649 } else if (Bpb.SectorsPerFat != 0 && Bpb.RootEntries == 0) {
2650
2651 Result = FALSE;
2652
2653 //
2654 // If this is FAT32 (i.e., extended BPB), look for and refuse to mount
2655 // mirror-disabled volumes. If we did, we would need to only write to
2656 // the FAT# indicated in the ActiveFat field. The only user of this is
2657 // the FAT->FAT32 converter after the first pass of protected mode work
2658 // (booting into realmode) and NT should absolutely not be attempting
2659 // to mount such an in-transition volume.
2660 //
2661
2662 } else if (Bpb.SectorsPerFat == 0 && Bpb.MirrorDisabled) {
2663
2664 Result = FALSE;
2665 }
2666
2667 DebugTrace(-1, Dbg, "FatIsBootSectorFat -> %08lx\n", Result);
2668
2669 return Result;
2670 }
2671
2672
2673 //
2674 // Local Support Routine
2675 //
2676
2677 BOOLEAN
FatIsMediaWriteProtected(IN PIRP_CONTEXT IrpContext,IN PDEVICE_OBJECT TargetDeviceObject)2678 FatIsMediaWriteProtected (
2679 IN PIRP_CONTEXT IrpContext,
2680 IN PDEVICE_OBJECT TargetDeviceObject
2681 )
2682
2683 /*++
2684
2685 Routine Description:
2686
2687 This routine determines if the target media is write protected.
2688
2689 Arguments:
2690
2691 TargetDeviceObject - The target of the query
2692
2693 Return Value:
2694
2695 NTSTATUS - The return status for the operation
2696
2697 --*/
2698
2699 {
2700 PIRP Irp;
2701 KEVENT Event;
2702 NTSTATUS Status;
2703 IO_STATUS_BLOCK Iosb;
2704
2705 PAGED_CODE();
2706 UNREFERENCED_PARAMETER( IrpContext );
2707
2708 //
2709 // Query the partition table
2710 //
2711
2712 KeInitializeEvent( &Event, NotificationEvent, FALSE );
2713
2714 //
2715 // See if the media is write protected. On success or any kind
2716 // of error (possibly illegal device function), assume it is
2717 // writeable, and only complain if he tells us he is write protected.
2718 //
2719
2720 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
2721 TargetDeviceObject,
2722 NULL,
2723 0,
2724 NULL,
2725 0,
2726 FALSE,
2727 &Event,
2728 &Iosb );
2729
2730 //
2731 // Just return FALSE in the unlikely event we couldn't allocate an Irp.
2732 //
2733
2734 if ( Irp == NULL ) {
2735
2736 return FALSE;
2737 }
2738
2739 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
2740
2741 Status = IoCallDriver( TargetDeviceObject, Irp );
2742
2743 if ( Status == STATUS_PENDING ) {
2744
2745 (VOID) KeWaitForSingleObject( &Event,
2746 Executive,
2747 KernelMode,
2748 FALSE,
2749 (PLARGE_INTEGER)NULL );
2750
2751 Status = Iosb.Status;
2752 }
2753
2754 return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
2755 }
2756
2757
2758 //
2759 // Local Support Routine
2760 //
2761
_Requires_lock_held_(_Global_critical_region_)2762 _Requires_lock_held_(_Global_critical_region_)
2763 NTSTATUS
2764 FatUserFsCtrl (
2765 IN PIRP_CONTEXT IrpContext,
2766 IN PIRP Irp
2767 )
2768
2769 /*++
2770
2771 Routine Description:
2772
2773 This is the common routine for implementing the user's requests made
2774 through NtFsControlFile.
2775
2776 Arguments:
2777
2778 Irp - Supplies the Irp being processed
2779
2780 Return Value:
2781
2782 NTSTATUS - The return status for the operation
2783
2784 --*/
2785
2786 {
2787 NTSTATUS Status;
2788 ULONG FsControlCode;
2789
2790 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2791
2792 PAGED_CODE();
2793
2794 //
2795 // Save some references to make our life a little easier
2796 //
2797
2798 FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
2799
2800 DebugTrace(+1, Dbg,"FatUserFsCtrl...\n", 0);
2801 DebugTrace( 0, Dbg,"FsControlCode = %08lx\n", FsControlCode);
2802
2803 //
2804 // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode
2805 // of the caller was userspace and this is a METHOD_NEITHER, we have the choice
2806 // of realy buffering the request through so we can possibly post, or making the
2807 // request synchronous. Since the former was not done by design, do the latter.
2808 //
2809
2810 if (Irp->RequestorMode != KernelMode && (FsControlCode & 3) == METHOD_NEITHER) {
2811
2812 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2813 }
2814
2815 //
2816 // Case on the control code.
2817 //
2818
2819 switch ( FsControlCode ) {
2820
2821 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
2822 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
2823 case FSCTL_REQUEST_BATCH_OPLOCK:
2824 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
2825 case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
2826 case FSCTL_OPLOCK_BREAK_NOTIFY:
2827 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
2828 case FSCTL_REQUEST_FILTER_OPLOCK:
2829 #if (NTDDI_VERSION >= NTDDI_WIN7)
2830 case FSCTL_REQUEST_OPLOCK:
2831 #endif
2832 Status = FatOplockRequest( IrpContext, Irp );
2833 break;
2834
2835 case FSCTL_LOCK_VOLUME:
2836
2837 Status = FatLockVolume( IrpContext, Irp );
2838 break;
2839
2840 case FSCTL_UNLOCK_VOLUME:
2841
2842 Status = FatUnlockVolume( IrpContext, Irp );
2843 break;
2844
2845 case FSCTL_DISMOUNT_VOLUME:
2846
2847 Status = FatDismountVolume( IrpContext, Irp );
2848 break;
2849
2850 case FSCTL_MARK_VOLUME_DIRTY:
2851
2852 Status = FatDirtyVolume( IrpContext, Irp );
2853 break;
2854
2855 case FSCTL_IS_VOLUME_DIRTY:
2856
2857 Status = FatIsVolumeDirty( IrpContext, Irp );
2858 break;
2859
2860 case FSCTL_IS_VOLUME_MOUNTED:
2861
2862 Status = FatIsVolumeMounted( IrpContext, Irp );
2863 break;
2864
2865 case FSCTL_IS_PATHNAME_VALID:
2866 Status = FatIsPathnameValid( IrpContext, Irp );
2867 break;
2868
2869 case FSCTL_QUERY_RETRIEVAL_POINTERS:
2870 Status = FatQueryRetrievalPointers( IrpContext, Irp );
2871 break;
2872
2873 case FSCTL_QUERY_FAT_BPB:
2874 Status = FatQueryBpb( IrpContext, Irp );
2875 break;
2876
2877 case FSCTL_FILESYSTEM_GET_STATISTICS:
2878 Status = FatGetStatistics( IrpContext, Irp );
2879 break;
2880
2881 #if (NTDDI_VERSION >= NTDDI_WIN7)
2882 case FSCTL_GET_RETRIEVAL_POINTER_BASE:
2883 Status = FatGetRetrievalPointerBase( IrpContext, Irp );
2884 break;
2885
2886 case FSCTL_GET_BOOT_AREA_INFO:
2887 Status = FatGetBootAreaInfo( IrpContext, Irp );
2888 break;
2889 #endif
2890
2891 case FSCTL_GET_VOLUME_BITMAP:
2892 Status = FatGetVolumeBitmap( IrpContext, Irp );
2893 break;
2894
2895 case FSCTL_GET_RETRIEVAL_POINTERS:
2896 Status = FatGetRetrievalPointers( IrpContext, Irp );
2897 break;
2898
2899 case FSCTL_MOVE_FILE:
2900 Status = FatMoveFile( IrpContext, Irp );
2901 break;
2902
2903 case FSCTL_ALLOW_EXTENDED_DASD_IO:
2904 Status = FatAllowExtendedDasdIo( IrpContext, Irp );
2905 break;
2906
2907 case FSCTL_MARK_HANDLE:
2908 Status = FatMarkHandle( IrpContext, Irp );
2909 break;
2910
2911 #if (NTDDI_VERSION >= NTDDI_WIN8)
2912
2913 case FSCTL_SET_PURGE_FAILURE_MODE:
2914 Status = FatSetPurgeFailureMode( IrpContext, Irp );
2915 break;
2916
2917 #endif
2918
2919
2920 #if (NTDDI_VERSION >= NTDDI_WIN7)
2921 case FSCTL_SET_ZERO_ON_DEALLOCATION:
2922 Status = FatSetZeroOnDeallocate( IrpContext, Irp );
2923 break;
2924 #endif
2925
2926 default :
2927
2928 DebugTrace(0, Dbg, "Invalid control code -> %08lx\n", FsControlCode );
2929
2930 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
2931 Status = STATUS_INVALID_DEVICE_REQUEST;
2932 break;
2933 }
2934
2935 DebugTrace(-1, Dbg, "FatUserFsCtrl -> %08lx\n", Status );
2936 return Status;
2937 }
2938
2939
2940
2941 //
2942 // Local support routine
2943 //
2944
_Requires_lock_held_(_Global_critical_region_)2945 _Requires_lock_held_(_Global_critical_region_)
2946 NTSTATUS
2947 FatOplockRequest (
2948 _In_ PIRP_CONTEXT IrpContext,
2949 _In_ PIRP Irp
2950 )
2951
2952 /*++
2953
2954 Routine Description:
2955
2956 This is the common routine to handle oplock requests made via the
2957 NtFsControlFile call.
2958
2959 Arguments:
2960
2961 Irp - Supplies the Irp being processed
2962
2963 Return Value:
2964
2965 NTSTATUS - The return status for the operation
2966
2967 --*/
2968
2969 {
2970 NTSTATUS Status = STATUS_SUCCESS;
2971 ULONG FsControlCode;
2972 PFCB Fcb;
2973 PVCB Vcb;
2974 PCCB Ccb;
2975
2976 ULONG OplockCount = 0;
2977
2978 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
2979
2980 BOOLEAN AcquiredVcb = FALSE;
2981 BOOLEAN AcquiredFcb = FALSE;
2982
2983 #if (NTDDI_VERSION >= NTDDI_WIN7)
2984 PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL;
2985 ULONG InputBufferLength;
2986 ULONG OutputBufferLength;
2987 #endif
2988
2989 TYPE_OF_OPEN TypeOfOpen;
2990
2991 PAGED_CODE();
2992
2993 //
2994 // Save some references to make our life a little easier
2995 //
2996
2997 FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
2998
2999 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
3000
3001 DebugTrace(+1, Dbg, "FatOplockRequest...\n", 0);
3002 DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode);
3003
3004 //
3005 // We permit oplock requests on files and directories.
3006 //
3007
3008 if ((TypeOfOpen != UserFileOpen)
3009 #if (NTDDI_VERSION >= NTDDI_WIN8)
3010 &&
3011 (TypeOfOpen != UserDirectoryOpen)
3012 #endif
3013 ) {
3014
3015 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3016 DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
3017 return STATUS_INVALID_PARAMETER;
3018 }
3019
3020 #if (NTDDI_VERSION >= NTDDI_WIN7)
3021
3022 //
3023 // Get the input & output buffer lengths and pointers.
3024 //
3025
3026 if (FsControlCode == FSCTL_REQUEST_OPLOCK) {
3027
3028 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
3029 InputBuffer = (PREQUEST_OPLOCK_INPUT_BUFFER) Irp->AssociatedIrp.SystemBuffer;
3030
3031 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
3032
3033 //
3034 // Check for a minimum length on the input and ouput buffers.
3035 //
3036
3037 if ((InputBufferLength < sizeof( REQUEST_OPLOCK_INPUT_BUFFER )) ||
3038 (OutputBufferLength < sizeof( REQUEST_OPLOCK_OUTPUT_BUFFER ))) {
3039
3040 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
3041 DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_BUFFER_TOO_SMALL\n", 0);
3042 return STATUS_BUFFER_TOO_SMALL;
3043 }
3044 }
3045
3046 //
3047 // If the oplock request is on a directory it must be for a Read or Read-Handle
3048 // oplock only.
3049 //
3050
3051 if ((TypeOfOpen == UserDirectoryOpen) &&
3052 ((FsControlCode != FSCTL_REQUEST_OPLOCK) ||
3053 !FsRtlOplockIsSharedRequest( Irp ))) {
3054
3055 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3056 DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
3057 return STATUS_INVALID_PARAMETER;
3058 }
3059
3060 #endif
3061
3062 //
3063 // Make this a waitable Irpcontext so we don't fail to acquire
3064 // the resources.
3065 //
3066
3067 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
3068
3069 //
3070 // Use a try finally to free the Fcb/Vcb
3071 //
3072
3073 _SEH2_TRY {
3074
3075 //
3076 // We grab the Fcb exclusively for oplock requests, shared for oplock
3077 // break acknowledgement.
3078 //
3079
3080 if ((FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1) ||
3081 (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) ||
3082 (FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) ||
3083 (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2)
3084 #if (NTDDI_VERSION >= NTDDI_WIN7)
3085 ||
3086 ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_REQUEST ))
3087 #endif
3088 ) {
3089
3090 FatAcquireSharedVcb( IrpContext, Fcb->Vcb );
3091 AcquiredVcb = TRUE;
3092 FatAcquireExclusiveFcb( IrpContext, Fcb );
3093 AcquiredFcb = TRUE;
3094
3095 #if (NTDDI_VERSION >= NTDDI_WIN7)
3096 if (FsRtlOplockIsSharedRequest( Irp )) {
3097 #else
3098 if (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
3099 #endif
3100
3101 //
3102 // Byte-range locks are only valid on files.
3103 //
3104
3105 if (TypeOfOpen == UserFileOpen) {
3106
3107 //
3108 // Set OplockCount to nonzero if FsRtl denies access
3109 // based on current byte-range lock state.
3110 //
3111
3112 #if (NTDDI_VERSION >= NTDDI_WIN8)
3113 OplockCount = (ULONG) !FsRtlCheckLockForOplockRequest( &Fcb->Specific.Fcb.FileLock, &Fcb->Header.AllocationSize );
3114 #elif (NTDDI_VERSION >= NTDDI_WIN7)
3115 OplockCount = (ULONG) FsRtlAreThereCurrentOrInProgressFileLocks( &Fcb->Specific.Fcb.FileLock );
3116 #else
3117 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( &Fcb->Specific.Fcb.FileLock );
3118 #endif
3119
3120 }
3121
3122 } else {
3123
3124 OplockCount = Fcb->UncleanCount;
3125 }
3126
3127 } else if ((FsControlCode == FSCTL_OPLOCK_BREAK_ACKNOWLEDGE) ||
3128 (FsControlCode == FSCTL_OPBATCH_ACK_CLOSE_PENDING) ||
3129 (FsControlCode == FSCTL_OPLOCK_BREAK_NOTIFY) ||
3130 (FsControlCode == FSCTL_OPLOCK_BREAK_ACK_NO_2)
3131 #if (NTDDI_VERSION >= NTDDI_WIN7)
3132 ||
3133 ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_ACK ))
3134 #endif
3135 ) {
3136
3137 FatAcquireSharedFcb( IrpContext, Fcb );
3138 AcquiredFcb = TRUE;
3139 #if (NTDDI_VERSION >= NTDDI_WIN7)
3140 } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) {
3141
3142 //
3143 // The caller didn't provide either REQUEST_OPLOCK_INPUT_FLAG_REQUEST or
3144 // REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer.
3145 //
3146
3147 try_leave( Status = STATUS_INVALID_PARAMETER );
3148
3149 } else {
3150 #else
3151 } else {
3152 #endif
3153
3154 #ifdef _MSC_VER
3155 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
3156 #endif
3157 FatBugCheck( FsControlCode, 0, 0 );
3158 }
3159
3160 //
3161 // Fail batch, filter, and handle oplock requests if the file is marked
3162 // for delete.
3163 //
3164
3165 if (((FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) ||
3166 (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK)
3167 #if (NTDDI_VERSION >= NTDDI_WIN7)
3168 ||
3169 ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->RequestedOplockLevel, OPLOCK_LEVEL_CACHE_HANDLE ))
3170 #endif
3171 ) &&
3172 FlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE )) {
3173
3174 try_leave( Status = STATUS_DELETE_PENDING );
3175 }
3176
3177 //
3178 // Call the FsRtl routine to grant/acknowledge oplock.
3179 //
3180
3181 Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb),
3182 Irp,
3183 OplockCount );
3184
3185 //
3186 // Once we call FsRtlOplockFsctrl, we no longer own the IRP and we should not complete it.
3187 //
3188
3189 Irp = NULL;
3190
3191 //
3192 // Set the flag indicating if Fast I/O is possible
3193 //
3194
3195 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
3196
3197 } _SEH2_FINALLY {
3198
3199 DebugUnwind( FatOplockRequest );
3200
3201 //
3202 // Release all of our resources
3203 //
3204
3205 if (AcquiredVcb) {
3206
3207 FatReleaseVcb( IrpContext, Fcb->Vcb );
3208 }
3209
3210 if (AcquiredFcb) {
3211
3212 FatReleaseFcb( IrpContext, Fcb );
3213 }
3214
3215 DebugTrace(-1, Dbg, "FatOplockRequest -> %08lx\n", Status );
3216 } _SEH2_END;
3217
3218 FatCompleteRequest( IrpContext, Irp, Status );
3219
3220 return Status;
3221 }
3222
3223
3224 //
3225 // Local Support Routine
3226 //
3227
3228 _Requires_lock_held_(_Global_critical_region_)
3229 NTSTATUS
3230 FatLockVolume (
3231 IN PIRP_CONTEXT IrpContext,
3232 IN PIRP Irp
3233 )
3234
3235 /*++
3236
3237 Routine Description:
3238
3239 This routine performs the lock volume operation. It is responsible for
3240 either completing of enqueuing the input Irp.
3241
3242 Arguments:
3243
3244 Irp - Supplies the Irp to process
3245
3246 Return Value:
3247
3248 NTSTATUS - The return status for the operation
3249
3250 --*/
3251
3252 {
3253 NTSTATUS Status = STATUS_SUCCESS;
3254
3255 PIO_STACK_LOCATION IrpSp;
3256
3257 PVCB Vcb;
3258 PFCB Fcb;
3259 PCCB Ccb;
3260
3261 PAGED_CODE();
3262
3263 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3264
3265 DebugTrace(+1, Dbg, "FatLockVolume...\n", 0);
3266
3267 //
3268 // Decode the file object, the only type of opens we accept are
3269 // user volume opens.
3270 //
3271
3272 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
3273
3274 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3275
3276 DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3277 return STATUS_INVALID_PARAMETER;
3278 }
3279
3280 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3281
3282 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3283
3284 DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3285 return STATUS_INVALID_PARAMETER;
3286 }
3287
3288 //
3289 // Send our notification so that folks that like to hold handles on
3290 // volumes can get out of the way.
3291 //
3292
3293 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK );
3294
3295 //
3296 // Acquire exclusive access to the Vcb and enqueue the Irp if we
3297 // didn't get access.
3298 //
3299
3300 if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
3301
3302 DebugTrace( 0, Dbg, "Cannot acquire Vcb\n", 0);
3303
3304 Status = FatFsdPostRequest( IrpContext, Irp );
3305
3306 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status);
3307 return Status;
3308 }
3309
3310 _SEH2_TRY {
3311
3312 Status = FatLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
3313
3314 } _SEH2_FINALLY {
3315
3316 //
3317 // Since we drop and release the vcb while trying to punch the volume
3318 // down, it may be the case that we decide the operation should not
3319 // continue if the user raced a CloeseHandle() with us (and it finished
3320 // the cleanup) while we were waiting for our closes to finish.
3321 //
3322 // In this case, we will have been raised out of the acquire logic with
3323 // STATUS_FILE_CLOSED, and the volume will not be held.
3324 //
3325
3326 if (!_SEH2_AbnormalTermination() || ExIsResourceAcquiredExclusiveLite( &Vcb->Resource )) {
3327
3328 FatReleaseVcb( IrpContext, Vcb );
3329 }
3330
3331 if (!NT_SUCCESS( Status ) || _SEH2_AbnormalTermination()) {
3332
3333 //
3334 // The volume lock will be failing.
3335 //
3336
3337 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED );
3338 }
3339 } _SEH2_END;
3340
3341 FatCompleteRequest( IrpContext, Irp, Status );
3342
3343 DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", Status);
3344
3345 return Status;
3346 }
3347
3348
3349 //
3350 // Local Support Routine
3351 //
3352
3353 NTSTATUS
3354 FatUnlockVolume (
3355 IN PIRP_CONTEXT IrpContext,
3356 IN PIRP Irp
3357 )
3358
3359 /*++
3360
3361 Routine Description:
3362
3363 This routine performs the unlock volume operation. It is responsible for
3364 either completing of enqueuing the input Irp.
3365
3366 Arguments:
3367
3368 Irp - Supplies the Irp to process
3369
3370 Return Value:
3371
3372 NTSTATUS - The return status for the operation
3373
3374 --*/
3375
3376 {
3377 NTSTATUS Status;
3378
3379 PIO_STACK_LOCATION IrpSp;
3380
3381 PVCB Vcb;
3382 PFCB Fcb;
3383 PCCB Ccb;
3384
3385 PAGED_CODE();
3386
3387 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3388
3389 DebugTrace(+1, Dbg, "FatUnlockVolume...\n", 0);
3390
3391 //
3392 // Decode the file object, the only type of opens we accept are
3393 // user volume opens.
3394 //
3395
3396 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
3397
3398 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3399
3400 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3401 return STATUS_INVALID_PARAMETER;
3402 }
3403
3404 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3405
3406 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3407
3408 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3409 return STATUS_INVALID_PARAMETER;
3410 }
3411
3412 Status = FatUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
3413
3414 //
3415 // Send notification that the volume is avaliable.
3416 //
3417
3418 if (NT_SUCCESS( Status )) {
3419
3420 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK );
3421 }
3422
3423 FatCompleteRequest( IrpContext, Irp, Status );
3424
3425 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status);
3426
3427 return Status;
3428 }
3429
3430
3431 _Requires_lock_held_(_Global_critical_region_)
3432 NTSTATUS
3433 FatLockVolumeInternal (
3434 IN PIRP_CONTEXT IrpContext,
3435 IN PVCB Vcb,
3436 IN PFILE_OBJECT FileObject OPTIONAL
3437 )
3438
3439 /*++
3440
3441 Routine Description:
3442
3443 This routine performs the actual lock volume operation. It will be called
3444 by anyone wishing to try to protect the volume for a long duration. PNP
3445 operations are such a user.
3446
3447 The volume must be held exclusive by the caller.
3448
3449 Arguments:
3450
3451 Vcb - The volume being locked.
3452
3453 FileObject - File corresponding to the handle locking the volume. If this
3454 is not specified, a system lock is assumed.
3455
3456 Return Value:
3457
3458 NTSTATUS - The return status for the operation
3459
3460 --*/
3461
3462 {
3463 NTSTATUS Status = STATUS_SUCCESS;
3464 KIRQL SavedIrql;
3465 ULONG RemainingUserReferences = (FileObject? 1: 0);
3466
3467 NT_ASSERT( ExIsResourceAcquiredExclusiveLite( &Vcb->Resource ) &&
3468 !ExIsResourceAcquiredExclusiveLite( &FatData.Resource ));
3469 //
3470 // Go synchronous for the rest of the lock operation. It may be
3471 // reasonable to try to revisit this in the future, but for now
3472 // the purge below expects to be able to wait.
3473 //
3474 // We know it is OK to leave the flag up given how we're used at
3475 // the moment.
3476 //
3477
3478 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
3479
3480 //
3481 // If there are any open handles, this will fail.
3482 //
3483
3484 if (!FatIsHandleCountZero( IrpContext, Vcb )) {
3485
3486 return STATUS_ACCESS_DENIED;
3487 }
3488
3489 //
3490 // Force Mm to get rid of its referenced file objects.
3491 //
3492
3493 FatFlushFat( IrpContext, Vcb );
3494
3495 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
3496
3497 FatCloseEaFile( IrpContext, Vcb, TRUE );
3498
3499 //
3500 // Now back out of our synchronization and wait for the lazy writer
3501 // to finish off any lazy closes that could have been outstanding.
3502 //
3503 // Since we flushed, we know that the lazy writer will issue all
3504 // possible lazy closes in the next tick - if we hadn't, an otherwise
3505 // unopened file with a large amount of dirty data could have hung
3506 // around for a while as the data trickled out to the disk.
3507 //
3508 // This is even more important now since we send notification to
3509 // alert other folks that this style of check is about to happen so
3510 // that they can close their handles. We don't want to enter a fast
3511 // race with the lazy writer tearing down his references to the file.
3512 //
3513
3514 FatReleaseVcb( IrpContext, Vcb );
3515
3516 Status = CcWaitForCurrentLazyWriterActivity();
3517
3518 FatAcquireExclusiveVcb( IrpContext, Vcb );
3519
3520 if (!NT_SUCCESS( Status )) {
3521
3522 return Status;
3523 }
3524
3525 //
3526 // The act of closing and purging may have touched pages in various
3527 // parent DCBs. We handle this by purging a second time.
3528 //
3529
3530 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
3531
3532 FatReleaseVcb( IrpContext, Vcb );
3533
3534 Status = CcWaitForCurrentLazyWriterActivity();
3535
3536 FatAcquireExclusiveVcb( IrpContext, Vcb );
3537
3538 if (!NT_SUCCESS( Status )) {
3539
3540 return Status;
3541 }
3542
3543 //
3544 // Now rundown the delayed closes one last time. We appear to be able
3545 // to have additional collisions.
3546 //
3547
3548 FatFspClose( Vcb );
3549
3550 //
3551 // Check if the Vcb is already locked, or if the open file count
3552 // is greater than 1 (which implies that someone else also is
3553 // currently using the volume, or a file on the volume), and that the
3554 // VPB reference count only includes our residual and the handle (as
3555 // appropriate).
3556 //
3557 // We used to only check for the vpb refcount. This is unreliable since
3558 // the vpb refcount is dropped immediately before final close, meaning
3559 // that even though we had a good refcount, the close was inflight and
3560 // subsequent operations could get confused. Especially if the PNP path
3561 // was the lock caller, we delete the VCB with an outstanding opencount!
3562 //
3563
3564 IoAcquireVpbSpinLock( &SavedIrql );
3565
3566 if (!FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) &&
3567 (Vcb->Vpb->ReferenceCount <= 2 + RemainingUserReferences) &&
3568 (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 ))) {
3569
3570 SetFlag(Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED));
3571 SetFlag(Vcb->VcbState, VCB_STATE_FLAG_LOCKED);
3572 Vcb->FileObjectWithVcbLocked = FileObject;
3573
3574 } else {
3575
3576 Status = STATUS_ACCESS_DENIED;
3577 }
3578
3579 IoReleaseVpbSpinLock( SavedIrql );
3580
3581 //
3582 // If we successully locked the volume, see if it is clean now.
3583 //
3584
3585 if (NT_SUCCESS( Status ) &&
3586 FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) &&
3587 !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) &&
3588 !CcIsThereDirtyData(Vcb->Vpb)) {
3589
3590 FatMarkVolume( IrpContext, Vcb, VolumeClean );
3591 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
3592 }
3593
3594 NT_ASSERT( !NT_SUCCESS(Status) || (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 )));
3595
3596 return Status;
3597 }
3598
3599
3600 NTSTATUS
3601 FatUnlockVolumeInternal (
3602 IN PIRP_CONTEXT IrpContext,
3603 IN PVCB Vcb,
3604 IN PFILE_OBJECT FileObject OPTIONAL
3605 )
3606
3607 /*++
3608
3609 Routine Description:
3610
3611 This routine performs the actual unlock volume operation.
3612
3613 The volume must be held exclusive by the caller.
3614
3615 Arguments:
3616
3617 Vcb - The volume being locked.
3618
3619 FileObject - File corresponding to the handle locking the volume. If this
3620 is not specified, a system lock is assumed.
3621
3622 Return Value:
3623
3624 NTSTATUS - The return status for the operation
3625
3626 Attempting to remove a system lock that did not exist is OK.
3627
3628 --*/
3629
3630 {
3631 KIRQL SavedIrql;
3632 NTSTATUS Status = STATUS_NOT_LOCKED;
3633
3634 UNREFERENCED_PARAMETER( IrpContext );
3635
3636 IoAcquireVpbSpinLock( &SavedIrql );
3637
3638 if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && FileObject == Vcb->FileObjectWithVcbLocked) {
3639
3640 //
3641 // This one locked it, unlock the volume
3642 //
3643
3644 ClearFlag( Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED) );
3645 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_LOCKED );
3646 Vcb->FileObjectWithVcbLocked = NULL;
3647
3648 Status = STATUS_SUCCESS;
3649 }
3650
3651 IoReleaseVpbSpinLock( SavedIrql );
3652
3653 return Status;
3654 }
3655
3656
3657 //
3658 // Local Support Routine
3659 //
3660
3661 _Requires_lock_held_(_Global_critical_region_)
3662 NTSTATUS
3663 FatDismountVolume (
3664 IN PIRP_CONTEXT IrpContext,
3665 IN PIRP Irp
3666 )
3667
3668 /*++
3669
3670 Routine Description:
3671
3672 This routine performs the dismount volume operation. It is responsible for
3673 either completing of enqueuing the input Irp.
3674
3675 Arguments:
3676
3677 Irp - Supplies the Irp to process
3678
3679 Return Value:
3680
3681 NTSTATUS - The return status for the operation
3682
3683 --*/
3684
3685 {
3686 PIO_STACK_LOCATION IrpSp;
3687 NTSTATUS Status = STATUS_SUCCESS;
3688 BOOLEAN VcbHeld = FALSE;
3689 KIRQL SavedIrql;
3690
3691 PVCB Vcb;
3692 PFCB Fcb;
3693 PCCB Ccb;
3694
3695 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3696
3697 DebugTrace(+1, Dbg, "FatDismountVolume...\n", 0);
3698
3699 //
3700 // Decode the file object, the only type of opens we accept are
3701 // user volume opens on media that is not boot/paging and is not
3702 // already dismounted ... (but we need to check that stuff while
3703 // synchronized)
3704 //
3705
3706 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
3707
3708 Status = STATUS_INVALID_PARAMETER;
3709 goto fn_return;
3710 }
3711
3712 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3713
3714 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3715
3716 DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3717 return STATUS_INVALID_PARAMETER;
3718 }
3719
3720 //
3721 // Make some unsynchronized checks to see if this operation is possible.
3722 // We will repeat the appropriate ones inside synchronization, but it is
3723 // good to avoid bogus notifications.
3724 //
3725
3726 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE )) {
3727
3728 Status = STATUS_ACCESS_DENIED;
3729 goto fn_return;
3730 }
3731
3732 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
3733
3734 Status = STATUS_VOLUME_DISMOUNTED;
3735 goto fn_return;
3736 }
3737
3738 //
3739 // A bit of historical comment is in order.
3740 //
3741 // In all versions prior to NT5, we only permitted dismount if the volume had
3742 // previously been locked. Now we must permit a forced dismount, meaning that
3743 // we grab ahold of the whole kit-n-kaboodle - regardless of activity, open
3744 // handles, etc. - to flush and invalidate the volume.
3745 //
3746 // Previously, dismount assumed that lock had come along earlier and done some
3747 // of the work that we are now going to do - i.e., flush, tear down the eas. All
3748 // we had to do here is flush the device out and kill off as many of the orphan
3749 // fcbs as possible. This now changes.
3750 //
3751 // In fact, everything is a forced dismount now. This changes one interesting
3752 // aspect, which is that it used to be the case that the handle used to dismount
3753 // could come back, read, and induce a verify/remount. This is just not possible
3754 // now. The point of forced dismount is that very shortly someone will come along
3755 // and be destructive to the possibility of using the media further - format, eject,
3756 // etc. By using this path, callers are expected to tolerate the consequences.
3757 //
3758 // Note that the volume can still be successfully unlocked by this handle.
3759 //
3760
3761 //
3762 // Send notification.
3763 //
3764
3765 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT );
3766
3767 //
3768 // Force ourselves to wait and grab everything.
3769 //
3770
3771 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
3772
3773 #ifdef _MSC_VER
3774 #pragma prefast( push )
3775 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
3776 #pragma prefast( disable: 28193, "this will always wait" )
3777 #endif
3778
3779 (VOID)FatAcquireExclusiveGlobal( IrpContext );
3780
3781 #ifdef _MSC_VER
3782 #pragma prefast( pop )
3783 #endif
3784
3785 _SEH2_TRY {
3786
3787 //
3788 // Guess what? This can raise if a cleanup on the fileobject we
3789 // got races in ahead of us.
3790 //
3791
3792 FatAcquireExclusiveVolume( IrpContext, Vcb );
3793 VcbHeld = TRUE;
3794
3795 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
3796
3797 try_return( Status = STATUS_VOLUME_DISMOUNTED );
3798 }
3799
3800 FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushAndInvalidate );
3801
3802 //
3803 // We defer the physical dismount until this handle is closed, per symmetric
3804 // implemntation in the other FS. This permits a dismounter to issue IOCTL
3805 // through this handle and perform device manipulation without racing with
3806 // creates attempting to mount the volume again.
3807 //
3808 // Raise a flag to tell the cleanup path to complete the dismount.
3809 //
3810
3811 SetFlag( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT );
3812
3813 //
3814 // Indicate that the volume was dismounted so that we may return the
3815 // correct error code when operations are attempted via open handles.
3816 //
3817
3818 FatSetVcbCondition( Vcb, VcbBad);
3819
3820 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED );
3821
3822 //
3823 // Set a flag in the VPB to let others know that direct volume access is allowed.
3824 //
3825
3826 IoAcquireVpbSpinLock( &SavedIrql );
3827 SetFlag( Vcb->Vpb->Flags, VPB_DIRECT_WRITES_ALLOWED );
3828 IoReleaseVpbSpinLock( SavedIrql );
3829
3830 Status = STATUS_SUCCESS;
3831
3832 try_exit: NOTHING;
3833
3834 } _SEH2_FINALLY {
3835
3836 #if (NTDDI_VERSION >= NTDDI_WIN8)
3837
3838 FsRtlDismountComplete( Vcb->TargetDeviceObject, Status );
3839
3840 #endif
3841
3842 if (VcbHeld) {
3843
3844 FatReleaseVolume( IrpContext, Vcb );
3845 }
3846
3847 FatReleaseGlobal( IrpContext );
3848
3849 //
3850 // I do not believe it is possible to raise, but for completeness
3851 // notice and send notification of failure. We absolutely
3852 // cannot have raised in CheckForDismount.
3853 //
3854 // We decline to call an attempt to dismount a dismounted volume
3855 // a failure to do so.
3856 //
3857
3858 if ((!NT_SUCCESS( Status ) && Status != STATUS_VOLUME_DISMOUNTED)
3859 || _SEH2_AbnormalTermination()) {
3860
3861 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED );
3862 }
3863 } _SEH2_END;
3864
3865 fn_return:
3866
3867 FatCompleteRequest( IrpContext, Irp, Status );
3868 DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", Status);
3869 return Status;
3870 }
3871
3872
3873 //
3874 // Local Support Routine
3875 //
3876
3877 _Requires_lock_held_(_Global_critical_region_)
3878 NTSTATUS
3879 FatDirtyVolume (
3880 IN PIRP_CONTEXT IrpContext,
3881 IN PIRP Irp
3882 )
3883
3884 /*++
3885
3886 Routine Description:
3887
3888 This routine marks the volume as dirty.
3889
3890 Arguments:
3891
3892 Irp - Supplies the Irp to process
3893
3894 Return Value:
3895
3896 NTSTATUS - The return status for the operation
3897
3898 --*/
3899
3900 {
3901 PIO_STACK_LOCATION IrpSp;
3902
3903 PVCB Vcb;
3904 PFCB Fcb;
3905 PCCB Ccb;
3906
3907 PAGED_CODE();
3908
3909 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3910
3911 DebugTrace(+1, Dbg, "FatDirtyVolume...\n", 0);
3912
3913 //
3914 // Decode the file object, the only type of opens we accept are
3915 // user volume opens.
3916 //
3917
3918 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
3919
3920 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3921
3922 DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3923 return STATUS_INVALID_PARAMETER;
3924 }
3925
3926 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3927
3928 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
3929
3930 DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3931 return STATUS_INVALID_PARAMETER;
3932 }
3933
3934
3935 //
3936 // Disable popups, we will just return any error.
3937 //
3938
3939 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
3940
3941 //
3942 // Verify the Vcb. We want to make sure we don't dirty some
3943 // random chunk of media that happens to be in the drive now.
3944 //
3945
3946 FatVerifyVcb( IrpContext, Vcb );
3947
3948 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
3949
3950 FatMarkVolume( IrpContext, Vcb, VolumeDirty );
3951
3952 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
3953
3954 DebugTrace(-1, Dbg, "FatDirtyVolume -> STATUS_SUCCESS\n", 0);
3955
3956 return STATUS_SUCCESS;
3957 }
3958
3959
3960 //
3961 // Local Support Routine
3962 //
3963
3964 NTSTATUS
3965 FatIsVolumeDirty (
3966 IN PIRP_CONTEXT IrpContext,
3967 IN PIRP Irp
3968 )
3969
3970 /*++
3971
3972 Routine Description:
3973
3974 This routine determines if a volume is currently dirty.
3975
3976 Arguments:
3977
3978 Irp - Supplies the Irp to process
3979
3980 Return Value:
3981
3982 NTSTATUS - The return status for the operation
3983
3984 --*/
3985
3986 {
3987 PIO_STACK_LOCATION IrpSp;
3988
3989 TYPE_OF_OPEN TypeOfOpen;
3990 PVCB Vcb;
3991 PFCB Fcb;
3992 PCCB Ccb;
3993
3994 PULONG VolumeState;
3995
3996 PAGED_CODE();
3997
3998 //
3999 // Get the current stack location and extract the output
4000 // buffer information.
4001 //
4002
4003 IrpSp = IoGetCurrentIrpStackLocation( Irp );
4004
4005 //
4006 // Get a pointer to the output buffer. Look at the system buffer field in the
4007 // irp first. Then the Irp Mdl.
4008 //
4009
4010 if (Irp->AssociatedIrp.SystemBuffer != NULL) {
4011
4012 VolumeState = Irp->AssociatedIrp.SystemBuffer;
4013
4014 } else if (Irp->MdlAddress != NULL) {
4015
4016 VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, LowPagePriority | MdlMappingNoExecute );
4017
4018 if (VolumeState == NULL) {
4019
4020 FatCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
4021 return STATUS_INSUFFICIENT_RESOURCES;
4022 }
4023
4024 } else {
4025
4026 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
4027 return STATUS_INVALID_USER_BUFFER;
4028 }
4029
4030 //
4031 // Make sure the output buffer is large enough and then initialize
4032 // the answer to be that the volume isn't dirty.
4033 //
4034
4035 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
4036
4037 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
4038 return STATUS_INVALID_PARAMETER;
4039 }
4040
4041 *VolumeState = 0;
4042
4043 //
4044 // Decode the file object
4045 //
4046
4047 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
4048
4049 if (TypeOfOpen != UserVolumeOpen) {
4050
4051 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
4052 return STATUS_INVALID_PARAMETER;
4053 }
4054
4055 if (Vcb->VcbCondition != VcbGood) {
4056
4057 FatCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
4058 return STATUS_VOLUME_DISMOUNTED;
4059 }
4060
4061 //
4062 // Disable PopUps, we want to return any error.
4063 //
4064
4065 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
4066
4067 //
4068 // Verify the Vcb. We want to make double sure that this volume
4069 // is around so that we know our information is good.
4070 //
4071
4072 FatVerifyVcb( IrpContext, Vcb );
4073
4074 //
4075 // Now set the returned information. We can avoid probing the disk since
4076 // we know our internal state is in sync.
4077 //
4078
4079 if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY) ) {
4080
4081 SetFlag( *VolumeState, VOLUME_IS_DIRTY );
4082 }
4083
4084 Irp->IoStatus.Information = sizeof( ULONG );
4085
4086 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
4087 return STATUS_SUCCESS;
4088 }
4089
4090
4091 //
4092 // Local Support Routine
4093 //
4094
4095 NTSTATUS
4096 FatIsVolumeMounted (
4097 IN PIRP_CONTEXT IrpContext,
4098 IN PIRP Irp
4099 )
4100
4101 /*++
4102
4103 Routine Description:
4104
4105 This routine determines if a volume is currently mounted.
4106
4107 Arguments:
4108
4109 Irp - Supplies the Irp to process
4110
4111 Return Value:
4112
4113 NTSTATUS - The return status for the operation
4114
4115 --*/
4116
4117 {
4118 NTSTATUS Status;
4119
4120 PIO_STACK_LOCATION IrpSp;
4121
4122 PVCB Vcb = NULL;
4123 PFCB Fcb;
4124 PCCB Ccb;
4125
4126 PAGED_CODE();
4127
4128 IrpSp = IoGetCurrentIrpStackLocation( Irp );
4129
4130 Status = STATUS_SUCCESS;
4131
4132 DebugTrace(+1, Dbg, "FatIsVolumeMounted...\n", 0);
4133
4134 //
4135 // Decode the file object.
4136 //
4137
4138 (VOID)FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
4139
4140 NT_ASSERT( Vcb != NULL );
4141 _Analysis_assume_( Vcb != NULL );
4142
4143 //
4144 // Disable PopUps, we want to return any error.
4145 //
4146
4147 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
4148
4149 //
4150 // Verify the Vcb.
4151 //
4152
4153 FatVerifyVcb( IrpContext, Vcb );
4154
4155 FatCompleteRequest( IrpContext, Irp, Status );
4156
4157 DebugTrace(-1, Dbg, "FatIsVolumeMounted -> %08lx\n", Status);
4158
4159 return Status;
4160 }
4161
4162
4163 //
4164 // Local Support Routine
4165 //
4166
4167 NTSTATUS
4168 FatIsPathnameValid (
4169 IN PIRP_CONTEXT IrpContext,
4170 IN PIRP Irp
4171 )
4172
4173 /*++
4174
4175 Routine Description:
4176
4177 This routine determines if a pathname is a-priori illegal by inspecting
4178 the the characters used. It is required to be correct on a FALSE return.
4179
4180 N.B.: current implementation is intentioanlly a no-op. This may change
4181 in the future. A careful reader of the previous implementation of this
4182 FSCTL in FAT would discover that it violated the requirement stated above
4183 and could return FALSE for a valid (createable) pathname.
4184
4185 Arguments:
4186
4187 Irp - Supplies the Irp to process
4188
4189 Return Value:
4190
4191 NTSTATUS - The return status for the operation
4192
4193 --*/
4194
4195 {
4196 PAGED_CODE();
4197
4198 DebugTrace(+1, Dbg, "FatIsPathnameValid...\n", 0);
4199
4200 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
4201
4202 DebugTrace(-1, Dbg, "FatIsPathnameValid -> %08lx\n", STATUS_SUCCESS);
4203
4204 return STATUS_SUCCESS;
4205 }
4206
4207
4208 //
4209 // Local Support Routine
4210 //
4211
4212 NTSTATUS
4213 FatQueryBpb (
4214 IN PIRP_CONTEXT IrpContext,
4215 IN PIRP Irp
4216 )
4217
4218 /*++
4219
4220 Routine Description:
4221
4222 This routine simply returns the first 0x24 bytes of sector 0.
4223
4224 Arguments:
4225
4226 Irp - Supplies the Irp to process
4227
4228 Return Value:
4229
4230 NTSTATUS - The return status for the operation
4231
4232 --*/
4233
4234 {
4235 PIO_STACK_LOCATION IrpSp;
4236
4237 PVCB Vcb;
4238
4239 PFSCTL_QUERY_FAT_BPB_BUFFER BpbBuffer;
4240
4241 PAGED_CODE();
4242
4243 IrpSp = IoGetCurrentIrpStackLocation( Irp );
4244
4245 DebugTrace(+1, Dbg, "FatQueryBpb...\n", 0);
4246
4247 //
4248 // Get the Vcb. If we didn't keep the information needed for this call,
4249 // we had a reason ...
4250 //
4251
4252 Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
4253
4254 if (Vcb->First0x24BytesOfBootSector == NULL) {
4255
4256 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
4257 DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST );
4258 return STATUS_INVALID_DEVICE_REQUEST;
4259 }
4260
4261 //
4262 // Extract the buffer
4263 //
4264
4265 BpbBuffer = (PFSCTL_QUERY_FAT_BPB_BUFFER)Irp->AssociatedIrp.SystemBuffer;
4266
4267 //
4268 // Make sure the buffer is big enough.
4269 //
4270
4271 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < 0x24) {
4272
4273 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
4274 DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
4275 return STATUS_BUFFER_TOO_SMALL;
4276 }
4277
4278 //
4279 // Fill in the output buffer
4280 //
4281
4282 RtlCopyMemory( BpbBuffer->First0x24BytesOfBootSector,
4283 Vcb->First0x24BytesOfBootSector,
4284 0x24 );
4285
4286 Irp->IoStatus.Information = 0x24;
4287
4288 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
4289 DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_SUCCESS);
4290 return STATUS_SUCCESS;
4291 }
4292
4293
4294 //
4295 // Local Support Routine
4296 //
4297
4298 _Requires_lock_held_(_Global_critical_region_)
4299 NTSTATUS
4300 FatInvalidateVolumes (
4301 IN PIRP Irp
4302 )
4303
4304 /*++
4305
4306 Routine Description:
4307
4308 This routine searches for all the volumes mounted on the same real device
4309 of the current DASD handle, and marks them all bad. The only operation
4310 that can be done on such handles is cleanup and close.
4311
4312 Arguments:
4313
4314 Irp - Supplies the Irp to process
4315
4316 Return Value:
4317
4318 NTSTATUS - The return status for the operation
4319
4320 --*/
4321
4322 {
4323 NTSTATUS Status;
4324 IRP_CONTEXT IrpContext;
4325 PIO_STACK_LOCATION IrpSp;
4326
4327 LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
4328
4329 HANDLE Handle;
4330
4331 PLIST_ENTRY Links;
4332
4333 PFILE_OBJECT FileToMarkBad;
4334 PDEVICE_OBJECT DeviceToMarkBad;
4335
4336 IrpSp = IoGetCurrentIrpStackLocation( Irp );
4337
4338 DebugTrace(+1, Dbg, "FatInvalidateVolumes...\n", 0);
4339
4340 //
4341 // Check for the correct security access.
4342 // The caller must have the SeTcbPrivilege.
4343 //
4344
4345 if (!SeSinglePrivilegeCheck(TcbPrivilege, Irp->RequestorMode)) {
4346
4347 FatCompleteRequest( FatNull, Irp, STATUS_PRIVILEGE_NOT_HELD );
4348
4349 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_PRIVILEGE_NOT_HELD);
4350 return STATUS_PRIVILEGE_NOT_HELD;
4351 }
4352
4353 //
4354 // Try to get a pointer to the device object from the handle passed in.
4355 //
4356
4357 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
4358 if (IoIs32bitProcess( Irp )) {
4359
4360 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(UINT32)) {
4361
4362 FatCompleteRequest( FatNull, Irp, STATUS_INVALID_PARAMETER );
4363
4364 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER);
4365 return STATUS_INVALID_PARAMETER;
4366 }
4367
4368 Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
4369 } else {
4370 #endif
4371 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(HANDLE)) {
4372
4373 FatCompleteRequest( FatNull, Irp, STATUS_INVALID_PARAMETER );
4374
4375 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER);
4376 return STATUS_INVALID_PARAMETER;
4377 }
4378
4379 Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
4380 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
4381 }
4382 #endif
4383
4384
4385 Status = ObReferenceObjectByHandle( Handle,
4386 0,
4387 *IoFileObjectType,
4388 KernelMode,
4389 #ifndef __REACTOS__
4390 &FileToMarkBad,
4391 #else
4392 (PVOID *)&FileToMarkBad,
4393 #endif
4394 NULL );
4395
4396 if (!NT_SUCCESS(Status)) {
4397
4398 FatCompleteRequest( FatNull, Irp, Status );
4399
4400 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", Status);
4401 return Status;
4402
4403 } else {
4404
4405 //
4406 // We only needed the pointer, not a reference.
4407 //
4408
4409 ObDereferenceObject( FileToMarkBad );
4410
4411 //
4412 // Grab the DeviceObject from the FileObject.
4413 //
4414
4415 DeviceToMarkBad = FileToMarkBad->DeviceObject;
4416 }
4417
4418 RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
4419
4420 SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
4421 IrpContext.MajorFunction = IrpSp->MajorFunction;
4422 IrpContext.MinorFunction = IrpSp->MinorFunction;
4423
4424 #ifdef _MSC_VER
4425 #pragma prefast( push )
4426 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
4427 #pragma prefast( disable: 28193, "this will always wait" )
4428 #endif
4429
4430 FatAcquireExclusiveGlobal( &IrpContext );
4431
4432 #ifdef _MSC_VER
4433 #pragma prefast( pop )
4434 #endif
4435
4436 //
4437 // First acquire the FatData resource shared, then walk through all the
4438 // mounted VCBs looking for candidates to mark BAD.
4439 //
4440 // On volumes we mark bad, check for dismount possibility (which is
4441 // why we have to get the next link early).
4442 //
4443
4444 Links = FatData.VcbQueue.Flink;
4445
4446 while (Links != &FatData.VcbQueue) {
4447
4448 PVCB ExistingVcb;
4449
4450 ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
4451
4452 Links = Links->Flink;
4453
4454 //
4455 // If we get a match, mark the volume Bad, and also check to
4456 // see if the volume should go away.
4457 //
4458
4459 if (ExistingVcb->Vpb->RealDevice == DeviceToMarkBad) {
4460
4461 BOOLEAN VcbDeleted = FALSE;
4462
4463 //
4464 // Here we acquire the Vcb exclusive and try to purge
4465 // all the open files. The idea is to have as little as
4466 // possible stale data visible and to hasten the volume
4467 // going away.
4468 //
4469
4470 (VOID)FatAcquireExclusiveVcb( &IrpContext, ExistingVcb );
4471
4472 #ifdef _MSC_VER
4473 #pragma prefast( push )
4474 #pragma prefast( disable: 28175, "touching Vpb is ok for a filesystem" )
4475 #endif
4476
4477 if (ExistingVcb->Vpb == DeviceToMarkBad->Vpb) {
4478
4479 KIRQL OldIrql;
4480
4481 IoAcquireVpbSpinLock( &OldIrql );
4482
4483 if (FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_MOUNTED )) {
4484
4485 PVPB NewVpb;
4486
4487 NewVpb = ExistingVcb->SwapVpb;
4488 ExistingVcb->SwapVpb = NULL;
4489 SetFlag( ExistingVcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED );
4490
4491 RtlZeroMemory( NewVpb, sizeof( VPB ) );
4492 NewVpb->Type = IO_TYPE_VPB;
4493 NewVpb->Size = sizeof( VPB );
4494 NewVpb->RealDevice = DeviceToMarkBad;
4495 NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING );
4496
4497 DeviceToMarkBad->Vpb = NewVpb;
4498 }
4499
4500 NT_ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL );
4501
4502 #ifdef _MSC_VER
4503 #pragma prefast( pop )
4504 #endif
4505
4506 IoReleaseVpbSpinLock( OldIrql );
4507 }
4508
4509 FatSetVcbCondition( ExistingVcb, VcbBad );
4510
4511 //
4512 // Process the root directory, if it is present.
4513 //
4514
4515 if (ExistingVcb->RootDcb != NULL) {
4516
4517 //
4518 // In order to safely mark all FCBs bad, we must acquire everything.
4519 //
4520
4521 FatAcquireExclusiveVolume(&IrpContext, ExistingVcb);
4522 FatMarkFcbCondition( &IrpContext, ExistingVcb->RootDcb, FcbBad, TRUE );
4523 FatReleaseVolume(&IrpContext, ExistingVcb);
4524
4525 //
4526 // Purging the file objects on this volume could result in the memory manager
4527 // dereferencing it's file pointer which could be the last reference and
4528 // trigger object deletion and VCB deletion. Protect against that here by
4529 // temporarily biasing the file count, and later checking for dismount.
4530 //
4531
4532 ExistingVcb->OpenFileCount += 1;
4533
4534 FatPurgeReferencedFileObjects( &IrpContext,
4535 ExistingVcb->RootDcb,
4536 NoFlush );
4537
4538 ExistingVcb->OpenFileCount -= 1;
4539
4540 VcbDeleted = FatCheckForDismount( &IrpContext, ExistingVcb, FALSE );
4541 }
4542
4543 //
4544 // Only release the VCB if it did not go away.
4545 //
4546
4547 if (!VcbDeleted) {
4548
4549 FatReleaseVcb( &IrpContext, ExistingVcb );
4550 }
4551 }
4552 }
4553
4554 FatReleaseGlobal( &IrpContext );
4555
4556 FatCompleteRequest( FatNull, Irp, STATUS_SUCCESS );
4557
4558 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> STATUS_SUCCESS\n", 0);
4559
4560 return STATUS_SUCCESS;
4561 }
4562
4563
4564 //
4565 // Local Support routine
4566 //
4567
4568 BOOLEAN
4569 FatPerformVerifyDiskRead (
4570 IN PIRP_CONTEXT IrpContext,
4571 IN PVCB Vcb,
4572 IN PVOID Buffer,
4573 IN LBO Lbo,
4574 IN ULONG NumberOfBytesToRead,
4575 IN BOOLEAN ReturnOnError
4576 )
4577
4578 /*++
4579
4580 Routine Description:
4581
4582 This routine is used to read in a range of bytes from the disk. It
4583 bypasses all of the caching and regular I/O logic, and builds and issues
4584 the requests itself. It does this operation overriding the verify
4585 volume flag in the device object.
4586
4587 Arguments:
4588
4589 Vcb - Supplies the target device object for this operation.
4590
4591 Buffer - Supplies the buffer that will recieve the results of this operation
4592
4593 Lbo - Supplies the byte offset of where to start reading
4594
4595 NumberOfBytesToRead - Supplies the number of bytes to read, this must
4596 be in multiple of bytes units acceptable to the disk driver.
4597
4598 ReturnOnError - Indicates that we should return on an error, instead
4599 of raising.
4600
4601 Return Value:
4602
4603 BOOLEAN - TRUE if the operation succeded, FALSE otherwise.
4604
4605 --*/
4606
4607 {
4608 KEVENT Event;
4609 PIRP Irp;
4610 LARGE_INTEGER ByteOffset;
4611 NTSTATUS Status;
4612 IO_STATUS_BLOCK Iosb;
4613
4614 PAGED_CODE();
4615
4616 DebugTrace(0, Dbg, "FatPerformVerifyDiskRead, Lbo = %08lx\n", Lbo );
4617
4618 //
4619 // Initialize the event we're going to use
4620 //
4621
4622 KeInitializeEvent( &Event, NotificationEvent, FALSE );
4623
4624 //
4625 // Build the irp for the operation and also set the overrride flag
4626 //
4627
4628 ByteOffset.QuadPart = Lbo;
4629
4630 Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
4631 Vcb->TargetDeviceObject,
4632 Buffer,
4633 NumberOfBytesToRead,
4634 &ByteOffset,
4635 &Event,
4636 &Iosb );
4637
4638 if ( Irp == NULL ) {
4639
4640 FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
4641 }
4642
4643 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
4644
4645 //
4646 // Call the device to do the read and wait for it to finish.
4647 //
4648
4649 Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
4650
4651 if (Status == STATUS_PENDING) {
4652
4653 (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
4654
4655 Status = Iosb.Status;
4656 }
4657
4658 NT_ASSERT( Status != STATUS_VERIFY_REQUIRED );
4659
4660 //
4661 // Special case this error code because this probably means we used
4662 // the wrong sector size and we want to reject STATUS_WRONG_VOLUME.
4663 //
4664
4665 if (Status == STATUS_INVALID_PARAMETER) {
4666
4667 return FALSE;
4668 }
4669
4670 //
4671 // If it doesn't succeed then either return or raise the error.
4672 //
4673
4674 if (!NT_SUCCESS(Status)) {
4675
4676 if (ReturnOnError) {
4677
4678 return FALSE;
4679
4680 } else {
4681
4682 FatNormalizeAndRaiseStatus( IrpContext, Status );
4683 }
4684 }
4685
4686 //
4687 // And return to our caller
4688 //
4689
4690 return TRUE;
4691 }
4692
4693
4694 //
4695 // Local Support Routine
4696 //
4697
4698 _Requires_lock_held_(_Global_critical_region_)
4699 NTSTATUS
4700 FatQueryRetrievalPointers (
4701 IN PIRP_CONTEXT IrpContext,
4702 IN PIRP Irp
4703 )
4704
4705 /*++
4706
4707 Routine Description:
4708
4709 This routine performs the query retrieval pointers operation.
4710 It returns the retrieval pointers for the specified input
4711 file from the start of the file to the request map size specified
4712 in the input buffer.
4713
4714 Arguments:
4715
4716 Irp - Supplies the Irp to process
4717
4718 Return Value:
4719
4720 NTSTATUS - The return status for the operation
4721
4722 --*/
4723
4724 {
4725 NTSTATUS Status = STATUS_SUCCESS;
4726
4727 PIO_STACK_LOCATION IrpSp;
4728
4729 PVCB Vcb;
4730 PFCB Fcb;
4731 PCCB Ccb;
4732
4733 PLARGE_INTEGER RequestedMapSize;
4734 PLARGE_INTEGER *MappingPairs;
4735
4736 ULONG Index;
4737 ULONG i;
4738 ULONG SectorCount;
4739 LBO Lbo;
4740 ULONG Vbo;
4741 ULONG MapSize;
4742 BOOLEAN Result;
4743
4744 PAGED_CODE();
4745
4746 //
4747 // Get the current stack location
4748 //
4749
4750 IrpSp = IoGetCurrentIrpStackLocation( Irp );
4751
4752 //
4753 // Make this a synchronous IRP because we need access to the input buffer and
4754 // this Irp is marked METHOD_NEITHER.
4755 //
4756
4757 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
4758
4759 //
4760 // Decode the file object and ensure that it is the paging file
4761 //
4762 // Only Kernel mode clients may query retrieval pointer information about
4763 // a file. Ensure that this is the case for this caller.
4764 //
4765
4766 (VOID)FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
4767
4768 if (Irp->RequestorMode != KernelMode ||
4769 Fcb == NULL ||
4770 !FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ) {
4771
4772 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
4773 return STATUS_INVALID_PARAMETER;
4774 }
4775
4776 //
4777 // Extract the input and output buffer information. The input contains
4778 // the requested size of the mappings in terms of VBO. The output
4779 // parameter will receive a pointer to nonpaged pool where the mapping
4780 // pairs are stored.
4781 //
4782
4783 NT_ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof(LARGE_INTEGER) );
4784 NT_ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength == sizeof(PVOID) );
4785
4786 RequestedMapSize = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
4787 MappingPairs = Irp->UserBuffer;
4788
4789 //
4790 // Acquire exclusive access to the Fcb
4791 //
4792
4793 FatAcquireExclusiveFcb( IrpContext, Fcb );
4794
4795 _SEH2_TRY {
4796
4797 //
4798 // Verify the Fcb is still OK
4799 //
4800
4801 FatVerifyFcb( IrpContext, Fcb );
4802
4803 //
4804 // Check if the mapping the caller requested is too large
4805 //
4806
4807 if ((*RequestedMapSize).QuadPart > Fcb->Header.FileSize.QuadPart) {
4808
4809 try_leave( Status = STATUS_INVALID_PARAMETER );
4810 }
4811
4812 //
4813 // Now get the index for the mcb entry that will contain the
4814 // callers request and allocate enough pool to hold the
4815 // output mapping pairs. Mapping should always be present, but handle
4816 // the case where it isn't.
4817 //
4818
4819 Result = FatLookupMcbEntry( Fcb->Vcb,
4820 &Fcb->Mcb,
4821 RequestedMapSize->LowPart - 1,
4822 &Lbo,
4823 NULL,
4824 &Index );
4825
4826 if (!Result) {
4827
4828 NT_ASSERT(FALSE);
4829 try_leave( Status = STATUS_FILE_CORRUPT_ERROR);
4830 }
4831
4832 *MappingPairs = FsRtlAllocatePoolWithTag( NonPagedPoolNx,
4833 (Index + 2) * (2 * sizeof(LARGE_INTEGER)),
4834 TAG_OUTPUT_MAPPINGPAIRS );
4835
4836 //
4837 // Now copy over the mapping pairs from the mcb
4838 // to the output buffer. We store in [sector count, lbo]
4839 // mapping pairs and end with a zero sector count.
4840 //
4841
4842 MapSize = RequestedMapSize->LowPart;
4843
4844 for (i = 0; i <= Index; i += 1) {
4845
4846 (VOID)FatGetNextMcbEntry( Fcb->Vcb, &Fcb->Mcb, i, (PVBO)&Vbo, &Lbo, &SectorCount );
4847
4848 if (SectorCount > MapSize) {
4849 SectorCount = MapSize;
4850 }
4851
4852 (*MappingPairs)[ i*2 + 0 ].QuadPart = SectorCount;
4853 (*MappingPairs)[ i*2 + 1 ].QuadPart = Lbo;
4854
4855 MapSize -= SectorCount;
4856 }
4857
4858 (*MappingPairs)[ i*2 + 0 ].QuadPart = 0;
4859
4860 Status = STATUS_SUCCESS;
4861 }
4862 _SEH2_FINALLY {
4863
4864 DebugUnwind( FatQueryRetrievalPointers );
4865
4866 //
4867 // Release all of our resources
4868 //
4869
4870 FatReleaseFcb( IrpContext, Fcb );
4871
4872 //
4873 // If this is an abnormal termination then undo our work, otherwise
4874 // complete the irp
4875 //
4876
4877 if (!_SEH2_AbnormalTermination()) {
4878
4879 FatCompleteRequest( IrpContext, Irp, Status );
4880 }
4881 } _SEH2_END;
4882
4883 return Status;
4884 }
4885
4886
4887 //
4888 // Local Support Routine
4889 //
4890
4891 NTSTATUS
4892 FatGetStatistics (
4893 IN PIRP_CONTEXT IrpContext,
4894 IN PIRP Irp
4895 )
4896
4897 /*++
4898
4899 Routine Description:
4900
4901 This routine returns the filesystem performance counters from the
4902 appropriate VCB.
4903
4904 Arguments:
4905
4906 Irp - Supplies the Irp to process
4907
4908 Return Value:
4909
4910 NTSTATUS - The return status for the operation
4911
4912 --*/
4913
4914 {
4915 PIO_STACK_LOCATION IrpSp;
4916 NTSTATUS Status;
4917 PVCB Vcb;
4918
4919 PFILE_SYSTEM_STATISTICS Buffer;
4920 ULONG BufferLength;
4921 ULONG StatsSize;
4922 ULONG BytesToCopy;
4923
4924 PAGED_CODE();
4925
4926 IrpSp = IoGetCurrentIrpStackLocation( Irp );
4927
4928 DebugTrace(+1, Dbg, "FatGetStatistics...\n", 0);
4929
4930 //
4931 // Extract the buffer
4932 //
4933
4934 BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
4935
4936 //
4937 // Get a pointer to the output buffer.
4938 //
4939
4940 Buffer = Irp->AssociatedIrp.SystemBuffer;
4941
4942 //
4943 // Make sure the buffer is big enough for at least the common part.
4944 //
4945
4946 if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) {
4947
4948 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
4949
4950 DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
4951
4952 return STATUS_BUFFER_TOO_SMALL;
4953 }
4954
4955 //
4956 // Now see how many bytes we can copy.
4957 //
4958
4959 StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * FatData.NumberProcessors;
4960
4961 if (BufferLength < StatsSize) {
4962
4963 BytesToCopy = BufferLength;
4964 Status = STATUS_BUFFER_OVERFLOW;
4965
4966 } else {
4967
4968 BytesToCopy = StatsSize;
4969 Status = STATUS_SUCCESS;
4970 }
4971
4972 //
4973 // Get the Vcb.
4974 //
4975
4976 Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
4977
4978 //
4979 // Fill in the output buffer
4980 //
4981
4982 RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
4983
4984 Irp->IoStatus.Information = BytesToCopy;
4985
4986 FatCompleteRequest( IrpContext, Irp, Status );
4987
4988 DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", Status);
4989
4990 return Status;
4991 }
4992
4993 //
4994 // Local Support Routine
4995 //
4996
4997 _Requires_lock_held_(_Global_critical_region_)
4998 NTSTATUS
4999 FatGetVolumeBitmap(
5000 IN PIRP_CONTEXT IrpContext,
5001 IN PIRP Irp
5002 )
5003
5004 /*++
5005
5006 Routine Description:
5007
5008 This routine returns the volume allocation bitmap.
5009
5010 Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in
5011 through the input buffer.
5012 Output = the VOLUME_BITMAP_BUFFER data structure is returned through
5013 the output buffer.
5014
5015 We return as much as the user buffer allows starting the specified input
5016 LCN (trucated to a byte). If there is no input buffer, we start at zero.
5017
5018 Arguments:
5019
5020 Irp - Supplies the Irp being processed.
5021
5022 Return Value:
5023
5024 NTSTATUS - The return status for the operation.
5025
5026 --*/
5027 {
5028 NTSTATUS Status;
5029 PIO_STACK_LOCATION IrpSp;
5030
5031 PVCB Vcb;
5032 PFCB Fcb;
5033 PCCB Ccb;
5034
5035 ULONG BytesToCopy;
5036 ULONG TotalClusters;
5037 ULONG DesiredClusters;
5038 ULONG StartingCluster;
5039 ULONG EndingCluster;
5040 ULONG InputBufferLength;
5041 ULONG OutputBufferLength;
5042 LARGE_INTEGER StartingLcn;
5043 PVOLUME_BITMAP_BUFFER OutputBuffer;
5044
5045 PAGED_CODE();
5046
5047 //
5048 // Get the current Irp stack location and save some references.
5049 //
5050
5051 IrpSp = IoGetCurrentIrpStackLocation( Irp );
5052
5053 DebugTrace(+1, Dbg, "FatGetVolumeBitmap, FsControlCode = %08lx\n",
5054 IrpSp->Parameters.FileSystemControl.FsControlCode);
5055
5056 //
5057 // Make this a synchronous IRP because we need access to the input buffer and
5058 // this Irp is marked METHOD_NEITHER.
5059 //
5060
5061 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
5062
5063 //
5064 // Extract and decode the file object and check for type of open.
5065 //
5066
5067 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
5068
5069 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5070 return STATUS_INVALID_PARAMETER;
5071 }
5072
5073 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
5074
5075 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5076
5077 DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> %08lx\n", STATUS_INVALID_PARAMETER);
5078 return STATUS_INVALID_PARAMETER;
5079 }
5080
5081 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
5082 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
5083
5084 OutputBuffer = (PVOLUME_BITMAP_BUFFER)FatMapUserBuffer( IrpContext, Irp );
5085
5086 //
5087 // Check for a minimum length on the input and output buffers.
5088 //
5089
5090 if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) ||
5091 (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) {
5092
5093 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
5094 return STATUS_BUFFER_TOO_SMALL;
5095 }
5096
5097 //
5098 // Check if a starting cluster was specified.
5099 //
5100
5101 TotalClusters = Vcb->AllocationSupport.NumberOfClusters;
5102
5103 //
5104 // Check for valid buffers
5105 //
5106
5107 _SEH2_TRY {
5108
5109 if (Irp->RequestorMode != KernelMode) {
5110
5111 ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
5112 InputBufferLength,
5113 sizeof(UCHAR) );
5114
5115 ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
5116 }
5117
5118 StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn;
5119
5120 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
5121
5122 Status = _SEH2_GetExceptionCode();
5123
5124 FatRaiseStatus( IrpContext,
5125 FsRtlIsNtstatusExpected(Status) ?
5126 Status : STATUS_INVALID_USER_BUFFER );
5127 } _SEH2_END;
5128
5129 if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) {
5130
5131 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5132 return STATUS_INVALID_PARAMETER;
5133
5134 } else {
5135
5136 StartingCluster = StartingLcn.LowPart & ~7;
5137 }
5138
5139 (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
5140
5141 //
5142 // Only return what will fit in the user buffer.
5143 //
5144
5145 OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
5146 DesiredClusters = TotalClusters - StartingCluster;
5147
5148 if (OutputBufferLength < (DesiredClusters + 7) / 8) {
5149
5150 BytesToCopy = OutputBufferLength;
5151 Status = STATUS_BUFFER_OVERFLOW;
5152
5153 } else {
5154
5155 BytesToCopy = (DesiredClusters + 7) / 8;
5156 Status = STATUS_SUCCESS;
5157 }
5158
5159 //
5160 // Use try/finally for cleanup.
5161 //
5162
5163 _SEH2_TRY {
5164
5165 _SEH2_TRY {
5166
5167 //
5168 // Verify the Vcb is still OK
5169 //
5170
5171 FatQuickVerifyVcb( IrpContext, Vcb );
5172
5173 //
5174 // Fill in the fixed part of the output buffer
5175 //
5176
5177 OutputBuffer->StartingLcn.QuadPart = StartingCluster;
5178 OutputBuffer->BitmapSize.QuadPart = DesiredClusters;
5179
5180 if (Vcb->NumberOfWindows == 1) {
5181
5182 //
5183 // Just copy the volume bitmap into the user buffer.
5184 //
5185
5186 NT_ASSERT( Vcb->FreeClusterBitMap.Buffer != NULL );
5187
5188 RtlCopyMemory( &OutputBuffer->Buffer[0],
5189 (PUCHAR)Vcb->FreeClusterBitMap.Buffer + StartingCluster/8,
5190 BytesToCopy );
5191 } else {
5192
5193 //
5194 // Call out to analyze the FAT. We must bias by two to account for
5195 // the zero base of this API and FAT's physical reality of starting
5196 // the file heap at cluster 2.
5197 //
5198 // Note that the end index is inclusive - we need to subtract one to
5199 // calculcate it.
5200 //
5201 // I.e.: StartingCluster 0 for one byte of bitmap means a start cluster
5202 // of 2 and end cluster of 9, a run of eight clusters.
5203 //
5204
5205 EndingCluster = StartingCluster + (BytesToCopy * 8);
5206
5207 //
5208 // Make sure we do not read past the end of the entries.
5209 //
5210
5211 if (EndingCluster > TotalClusters) {
5212
5213 EndingCluster = TotalClusters;
5214 }
5215
5216 FatExamineFatEntries( IrpContext,
5217 Vcb,
5218 StartingCluster + 2,
5219 EndingCluster + 2 - 1,
5220 FALSE,
5221 NULL,
5222 (PULONG)&OutputBuffer->Buffer[0] );
5223 }
5224
5225 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
5226
5227 Status = _SEH2_GetExceptionCode();
5228
5229 FatRaiseStatus( IrpContext,
5230 FsRtlIsNtstatusExpected(Status) ?
5231 Status : STATUS_INVALID_USER_BUFFER );
5232 } _SEH2_END;
5233
5234 } _SEH2_FINALLY {
5235
5236 FatReleaseVcb( IrpContext, Vcb );
5237 } _SEH2_END;
5238
5239 Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) +
5240 BytesToCopy;
5241
5242 FatCompleteRequest( IrpContext, Irp, Status );
5243
5244 DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> VOID\n", 0);
5245
5246 return Status;
5247 }
5248
5249
5250 //
5251 // Local Support Routine
5252 //
5253
5254 _Requires_lock_held_(_Global_critical_region_)
5255 NTSTATUS
5256 FatGetRetrievalPointers (
5257 IN PIRP_CONTEXT IrpContext,
5258 IN PIRP Irp
5259 )
5260
5261 /*++
5262
5263 Routine Description:
5264
5265 This routine scans the MCB and builds an extent list. The first run in
5266 the output extent list will start at the begining of the contiguous
5267 run specified by the input parameter.
5268
5269 Input = STARTING_VCN_INPUT_BUFFER;
5270 Output = RETRIEVAL_POINTERS_BUFFER.
5271
5272 Arguments:
5273
5274 Irp - Supplies the Irp being processed.
5275
5276 Return Value:
5277
5278 NTSTATUS - The return status for the operation.
5279
5280 --*/
5281 {
5282 NTSTATUS Status = STATUS_SUCCESS;
5283 PIO_STACK_LOCATION IrpSp;
5284
5285 PVCB Vcb;
5286 PFCB FcbOrDcb;
5287 PCCB Ccb;
5288 PLARGE_MCB McbToUse = NULL;
5289 TYPE_OF_OPEN TypeOfOpen;
5290
5291 ULONG Index;
5292 ULONG ClusterShift = 0;
5293 ULONG ClusterSize;
5294 LONGLONG AllocationSize = 0;
5295
5296 ULONG Run;
5297 ULONG RunCount;
5298 ULONG StartingRun;
5299 LARGE_INTEGER StartingVcn;
5300
5301 ULONG InputBufferLength;
5302 ULONG OutputBufferLength;
5303
5304 VBO LastVbo;
5305 LBO LastLbo;
5306 ULONG LastIndex;
5307
5308 PRETRIEVAL_POINTERS_BUFFER OutputBuffer;
5309
5310 PAGED_CODE();
5311
5312 //
5313 // Get the current Irp stack location and save some references.
5314 //
5315
5316 IrpSp = IoGetCurrentIrpStackLocation( Irp );
5317
5318 DebugTrace(+1, Dbg, "FatGetRetrievalPointers, FsControlCode = %08lx\n",
5319 IrpSp->Parameters.FileSystemControl.FsControlCode);
5320
5321 //
5322 // Make this a synchronous IRP because we need access to the input buffer and
5323 // this Irp is marked METHOD_NEITHER.
5324 //
5325
5326 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
5327
5328 //
5329 // Extract and decode the file object and check for type of open.
5330 //
5331
5332 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb );
5333
5334 if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen) && (TypeOfOpen != UserVolumeOpen) ) {
5335
5336 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5337 return STATUS_INVALID_PARAMETER;
5338 }
5339
5340 //
5341 // Get the input and output buffer lengths and pointers.
5342 // Initialize some variables.
5343 //
5344
5345 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
5346 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
5347
5348 OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)FatMapUserBuffer( IrpContext, Irp );
5349
5350 //
5351 // Check for a minimum length on the input and ouput buffers.
5352 //
5353
5354 if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) ||
5355 (OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))) {
5356
5357 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
5358 return STATUS_BUFFER_TOO_SMALL;
5359 }
5360
5361 //
5362 // Acquire the Fcb and enqueue the Irp if we didn't get access. Go for
5363 // shared on read-only media so we can allow prototype XIP to get
5364 // recursive, as well as recognizing this is safe anyway.
5365 //
5366 if( (TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen) ) {
5367
5368 if (FlagOn( FcbOrDcb->Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED )) {
5369
5370 (VOID)FatAcquireSharedFcb( IrpContext, FcbOrDcb );
5371
5372 } else {
5373
5374 (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
5375 }
5376 } else if ((TypeOfOpen == UserVolumeOpen )) {
5377
5378 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
5379
5380 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
5381
5382 DebugTrace(-1, Dbg, "FatMoveFile -> 0x%x\n", STATUS_ACCESS_DENIED);
5383 return STATUS_ACCESS_DENIED;
5384 }
5385
5386 (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
5387 }
5388
5389 _SEH2_TRY {
5390
5391 //
5392 // Verify the Fcb is still OK, or if it is a volume handle, the VCB.
5393 //
5394
5395 if( (TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen) ) {
5396
5397 FatVerifyFcb( IrpContext, FcbOrDcb );
5398
5399 //
5400 // If we haven't yet set the correct AllocationSize, do so.
5401 //
5402
5403 if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
5404
5405 FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
5406
5407 //
5408 // If this is a non-root directory, we have a bit more to
5409 // do since it has not gone through FatOpenDirectoryFile().
5410 //
5411
5412 if (NodeType(FcbOrDcb) == FAT_NTC_DCB ||
5413 (NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && FatIsFat32(Vcb))) {
5414
5415 FcbOrDcb->Header.FileSize.LowPart =
5416 FcbOrDcb->Header.AllocationSize.LowPart;
5417 }
5418 }
5419
5420
5421 ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
5422
5423 #ifdef _MSC_VER
5424 #pragma prefast( suppress:28931, "calculate it anyway, in case someone adds code that uses this in the future" )
5425 #endif
5426 ClusterSize = 1 << ClusterShift;
5427
5428 AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
5429 McbToUse = &FcbOrDcb->Mcb;
5430
5431 } else if ((TypeOfOpen == UserVolumeOpen )) {
5432
5433 FatQuickVerifyVcb( IrpContext, Vcb );
5434
5435 if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BAD_BLOCKS_POPULATED)) {
5436
5437 //
5438 // If the bad cluster mcb isn't populated, something is wrong. (It should have been
5439 // populated during mount when we scanned the FAT.
5440 //
5441
5442 FatRaiseStatus(IrpContext, STATUS_FILE_CORRUPT_ERROR );
5443 }
5444
5445 ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
5446 ClusterSize = 1 << ClusterShift;
5447
5448 if (!FatLookupLastMcbEntry(Vcb, &Vcb->BadBlockMcb, &LastVbo, &LastLbo, &LastIndex)) {
5449 AllocationSize = 0;
5450 } else {
5451
5452 //
5453 // Round the allocation size to a multiple of of the cluster size.
5454 //
5455
5456 AllocationSize = (LastVbo + ((LONGLONG)ClusterSize-1)) & ~((LONGLONG)ClusterSize-1);
5457 }
5458
5459 McbToUse = &Vcb->BadBlockMcb;
5460
5461 }
5462
5463 //
5464 // Check if a starting cluster was specified.
5465 //
5466
5467 _SEH2_TRY {
5468
5469 if (Irp->RequestorMode != KernelMode) {
5470
5471 ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
5472 InputBufferLength,
5473 sizeof(UCHAR) );
5474
5475 ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
5476 }
5477
5478 StartingVcn = ((PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingVcn;
5479
5480 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
5481
5482 Status = _SEH2_GetExceptionCode();
5483
5484 FatRaiseStatus( IrpContext,
5485 FsRtlIsNtstatusExpected(Status) ?
5486 Status : STATUS_INVALID_USER_BUFFER );
5487 } _SEH2_END;
5488
5489 if (StartingVcn.HighPart ||
5490 StartingVcn.LowPart >= (AllocationSize >> ClusterShift)) {
5491
5492 try_return( Status = STATUS_END_OF_FILE );
5493
5494 } else {
5495
5496 //
5497 // If we don't find the run, something is very wrong.
5498 //
5499
5500 LBO Lbo;
5501
5502 if (!FatLookupMcbEntry( Vcb, McbToUse,
5503 StartingVcn.LowPart << ClusterShift,
5504 &Lbo,
5505 NULL,
5506 &StartingRun)) {
5507
5508 #ifdef _MSC_VER
5509 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
5510 #endif
5511 FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)McbToUse, StartingVcn.LowPart );
5512 }
5513 }
5514
5515 //
5516 // Now go fill in the ouput buffer with run information
5517 //
5518
5519 RunCount = FsRtlNumberOfRunsInLargeMcb( McbToUse );
5520
5521 for (Index = 0, Run = StartingRun; Run < RunCount; Index++, Run++) {
5522
5523 ULONG Vcn;
5524 LBO Lbo;
5525 ULONG ByteLength;
5526
5527 //
5528 // Check for an exhausted output buffer.
5529 //
5530
5531 if ((ULONG)FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index+1]) > OutputBufferLength) {
5532
5533
5534 //
5535 // We've run out of space, so we won't be storing as many runs to the
5536 // user's buffer as we had originally planned. We need to return the
5537 // number of runs that we did have room for.
5538 //
5539
5540 _SEH2_TRY {
5541
5542 OutputBuffer->ExtentCount = Index;
5543
5544 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
5545
5546 Status = _SEH2_GetExceptionCode();
5547
5548 FatRaiseStatus( IrpContext,
5549 FsRtlIsNtstatusExpected(Status) ?
5550 Status : STATUS_INVALID_USER_BUFFER );
5551 } _SEH2_END;
5552
5553 Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]);
5554 try_return( Status = STATUS_BUFFER_OVERFLOW );
5555 }
5556
5557 //
5558 // Get the extent. If it's not there or malformed, something is very wrong.
5559 //
5560
5561 if (!FatGetNextMcbEntry(Vcb, McbToUse, Run, (PVBO)&Vcn, &Lbo, &ByteLength)) {
5562
5563 #ifdef _MSC_VER
5564 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
5565 #endif
5566 FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)McbToUse, Run );
5567 }
5568
5569 //
5570 // Fill in the next array element.
5571 //
5572
5573 _SEH2_TRY {
5574
5575 OutputBuffer->Extents[Index].NextVcn.QuadPart = ((LONGLONG)Vcn + ByteLength) >> ClusterShift;
5576 OutputBuffer->Extents[Index].Lcn.QuadPart = FatGetIndexFromLbo( Vcb, Lbo ) - 2;
5577
5578 //
5579 // If this is the first run, fill in the starting Vcn
5580 //
5581
5582 if (Index == 0) {
5583 OutputBuffer->ExtentCount = RunCount - StartingRun;
5584 OutputBuffer->StartingVcn.QuadPart = Vcn >> ClusterShift;
5585 }
5586
5587 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
5588
5589 Status = _SEH2_GetExceptionCode();
5590
5591 FatRaiseStatus( IrpContext,
5592 FsRtlIsNtstatusExpected(Status) ?
5593 Status : STATUS_INVALID_USER_BUFFER );
5594 } _SEH2_END;
5595 }
5596
5597 //
5598 // We successfully retrieved extent info to the end of the allocation.
5599 //
5600
5601 Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]);
5602 Status = STATUS_SUCCESS;
5603
5604 try_exit: NOTHING;
5605
5606 } _SEH2_FINALLY {
5607
5608 DebugUnwind( FatGetRetrievalPointers );
5609
5610 //
5611 // Release resources
5612 //
5613
5614 if( (TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen) ) {
5615
5616 FatReleaseFcb( IrpContext, FcbOrDcb );
5617 } else if ((TypeOfOpen == UserVolumeOpen )) {
5618
5619 FatReleaseVcb(IrpContext, Vcb);
5620 }
5621
5622 //
5623 // If nothing raised then complete the irp.
5624 //
5625
5626 if (!_SEH2_AbnormalTermination()) {
5627
5628 FatCompleteRequest( IrpContext, Irp, Status );
5629 }
5630
5631 DebugTrace(-1, Dbg, "FatGetRetrievalPointers -> VOID\n", 0);
5632 } _SEH2_END;
5633
5634 return Status;
5635 }
5636
5637
5638 //
5639 // Local Support Routine
5640 //
5641
5642 _Requires_lock_held_(_Global_critical_region_)
5643 VOID
5644 FatMoveFileNeedsWriteThrough (
5645 _In_ PIRP_CONTEXT IrpContext,
5646 _In_ PFCB FcbOrDcb,
5647 _In_ ULONG OldWriteThroughFlags
5648 )
5649 {
5650 PAGED_CODE();
5651
5652 if (NodeType(FcbOrDcb) == FAT_NTC_FCB) {
5653
5654
5655 if (FcbOrDcb->Header.ValidDataLength.QuadPart == 0) {
5656
5657
5658 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
5659 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH );
5660
5661 } else {
5662
5663 IrpContext->Flags &= ~(IRP_CONTEXT_FLAG_WRITE_THROUGH|IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);
5664 IrpContext->Flags |= OldWriteThroughFlags;
5665
5666 }
5667 }
5668 }
5669
5670 _Requires_lock_held_(_Global_critical_region_)
5671 NTSTATUS
5672 FatMoveFile (
5673 IN PIRP_CONTEXT IrpContext,
5674 IN PIRP Irp
5675 )
5676
5677 /*++
5678
5679 Routine Description:
5680
5681 Routine moves a file to the requested Starting Lcn from Starting Vcn for the length
5682 of cluster count. These values are passed in through the the input buffer as a
5683 MOVE_DATA structure.
5684
5685 The call must be made with a DASD handle. The file to move is passed in as a
5686 parameter.
5687
5688 Arguments:
5689
5690 Irp - Supplies the Irp being processed.
5691
5692 Return Value:
5693
5694 NTSTATUS - The return status for the operation.
5695
5696 --*/
5697
5698 {
5699 NTSTATUS Status;
5700 PIO_STACK_LOCATION IrpSp;
5701
5702 PFILE_OBJECT FileObject;
5703 TYPE_OF_OPEN TypeOfOpen;
5704 PVCB Vcb;
5705 PFCB FcbOrDcb;
5706 PCCB Ccb;
5707
5708 ULONG InputBufferLength;
5709 PMOVE_FILE_DATA InputBuffer;
5710
5711 ULONG ClusterShift;
5712 ULONG MaxClusters;
5713
5714 ULONG FileOffset;
5715
5716 LBO TargetLbo;
5717 ULONG TargetCluster;
5718 LARGE_INTEGER LargeSourceLbo;
5719 LARGE_INTEGER LargeTargetLbo;
5720
5721 ULONG ByteCount;
5722 ULONG BytesToWrite;
5723 ULONG BytesToReallocate;
5724
5725 ULONG FirstSpliceSourceCluster;
5726 ULONG FirstSpliceTargetCluster;
5727 ULONG SecondSpliceSourceCluster;
5728 ULONG SecondSpliceTargetCluster;
5729
5730 LARGE_MCB SourceMcb;
5731 LARGE_MCB TargetMcb;
5732
5733 KEVENT StackEvent;
5734
5735 PVOID Buffer = NULL;
5736 ULONG BufferSize;
5737
5738 BOOLEAN SourceMcbInitialized = FALSE;
5739 BOOLEAN TargetMcbInitialized = FALSE;
5740
5741 BOOLEAN FcbAcquired = FALSE;
5742 BOOLEAN EventArmed = FALSE;
5743 BOOLEAN DiskSpaceAllocated = FALSE;
5744
5745 PDIRENT Dirent;
5746 PBCB DirentBcb = NULL;
5747
5748 ULONG OldWriteThroughFlags = (IrpContext->Flags & (IRP_CONTEXT_FLAG_WRITE_THROUGH|IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH));
5749
5750 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
5751 MOVE_FILE_DATA LocalMoveFileData;
5752 PMOVE_FILE_DATA32 MoveFileData32;
5753 #endif
5754
5755 ULONG LocalAbnormalTermination = 0;
5756
5757 PAGED_CODE();
5758
5759 //
5760 // Get the current Irp stack location and save some references.
5761 //
5762
5763 IrpSp = IoGetCurrentIrpStackLocation( Irp );
5764
5765 DebugTrace(+1, Dbg, "FatMoveFile, FsControlCode = %08lx\n",
5766 IrpSp->Parameters.FileSystemControl.FsControlCode);
5767
5768 //
5769 // Force WAIT to true. We have a handle in the input buffer which can only
5770 // be referenced within the originating process.
5771 //
5772
5773 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
5774
5775 //
5776 // Extract and decode the file object and check for type of open.
5777 //
5778
5779 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ) != UserVolumeOpen) {
5780
5781 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5782
5783 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
5784 return STATUS_INVALID_PARAMETER;
5785 }
5786
5787 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
5788
5789 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5790
5791 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
5792 return STATUS_INVALID_PARAMETER;
5793 }
5794
5795 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
5796 InputBuffer = (PMOVE_FILE_DATA)Irp->AssociatedIrp.SystemBuffer;
5797
5798 //
5799 // Do a quick check on the input buffer.
5800 //
5801
5802 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
5803 if (IoIs32bitProcess( Irp )) {
5804
5805 if (InputBuffer == NULL || InputBufferLength < sizeof(MOVE_FILE_DATA32)) {
5806
5807 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
5808 return STATUS_BUFFER_TOO_SMALL;
5809 }
5810
5811 MoveFileData32 = (PMOVE_FILE_DATA32) InputBuffer;
5812
5813 LocalMoveFileData.FileHandle = (HANDLE) LongToHandle( MoveFileData32->FileHandle );
5814 LocalMoveFileData.StartingVcn = MoveFileData32->StartingVcn;
5815 LocalMoveFileData.StartingLcn = MoveFileData32->StartingLcn;
5816 LocalMoveFileData.ClusterCount = MoveFileData32->ClusterCount;
5817
5818 InputBuffer = &LocalMoveFileData;
5819
5820 } else {
5821 #endif
5822 if (InputBuffer == NULL || InputBufferLength < sizeof(MOVE_FILE_DATA)) {
5823
5824 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
5825 return STATUS_BUFFER_TOO_SMALL;
5826 }
5827 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
5828 }
5829 #endif
5830
5831 MaxClusters = Vcb->AllocationSupport.NumberOfClusters;
5832 TargetCluster = InputBuffer->StartingLcn.LowPart + 2;
5833
5834 if (InputBuffer->StartingVcn.HighPart ||
5835 InputBuffer->StartingLcn.HighPart ||
5836 (TargetCluster < 2) ||
5837 (TargetCluster + InputBuffer->ClusterCount < TargetCluster) ||
5838 (TargetCluster + InputBuffer->ClusterCount > MaxClusters + 2) ||
5839 (InputBuffer->StartingVcn.LowPart >= MaxClusters) ||
5840 InputBuffer->ClusterCount == 0
5841 ) {
5842
5843 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5844
5845 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
5846 return STATUS_INVALID_PARAMETER;
5847 }
5848
5849 //
5850 // Try to get a pointer to the file object from the handle passed in.
5851 //
5852
5853 Status = ObReferenceObjectByHandle( InputBuffer->FileHandle,
5854 0,
5855 *IoFileObjectType,
5856 Irp->RequestorMode,
5857 #ifndef __REACTOS__
5858 &FileObject,
5859 #else
5860 (PVOID *)&FileObject,
5861 #endif
5862 NULL );
5863
5864 if (!NT_SUCCESS(Status)) {
5865
5866 FatCompleteRequest( IrpContext, Irp, Status );
5867
5868 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", Status);
5869 return Status;
5870 }
5871
5872 //
5873 // There are three basic ways this could be an invalid attempt, so
5874 // we need to
5875 //
5876 // - check that this file object is opened on the same volume as the
5877 // DASD handle used to call this routine.
5878 //
5879 // - extract and decode the file object and check for type of open.
5880 //
5881 // - if this is a directory, verify that it's not the root and that
5882 // we are not trying to move the first cluster. We cannot move the
5883 // first cluster because sub-directories have this cluster number
5884 // in them and there is no safe way to simultaneously update them
5885 // all.
5886 //
5887 // We'll allow movefile on the root dir if its fat32, since the root dir
5888 // is a real chained file there.
5889 //
5890
5891 if (FileObject->Vpb != Vcb->Vpb) {
5892
5893 ObDereferenceObject( FileObject );
5894 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5895
5896 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
5897 return STATUS_INVALID_PARAMETER;
5898 }
5899
5900 TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &FcbOrDcb, &Ccb );
5901
5902 if ((TypeOfOpen != UserFileOpen &&
5903 TypeOfOpen != UserDirectoryOpen) ||
5904
5905 ((TypeOfOpen == UserDirectoryOpen) &&
5906 ((NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && !FatIsFat32(Vcb)) ||
5907 (InputBuffer->StartingVcn.QuadPart == 0)))) {
5908
5909 ObDereferenceObject( FileObject );
5910 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
5911
5912 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
5913 return STATUS_INVALID_PARAMETER;
5914 }
5915
5916 //
5917 // If the VDL of the file is zero, it has no valid data in it anyway.
5918 // So it should be safe to avoid flushing the FAT entries and let them be
5919 // lazily written out.
5920 //
5921 // This is done so that bitlocker's cover file doesn't cause
5922 // unnecessary FAT table I/O when it's moved around.
5923 // (See Win8 bug 106505)
5924 //
5925
5926 //
5927 // If this is a file, and the VDL is zero, clear write through.
5928 //
5929
5930 FatMoveFileNeedsWriteThrough(IrpContext, FcbOrDcb, OldWriteThroughFlags);
5931
5932
5933 //
5934 // Indicate we're getting to parents of this fcb by their child, and that
5935 // this is a sufficient assertion of our ability to by synchronized
5936 // with respect to the parent directory going away.
5937 //
5938 // The defrag path is an example of one which arrives at an Fcb by
5939 // a means which would be unreasonable to duplicate in the assertion
5940 // code. See FatOpenDirectoryFile.
5941 //
5942
5943 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD );
5944
5945 ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
5946
5947 _SEH2_TRY {
5948
5949 //
5950 // Initialize our state variables and the event.
5951 //
5952
5953 FileOffset = InputBuffer->StartingVcn.LowPart << ClusterShift;
5954
5955 ByteCount = InputBuffer->ClusterCount << ClusterShift;
5956
5957 TargetLbo = FatGetLboFromIndex( Vcb, TargetCluster );
5958 LargeTargetLbo.QuadPart = TargetLbo;
5959
5960 Buffer = NULL;
5961
5962 //
5963 // Do a quick check on parameters here
5964 //
5965
5966 if (FileOffset + ByteCount < FileOffset) {
5967
5968 try_return( Status = STATUS_INVALID_PARAMETER );
5969 }
5970
5971 KeInitializeEvent( &StackEvent, NotificationEvent, FALSE );
5972
5973 //
5974 // Initialize two MCBs we will be using
5975 //
5976
5977 FsRtlInitializeLargeMcb( &SourceMcb, PagedPool );
5978 SourceMcbInitialized = TRUE;
5979
5980 FsRtlInitializeLargeMcb( &TargetMcb, PagedPool );
5981 TargetMcbInitialized = TRUE;
5982
5983 //
5984 // Ok, now if this is a directory open we need to switch to the internal
5985 // stream fileobject since it is set up for caching. The top-level
5986 // fileobject has no section object pointers in order prevent folks from
5987 // mapping it.
5988 //
5989
5990 if (TypeOfOpen == UserDirectoryOpen) {
5991
5992 PFILE_OBJECT DirStreamFileObject;
5993
5994 //
5995 // Open the stream fileobject if neccesary. We must acquire the Fcb
5996 // now to synchronize with other operations (such as dismount ripping
5997 // apart the allocator).
5998 //
5999
6000 (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
6001 FcbAcquired = TRUE;
6002
6003 FatVerifyFcb( IrpContext, FcbOrDcb );
6004
6005 FatOpenDirectoryFile( IrpContext, FcbOrDcb );
6006 DirStreamFileObject = FcbOrDcb->Specific.Dcb.DirectoryFile;
6007
6008 //
6009 // Transfer our reference to the internal stream and proceed. Note that
6010 // if we dereferenced first, the user could sneak a teardown through since
6011 // we'd have no references.
6012 //
6013
6014 ObReferenceObject( DirStreamFileObject );
6015 ObDereferenceObject( FileObject );
6016 FileObject = DirStreamFileObject;
6017
6018 //
6019 // We've referenced the DirStreamFileObject, so it should be ok to drop
6020 // the Dcb now.
6021 //
6022
6023 FatReleaseFcb( IrpContext, FcbOrDcb );
6024 FcbAcquired = FALSE;
6025 }
6026
6027 //
6028 // Determine the size of the buffer we will use to move data.
6029 //
6030
6031 BufferSize = FAT_DEFAULT_DEFRAG_CHUNK_IN_BYTES;
6032
6033 if (BufferSize < (ULONG)(1 << ClusterShift)) {
6034
6035 BufferSize = (1 << ClusterShift);
6036 }
6037
6038 while (ByteCount) {
6039
6040 VBO TempVbo;
6041 LBO TempLbo;
6042 ULONG TempByteCount;
6043
6044 //
6045 // We must throttle our writes.
6046 //
6047
6048 CcCanIWrite( FileObject,
6049 BufferSize,
6050 TRUE,
6051 FALSE );
6052
6053 //
6054 // Aqcuire file resource exclusive to freeze FileSize and block
6055 // user non-cached I/O. Verify the integrity of the fcb - the
6056 // media may have changed (or been dismounted) on us.
6057 //
6058
6059 if (FcbAcquired == FALSE) {
6060
6061 (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
6062 FcbAcquired = TRUE;
6063
6064 FatVerifyFcb( IrpContext, FcbOrDcb );
6065 }
6066
6067 //
6068 // Check if the handle indicates we're allowed to move the file.
6069 //
6070 // FCB_STATE_DENY_DEFRAG indicates that someone blocked move file on this FCB.
6071 // CCB_FLAG_DENY_DEFRAG indicates that this handle was the one that blocked move file, and hence
6072 // it still gets to move the file around.
6073 //
6074
6075 if ((FcbOrDcb->FcbState & FCB_STATE_DENY_DEFRAG) && !(Ccb->Flags & CCB_FLAG_DENY_DEFRAG)) {
6076 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_ACCESS_DENIED);
6077 try_return( Status = STATUS_ACCESS_DENIED );
6078 }
6079
6080 //
6081 // Allocate our buffer, if we need to.
6082 //
6083
6084 if (Buffer == NULL) {
6085
6086 Buffer = FsRtlAllocatePoolWithTag( NonPagedPoolNx,
6087 BufferSize,
6088 TAG_DEFRAG_BUFFER );
6089 }
6090
6091 //
6092 // Analyzes the range of file allocation we are moving
6093 // and determines the actual amount of allocation to be
6094 // moved and how much needs to be written. In addition
6095 // it guarantees that the Mcb in the file is large enough
6096 // so that later MCB operations cannot fail.
6097 //
6098
6099 FatComputeMoveFileParameter( IrpContext,
6100 FcbOrDcb,
6101 BufferSize,
6102 FileOffset,
6103 &ByteCount,
6104 &BytesToReallocate,
6105 &BytesToWrite,
6106 &LargeSourceLbo );
6107
6108 //
6109 // If ByteCount comes back zero, break here.
6110 //
6111
6112 if (ByteCount == 0) {
6113 break;
6114 }
6115
6116 //
6117 // At this point (before actually doing anything with the disk
6118 // meta data), calculate the FAT splice clusters and build an
6119 // MCB describing the space to be deallocated.
6120 //
6121
6122 FatComputeMoveFileSplicePoints( IrpContext,
6123 FcbOrDcb,
6124 FileOffset,
6125 TargetCluster,
6126 BytesToReallocate,
6127 &FirstSpliceSourceCluster,
6128 &FirstSpliceTargetCluster,
6129 &SecondSpliceSourceCluster,
6130 &SecondSpliceTargetCluster,
6131 &SourceMcb );
6132
6133 //
6134 // Now attempt to allocate the new disk storage using the
6135 // Target Lcn as a hint.
6136 //
6137
6138 TempByteCount = BytesToReallocate;
6139 FatAllocateDiskSpace( IrpContext,
6140 Vcb,
6141 TargetCluster,
6142 &TempByteCount,
6143 TRUE,
6144 &TargetMcb );
6145
6146 DiskSpaceAllocated = TRUE;
6147
6148 //
6149 // If we didn't get EXACTLY what we wanted, return immediately.
6150 //
6151
6152 if ((FsRtlNumberOfRunsInLargeMcb( &TargetMcb ) != 1) ||
6153 !FatGetNextMcbEntry( Vcb, &TargetMcb, 0, &TempVbo, &TempLbo, &TempByteCount ) ||
6154 (FatGetIndexFromLbo( Vcb, TempLbo) != TargetCluster ) ||
6155 (TempByteCount != BytesToReallocate)) {
6156
6157 //
6158 // It would be nice if we could be more specific, but such is life.
6159 //
6160 try_return( Status = STATUS_INVALID_PARAMETER );
6161 }
6162
6163 #if DBG
6164 //
6165 // We are going to attempt a move, note it.
6166 //
6167
6168 if (FatMoveFileDebug) {
6169 DbgPrint("0x%p: Vcn 0x%lx, Lcn 0x%lx, Count 0x%lx.\n",
6170 PsGetCurrentThread(),
6171 FileOffset >> ClusterShift,
6172 TargetCluster,
6173 BytesToReallocate >> ClusterShift );
6174 }
6175 #endif
6176
6177 //
6178 // Now attempt to commit the new allocation to disk. If this
6179 // raises, the allocation will be deallocated.
6180 //
6181 // If the VDL of the file is zero, it has no valid data in it anyway.
6182 // So it should be safe to avoid flushing the FAT entries and let them be
6183 // lazily written out.
6184 //
6185 // This is done so that bitlocker's cover file doesn't cause
6186 // unnecessary FAT table I/O when it's moved around.
6187 // (See Win8 bug 106505)
6188 //
6189
6190 if ((FcbOrDcb->Header.ValidDataLength.QuadPart != 0) || (NodeType(FcbOrDcb) != FAT_NTC_FCB)) {
6191
6192 FatFlushFatEntries( IrpContext,
6193 Vcb,
6194 TargetCluster,
6195 BytesToReallocate >> ClusterShift );
6196 }
6197
6198 //
6199 // Aqcuire both resources exclusive now, guaranteeing that NOBODY
6200 // is in either the read or write paths.
6201 //
6202
6203 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
6204
6205 //
6206 // This is the first part of some tricky synchronization.
6207 //
6208 // Set the Event pointer in the FCB. Any paging I/O will block on
6209 // this event (if set in FCB) after acquiring the PagingIo resource.
6210 //
6211 // This is how I keep ALL I/O out of this path without holding the
6212 // PagingIo resource exclusive for an extended time.
6213 //
6214
6215 FcbOrDcb->MoveFileEvent = &StackEvent;
6216 EventArmed = TRUE;
6217
6218 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
6219
6220 //
6221 // Now write out the data, but only if we have to. We don't have
6222 // to copy any file data if the range being reallocated is wholly
6223 // beyond valid data length.
6224 //
6225
6226 if (BytesToWrite) {
6227
6228 PIRP IoIrp;
6229 KEVENT IoEvent;
6230 IO_STATUS_BLOCK Iosb;
6231
6232 KeInitializeEvent( &IoEvent,
6233 NotificationEvent,
6234 FALSE );
6235
6236 NT_ASSERT( LargeTargetLbo.QuadPart >= Vcb->AllocationSupport.FileAreaLbo );
6237
6238 //
6239 // Read in the data that is being moved.
6240 //
6241
6242 IoIrp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
6243 Vcb->TargetDeviceObject,
6244 Buffer,
6245 BytesToWrite,
6246 &LargeSourceLbo,
6247 &IoEvent,
6248 &Iosb );
6249
6250 if (IoIrp == NULL) {
6251
6252 FatRaiseStatus( IrpContext,
6253 STATUS_INSUFFICIENT_RESOURCES );
6254 }
6255
6256 Status = IoCallDriver( Vcb->TargetDeviceObject, IoIrp );
6257
6258 if (Status == STATUS_PENDING) {
6259
6260 (VOID)KeWaitForSingleObject( &IoEvent,
6261 Executive,
6262 KernelMode,
6263 FALSE,
6264 (PLARGE_INTEGER)NULL );
6265
6266 Status = Iosb.Status;
6267 }
6268
6269 if (!NT_SUCCESS( Status )) {
6270
6271 FatNormalizeAndRaiseStatus( IrpContext,
6272 Status );
6273 }
6274
6275 //
6276 // Write the data to its new location.
6277 //
6278
6279 KeClearEvent( &IoEvent );
6280
6281 IoIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE,
6282 Vcb->TargetDeviceObject,
6283 Buffer,
6284 BytesToWrite,
6285 &LargeTargetLbo,
6286 &IoEvent,
6287 &Iosb );
6288
6289 if (IoIrp == NULL) {
6290
6291 FatRaiseStatus( IrpContext,
6292 STATUS_INSUFFICIENT_RESOURCES );
6293 }
6294
6295 //
6296 // Set a flag indicating that we want to write through any
6297 // cache on the controller. This eliminates the need for
6298 // an explicit flush-device after the write.
6299 //
6300
6301 SetFlag( IoGetNextIrpStackLocation(IoIrp)->Flags, SL_WRITE_THROUGH );
6302
6303 Status = IoCallDriver( Vcb->TargetDeviceObject, IoIrp );
6304
6305 if (Status == STATUS_PENDING) {
6306
6307 (VOID)KeWaitForSingleObject( &IoEvent,
6308 Executive,
6309 KernelMode,
6310 FALSE,
6311 (PLARGE_INTEGER)NULL );
6312
6313 Status = Iosb.Status;
6314 }
6315
6316 if (!NT_SUCCESS( Status )) {
6317
6318 FatNormalizeAndRaiseStatus( IrpContext,
6319 Status );
6320 }
6321 }
6322
6323 //
6324 // Now that the file data has been moved successfully, we'll go
6325 // to fix up the links in the FAT table and perhaps change the
6326 // entry in the parent directory.
6327 //
6328 // First we'll do the second splice and commit it. At that point,
6329 // while the volume is in an inconsistent state, the file is
6330 // still OK.
6331 //
6332
6333 FatSetFatEntry( IrpContext,
6334 Vcb,
6335 SecondSpliceSourceCluster,
6336 (FAT_ENTRY)SecondSpliceTargetCluster );
6337
6338 if ((FcbOrDcb->Header.ValidDataLength.QuadPart != 0) || (NodeType(FcbOrDcb) != FAT_NTC_FCB)) {
6339
6340 FatFlushFatEntries( IrpContext, Vcb, SecondSpliceSourceCluster, 1 );
6341 }
6342
6343 //
6344 // Now do the first splice OR update the dirent in the parent
6345 // and flush the respective object. After this flush the file
6346 // now points to the new allocation.
6347 //
6348
6349 if (FirstSpliceSourceCluster == 0) {
6350
6351 NT_ASSERT( NodeType(FcbOrDcb) == FAT_NTC_FCB );
6352
6353 //
6354 // We are moving the first cluster of the file, so we need
6355 // to update our parent directory.
6356 //
6357
6358 FatGetDirentFromFcbOrDcb( IrpContext,
6359 FcbOrDcb,
6360 FALSE,
6361 &Dirent,
6362 &DirentBcb );
6363
6364 Dirent->FirstClusterOfFile = (USHORT)FirstSpliceTargetCluster;
6365
6366 if (FatIsFat32(Vcb)) {
6367
6368 Dirent->FirstClusterOfFileHi =
6369 (USHORT)(FirstSpliceTargetCluster >> 16);
6370
6371 }
6372
6373 FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
6374
6375 FatUnpinBcb( IrpContext, DirentBcb );
6376 DirentBcb = NULL;
6377
6378 FatFlushDirentForFile( IrpContext, FcbOrDcb );
6379
6380 FcbOrDcb->FirstClusterOfFile = FirstSpliceTargetCluster;
6381
6382 } else {
6383
6384 FatSetFatEntry( IrpContext,
6385 Vcb,
6386 FirstSpliceSourceCluster,
6387 (FAT_ENTRY)FirstSpliceTargetCluster );
6388
6389 if ((FcbOrDcb->Header.ValidDataLength.QuadPart != 0) || (NodeType(FcbOrDcb) != FAT_NTC_FCB)) {
6390
6391 FatFlushFatEntries( IrpContext, Vcb, FirstSpliceSourceCluster, 1 );
6392 }
6393 }
6394
6395 //
6396 // This was successfully committed. We no longer want to free
6397 // this allocation on error.
6398 //
6399
6400 DiskSpaceAllocated = FALSE;
6401
6402 //
6403 // Check if we need to turn off write through for this file.
6404 //
6405
6406 FatMoveFileNeedsWriteThrough(IrpContext, FcbOrDcb, OldWriteThroughFlags);
6407
6408 //
6409 // Now we just have to free the orphaned space. We don't have
6410 // to commit this right now as the integrity of the file doesn't
6411 // depend on it.
6412 //
6413
6414 FatDeallocateDiskSpace( IrpContext, Vcb, &SourceMcb, FALSE );
6415
6416 FatUnpinRepinnedBcbs( IrpContext );
6417
6418 Status = FatHijackIrpAndFlushDevice( IrpContext,
6419 Irp,
6420 Vcb->TargetDeviceObject );
6421
6422 if (!NT_SUCCESS(Status)) {
6423 FatNormalizeAndRaiseStatus( IrpContext, Status );
6424 }
6425
6426 //
6427 // Finally we must replace the old MCB extent information with
6428 // the new. If this fails from pool allocation, we fix it in
6429 // the finally clause by resetting the file's Mcb.
6430 //
6431
6432 FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb,
6433 FileOffset,
6434 BytesToReallocate );
6435
6436 FatAddMcbEntry( Vcb, &FcbOrDcb->Mcb,
6437 FileOffset,
6438 TargetLbo,
6439 BytesToReallocate );
6440
6441 //
6442 // Now this is the second part of the tricky synchronization.
6443 //
6444 // We drop the paging I/O here and signal the notification
6445 // event which allows all waiters (present or future) to proceed.
6446 // Then we block again on the PagingIo exclusive. When
6447 // we have it, we again know that there can be nobody in the
6448 // read/write path and thus nobody touching the event, so we
6449 // NULL the pointer to it and then drop the PagingIo resource.
6450 //
6451 // This combined with our synchronization before the write above
6452 // guarantees that while we were moving the allocation, there
6453 // was no other I/O to this file and because we do not hold
6454 // the paging resource across a flush, we are not exposed to
6455 // a deadlock.
6456 //
6457
6458 KeSetEvent( &StackEvent, 0, FALSE );
6459
6460 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
6461
6462 FcbOrDcb->MoveFileEvent = NULL;
6463 EventArmed = FALSE;
6464
6465 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
6466
6467 //
6468 // Release the resources and let anyone else access the file before
6469 // looping back.
6470 //
6471
6472 FatReleaseFcb( IrpContext, FcbOrDcb );
6473 FcbAcquired = FALSE;
6474
6475 //
6476 // Advance the state variables.
6477 //
6478
6479 TargetCluster += BytesToReallocate >> ClusterShift;
6480
6481 FileOffset += BytesToReallocate;
6482 TargetLbo += BytesToReallocate;
6483 ByteCount -= BytesToReallocate;
6484
6485 LargeTargetLbo.QuadPart += BytesToReallocate;
6486
6487 //
6488 // Clear the two Mcbs
6489 //
6490
6491 FatRemoveMcbEntry( Vcb, &SourceMcb, 0, 0xFFFFFFFF );
6492 FatRemoveMcbEntry( Vcb, &TargetMcb, 0, 0xFFFFFFFF );
6493
6494 //
6495 // Make the event blockable again.
6496 //
6497
6498 KeClearEvent( &StackEvent );
6499 }
6500
6501 Status = STATUS_SUCCESS;
6502
6503 try_exit: NOTHING;
6504
6505 } _SEH2_FINALLY {
6506
6507 DebugUnwind( FatMoveFile );
6508
6509 LocalAbnormalTermination |= _SEH2_AbnormalTermination();
6510
6511 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD );
6512
6513 //
6514 // Free the data buffer, if it was allocated.
6515 //
6516
6517 if (Buffer != NULL) {
6518
6519 ExFreePool( Buffer );
6520 }
6521
6522 //
6523 // Use a nested try-finally for cleanup if our unpinrepinned
6524 // encounters write-through errors. This may even be a re-raise.
6525 //
6526
6527 _SEH2_TRY {
6528
6529 //
6530 // If we have some new allocation hanging around, remove it. The
6531 // pages needed to do this are guaranteed to be resident because
6532 // we have already repinned them.
6533 //
6534
6535 if (DiskSpaceAllocated) {
6536 FatDeallocateDiskSpace( IrpContext, Vcb, &TargetMcb, FALSE );
6537 FatUnpinRepinnedBcbs( IrpContext );
6538 }
6539
6540 } _SEH2_FINALLY {
6541
6542 LocalAbnormalTermination |= _SEH2_AbnormalTermination();
6543
6544 //
6545 // Check on the directory Bcb
6546 //
6547
6548 if (DirentBcb != NULL) {
6549 FatUnpinBcb( IrpContext, DirentBcb );
6550 }
6551
6552 //
6553 // Uninitialize our MCBs
6554 //
6555
6556 if (SourceMcbInitialized) {
6557 FsRtlUninitializeLargeMcb( &SourceMcb );
6558 }
6559
6560 if (TargetMcbInitialized) {
6561 FsRtlUninitializeLargeMcb( &TargetMcb );
6562 }
6563
6564 //
6565 // If this is an abnormal termination then presumably something
6566 // bad happened. Set the Allocation size to unknown and clear
6567 // the Mcb, but only if we still own the Fcb.
6568 //
6569 // It is important to make sure we use a 64bit form of -1. This is
6570 // what will convince the fastIO path that it cannot extend the file
6571 // in the cache until we have picked up the mapping pairs again.
6572 //
6573 // Also, we have to do this while owning PagingIo or we can tear the
6574 // Mcb down in the midst of the noncached IO path looking up extents
6575 // (after we drop it and let them all in).
6576 //
6577
6578 if (LocalAbnormalTermination && FcbAcquired) {
6579
6580 if (FcbOrDcb->FirstClusterOfFile == 0) {
6581
6582 FcbOrDcb->Header.AllocationSize.QuadPart = 0;
6583
6584 } else {
6585
6586 FcbOrDcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
6587 }
6588
6589 FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
6590 }
6591
6592 //
6593 // If we broke out of the loop with the Event armed, defuse it
6594 // in the same way we do it after a write.
6595 //
6596
6597 if (EventArmed) {
6598 KeSetEvent( &StackEvent, 0, FALSE );
6599 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
6600 FcbOrDcb->MoveFileEvent = NULL;
6601 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
6602 }
6603
6604 //
6605 // Finally release the main file resource.
6606 //
6607
6608 if (FcbAcquired) {
6609
6610 FatReleaseFcb( IrpContext, FcbOrDcb );
6611 }
6612
6613 //
6614 // Now dereference the fileobject. If the user was a wacko they could have
6615 // tried to nail us by closing the handle right after they threw this move
6616 // down, so we had to keep the fileobject referenced across the entire
6617 // operation.
6618 //
6619
6620 ObDereferenceObject( FileObject );
6621
6622 } _SEH2_END;
6623 } _SEH2_END;
6624
6625 //
6626 // Complete the irp if we terminated normally.
6627 //
6628
6629 FatCompleteRequest( IrpContext, Irp, Status );
6630
6631 return Status;
6632 }
6633
6634
6635 //
6636 // Local Support Routine
6637 //
6638
6639 _Requires_lock_held_(_Global_critical_region_)
6640 VOID
6641 FatComputeMoveFileParameter (
6642 IN PIRP_CONTEXT IrpContext,
6643 IN PFCB FcbOrDcb,
6644 IN ULONG BufferSize,
6645 IN ULONG FileOffset,
6646 IN OUT PULONG ByteCount,
6647 OUT PULONG BytesToReallocate,
6648 OUT PULONG BytesToWrite,
6649 OUT PLARGE_INTEGER SourceLbo
6650 )
6651
6652 /*++
6653
6654 Routine Description:
6655
6656 This is a helper routine for FatMoveFile that analyses the range of
6657 file allocation we are moving and determines the actual amount
6658 of allocation to be moved and how much needs to be written.
6659
6660 Arguments:
6661
6662 FcbOrDcb - Supplies the file and its various sizes.
6663
6664 BufferSize - Supplies the size of the buffer we are using to store the data
6665 being moved.
6666
6667 FileOffset - Supplies the beginning Vbo of the reallocation zone.
6668
6669 ByteCount - Supplies the request length to reallocate. This will
6670 be bounded by allocation size on return.
6671
6672 BytesToReallocate - Receives ByteCount bounded by the file allocation size
6673 and buffer size.
6674
6675 BytesToWrite - Receives BytesToReallocate bounded by ValidDataLength.
6676
6677 SourceLbo - Receives the logical byte offset of the source data on the volume.
6678
6679 Return Value:
6680
6681 VOID
6682
6683 --*/
6684
6685 {
6686 ULONG ClusterSize;
6687
6688 ULONG AllocationSize;
6689 ULONG ValidDataLength;
6690 ULONG ClusterAlignedVDL;
6691 LBO RunLbo;
6692 ULONG RunByteCount;
6693 ULONG RunIndex;
6694 BOOLEAN RunAllocated;
6695 BOOLEAN RunEndOnMax;
6696
6697 PAGED_CODE();
6698
6699 //
6700 // If we haven't yet set the correct AllocationSize, do so.
6701 //
6702
6703 if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
6704
6705 FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
6706
6707 //
6708 // If this is a non-root directory, we have a bit more to
6709 // do since it has not gone through FatOpenDirectoryFile().
6710 //
6711
6712 if (NodeType(FcbOrDcb) == FAT_NTC_DCB ||
6713 (NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && FatIsFat32(FcbOrDcb->Vcb))) {
6714
6715 FcbOrDcb->Header.FileSize.LowPart =
6716 FcbOrDcb->Header.AllocationSize.LowPart;
6717 }
6718 }
6719
6720 //
6721 // Get the number of bytes left to write and ensure that it does
6722 // not extend beyond allocation size. We return here if FileOffset
6723 // is beyond AllocationSize which can happn on a truncation.
6724 //
6725
6726 AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
6727 ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
6728
6729 if (FileOffset + *ByteCount > AllocationSize) {
6730
6731 if (FileOffset >= AllocationSize) {
6732 *ByteCount = 0;
6733 *BytesToReallocate = 0;
6734 *BytesToWrite = 0;
6735
6736 return;
6737 }
6738
6739 *ByteCount = AllocationSize - FileOffset;
6740 }
6741
6742 //
6743 // If there is more than our max, then reduce the byte count for this
6744 // pass to our maximum. We must also align the file offset to a
6745 // buffer size byte boundary.
6746 //
6747
6748 if ((FileOffset & (BufferSize - 1)) + *ByteCount > BufferSize) {
6749
6750 *BytesToReallocate = BufferSize - (FileOffset & (BufferSize - 1));
6751
6752 } else {
6753
6754 *BytesToReallocate = *ByteCount;
6755 }
6756
6757 //
6758 // Find where this data exists on the volume.
6759 //
6760
6761 FatLookupFileAllocation( IrpContext,
6762 FcbOrDcb,
6763 FileOffset,
6764 &RunLbo,
6765 &RunByteCount,
6766 &RunAllocated,
6767 &RunEndOnMax,
6768 &RunIndex );
6769
6770 NT_ASSERT( RunAllocated );
6771
6772 //
6773 // Limit this run to the contiguous length.
6774 //
6775
6776 if (RunByteCount < *BytesToReallocate) {
6777
6778 *BytesToReallocate = RunByteCount;
6779 }
6780
6781 //
6782 // Set the starting offset of the source.
6783 //
6784
6785 SourceLbo->QuadPart = RunLbo;
6786
6787 //
6788 // We may be able to skip some (or all) of the write
6789 // if allocation size is significantly greater than valid data length.
6790 //
6791
6792 ClusterSize = 1 << FcbOrDcb->Vcb->AllocationSupport.LogOfBytesPerCluster;
6793
6794 NT_ASSERT( ClusterSize <= BufferSize );
6795
6796 ClusterAlignedVDL = (ValidDataLength + (ClusterSize - 1)) & ~(ClusterSize - 1);
6797
6798 if ((NodeType(FcbOrDcb) == FAT_NTC_FCB) &&
6799 (FileOffset + *BytesToReallocate > ClusterAlignedVDL)) {
6800
6801 if (FileOffset > ClusterAlignedVDL) {
6802
6803 *BytesToWrite = 0;
6804
6805 } else {
6806
6807 *BytesToWrite = ClusterAlignedVDL - FileOffset;
6808 }
6809
6810 } else {
6811
6812 *BytesToWrite = *BytesToReallocate;
6813 }
6814 }
6815
6816
6817 //
6818 // Local Support Routine
6819 //
6820
6821 VOID
6822 FatComputeMoveFileSplicePoints (
6823 IN PIRP_CONTEXT IrpContext,
6824 IN PFCB FcbOrDcb,
6825 IN ULONG FileOffset,
6826 IN ULONG TargetCluster,
6827 IN ULONG BytesToReallocate,
6828 OUT PULONG FirstSpliceSourceCluster,
6829 OUT PULONG FirstSpliceTargetCluster,
6830 OUT PULONG SecondSpliceSourceCluster,
6831 OUT PULONG SecondSpliceTargetCluster,
6832 IN OUT PLARGE_MCB SourceMcb
6833 )
6834
6835 /*++
6836
6837 Routine Description:
6838
6839 This is a helper routine for FatMoveFile that analyzes the range of
6840 file allocation we are moving and generates the splice points in the
6841 FAT table.
6842
6843 Arguments:
6844
6845 FcbOrDcb - Supplies the file and thus Mcb.
6846
6847 FileOffset - Supplies the beginning Vbo of the reallocation zone.
6848
6849 TargetCluster - Supplies the beginning cluster of the reallocation target.
6850
6851 BytesToReallocate - Suppies the length of the reallocation zone.
6852
6853 FirstSpliceSourceCluster - Receives the last cluster in previous allocation
6854 or zero if we are reallocating from VBO 0.
6855
6856 FirstSpliceTargetCluster - Receives the target cluster (i.e. new allocation)
6857
6858 SecondSpliceSourceCluster - Receives the final target cluster.
6859
6860 SecondSpliceTargetCluster - Receives the first cluster of the remaining
6861 source allocation or FAT_CLUSTER_LAST if the reallocation zone
6862 extends to the end of the file.
6863
6864 SourceMcb - This supplies an MCB that will be filled in with run
6865 information describing the file allocation being replaced. The Mcb
6866 must be initialized by the caller.
6867
6868 Return Value:
6869
6870 VOID
6871
6872 --*/
6873
6874 {
6875 VBO SourceVbo;
6876 LBO SourceLbo;
6877 ULONG SourceIndex;
6878 ULONG SourceBytesInRun;
6879 ULONG SourceBytesRemaining;
6880
6881 ULONG SourceMcbVbo = 0;
6882 ULONG SourceMcbBytesInRun = 0;
6883
6884 PVCB Vcb;
6885 BOOLEAN Result;
6886
6887 PAGED_CODE();
6888
6889 Vcb = FcbOrDcb->Vcb;
6890
6891 //
6892 // Get information on the final cluster in the previous allocation and
6893 // prepare to enumerate it in the follow loop.
6894 //
6895
6896 if (FileOffset == 0) {
6897
6898 SourceIndex = 0;
6899 *FirstSpliceSourceCluster = 0;
6900 Result = FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
6901 0,
6902 &SourceVbo,
6903 &SourceLbo,
6904 &SourceBytesInRun );
6905
6906 } else {
6907
6908 Result = FatLookupMcbEntry( Vcb, &FcbOrDcb->Mcb,
6909 FileOffset-1,
6910 &SourceLbo,
6911 &SourceBytesInRun,
6912 &SourceIndex);
6913
6914 *FirstSpliceSourceCluster = FatGetIndexFromLbo( Vcb, SourceLbo );
6915
6916 if ((Result) && (SourceBytesInRun == 1)) {
6917
6918 SourceIndex += 1;
6919 Result = FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
6920 SourceIndex,
6921 &SourceVbo,
6922 &SourceLbo,
6923 &SourceBytesInRun);
6924
6925 } else {
6926
6927 SourceVbo = FileOffset;
6928 SourceLbo += 1;
6929 SourceBytesInRun -= 1;
6930 }
6931 }
6932
6933 //
6934 // Run should always be present, but don't bugcheck in the case where it's not.
6935 //
6936
6937 if (!Result) {
6938
6939 NT_ASSERT( FALSE);
6940 FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR);
6941 }
6942
6943 //
6944 // At this point the variables:
6945 //
6946 // - SourceIndex - SourceLbo - SourceBytesInRun -
6947 //
6948 // all correctly decribe the allocation to be removed. In the loop
6949 // below we will start here and continue enumerating the Mcb runs
6950 // until we are finished with the allocation to be relocated.
6951 //
6952
6953 *FirstSpliceTargetCluster = TargetCluster;
6954
6955 *SecondSpliceSourceCluster =
6956 *FirstSpliceTargetCluster +
6957 (BytesToReallocate >> Vcb->AllocationSupport.LogOfBytesPerCluster) - 1;
6958
6959 for (SourceBytesRemaining = BytesToReallocate, SourceMcbVbo = 0;
6960
6961 SourceBytesRemaining > 0;
6962
6963 SourceIndex += 1,
6964 SourceBytesRemaining -= SourceMcbBytesInRun,
6965 SourceMcbVbo += SourceMcbBytesInRun) {
6966
6967 if (SourceMcbVbo != 0) {
6968 #ifdef _MSC_VER
6969 #pragma prefast( suppress:28931, "needed for debug build" )
6970 #endif
6971 Result = FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
6972 SourceIndex,
6973 &SourceVbo,
6974 &SourceLbo,
6975 &SourceBytesInRun );
6976 NT_ASSERT( Result);
6977 }
6978
6979 NT_ASSERT( SourceVbo == SourceMcbVbo + FileOffset );
6980
6981 SourceMcbBytesInRun =
6982 SourceBytesInRun < SourceBytesRemaining ?
6983 SourceBytesInRun : SourceBytesRemaining;
6984
6985 FatAddMcbEntry( Vcb, SourceMcb,
6986 SourceMcbVbo,
6987 SourceLbo,
6988 SourceMcbBytesInRun );
6989 }
6990
6991 //
6992 // Now compute the cluster of the target of the second
6993 // splice. If the final run in the above loop was
6994 // more than we needed, then we can just do arithmetic,
6995 // otherwise we have to look up the next run.
6996 //
6997
6998 if (SourceMcbBytesInRun < SourceBytesInRun) {
6999
7000 *SecondSpliceTargetCluster =
7001 FatGetIndexFromLbo( Vcb, SourceLbo + SourceMcbBytesInRun );
7002
7003 } else {
7004
7005 if (FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
7006 SourceIndex,
7007 &SourceVbo,
7008 &SourceLbo,
7009 &SourceBytesInRun )) {
7010
7011 *SecondSpliceTargetCluster = FatGetIndexFromLbo( Vcb, SourceLbo );
7012
7013 } else {
7014
7015 *SecondSpliceTargetCluster = FAT_CLUSTER_LAST;
7016 }
7017 }
7018 }
7019
7020
7021 NTSTATUS
7022 FatAllowExtendedDasdIo(
7023 IN PIRP_CONTEXT IrpContext,
7024 IN PIRP Irp
7025 )
7026 /*++
7027
7028 Routine Description:
7029
7030 This routine marks the CCB to indicate that the handle
7031 may be used to read past the end of the volume file. The
7032 handle must be a dasd handle.
7033
7034 Arguments:
7035
7036 Irp - Supplies the Irp being processed.
7037
7038 Return Value:
7039
7040 NTSTATUS - The return status for the operation.
7041
7042 --*/
7043 {
7044 PIO_STACK_LOCATION IrpSp;
7045 PVCB Vcb;
7046 PFCB Fcb;
7047 PCCB Ccb;
7048
7049 PAGED_CODE();
7050
7051 //
7052 // Get the current Irp stack location and save some references.
7053 //
7054
7055 IrpSp = IoGetCurrentIrpStackLocation( Irp );
7056
7057 //
7058 // Extract and decode the file object and check for type of open.
7059 //
7060
7061 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
7062
7063 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7064 return STATUS_INVALID_PARAMETER;
7065 }
7066
7067 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
7068
7069 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7070
7071 DebugTrace(-1, Dbg, "FatAllowExtendedDasdIo -> %08lx\n", STATUS_INVALID_PARAMETER);
7072 return STATUS_INVALID_PARAMETER;
7073 }
7074
7075 SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO );
7076
7077 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
7078 return STATUS_SUCCESS;
7079 }
7080
7081 #if (NTDDI_VERSION >= NTDDI_WIN7)
7082
7083 _Requires_lock_held_(_Global_critical_region_)
7084 NTSTATUS
7085 FatGetRetrievalPointerBase (
7086 _In_ PIRP_CONTEXT IrpContext,
7087 _In_ PIRP Irp
7088 )
7089 /*++
7090
7091 Routine Description:
7092
7093 This routine retrieves the sector offset to the first allocation unit.
7094
7095 Arguments:
7096
7097 IrpContext - Supplies the Irp Context.
7098 Irp - Supplies the Irp being processed.
7099
7100 Return Value:
7101
7102 NTSTATUS - The return status for the operation.
7103
7104 --*/
7105 {
7106 PIO_STACK_LOCATION IrpSp = NULL;
7107 PVCB Vcb = NULL;
7108 PFCB Fcb = NULL;
7109 PCCB Ccb = NULL;
7110 ULONG BufferLength = 0;
7111 PRETRIEVAL_POINTER_BASE RetrievalPointerBase = NULL;
7112
7113 PAGED_CODE();
7114
7115 IrpSp = IoGetCurrentIrpStackLocation( Irp );
7116
7117 //
7118 // Force WAIT to true.
7119 //
7120
7121 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
7122
7123 //
7124 // Extract and decode the file object and check for type of open.
7125 //
7126
7127 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
7128
7129 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7130 return STATUS_INVALID_PARAMETER;
7131 }
7132
7133 //
7134 // Extract the buffer
7135 //
7136
7137 RetrievalPointerBase = Irp->AssociatedIrp.SystemBuffer;
7138 BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
7139
7140 //
7141 // Verify the handle has manage volume access.
7142 //
7143
7144 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
7145
7146 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7147 return STATUS_INVALID_PARAMETER;
7148 }
7149
7150 //
7151 // Validate the output buffer is the right size.
7152 //
7153 // Note that the default size of BOOT_AREA_INFO has enough room for 2 boot sectors, so we're fine.
7154 //
7155
7156 if (BufferLength < sizeof(RETRIEVAL_POINTER_BASE)) {
7157
7158 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
7159 return STATUS_BUFFER_TOO_SMALL;
7160 }
7161
7162 //
7163 // Fill out the offset to the file area.
7164 //
7165
7166 RtlZeroMemory( RetrievalPointerBase, BufferLength );
7167
7168 try {
7169
7170 FatAcquireSharedVcb(IrpContext, Vcb);
7171 FatQuickVerifyVcb(IrpContext, Vcb);
7172
7173 RetrievalPointerBase->FileAreaOffset.QuadPart = Vcb->AllocationSupport.FileAreaLbo >> Vcb->AllocationSupport.LogOfBytesPerSector;
7174 Irp->IoStatus.Information = sizeof( RETRIEVAL_POINTER_BASE );
7175
7176 } finally {
7177
7178 FatReleaseVcb(IrpContext, Vcb);
7179
7180 }
7181
7182 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
7183
7184 return STATUS_SUCCESS;
7185
7186 }
7187
7188
7189 _Requires_lock_held_(_Global_critical_region_)
7190 NTSTATUS
7191 FatGetBootAreaInfo (
7192 _In_ PIRP_CONTEXT IrpContext,
7193 _In_ PIRP Irp
7194 )
7195 /*++
7196
7197 Routine Description:
7198
7199 This routine retrieves information about the boot areas of the filesystem.
7200
7201 Arguments:
7202
7203 IrpContext - Supplies the Irp Context.
7204 Irp - Supplies the Irp being processed.
7205
7206 Return Value:
7207
7208 NTSTATUS - The return status for the operation.
7209
7210 --*/
7211 {
7212 PIO_STACK_LOCATION IrpSp = NULL;
7213 PVCB Vcb = NULL;
7214 PFCB Fcb = NULL;
7215 PCCB Ccb = NULL;
7216 ULONG BufferLength = 0;
7217 PBOOT_AREA_INFO BootAreaInfo = NULL;
7218
7219 PAGED_CODE();
7220
7221 IrpSp = IoGetCurrentIrpStackLocation( Irp );
7222
7223 //
7224 // Force WAIT to true.
7225 //
7226
7227 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
7228
7229 //
7230 // Extract and decode the file object and check for type of open.
7231 //
7232
7233 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
7234
7235 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7236 return STATUS_INVALID_PARAMETER;
7237 }
7238
7239 //
7240 // Extract the buffer
7241 //
7242
7243 BootAreaInfo = Irp->AssociatedIrp.SystemBuffer;
7244 BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
7245
7246 //
7247 // Verify the handle has manage volume access.
7248 //
7249
7250 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
7251
7252 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7253 return STATUS_INVALID_PARAMETER;
7254 }
7255
7256 //
7257 // Validate the output buffer is the right size.
7258 //
7259 // Note that the default size of BOOT_AREA_INFO has enough room for 2 boot sectors, so we're fine.
7260 //
7261
7262 if (BufferLength < sizeof(BOOT_AREA_INFO)) {
7263
7264 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
7265 return STATUS_BUFFER_TOO_SMALL;
7266 }
7267
7268 //
7269 // Fill out our boot areas.
7270 //
7271
7272 RtlZeroMemory( BootAreaInfo, BufferLength );
7273
7274 try {
7275
7276 FatAcquireSharedVcb(IrpContext, Vcb);
7277 FatQuickVerifyVcb(IrpContext, Vcb);
7278
7279 if (FatIsFat32( Vcb )) {
7280
7281 BootAreaInfo->BootSectorCount = 2;
7282 BootAreaInfo->BootSectors[0].Offset.QuadPart = 0;
7283 BootAreaInfo->BootSectors[1].Offset.QuadPart = 6;
7284 } else {
7285
7286 BootAreaInfo->BootSectorCount = 1;
7287 BootAreaInfo->BootSectors[0].Offset.QuadPart = 0;
7288 }
7289
7290 Irp->IoStatus.Information = sizeof( BOOT_AREA_INFO );
7291
7292 } finally {
7293
7294 FatReleaseVcb(IrpContext, Vcb);
7295 }
7296
7297 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
7298 return STATUS_SUCCESS;
7299 }
7300
7301 #endif
7302
7303
7304 _Requires_lock_held_(_Global_critical_region_)
7305 NTSTATUS
7306 FatMarkHandle (
7307 _In_ PIRP_CONTEXT IrpContext,
7308 _In_ PIRP Irp
7309 )
7310 /*++
7311
7312 Routine Description:
7313
7314 This routine is used to attach special properties to a user handle.
7315
7316 Arguments:
7317
7318 IrpContext - Supplies the Irp Context.
7319 Irp - Supplies the Irp being processed.
7320
7321 Return Value:
7322
7323 NTSTATUS - The return status for the operation.
7324
7325 --*/
7326 {
7327 NTSTATUS Status = STATUS_SUCCESS;
7328 PIO_STACK_LOCATION IrpSp = NULL;
7329 PVCB Vcb = NULL;
7330 PFCB Fcb = NULL;
7331 PCCB Ccb = NULL;
7332 PFCB DasdFcb = NULL;
7333 PCCB DasdCcb = NULL;
7334 TYPE_OF_OPEN TypeOfOpen;
7335 PMARK_HANDLE_INFO HandleInfo = NULL;
7336 PFILE_OBJECT DasdFileObject = NULL;
7337 BOOLEAN ReleaseFcb = FALSE;
7338
7339 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
7340 MARK_HANDLE_INFO LocalMarkHandleInfo = {0};
7341 #endif
7342
7343 PAGED_CODE();
7344
7345 IrpSp = IoGetCurrentIrpStackLocation( Irp );
7346
7347 //
7348 // Always make this a synchronous IRP.
7349 //
7350
7351 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
7352
7353 //
7354 // Extract and decode the file object and check for type of open.
7355 //
7356
7357 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) ;
7358
7359 //
7360 // We currently support this call for files and directories only.
7361 //
7362
7363 if ((TypeOfOpen != UserFileOpen) &&
7364 (TypeOfOpen != UserDirectoryOpen)) {
7365
7366 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7367 return STATUS_INVALID_PARAMETER;
7368 }
7369
7370 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
7371
7372 //
7373 // Win32/64 thunking code
7374 //
7375
7376 if (IoIs32bitProcess( Irp )) {
7377
7378 PMARK_HANDLE_INFO32 MarkHandle32;
7379
7380 if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO32 )) {
7381
7382 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
7383 return STATUS_BUFFER_TOO_SMALL;
7384 }
7385
7386 MarkHandle32 = (PMARK_HANDLE_INFO32) Irp->AssociatedIrp.SystemBuffer;
7387 LocalMarkHandleInfo.HandleInfo = MarkHandle32->HandleInfo;
7388 LocalMarkHandleInfo.UsnSourceInfo = MarkHandle32->UsnSourceInfo;
7389 LocalMarkHandleInfo.VolumeHandle = (HANDLE)(ULONG_PTR)(LONG) MarkHandle32->VolumeHandle;
7390
7391 HandleInfo = &LocalMarkHandleInfo;
7392
7393 } else {
7394
7395 #endif
7396
7397 //
7398 // Get the input buffer pointer and check its length.
7399 //
7400
7401 if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO )) {
7402
7403 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
7404 return STATUS_BUFFER_TOO_SMALL;
7405 }
7406
7407 HandleInfo = (PMARK_HANDLE_INFO) Irp->AssociatedIrp.SystemBuffer;
7408
7409 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
7410 }
7411 #endif
7412
7413 //
7414 // Check that only legal bits are being set.
7415 // We currently only support two bits: protect clusters and unprotect clusters.
7416 //
7417 // Note that we don't actually support the USN journal, but we must ignore the flags in order
7418 // to preserve compatibility.
7419 //
7420
7421 if (FlagOn( HandleInfo->HandleInfo,
7422 ~(MARK_HANDLE_PROTECT_CLUSTERS)) ||
7423 (FlagOn( HandleInfo->HandleInfo,
7424 0 ) &&
7425 (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL)) ||
7426 FlagOn(HandleInfo->UsnSourceInfo,
7427 ~(USN_SOURCE_DATA_MANAGEMENT |
7428 USN_SOURCE_AUXILIARY_DATA |
7429 USN_SOURCE_REPLICATION_MANAGEMENT) ) ) {
7430
7431 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7432 return STATUS_INVALID_PARAMETER;
7433 }
7434
7435 //
7436 // Check that the user has a valid volume handle or the manage volume
7437 // privilege or is a kernel mode caller
7438 //
7439 // NOTE: the kernel mode check is only valid because the rdr doesn't support this
7440 // FSCTL.
7441 //
7442
7443 if ((Irp->RequestorMode != KernelMode) &&
7444 (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL) &&
7445 !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ) &&
7446 ( FlagOn( HandleInfo->HandleInfo, MARK_HANDLE_PROTECT_CLUSTERS ) || (HandleInfo->UsnSourceInfo != 0) )) {
7447
7448 if (HandleInfo->VolumeHandle == 0) {
7449 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
7450 return STATUS_ACCESS_DENIED;
7451 }
7452
7453 Status = ObReferenceObjectByHandle( HandleInfo->VolumeHandle,
7454 0,
7455 *IoFileObjectType,
7456 UserMode,
7457 #ifndef __REACTOS__
7458 &DasdFileObject,
7459 #else
7460 (PVOID *)&DasdFileObject,
7461 #endif
7462 NULL );
7463
7464 if (!NT_SUCCESS(Status)) {
7465
7466 FatCompleteRequest( IrpContext, Irp, Status );
7467 return Status;
7468 }
7469
7470 //
7471 // Check that this file object is opened on the same volume as the
7472 // handle used to call this routine.
7473 //
7474
7475 if (DasdFileObject->Vpb != Vcb->Vpb) {
7476
7477 ObDereferenceObject( DasdFileObject );
7478
7479 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7480 return STATUS_INVALID_PARAMETER;
7481 }
7482
7483 //
7484 // Now decode this FileObject and verify it is a volume handle.
7485 // We don't care to raise on dismounts here because
7486 // we check for that further down anyway. So send FALSE.
7487 //
7488
7489 #ifdef _MSC_VER
7490 #pragma prefast( suppress:28931, "convenient for debugging" )
7491 #endif
7492 TypeOfOpen = FatDecodeFileObject( DasdFileObject, &Vcb, &DasdFcb, &DasdCcb ) ;
7493
7494 ObDereferenceObject( DasdFileObject );
7495
7496 if ((DasdCcb == NULL) || !FlagOn( DasdCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
7497
7498 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
7499 return STATUS_ACCESS_DENIED;
7500 }
7501
7502 }
7503
7504 _SEH2_TRY {
7505
7506 FatAcquireExclusiveFcb(IrpContext, Fcb);
7507 ReleaseFcb = TRUE;
7508
7509 FatVerifyFcb( IrpContext, Fcb );
7510
7511 if (HandleInfo->HandleInfo & MARK_HANDLE_PROTECT_CLUSTERS) {
7512
7513 if (Fcb->FcbState & FCB_STATE_DENY_DEFRAG) {
7514
7515 //
7516 // It's already set, bail out.
7517 //
7518
7519 try_return( Status = STATUS_ACCESS_DENIED );
7520 }
7521
7522 Ccb->Flags |= CCB_FLAG_DENY_DEFRAG;
7523 Fcb->FcbState|= FCB_STATE_DENY_DEFRAG;
7524
7525 }
7526
7527 try_exit: NOTHING;
7528
7529 } _SEH2_FINALLY {
7530
7531 if (ReleaseFcb) {
7532
7533 FatReleaseFcb(IrpContext, Fcb);
7534 }
7535
7536 } _SEH2_END;
7537
7538 FatCompleteRequest( IrpContext, Irp, Status );
7539 return Status;
7540 }
7541
7542
7543 _Requires_lock_held_(_Global_critical_region_)
7544 VOID
7545 FatFlushAndCleanVolume(
7546 IN PIRP_CONTEXT IrpContext,
7547 IN PIRP Irp,
7548 IN PVCB Vcb,
7549 IN FAT_FLUSH_TYPE FlushType
7550 )
7551 /*++
7552
7553 Routine Description:
7554
7555 This routine flushes and otherwise preparse a volume to be eligible
7556 for deletion. The dismount and PNP paths share the need for this
7557 common work.
7558
7559 The Vcb will always be valid on return from this function. It is the
7560 caller's responsibility to attempt the dismount/deletion, and to setup
7561 allocation support again if the volume will be brought back from the
7562 brink.
7563
7564 Arguments:
7565
7566 Irp - Irp for the overlying request
7567
7568 Vcb - the volume being operated on
7569
7570 FlushType - specifies the kind of flushing desired
7571
7572 Return Value:
7573
7574 NTSTATUS - The return status for the operation.
7575
7576 --*/
7577 {
7578 PAGED_CODE();
7579
7580 //
7581 // The volume must be held exclusive.
7582 //
7583
7584 NT_ASSERT( FatVcbAcquiredExclusive( IrpContext, Vcb ));
7585
7586 //
7587 // There is no fail, flush everything. If invalidating, it is important
7588 // that we invalidate as we flush (eventually, w/ paging io held) so that we
7589 // error out the maximum number of late writes.
7590 //
7591
7592 if (FlushType != NoFlush) {
7593
7594 (VOID) FatFlushVolume( IrpContext, Vcb, FlushType );
7595 }
7596
7597 FatCloseEaFile( IrpContext, Vcb, FALSE );
7598
7599 //
7600 // Now, tell the device to flush its buffers.
7601 //
7602
7603 if (FlushType != NoFlush) {
7604
7605 (VOID)FatHijackIrpAndFlushDevice( IrpContext, Irp, Vcb->TargetDeviceObject );
7606 }
7607
7608 //
7609 // Now purge everything in sight. We're trying to provoke as many closes as
7610 // soon as possible, this volume may be on its way out.
7611 //
7612
7613 if (FlushType != FlushWithoutPurge) {
7614
7615 CcPurgeCacheSection( &Vcb->SectionObjectPointers,
7616 NULL,
7617 0,
7618 FALSE );
7619
7620 (VOID) FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush );
7621 }
7622
7623 //
7624 // If the volume was dirty and we were allowed to flush, do the processing that
7625 // the delayed callback would have done.
7626 //
7627
7628 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
7629
7630 //
7631 // Cancel any pending clean volumes.
7632 //
7633
7634 (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
7635 (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
7636
7637
7638 if (FlushType != NoFlush) {
7639
7640 //
7641 // The volume is now clean, note it.
7642 //
7643
7644 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
7645
7646 FatMarkVolume( IrpContext, Vcb, VolumeClean );
7647 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
7648 }
7649
7650 //
7651 // Unlock the volume if it is removable.
7652 //
7653
7654 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
7655 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
7656
7657 FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
7658 }
7659 }
7660 }
7661
7662 }
7663
7664 #if (NTDDI_VERSION >= NTDDI_WIN8)
7665
7666
7667 _Requires_lock_held_(_Global_critical_region_)
7668 NTSTATUS
7669 FatSetPurgeFailureMode (
7670 _In_ PIRP_CONTEXT IrpContext,
7671 _In_ PIRP Irp
7672 )
7673 /*++
7674
7675 This routine is used to enable or disable the purge failure mode
7676 on a file. When in this mode the file system will propagate purge
7677 failures encountered during coherency purges. Normally these are
7678 ignored for application compatibilty purposes. Since the normal
7679 behavior can lead to cache incoherency there needs to be a way to
7680 force error propagation, particulary when a filter has mapped a
7681 section for the purposes of scanning the file in the background.
7682
7683 The purge failure mode is a reference count because it is set
7684 per mapped section and there may be multiple sections backed by
7685 the file.
7686
7687 Arguments:
7688
7689 IrpContext - Supplies the Irp Context.
7690 Irp - Supplies the Irp being processed.
7691
7692 Return Value:
7693
7694 NTSTATUS - The return status for the operation.
7695
7696 --*/
7697 {
7698 NTSTATUS Status = STATUS_SUCCESS;
7699 PIO_STACK_LOCATION IrpSp;
7700 TYPE_OF_OPEN TypeOfOpen;
7701 PVCB Vcb;
7702 PFCB Fcb;
7703 PCCB Ccb;
7704 PSET_PURGE_FAILURE_MODE_INPUT SetPurgeInput;
7705 BOOLEAN FcbAcquired = FALSE;
7706
7707 PAGED_CODE();
7708
7709 IrpSp = IoGetCurrentIrpStackLocation( Irp );
7710
7711 //
7712 // Force WAIT to true.
7713 //
7714
7715 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
7716
7717 //
7718 // This has to be a kernel only call. Can't let a user request
7719 // change the purge failure mode count
7720 //
7721
7722 if (Irp->RequestorMode != KernelMode) {
7723
7724 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7725 return STATUS_INVALID_PARAMETER;
7726 }
7727
7728 //
7729 // Extract and decode the file object and check for type of open.
7730 //
7731
7732 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
7733
7734 if (TypeOfOpen == UserDirectoryOpen) {
7735
7736 FatCompleteRequest( IrpContext, Irp, STATUS_FILE_IS_A_DIRECTORY );
7737 return STATUS_FILE_IS_A_DIRECTORY;
7738 }
7739
7740 if (TypeOfOpen != UserFileOpen) {
7741
7742 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7743 return STATUS_INVALID_PARAMETER;
7744 }
7745
7746 //
7747 // Get the input buffer pointer and check its length.
7748 //
7749
7750 if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( SET_PURGE_FAILURE_MODE_INPUT )) {
7751
7752 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
7753 return STATUS_BUFFER_TOO_SMALL;
7754 }
7755
7756 SetPurgeInput = (PSET_PURGE_FAILURE_MODE_INPUT) Irp->AssociatedIrp.SystemBuffer;
7757
7758 if (!FlagOn( SetPurgeInput->Flags, SET_PURGE_FAILURE_MODE_ENABLED | SET_PURGE_FAILURE_MODE_DISABLED )) {
7759
7760 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
7761 return STATUS_INVALID_PARAMETER;
7762 }
7763
7764 try {
7765
7766 //
7767 // Acquire the FCB exclusively to synchronize with coherency flush
7768 // and purge.
7769 //
7770
7771 FatAcquireExclusiveFcb( IrpContext, Fcb );
7772 FcbAcquired = TRUE;
7773
7774 FatVerifyFcb( IrpContext, Fcb );
7775
7776 if (FlagOn( SetPurgeInput->Flags, SET_PURGE_FAILURE_MODE_ENABLED )) {
7777
7778 if (Fcb->PurgeFailureModeEnableCount == MAXULONG) {
7779
7780 try_return( Status = STATUS_INVALID_PARAMETER );
7781 }
7782
7783 Fcb->PurgeFailureModeEnableCount += 1;
7784
7785 } else {
7786
7787 ASSERT( FlagOn( SetPurgeInput->Flags, SET_PURGE_FAILURE_MODE_DISABLED ));
7788
7789 if (Fcb->PurgeFailureModeEnableCount == 0) {
7790
7791 try_return( Status = STATUS_INVALID_PARAMETER );
7792 }
7793
7794 Fcb->PurgeFailureModeEnableCount -= 1;
7795 }
7796
7797 try_exit: NOTHING;
7798
7799 } finally {
7800
7801 if (FcbAcquired) {
7802 FatReleaseFcb( IrpContext, Fcb );
7803 }
7804 }
7805
7806 //
7807 // Complete the irp if we terminated normally.
7808 //
7809
7810 FatCompleteRequest( IrpContext, Irp, Status );
7811
7812 return Status;
7813 }
7814
7815 #endif
7816
7817
7818 NTSTATUS
7819 FatSearchBufferForLabel(
7820 IN PIRP_CONTEXT IrpContext,
7821 IN PVPB Vpb,
7822 IN PVOID Buffer,
7823 IN ULONG Size,
7824 OUT PBOOLEAN LabelFound
7825 )
7826 /*++
7827
7828 Routine Description:
7829
7830 Search a buffer (taken from the root directory) for a volume label
7831 matching the label in the
7832
7833 Arguments:
7834
7835 IrpContext - Supplies our irp context
7836 Vpb - Vpb supplying the volume label
7837 Buffer - Supplies the buffer we'll search
7838 Size - The size of the buffer in bytes.
7839 LabelFound - Returns whether a label was found.
7840
7841 Return Value:
7842
7843 There are four interesting cases:
7844
7845 1) Some random error occurred - that error returned as status, LabelFound
7846 is indeterminate.
7847
7848 2) No label was found - STATUS_SUCCESS returned, LabelFound is FALSE.
7849
7850 3) A matching label was found - STATUS_SUCCESS returned, LabelFound is TRUE.
7851
7852 4) A non-matching label found - STATUS_WRONG_VOLUME returned, LabelFound
7853 is indeterminate.
7854
7855 --*/
7856
7857 {
7858 NTSTATUS Status;
7859 WCHAR UnicodeBuffer[11];
7860
7861 PDIRENT Dirent;
7862 PDIRENT TerminationDirent;
7863 ULONG VolumeLabelLength;
7864 UCHAR OemBuffer[11];
7865 OEM_STRING OemString;
7866 UNICODE_STRING UnicodeString;
7867
7868 PAGED_CODE();
7869
7870 UNREFERENCED_PARAMETER( IrpContext );
7871
7872 Dirent = Buffer;
7873
7874 TerminationDirent = Dirent + Size / sizeof(DIRENT);
7875
7876 while ( Dirent < TerminationDirent ) {
7877
7878 if ( Dirent->FileName[0] == FAT_DIRENT_NEVER_USED ) {
7879
7880 Dirent = TerminationDirent;
7881 break;
7882 }
7883
7884 //
7885 // If the entry is the non-deleted volume label break from the loop.
7886 //
7887 // Note that all out parameters are already correctly set.
7888 //
7889
7890 if (((Dirent->Attributes & ~FAT_DIRENT_ATTR_ARCHIVE) ==
7891 FAT_DIRENT_ATTR_VOLUME_ID) &&
7892 (Dirent->FileName[0] != FAT_DIRENT_DELETED)) {
7893
7894 break;
7895 }
7896
7897 Dirent += 1;
7898 }
7899
7900 if (Dirent >= TerminationDirent) {
7901
7902 //
7903 // We've run out of buffer.
7904 //
7905
7906 *LabelFound = FALSE;
7907 return STATUS_SUCCESS;
7908 }
7909
7910
7911 OemString.Buffer = (PCHAR)&OemBuffer[0];
7912 OemString.MaximumLength = 11;
7913
7914 RtlCopyMemory( OemString.Buffer, Dirent->FileName, 11 );
7915
7916 //
7917 // Translate the first character from 0x5 to 0xe5.
7918 //
7919
7920 if (OemString.Buffer[0] == FAT_DIRENT_REALLY_0E5) {
7921
7922 OemString.Buffer[0] = 0xe5;
7923 }
7924
7925 //
7926 // Compute the length of the volume name
7927 //
7928
7929 for ( OemString.Length = 11;
7930 OemString.Length > 0;
7931 OemString.Length -= 1) {
7932
7933 if ( (OemString.Buffer[OemString.Length-1] != 0x00) &&
7934 (OemString.Buffer[OemString.Length-1] != 0x20) ) { break; }
7935 }
7936
7937 UnicodeString.MaximumLength = sizeof( UnicodeBuffer );
7938 UnicodeString.Buffer = &UnicodeBuffer[0];
7939
7940 Status = RtlOemStringToCountedUnicodeString( &UnicodeString,
7941 &OemString,
7942 FALSE );
7943
7944 if ( !NT_SUCCESS( Status ) ) {
7945
7946 return Status;
7947 }
7948
7949 VolumeLabelLength = UnicodeString.Length;
7950
7951 if ( (VolumeLabelLength != (ULONG)Vpb->VolumeLabelLength) ||
7952 (!RtlEqualMemory(&UnicodeBuffer[0],
7953 &Vpb->VolumeLabel[0],
7954 VolumeLabelLength)) ) {
7955
7956 return STATUS_WRONG_VOLUME;
7957 }
7958
7959 //
7960 // We found a matching label.
7961 //
7962
7963 *LabelFound = TRUE;
7964 return STATUS_SUCCESS;
7965 }
7966
7967
7968 VOID
7969 FatVerifyLookupFatEntry (
7970 IN PIRP_CONTEXT IrpContext,
7971 IN PVCB Vcb,
7972 IN ULONG FatIndex,
7973 IN OUT PULONG FatEntry
7974 )
7975 {
7976 ULONG PageEntryOffset;
7977 ULONG OffsetIntoVolumeFile;
7978 PVOID Buffer;
7979
7980 PAGED_CODE();
7981
7982 NT_ASSERT(Vcb->AllocationSupport.FatIndexBitSize == 32);
7983
7984 FatVerifyIndexIsValid( IrpContext, Vcb, FatIndex);
7985
7986 Buffer = FsRtlAllocatePoolWithTag( NonPagedPoolNxCacheAligned,
7987 PAGE_SIZE,
7988 TAG_ENTRY_LOOKUP_BUFFER );
7989
7990 OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(ULONG);
7991 PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(ULONG);
7992
7993 _SEH2_TRY {
7994
7995 FatPerformVerifyDiskRead( IrpContext,
7996 Vcb,
7997 Buffer,
7998 OffsetIntoVolumeFile & ~(PAGE_SIZE - 1),
7999 PAGE_SIZE,
8000 TRUE );
8001
8002 *FatEntry = ((PULONG)(Buffer))[PageEntryOffset];
8003
8004 } _SEH2_FINALLY {
8005
8006 ExFreePool( Buffer );
8007 } _SEH2_END;
8008 }
8009
8010 //
8011 // Local support routine
8012 //
8013
8014 _Requires_lock_held_(_Global_critical_region_)
8015 VOID
8016 FatScanForDismountedVcb (
8017 IN PIRP_CONTEXT IrpContext
8018 )
8019
8020 /*++
8021
8022 Routine Description:
8023
8024 This routine walks through the list of Vcb's looking for any which may
8025 now be deleted. They may have been left on the list because there were
8026 outstanding references.
8027
8028 Arguments:
8029
8030 Return Value:
8031
8032 None
8033
8034 --*/
8035
8036 {
8037 PVCB Vcb;
8038 PLIST_ENTRY Links;
8039 BOOLEAN VcbDeleted;
8040
8041
8042 PAGED_CODE();
8043
8044 //
8045 // Walk through all of the Vcb's attached to the global data.
8046 //
8047
8048 NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
8049
8050 #ifdef _MSC_VER
8051 #pragma prefast( push )
8052 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
8053 #pragma prefast( disable: 28193, "this will always wait" )
8054 #endif
8055
8056 FatAcquireExclusiveGlobal( IrpContext );
8057
8058 #ifdef _MSC_VER
8059 #pragma prefast( pop )
8060 #endif
8061
8062 Links = FatData.VcbQueue.Flink;
8063
8064 while (Links != &FatData.VcbQueue) {
8065
8066 Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
8067
8068 //
8069 // Move to the next link now since the current Vcb may be deleted.
8070 //
8071
8072 Links = Links->Flink;
8073
8074 //
8075 // Try to acquire the VCB for exclusive access. If we cannot, just skip
8076 // it for now.
8077 //
8078
8079 #ifdef _MSC_VER
8080 #pragma prefast( push )
8081 #pragma prefast( disable:28103,"prefast cannot work out that Vcb->Resource will be released below." )
8082 #pragma prefast( disable:28109,"prefast cannot work out the Vcb is not already held" );
8083 #endif
8084
8085 if (!ExAcquireResourceExclusiveLite( &(Vcb->Resource), FALSE )) {
8086
8087 continue;
8088 }
8089
8090 #ifdef _MSC_VER
8091 #pragma prefast( pop )
8092 #endif
8093 //
8094 // Check if this Vcb can go away.
8095 //
8096
8097 VcbDeleted = FatCheckForDismount( IrpContext,
8098 Vcb,
8099 FALSE );
8100
8101 //
8102 // If the VCB was not deleted, release it.
8103 //
8104
8105 if (!VcbDeleted) {
8106
8107 ExReleaseResourceLite( &(Vcb->Resource) );
8108 }
8109 }
8110
8111 FatReleaseGlobal( IrpContext);
8112
8113 return;
8114 }
8115
8116 #if (NTDDI_VERSION >= NTDDI_WIN7)
8117 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8118 //
8119 // FatSetZeroOnDeallocate is used when we need to stomp over the contents with zeros when a file is deleted.
8120 //
8121
8122 NTSTATUS
8123 FatSetZeroOnDeallocate (
8124 __in PIRP_CONTEXT IrpContext,
8125 __in PIRP Irp
8126 )
8127 {
8128 NTSTATUS Status = STATUS_SUCCESS;
8129
8130 PVCB Vcb;
8131 PFCB FcbOrDcb;
8132 PCCB Ccb;
8133
8134 TYPE_OF_OPEN TypeOfOpen;
8135
8136 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
8137
8138 BOOLEAN ReleaseFcb = FALSE;
8139
8140 PAGED_CODE();
8141
8142 //
8143 // This call should always be synchronous.
8144 //
8145
8146 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
8147
8148 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb );
8149
8150 if ((TypeOfOpen != UserFileOpen) ||
8151 (!IrpSp->FileObject->WriteAccess) ) {
8152
8153 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
8154 return STATUS_ACCESS_DENIED;
8155 }
8156
8157 //
8158 // Readonly mount should be just that: read only.
8159 //
8160
8161 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
8162
8163 FatCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
8164 return STATUS_MEDIA_WRITE_PROTECTED;
8165 }
8166
8167 //
8168 // Acquire main then paging to exclude everyone from this FCB.
8169 //
8170
8171 FatAcquireExclusiveFcb(IrpContext, FcbOrDcb);
8172 ReleaseFcb = TRUE;
8173
8174 _SEH2_TRY {
8175
8176 SetFlag( FcbOrDcb->FcbState, FCB_STATE_ZERO_ON_DEALLOCATION );
8177
8178 } _SEH2_FINALLY {
8179
8180 if (ReleaseFcb) {
8181 FatReleaseFcb(IrpContext, FcbOrDcb);
8182 }
8183
8184 } _SEH2_END;
8185
8186 FatCompleteRequest( IrpContext, Irp, Status );
8187 return Status;
8188 }
8189 #endif
8190
8191