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