ReactOS  0.4.15-dev-1187-g119f102
fsctrl.c
Go to the documentation of this file.
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_)
38 FatMountVolume (
39  IN PIRP_CONTEXT IrpContext,
41  IN PVPB Vpb,
43  );
44 
45 _Requires_lock_held_(_Global_critical_region_)
47 FatVerifyVolume (
48  IN PIRP_CONTEXT IrpContext,
49  IN PIRP Irp
50  );
51 
52 BOOLEAN
54  IN PIRP_CONTEXT IrpContext,
56  );
57 
58 _Requires_lock_held_(_Global_critical_region_)
60 FatUserFsCtrl (
61  IN PIRP_CONTEXT IrpContext,
62  IN PIRP Irp
63  );
64 
65 _Requires_lock_held_(_Global_critical_region_)
67 FatOplockRequest (
68  _In_ PIRP_CONTEXT IrpContext,
69  _In_ PIRP Irp
70  );
71 
72 _Requires_lock_held_(_Global_critical_region_)
74 FatLockVolume (
75  IN PIRP_CONTEXT IrpContext,
76  IN PIRP Irp
77  );
78 
81  IN PIRP_CONTEXT IrpContext,
82  IN PIRP Irp
83  );
84 
85 _Requires_lock_held_(_Global_critical_region_)
87 FatDismountVolume (
88  IN PIRP_CONTEXT IrpContext,
89  IN PIRP Irp
90  );
91 
92 _Requires_lock_held_(_Global_critical_region_)
94 FatDirtyVolume (
95  IN PIRP_CONTEXT IrpContext,
96  IN PIRP Irp
97  );
98 
101  IN PIRP_CONTEXT IrpContext,
102  IN PIRP Irp
103  );
104 
105 NTSTATUS
107  IN PIRP_CONTEXT IrpContext,
108  IN PIRP Irp
109  );
110 
111 NTSTATUS
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
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
154  IN PIRP_CONTEXT IrpContext,
155  IN PIRP Irp
156  );
157 
158 NTSTATUS
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
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,
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
233  PIRP_CONTEXT IrpContext,
234  PFCB FcbOrDcb,
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,
253  OUT PULONG BytesToReallocate,
254  OUT PULONG BytesToWrite,
255  OUT PLARGE_INTEGER SourceLbo
256 );
257 
258 NTSTATUS
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
269  IN PIRP_CONTEXT IrpContext,
270  IN PVCB Vcb,
271  IN ULONG FatIndex,
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,
338  _Out_ PVBO Vbo,
340  )
341 {
342  LBO Lbo;
343  ULONG Index = 0;
344  LONGLONG llVbo = 0;
345 
347 
348  while (FsRtlGetNextLargeMcbEntry(Mcb, Index, &llVbo, &Lbo, ByteCount)) {
349  *Vbo = (VBO)llVbo;
350  if (((ULONG)Lbo) == -1) {
351  return FALSE;
352  }
353 
354  Index++;
355  }
356 
357  *Vbo = (VBO)llVbo;
358 
359  return TRUE;
360 }
361 
362 
363 BOOLEAN
365  IN PVCB Vcb,
366  IN PLARGE_MCB Mcb,
367  IN VBO Vbo,
368  IN LBO Lbo,
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--;
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 
404  ((LONGLONG) Vbo),
405  ((LONGLONG) Lbo),
406  ((LONGLONG) SectorCount) );
407 
408  if (Mcb != &Vcb->DirtyFatMcb) {
409  NT_ASSERT( FatNonSparseMcb( Vcb, Mcb, &SparseVbo, &SparseByteCount ) ||
410  ((SparseVbo == Vbo) && (SparseByteCount == SectorCount )) );
411  }
412 
413  return Result;
414 }
415 
416 
417 BOOLEAN
419  IN PVCB Vcb,
420  IN PLARGE_MCB Mcb,
421  IN VBO Vbo,
422  OUT PLBO Lbo,
425  )
426 {
427  BOOLEAN Results;
428  LONGLONG LiLbo;
429  LONGLONG LiSectorCount;
431 
432  LiLbo = 0;
433  LiSectorCount = 0;
434 
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 
460 
461  *ByteCount = (ULONG) LiSectorCount;
462 
463  if (*ByteCount) {
464 
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
495  IN PVCB Vcb,
496  IN PLARGE_MCB Mcb,
497  OUT PVBO Vbo,
498  OUT PLBO Lbo,
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 
514  &LiVbo,
515  &LiLbo,
516  &LocalIndex );
517 
518  *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2;
519 
520  if (((ULONG) LiLbo) != -1) {
521 
522  *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2;
523 
524  *Lbo += (MCB_SCALE - 1);
525  *Vbo += (MCB_SCALE - 1);
526 
527  } else {
528 
529  *Lbo = 0;
530  }
531 
532  if (Index) {
533  *Index = LocalIndex;
534  }
535 
536  return Results;
537 }
538 
539 
540 BOOLEAN
542  IN PVCB Vcb,
543  IN PLARGE_MCB Mcb,
544  IN ULONG RunIndex,
545  OUT PVBO Vbo,
546  OUT PLBO Lbo,
548  )
549 
550 {
551  BOOLEAN Results;
552  LONGLONG LiVbo;
553  LONGLONG LiLbo;
554  LONGLONG LiSectorCount;
555 
556  PAGED_CODE();
557 
558  LiVbo = LiLbo = 0;
559 
560  Results = FsRtlGetNextLargeMcbEntry( Mcb,
561  RunIndex,
562  &LiVbo,
563  &LiLbo,
564  &LiSectorCount );
565 
566  if (Results) {
567 
568  *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2;
569 
570  if (((ULONG) LiLbo) != -1) {
571 
572  *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2;
573 
574  } else {
575 
576  *Lbo = 0;
577  }
578 
579  *ByteCount = ((ULONG) LiSectorCount) << MCB_SCALE_LOG2;
580 
581  if ((*ByteCount == 0) && (LiSectorCount != 0)) {
582 
583  //
584  // If 'ByteCount' overflows, then this is likely a file of
585  // max supported size (2^32 - 1) in one contiguous run.
586  //
587 
588  NT_ASSERT( RunIndex == 0 );
589 
590  *ByteCount = 0xFFFFFFFF;
591  }
592  }
593 
594  return Results;
595 }
596 
597 
598 VOID
600  IN PVCB Vcb,
601  IN PLARGE_MCB Mcb,
602  IN VBO Vbo,
604  )
605 {
606  PAGED_CODE();
607 
608  if ((SectorCount) && (SectorCount != 0xFFFFFFFF)) {
609 
610  SectorCount--;
612  SectorCount++;
613  }
614 
615  Vbo >>= MCB_SCALE_LOG2;
616 
617 #if DBG
618  _SEH2_TRY {
619 #endif
620 
622  (LONGLONG) Vbo,
624 
625 #if DBG
626  } _SEH2_EXCEPT(FatBugCheckExceptionFilter( _SEH2_GetExceptionInformation() )) {
627 
628  NOTHING;
629  } _SEH2_END;
630 #endif
631 
632 }
633 
634 
637 NTSTATUS
638 NTAPI
639 FatFsdFileSystemControl (
640  _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
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;
666  PIRP_CONTEXT IrpContext = NULL;
667 
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 
684 
685  Wait = TRUE;
686 
687  } else {
688 
689  Wait = CanFsdWait( Irp );
690  }
691 
693 
695 
696  _SEH2_TRY {
697 
699 
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 
711  (IrpSp->Parameters.FileSystemControl.FsControlCode ==
713 
714  Status = FatInvalidateVolumes( Irp );
715 
716  } else {
717 
718  IrpContext = FatCreateIrpContext( Irp, Wait );
719 
720  Status = FatCommonFileSystemControl( IrpContext, Irp );
721  }
722 
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 
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 
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 {
776 
777  PAGED_CODE();
778 
779  //
780  // Get a pointer to the current Irp stack location
781  //
782 
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 
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 
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 
833  break;
834  }
835 
836  DebugTrace(-1, Dbg, "FatCommonFileSystemControl -> %08lx\n", Status);
837 
838  return Status;
839 }
840 
841 
842 //
843 // Local Support Routine
844 //
845 
846 _Requires_lock_held_(_Global_critical_region_)
847 NTSTATUS
848 FatMountVolume (
849  IN PIRP_CONTEXT IrpContext,
851  IN PVPB Vpb,
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 );
897 
898  PBCB BootBcb;
900 
901  PBCB DirentBcb;
902  PDIRENT Dirent;
904 
905  BOOLEAN MountNewVolume = FALSE;
906  BOOLEAN WeClearedVerifyRequiredBit = FALSE;
907  BOOLEAN DoARemount = FALSE;
908 
909  PVCB OldVcb = NULL;
910  PVPB OldVpb = NULL;
911 
912  PDEVICE_OBJECT RealDevice = NULL;
913  PVOLUME_DEVICE_OBJECT VolDo = NULL;
914  PVCB Vcb = NULL;
915  PFILE_OBJECT RootDirectoryFile = NULL;
916 
917  PLIST_ENTRY Links;
918 
919  IO_STATUS_BLOCK Iosb = {0};
920  ULONG ChangeCount = 0;
921 
922  DISK_GEOMETRY Geometry;
923 
924  PARTITION_INFORMATION_EX PartitionInformation;
925  NTSTATUS StatusPartInfo;
926 
927 #if (NTDDI_VERSION > NTDDI_WIN8)
928  GUID VolumeGuid = {0};
929 #endif
930 
931 
932  PAGED_CODE();
933 
934  DebugTrace(+1, Dbg, "FatMountVolume\n", 0);
935  DebugTrace( 0, Dbg, "TargetDeviceObject = %p\n", TargetDeviceObject);
936  DebugTrace( 0, Dbg, "Vpb = %p\n", Vpb);
937 
938  NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
940 
941  //
942  // Only send down IOCTL_DISK_CHECK_VERIFY if it is removable media.
943  //
944 
945  if (FlagOn(TargetDeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
946 
947  //
948  // Verify that there is a disk here and pick up the change count.
949  //
950 
951  Status = FatPerformDevIoCtrl( IrpContext,
954  NULL,
955  0,
956  &ChangeCount,
957  sizeof(ULONG),
958  FALSE,
959  TRUE,
960  &Iosb );
961 
962  if (!NT_SUCCESS( Status )) {
963 
964  //
965  // If we will allow a raw mount then avoid sending the popup.
966  //
967  // Only send this on "true" disk devices to handle the accidental
968  // legacy of FAT. No other FS will throw a harderror on empty
969  // drives.
970  //
971  // Cmd should really handle this per 9x.
972  //
973 
974  if (!FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT ) &&
975  Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK) {
976 
977  FatNormalizeAndRaiseStatus( IrpContext, Status );
978  }
979 
980  return Status;
981  }
982 
983  }
984 
985  if (Iosb.Information != sizeof(ULONG)) {
986 
987  //
988  // Be safe about the count in case the driver didn't fill it in
989  //
990 
991  ChangeCount = 0;
992  }
993 
994  //
995  // If this is a CD class device, then check to see if there is a
996  // 'data track' or not. This is to avoid issuing paging reads which will
997  // fail later in the mount process (e.g. CD-DA or blank CD media)
998  //
999 
1000  if ((TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) &&
1001  !FatScanForDataTrack( IrpContext, TargetDeviceObject)) {
1002 
1004  }
1005 
1006  //
1007  // Ping the volume with a partition query and pick up the partition
1008  // type. We'll check this later to avoid some scurrilous volumes.
1009  //
1010 
1011  StatusPartInfo = FatPerformDevIoCtrl( IrpContext,
1014  NULL,
1015  0,
1016  &PartitionInformation,
1017  sizeof(PARTITION_INFORMATION_EX),
1018  FALSE,
1019  TRUE,
1020  &Iosb );
1021 
1022  //
1023  // Make sure we can wait.
1024  //
1025 
1026  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1027 
1028  //
1029  // Do a quick check to see if there any Vcb's which can be removed.
1030  //
1031 
1032  FatScanForDismountedVcb( IrpContext );
1033 
1034  //
1035  // Initialize the Bcbs and our final state so that the termination
1036  // handlers will know what to free or unpin
1037  //
1038 
1039  BootBcb = NULL;
1040  DirentBcb = NULL;
1041 
1042  Vcb = NULL;
1043  VolDo = NULL;
1044  MountNewVolume = FALSE;
1045 
1046  _SEH2_TRY {
1047 
1048  //
1049  // Synchronize with FatCheckForDismount(), which modifies the vpb.
1050  //
1051 
1052 #ifdef _MSC_VER
1053 #pragma prefast( push )
1054 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
1055 #pragma prefast( disable: 28193, "this will always wait" )
1056 #endif
1057 
1058  (VOID)FatAcquireExclusiveGlobal( IrpContext );
1059 
1060 #ifdef _MSC_VER
1061 #pragma prefast( pop )
1062 #endif
1063 
1064  //
1065  // Create a new volume device object. This will have the Vcb
1066  // hanging off of its end, and set its alignment requirement
1067  // from the device we talk to.
1068  //
1069 
1071  sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
1072  NULL,
1074  0,
1075  FALSE,
1076  (PDEVICE_OBJECT *)&VolDo))) {
1077 
1078  try_return( Status );
1079  }
1080 
1081  //
1082  // Our alignment requirement is the larger of the processor alignment requirement
1083  // already in the volume device object and that in the TargetDeviceObject
1084  //
1085 
1086  if (TargetDeviceObject->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
1087 
1088  VolDo->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
1089  }
1090 
1091  //
1092  // Initialize the overflow queue for the volume
1093  //
1094 
1095  VolDo->OverflowQueueCount = 0;
1096  InitializeListHead( &VolDo->OverflowQueue );
1097 
1098  VolDo->PostedRequestCount = 0;
1099  KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
1100 
1101  //
1102  // We must initialize the stack size in our device object before
1103  // the following reads, because the I/O system has not done it yet.
1104  // This must be done before we clear the device initializing flag
1105  // otherwise a filter could attach and copy the wrong stack size into
1106  // it's device object.
1107  //
1108 
1109  VolDo->DeviceObject.StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
1110 
1111  //
1112  // We must also set the sector size correctly in our device object
1113  // before clearing the device initializing flag.
1114  //
1115 
1116  Status = FatPerformDevIoCtrl( IrpContext,
1119  NULL,
1120  0,
1121  &Geometry,
1122  sizeof( DISK_GEOMETRY ),
1123  FALSE,
1124  TRUE,
1125  NULL );
1126 
1127  if (!NT_SUCCESS( Status )) {
1128 
1129  try_return( Status );
1130  }
1131 
1132 #ifdef _MSC_VER
1133 #pragma prefast( suppress: 28175, "this is a filesystem driver, touching SectorSize is fine" )
1134 #endif
1135  VolDo->DeviceObject.SectorSize = (USHORT)Geometry.BytesPerSector;
1136 
1137  //
1138  // Indicate that this device object is now completely initialized
1139  //
1140 
1141  ClearFlag(VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING);
1142 
1143  //
1144  // Now Before we can initialize the Vcb we need to set up the device
1145  // object field in the Vpb to point to our new volume device object.
1146  // This is needed when we create the virtual volume file's file object
1147  // in initialize vcb.
1148  //
1149 
1150  Vpb->DeviceObject = (PDEVICE_OBJECT)VolDo;
1151 
1152  //
1153  // If the real device needs verification, temporarily clear the
1154  // field.
1155  //
1156 
1157  RealDevice = Vpb->RealDevice;
1158 
1159  if ( FlagOn(RealDevice->Flags, DO_VERIFY_VOLUME) ) {
1160 
1161  ClearFlag(RealDevice->Flags, DO_VERIFY_VOLUME);
1162 
1163  WeClearedVerifyRequiredBit = TRUE;
1164  }
1165 
1166  //
1167  // Initialize the new vcb
1168  //
1169 
1170  FatInitializeVcb( IrpContext,
1171  &VolDo->Vcb,
1173  Vpb,
1174  FsDeviceObject);
1175  //
1176  // Get a reference to the Vcb hanging off the end of the device object
1177  //
1178 
1179  Vcb = &VolDo->Vcb;
1180 
1181  //
1182  // Read in the boot sector, and have the read be the minumum size
1183  // needed. We know we can wait.
1184  //
1185 
1186  //
1187  // We need to commute errors on CD so that CDFS will get its crack. Audio
1188  // and even data media may not be universally readable on sector zero.
1189  //
1190 
1191  _SEH2_TRY {
1192 
1193  FatReadVolumeFile( IrpContext,
1194  Vcb,
1195  0, // Starting Byte
1196  sizeof(PACKED_BOOT_SECTOR),
1197  &BootBcb,
1198  (PVOID *)&BootSector );
1199 
1200  } _SEH2_EXCEPT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
1202 
1203  NOTHING;
1204  } _SEH2_END;
1205 
1206  //
1207  // Call a routine to check the boot sector to see if it is fat
1208  //
1209 
1210  if (BootBcb == NULL || !FatIsBootSectorFat( BootSector)) {
1211 
1212  DebugTrace(0, Dbg, "Not a Fat Volume\n", 0);
1213 
1214  //
1215  // Complete the request and return to our caller
1216  //
1217 
1219  }
1220 
1221 #if (NTDDI_VERSION > NTDDI_WIN8)
1222  //
1223  // Initialize the volume guid.
1224  //
1225 
1226  if (NT_SUCCESS( IoVolumeDeviceToGuid( Vcb->TargetDeviceObject, &VolumeGuid ))) {
1227 
1228 
1229  //
1230  // Stash a copy away in the VCB.
1231  //
1232 
1233  RtlCopyMemory( &Vcb->VolumeGuid, &VolumeGuid, sizeof(GUID));
1234 
1235  }
1236 
1237 
1238  //
1239  // Stash away a copy of the volume GUID path in our VCB.
1240  //
1241 
1242  if (Vcb->VolumeGuidPath.Buffer) {
1243  ExFreePool( Vcb->VolumeGuidPath.Buffer );
1244  Vcb->VolumeGuidPath.Buffer = NULL;
1245  Vcb->VolumeGuidPath.Length = Vcb->VolumeGuidPath.MaximumLength = 0;
1246  }
1247 
1248  IoVolumeDeviceToGuidPath( Vcb->TargetDeviceObject, &Vcb->VolumeGuidPath );
1249 #endif
1250 
1251  //
1252  // Unpack the BPB. We used to do some sanity checking of the FATs at
1253  // this point, but authoring errors on third-party devices prevent
1254  // us from continuing to safeguard ourselves. We can only hope the
1255  // boot sector check is good enough.
1256  //
1257  // (read: digital cameras)
1258  //
1259  // Win9x does the same.
1260  //
1261 
1262  FatUnpackBios( &Vcb->Bpb, &BootSector->PackedBpb );
1263 
1264  //
1265  // Check if we have an OS/2 Boot Manager partition and treat it as an
1266  // unknown file system. We'll check the partition type in from the
1267  // partition table and we ensure that it has less than 0x80 sectors,
1268  // which is just a heuristic that will capture all real OS/2 BM partitions
1269  // and avoid the chance we'll discover partitions which erroneously
1270  // (but to this point, harmlessly) put down the OS/2 BM type.
1271  //
1272  // Note that this is only conceivable on good old MBR media.
1273  //
1274  // The OS/2 Boot Manager boot format mimics a FAT16 partition in sector
1275  // zero but does is not a real FAT16 file system. For example, the boot
1276  // sector indicates it has 2 FATs but only really has one, with the boot
1277  // manager code overlaying the second FAT. If we then set clean bits in
1278  // FAT[0] we'll corrupt that code.
1279  //
1280 
1281  if (NT_SUCCESS( StatusPartInfo ) &&
1282  (PartitionInformation.PartitionStyle == PARTITION_STYLE_MBR &&
1283  PartitionInformation.Mbr.PartitionType == PARTITION_OS2BOOTMGR) &&
1284  (Vcb->Bpb.Sectors != 0 &&
1285  Vcb->Bpb.Sectors < 0x80)) {
1286 
1287  DebugTrace( 0, Dbg, "OS/2 Boot Manager volume detected, volume not mounted. \n", 0 );
1288 
1289  //
1290  // Complete the request and return to our caller
1291  //
1292 
1294  }
1295 
1296  //
1297  // Verify that the sector size recorded in the Bpb matches what the
1298  // device currently reports it's sector size to be.
1299  //
1300 
1301  if ( !NT_SUCCESS( Status) ||
1302  (Geometry.BytesPerSector != Vcb->Bpb.BytesPerSector)) {
1303 
1305  }
1306 
1307  //
1308  // This is a fat volume, so extract the bpb, serial number. The
1309  // label we'll get later after we've created the root dcb.
1310  //
1311  // Note that the way data caching is done, we set neither the
1312  // direct I/O or Buffered I/O bit in the device object flags.
1313  //
1314 
1315  if (Vcb->Bpb.Sectors != 0) { Vcb->Bpb.LargeSectors = 0; }
1316 
1317  if (IsBpbFat32(&BootSector->PackedBpb)) {
1318 
1319  CopyUchar4( &Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id );
1320 
1321  } else {
1322 
1323  CopyUchar4( &Vpb->SerialNumber, BootSector->Id );
1324 
1325  //
1326  // Allocate space for the stashed boot sector chunk. This only has meaning on
1327  // FAT12/16 volumes since this only is kept for the FSCTL_QUERY_FAT_BPB and it and
1328  // its users are a bit wierd, thinking that a BPB exists wholly in the first 0x24
1329  // bytes.
1330  //
1331 
1332  Vcb->First0x24BytesOfBootSector =
1334  0x24,
1335  TAG_STASHED_BPB );
1336 
1337  //
1338  // Stash a copy of the first 0x24 bytes
1339  //
1340 
1341  RtlCopyMemory( Vcb->First0x24BytesOfBootSector,
1342  BootSector,
1343  0x24 );
1344  }
1345 
1346  //
1347  // Now unpin the boot sector, so when we set up allocation eveything
1348  // works.
1349  //
1350 
1351  FatUnpinBcb( IrpContext, BootBcb );
1352 
1353  //
1354  // Compute a number of fields for Vcb.AllocationSupport
1355  //
1356 
1357  FatSetupAllocationSupport( IrpContext, Vcb );
1358 
1359  //
1360  // Sanity check the FsInfo information for FAT32 volumes. Silently deal
1361  // with messed up information by effectively disabling FsInfo updates.
1362  //
1363 
1364  if (FatIsFat32( Vcb )) {
1365 
1366  if (Vcb->Bpb.FsInfoSector >= Vcb->Bpb.ReservedSectors) {
1367 
1368  Vcb->Bpb.FsInfoSector = 0;
1369  }
1370  }
1371 
1372 
1373  //
1374  // Create a root Dcb so we can read in the volume label. If this is FAT32, we can
1375  // discover corruption in the FAT chain.
1376  //
1377  // NOTE: this exception handler presumes that this is the only spot where we can
1378  // discover corruption in the mount process. If this ever changes, this handler
1379  // MUST be expanded. The reason we have this guy here is because we have to rip
1380  // the structures down now (in the finally below) and can't wait for the outer
1381  // exception handling to do it for us, at which point everything will have vanished.
1382  //
1383 
1384  _SEH2_TRY {
1385 
1386  FatCreateRootDcb( IrpContext, Vcb );
1387 
1390 
1391  //
1392  // The volume needs to be dirtied, do it now. Note that at this point we have built
1393  // enough of the Vcb to pull this off.
1394  //
1395 
1396  FatCheckDirtyBit( IrpContext,
1397  Vcb );
1398 
1399  //
1400  // Set the dirty bit if it is not set already
1401  //
1402 
1403  if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
1404 
1406  FatMarkVolume( IrpContext, Vcb, VolumeDirty );
1408  }
1409 
1410  //
1411  // Now keep bailing out ...
1412  //
1413 
1415  } _SEH2_END;
1416 
1417  FatLocateVolumeLabel( IrpContext,
1418  Vcb,
1419  &Dirent,
1420  &DirentBcb,
1421  (PVBO)&ByteOffset );
1422 
1423  if (Dirent != NULL) {
1424 
1425  UCHAR OemBuffer[11];
1428 
1429  OemString.Buffer = (PCHAR)&OemBuffer[0];
1430  OemString.MaximumLength = 11;
1431 
1432  RtlCopyMemory( OemString.Buffer, Dirent->FileName, 11 );
1433 
1434  //
1435  // Translate the first character from 0x5 to 0xe5.
1436  //
1437 
1438  if (OemString.Buffer[0] == FAT_DIRENT_REALLY_0E5) {
1439 
1440  OemString.Buffer[0] = 0xe5;
1441  }
1442 
1443  //
1444  // Compute the length of the volume name
1445  //
1446 
1447  for ( OemString.Length = 11;
1448  OemString.Length > 0;
1449  OemString.Length -= 1) {
1450 
1451  if ( (OemString.Buffer[OemString.Length-1] != 0x00) &&
1452  (OemString.Buffer[OemString.Length-1] != 0x20) ) { break; }
1453  }
1454 
1456  UnicodeString.Buffer = &Vcb->Vpb->VolumeLabel[0];
1457 
1459  &OemString,
1460  FALSE );
1461 
1462  if ( !NT_SUCCESS( Status ) ) {
1463 
1464  try_return( Status );
1465  }
1466 
1467  Vpb->VolumeLabelLength = UnicodeString.Length;
1468 
1469  } else {
1470 
1471  Vpb->VolumeLabelLength = 0;
1472  }
1473 
1474  //
1475  // Use the change count we noted initially *before* doing any work.
1476  // If something came along in the midst of this operation, we'll
1477  // verify and discover the problem.
1478  //
1479 
1480  Vcb->ChangeCount = ChangeCount;
1481 
1482  //
1483  // Now scan the list of previously mounted volumes and compare
1484  // serial numbers and volume labels off not currently mounted
1485  // volumes to see if we have a match.
1486  //
1487 
1488  for (Links = FatData.VcbQueue.Flink;
1489  Links != &FatData.VcbQueue;
1490  Links = Links->Flink) {
1491 
1492  OldVcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
1493  OldVpb = OldVcb->Vpb;
1494 
1495  //
1496  // Skip over ourselves since we're already in the VcbQueue
1497  //
1498 
1499  if (OldVpb == Vpb) { continue; }
1500 
1501  //
1502  // Check for a match:
1503  //
1504  // Serial Number, VolumeLabel and Bpb must all be the same.
1505  // Also the volume must have failed a verify before (ie.
1506  // VolumeNotMounted), and it must be in the same physical
1507  // drive than it was mounted in before.
1508  //
1509 
1510  if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
1511  (OldVcb->VcbCondition == VcbNotMounted) &&
1512  (OldVpb->RealDevice == RealDevice) &&
1513  (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
1514  (RtlEqualMemory(&OldVpb->VolumeLabel[0],
1515  &Vpb->VolumeLabel[0],
1516  Vpb->VolumeLabelLength)) &&
1517  (RtlEqualMemory(&OldVcb->Bpb,
1518  &Vcb->Bpb,
1519  IsBpbFat32(&Vcb->Bpb) ?
1520  sizeof(BIOS_PARAMETER_BLOCK) :
1522  LargeSectorsPerFat) ))) {
1523 
1524  DoARemount = TRUE;
1525 
1526  break;
1527  }
1528  }
1529 
1530  if ( DoARemount ) {
1531 
1532  PVPB *IrpVpb;
1533 
1534  DebugTrace(0, Dbg, "Doing a remount\n", 0);
1535  DebugTrace(0, Dbg, "Vcb = %p\n", Vcb);
1536  DebugTrace(0, Dbg, "Vpb = %p\n", Vpb);
1537  DebugTrace(0, Dbg, "OldVcb = %p\n", OldVcb);
1538  DebugTrace(0, Dbg, "OldVpb = %p\n", OldVpb);
1539 
1540  //
1541  // Swap target device objects between the VCBs. That way
1542  // the old VCB will start using the new target device object,
1543  // and the new VCB will be torn down and deference the old
1544  // target device object.
1545  //
1546 
1547  Vcb->TargetDeviceObject = OldVcb->TargetDeviceObject;
1549 
1550  //
1551  // This is a remount, so link the old vpb in place
1552  // of the new vpb.
1553  //
1554 
1556 
1557  FatSetVcbCondition( OldVcb, VcbGood);
1558  OldVpb->RealDevice = Vpb->RealDevice;
1560 
1561 #ifdef _MSC_VER
1562 #pragma prefast( suppress: 28175, "touching Vpb is ok for a filesystem" )
1563 #endif
1564  OldVpb->RealDevice->Vpb = OldVpb;
1565 
1566  //
1567  // Use the new changecount.
1568  //
1569 
1570  OldVcb->ChangeCount = Vcb->ChangeCount;
1571 
1572  //
1573  // If the new VPB is the VPB referenced in the original Irp, set
1574  // that reference back to the old VPB.
1575  //
1576 
1577  IrpVpb = &IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->Parameters.MountVolume.Vpb;
1578 
1579  if (*IrpVpb == Vpb) {
1580 
1581  *IrpVpb = OldVpb;
1582  }
1583 
1584  //
1585  // We do not want to touch this VPB again. It will get cleaned up when
1586  // the new VCB is cleaned up.
1587  //
1588 
1589  NT_ASSERT( Vcb->Vpb == Vpb );
1590 
1591  Vpb = NULL;
1594 
1595  //
1596  // Reinitialize the volume file cache and allocation support.
1597  //
1598 
1599  {
1601 
1603  FileSizes.FileSize.QuadPart = ( 0x40000 + 0x1000 );
1605 
1606  DebugTrace(0, Dbg, "Truncate and reinitialize the volume file\n", 0);
1607 
1609  &FileSizes,
1610  TRUE,
1612  Vcb );
1613 
1614  //
1615  // Redo the allocation support
1616  //
1617 
1618  FatSetupAllocationSupport( IrpContext, OldVcb );
1619 
1620  //
1621  // Get the state of the dirty bit.
1622  //
1623 
1624  FatCheckDirtyBit( IrpContext, OldVcb );
1625 
1626  //
1627  // Check for write protected media.
1628  //
1629 
1630  if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
1631 
1633 
1634  } else {
1635 
1637  }
1638  }
1639 
1640  //
1641  // Complete the request and return to our caller
1642  //
1643 
1645  }
1646 
1647  DebugTrace(0, Dbg, "Mount a new volume\n", 0);
1648 
1649  //
1650  // This is a new mount
1651  //
1652  // Create a blank ea data file fcb, just not for Fat32.
1653  //
1654 
1655  if (!FatIsFat32(Vcb)) {
1656 
1657  DIRENT TempDirent;
1658  PFCB EaFcb;
1659 
1660  RtlZeroMemory( &TempDirent, sizeof(DIRENT) );
1661  RtlCopyMemory( &TempDirent.FileName[0], "EA DATA SF", 11 );
1662 
1663  EaFcb = FatCreateFcb( IrpContext,
1664  Vcb,
1665  Vcb->RootDcb,
1666  0,
1667  0,
1668  &TempDirent,
1669  NULL,
1670  NULL,
1671  FALSE,
1672  TRUE );
1673 
1674  //
1675  // Deny anybody who trys to open the file.
1676  //
1677 
1679 
1680  Vcb->EaFcb = EaFcb;
1681  }
1682 
1683  //
1684  // Get the state of the dirty bit.
1685  //
1686 
1687  FatCheckDirtyBit( IrpContext, Vcb );
1688 
1689 
1690  //
1691  // Check for write protected media.
1692  //
1693 
1694  if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
1695 
1697 
1698  } else {
1699 
1701  }
1702 
1703 
1704  //
1705  // Lock volume in drive if we just mounted the boot drive.
1706  //
1707 
1708  if (FlagOn(RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION)) {
1709 
1711 
1712  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
1713 
1714  FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
1715  }
1716  }
1717 
1718 
1719  //
1720  // Indicate to our termination handler that we have mounted
1721  // a new volume.
1722  //
1723 
1724  MountNewVolume = TRUE;
1725 
1726  //
1727  // Complete the request
1728  //
1729 
1731 
1732  //
1733  // Ref the root dir stream object so we can send mount notification.
1734  //
1735 
1736  RootDirectoryFile = Vcb->RootDcb->Specific.Dcb.DirectoryFile;
1737  ObReferenceObject( RootDirectoryFile );
1738 
1739  //
1740  // Remove the extra reference to this target DO made on behalf of us
1741  // by the IO system. In the remount case, we permit regular Vcb
1742  // deletion to do this work.
1743  //
1744 
1746 
1747 
1748  try_exit: NOTHING;
1749 
1750  } _SEH2_FINALLY {
1751 
1752  DebugUnwind( FatMountVolume );
1753 
1754  FatUnpinBcb( IrpContext, BootBcb );
1755  FatUnpinBcb( IrpContext, DirentBcb );
1756 
1757  //
1758  // Check if a volume was mounted. If not then we need to
1759  // mark the Vpb not mounted again.
1760  //
1761 
1762  if ( !MountNewVolume ) {
1763 
1764  if ( Vcb != NULL ) {
1765 
1766  //
1767  // A VCB was created and initialized. We need to try to tear it down.
1768  //
1769 
1770  FatCheckForDismount( IrpContext,
1771  Vcb,
1772  TRUE );
1773 
1774  IrpContext->Vcb = NULL;
1775 
1776  } else if (VolDo != NULL) {
1777 
1778  //
1779  // The VCB was never initialized, so we need to delete the
1780  // device right here.
1781  //
1782 
1783  IoDeleteDevice( &VolDo->DeviceObject );
1784  }
1785 
1786  //
1787  // See if a remount failed.
1788  //
1789 
1790  if (DoARemount && _SEH2_AbnormalTermination()) {
1791 
1792  //
1793  // The remount failed. Try to tear down the old VCB as well.
1794  //
1795 
1796  FatCheckForDismount( IrpContext,
1797  OldVcb,
1798  TRUE );
1799  }
1800  }
1801 
1802  if ( WeClearedVerifyRequiredBit == TRUE ) {
1803 
1804  SetFlag(RealDevice->Flags, DO_VERIFY_VOLUME);
1805  }
1806 
1807  FatReleaseGlobal( IrpContext );
1808 
1809  DebugTrace(-1, Dbg, "FatMountVolume -> %08lx\n", Status);
1810  } _SEH2_END;
1811 
1812  //
1813  // Now send mount notification. Note that since this is outside of any
1814  // synchronization since the synchronous delivery of this may go to
1815  // folks that provoke re-entrance to the FS.
1816  //
1817 
1818  if (RootDirectoryFile != NULL) {
1819 
1820 #if (NTDDI_VERSION >= NTDDI_WIN8)
1822 
1823  CcSetAdditionalCacheAttributesEx( RootDirectoryFile, CC_ENABLE_DISK_IO_ACCOUNTING );
1824  }
1825 #endif
1826 
1827  FsRtlNotifyVolumeEvent( RootDirectoryFile, FSRTL_VOLUME_MOUNT );
1828  ObDereferenceObject( RootDirectoryFile );
1829  }
1830 
1831  return Status;
1832 }
1833 
1834 
1835 //
1836 // Local Support Routine
1837 //
1838 
1839 _Requires_lock_held_(_Global_critical_region_)
1840 NTSTATUS
1841 FatVerifyVolume (
1842  IN PIRP_CONTEXT IrpContext,
1843  IN PIRP Irp
1844  )
1845 
1846 /*++
1847 
1848 Routine Description:
1849 
1850  This routine performs the verify volume operation by checking the volume
1851  label and serial number physically on the media with the the Vcb
1852  currently claiming to have the volume mounted. It is responsible for
1853  either completing or enqueuing the input Irp.
1854 
1855  Regardless of whether the verify operation succeeds, the following
1856  operations are performed:
1857 
1858  - Set Vcb->VirtualEaFile back to its initial state.
1859  - Purge all cached data (flushing first if verify succeeds)
1860  - Mark all Fcbs as needing verification
1861 
1862  If the volumes verifies correctly we also must:
1863 
1864  - Check the volume dirty bit.
1865  - Reinitialize the allocation support
1866  - Flush any dirty data
1867 
1868  If the volume verify fails, it may never be mounted again. If it is
1869  mounted again, it will happen as a remount operation. In preparation
1870  for that, and to leave the volume in a state that can be "lazy deleted"
1871  the following operations are performed:
1872 
1873  - Set the Vcb condition to VcbNotMounted
1874  - Uninitialize the volume file cachemap
1875  - Tear down the allocation support
1876 
1877  In the case of an abnormal termination we haven't determined the state
1878  of the volume, so we set the Device Object as needing verification again.
1879 
1880 Arguments:
1881 
1882  Irp - Supplies the Irp to process
1883 
1884 Return Value:
1885 
1886  NTSTATUS - If the verify operation completes, it will return either
1887  STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. If an IO or
1888  other error is encountered, that status will be returned.
1889 
1890 --*/
1891 
1892 {
1894 
1896 
1899 
1901 
1902  PVOLUME_DEVICE_OBJECT VolDo;
1903  PVCB Vcb;
1904  PVPB Vpb;
1905 
1906  ULONG SectorSize;
1907  BOOLEAN ClearVerify = FALSE;
1908  BOOLEAN ReleaseEntireVolume = FALSE;
1909  BOOLEAN VerifyAlreadyDone = FALSE;
1910 
1911  DISK_GEOMETRY DiskGeometry;
1912 
1913  LBO RootDirectoryLbo;
1914  ULONG RootDirectorySize;
1915  BOOLEAN LabelFound;
1916 
1917  ULONG ChangeCount = 0;
1918  IO_STATUS_BLOCK Iosb = {0};
1919 
1920  PAGED_CODE();
1921 
1922  //
1923  // Get the current Irp stack location
1924  //
1925 
1927 
1928  DebugTrace(+1, Dbg, "FatVerifyVolume\n", 0);
1929  DebugTrace( 0, Dbg, "DeviceObject = %p\n", IrpSp->Parameters.VerifyVolume.DeviceObject);
1930  DebugTrace( 0, Dbg, "Vpb = %p\n", IrpSp->Parameters.VerifyVolume.Vpb);
1931 
1932  //
1933  // Save some references to make our life a little easier. Note the Vcb for the purposes
1934  // of exception handling.
1935  //
1936 
1937  VolDo = (PVOLUME_DEVICE_OBJECT)IrpSp->Parameters.VerifyVolume.DeviceObject;
1938 
1939  Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
1940  IrpContext->Vcb = Vcb = &VolDo->Vcb;
1941 
1942  //
1943  // If we cannot wait then enqueue the irp to the fsp and
1944  // return the status to our caller.
1945  //
1946 
1947  if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
1948 
1949  DebugTrace(0, Dbg, "Cannot wait for verify.\n", 0);
1950 
1951  Status = FatFsdPostRequest( IrpContext, Irp );
1952 
1953  DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status );
1954  return Status;
1955  }
1956 
1957  //
1958  // We are serialized at this point allowing only one thread to
1959  // actually perform the verify operation. Any others will just
1960  // wait and then no-op when checking if the volume still needs
1961  // verification.
1962  //
1963 
1964 #ifdef _MSC_VER
1965 #pragma prefast( push )
1966 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
1967 #pragma prefast( disable: 28193, "this will always wait" )
1968 #endif
1969 
1970  (VOID)FatAcquireExclusiveGlobal( IrpContext );
1971 
1972 #ifdef _MSC_VER
1973 #pragma prefast( pop )
1974 #endif
1975 
1976  (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
1977 
1978  _SEH2_TRY {
1979 
1980  BOOLEAN AllowRawMount = BooleanFlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT );
1981 
1982  //
1983  // Mark ourselves as verifying this volume so that recursive I/Os
1984  // will be able to complete.
1985  //
1986 
1987  NT_ASSERT( Vcb->VerifyThread == NULL );
1988  Vcb->VerifyThread = KeGetCurrentThread();
1989 
1990  //
1991  // Check if the real device still needs to be verified. If it doesn't
1992  // then obviously someone beat us here and already did the work
1993  // so complete the verify irp with success. Otherwise reenable
1994  // the real device and get to work.
1995  //
1996 
1997  if (!FlagOn(Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
1998 
1999  DebugTrace(0, Dbg, "RealDevice has already been verified\n", 0);
2000 
2001  VerifyAlreadyDone = TRUE;
2003  }
2004 
2005  //
2006  // Ping the volume with a partition query to make Jeff happy.
2007  //
2008 
2009  {
2010  PARTITION_INFORMATION_EX PartitionInformation;
2011 
2012  (VOID) FatPerformDevIoCtrl( IrpContext,
2014  Vcb->TargetDeviceObject,
2015  NULL,
2016  0,
2017  &PartitionInformation,
2018  sizeof(PARTITION_INFORMATION_EX),
2019  FALSE,
2020  TRUE,
2021  &Iosb );
2022  }
2023 
2024  //
2025  // Only send down IOCTL_DISK_CHECK_VERIFY if it is removable media.
2026  //
2027 
2028  if (FlagOn(Vcb->TargetDeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
2029 
2030  //
2031  // Verify that there is a disk here and pick up the change count.
2032  //
2033 
2034  Status = FatPerformDevIoCtrl( IrpContext,
2036  Vcb->TargetDeviceObject,
2037  NULL,
2038  0,
2039  &ChangeCount,
2040  sizeof(ULONG),
2041  FALSE,
2042  TRUE,
2043  &Iosb );
2044 
2045  if (!NT_SUCCESS( Status )) {
2046 
2047  //
2048  // If we will allow a raw mount then return WRONG_VOLUME to
2049  // allow the volume to be mounted by raw.
2050  //
2051 
2052  if (AllowRawMount) {
2053 
2055  }
2056 
2057  FatNormalizeAndRaiseStatus( IrpContext, Status );
2058  }
2059 
2060  }
2061 
2062  if (Iosb.Information != sizeof(ULONG)) {
2063 
2064  //
2065  // Be safe about the count in case the driver didn't fill it in
2066  //
2067 
2068  ChangeCount = 0;
2069  }
2070 
2071  //
2072  // Whatever happens we will have verified this volume at this change
2073  // count, so record that fact.
2074  //
2075 
2076  Vcb->ChangeCount = ChangeCount;
2077 
2078  //
2079  // If this is a CD class device, then check to see if there is a
2080  // 'data track' or not. This is to avoid issuing paging reads which will
2081  // fail later in the mount process (e.g. CD-DA or blank CD media)
2082  //
2083 
2084  if ((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) &&
2085  !FatScanForDataTrack( IrpContext, Vcb->TargetDeviceObject)) {
2086 
2088  }
2089 
2090  //
2091  // Some devices can change sector sizes on the fly. Obviously, it
2092  // isn't the same volume if that happens.
2093  //
2094 
2095  Status = FatPerformDevIoCtrl( IrpContext,
2097  Vcb->TargetDeviceObject,
2098  NULL,
2099  0,
2100  &DiskGeometry,
2101  sizeof( DISK_GEOMETRY ),
2102  FALSE,
2103  TRUE,
2104  NULL );
2105 
2106  if (!NT_SUCCESS( Status )) {
2107 
2108  //
2109  // If we will allow a raw mount then return WRONG_VOLUME to
2110  // allow the volume to be mounted by raw.
2111  //
2112 
2113  if (AllowRawMount) {
2114 
2116  }
2117 
2118  FatNormalizeAndRaiseStatus( IrpContext, Status );
2119  }
2120 
2121  //
2122  // Read in the boot sector
2123  //
2124 
2125  SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
2126 
2127  if (SectorSize != DiskGeometry.BytesPerSector) {
2128 
2130  }
2131 
2132  BootSector = FsRtlAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
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 
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 
2161  }
2162 
2163  //
2164  // This is a fat volume, so extract serial number and see if it is
2165  // ours.
2166  //
2167 
2168  {
2170 
2171  if (IsBpbFat32(&BootSector->PackedBpb)) {
2173  } else {
2175  }
2176 
2177  if (SerialNumber != Vpb->SerialNumber) {
2178 
2179  DebugTrace(0, Dbg, "Not our serial number\n", 0);
2180 
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) :
2200  LargeSectorsPerFat) )) {
2201 
2202  DebugTrace(0, Dbg, "Bpb is different\n", 0);
2203 
2205  }
2206 
2207  //
2208  // Check the volume label. We do this by trying to locate the
2209  // volume label, making two strings one for the saved volume label
2210  // and the other for the new volume label and then we compare the
2211  // two labels.
2212  //
2213 
2214  if (FatRootDirectorySize(&Bpb) > 0) {
2215 
2216  RootDirectorySize = FatRootDirectorySize(&Bpb);
2217 
2218  } else {
2219 
2220  RootDirectorySize = FatBytesPerCluster(&Bpb);
2221  }
2222 
2223  RootDirectory = FsRtlAllocatePoolWithTag( NonPagedPoolNxCacheAligned,
2224  (ULONG) ROUND_TO_PAGES( RootDirectorySize ),
2226 
2227  if (!IsBpbFat32(&BootSector->PackedBpb)) {
2228 
2229  //
2230  // The Fat12/16 case is simple -- read the root directory in and
2231  // search it.
2232  //
2233 
2234  RootDirectoryLbo = FatRootDirectoryLbo(&Bpb);
2235 
2236  if (!FatPerformVerifyDiskRead( IrpContext,
2237  Vcb,
2238  RootDirectory,
2239  RootDirectoryLbo,
2240  RootDirectorySize,
2241  AllowRawMount )) {
2242 
2244  }
2245 
2246  Status = FatSearchBufferForLabel(IrpContext, Vpb,
2247  RootDirectory, RootDirectorySize,
2248  &LabelFound);
2249 
2250  if (!NT_SUCCESS(Status)) {
2251 
2252  try_return( Status );
2253  }
2254 
2255  if (!LabelFound && Vpb->VolumeLabelLength > 0) {
2256 
2258  }
2259 
2260  } else {
2261 
2262  ULONG RootDirectoryCluster;
2263 
2264  RootDirectoryCluster = Bpb.RootDirFirstCluster;
2265 
2266  while (RootDirectoryCluster != FAT_CLUSTER_LAST) {
2267 
2268  RootDirectoryLbo = FatGetLboFromIndex(Vcb, RootDirectoryCluster);
2269 
2270  if (!FatPerformVerifyDiskRead( IrpContext,
2271  Vcb,
2272  RootDirectory,
2273  RootDirectoryLbo,
2274  RootDirectorySize,
2275  AllowRawMount )) {
2276 
2278  }
2279 
2280  Status = FatSearchBufferForLabel(IrpContext, Vpb,
2281  RootDirectory, RootDirectorySize,
2282  &LabelFound);
2283 
2284  if (!NT_SUCCESS(Status)) {
2285 
2286  try_return( Status );
2287  }
2288 
2289  if (LabelFound) {
2290 
2291  //
2292  // Found a matching label.
2293  //
2294 
2295  break;
2296  }
2297 
2298  //
2299  // Set ourselves up for the next loop iteration.
2300  //
2301 
2302  FatVerifyLookupFatEntry( IrpContext, Vcb,
2303  RootDirectoryCluster,
2304  &RootDirectoryCluster );
2305 
2306  switch (FatInterpretClusterType(Vcb, RootDirectoryCluster)) {
2307 
2308  case FatClusterAvailable:
2309  case FatClusterReserved:
2310  case FatClusterBad:
2311 
2312  //
2313  // Bail all the way out if we have a bad root.
2314  //
2315 
2317  break;
2318 
2319  default:
2320 
2321  break;
2322  }
2323 
2324  }
2325 
2326  if (RootDirectoryCluster == FAT_CLUSTER_LAST &&
2327  Vpb->VolumeLabelLength > 0) {
2328 
2329  //
2330  // Should have found a label, didn't find any.
2331  //
2332 
2334  }
2335  }
2336 
2337 
2338  try_exit: NOTHING;
2339 
2340  //
2341  // Note that we have previously acquired the Vcb to serialize
2342  // the EA file stuff the marking all the Fcbs as NeedToBeVerified.
2343  //
2344  // Put the Ea file back in a initial state.
2345  //
2346 
2347  FatCloseEaFile( IrpContext, Vcb, (BOOLEAN)(Status == STATUS_SUCCESS) );
2348 
2349  //
2350  // Mark all Fcbs as needing verification, but only if we really have
2351  // to do it.
2352  //
2353 
2354  if (!VerifyAlreadyDone) {
2355 
2356  FatAcquireExclusiveVolume( IrpContext, Vcb );
2357  ReleaseEntireVolume = TRUE;
2358 
2359  FatMarkFcbCondition( IrpContext, Vcb->RootDcb, FcbNeedsToBeVerified, TRUE );
2360  }
2361 
2362  //
2363  // If the verify didn't succeed, get the volume ready for a
2364  // remount or eventual deletion.
2365  //
2366 
2367  if (Vcb->VcbCondition == VcbNotMounted) {
2368 
2369  //
2370  // If the volume was already in an unmounted state, just bail
2371  // and make sure we return STATUS_WRONG_VOLUME.
2372  //
2373 
2375 
2376  } else if ( Status == STATUS_WRONG_VOLUME ) {
2377 
2378  //
2379  // Grab everything so we can safely transition the volume state without
2380  // having a thread stumble into the torn-down allocation engine.
2381  //
2382 
2383  if (!ReleaseEntireVolume) {
2384  FatAcquireExclusiveVolume( IrpContext, Vcb );
2385  ReleaseEntireVolume = TRUE;
2386  }
2387 
2388  //
2389  // Get rid of any cached data, without flushing
2390  //
2391 
2392  FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush );
2393 
2394  //
2395  // Uninitialize the volume file cache map. Note that we cannot
2396  // do a "FatSyncUninit" because of deadlock problems. However,
2397  // since this FileObject is referenced by us, and thus included
2398  // in the Vpb residual count, it is OK to do a normal CcUninit.
2399  //
2400 
2401  CcUninitializeCacheMap( Vcb->VirtualVolumeFile,
2402  &FatLargeZero,
2403  NULL );
2404 
2405  FatTearDownAllocationSupport( IrpContext, Vcb );
2406 
2408 
2409  ClearVerify = TRUE;
2410 
2411  } else if (!VerifyAlreadyDone) {
2412 
2413  //
2414  // Grab everything so we can safely transition the volume state without
2415  // having a thread stumble into the torn-down allocation engine.
2416  //
2417 
2418  if (!ReleaseEntireVolume) {
2419  FatAcquireExclusiveVolume( IrpContext, Vcb );
2420  ReleaseEntireVolume = TRUE;
2421  }
2422 
2423  //
2424  // Get rid of any cached data, flushing first.
2425  //
2426  // Future work (and for bonus points, around the other flush points)
2427  // could address the possibility that the dirent filesize hasn't been
2428  // updated yet, causing us to fail the re-verification of a file in
2429  // DetermineAndMark. This is pretty subtle and very very uncommon.
2430  //
2431 
2432  FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
2433 
2434  //
2435  // Flush and Purge the volume file.
2436  //
2437 
2438  (VOID)FatFlushFat( IrpContext, Vcb );
2439  CcPurgeCacheSection( &Vcb->SectionObjectPointers, NULL, 0, FALSE );
2440 
2441  //
2442  // Redo the allocation support with newly paged stuff.
2443  //
2444 
2445  FatTearDownAllocationSupport( IrpContext, Vcb );
2446  FatSetupAllocationSupport( IrpContext, Vcb );
2447 
2448  FatCheckDirtyBit( IrpContext, Vcb );
2449 
2450  //
2451  // Check for write protected media.
2452  //
2453 
2454  if (FatIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
2455 
2457 
2458  } else {
2459 
2461  }
2462 
2463  ClearVerify = TRUE;
2464  }
2465 
2466  if (ClearVerify) {
2467 
2468  //
2469  // Mark the device as no longer needing verification.
2470  //
2471 
2472  ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
2473  }
2474 
2475  } _SEH2_FINALLY {
2476 
2477  DebugUnwind( FatVerifyVolume );
2478 
2479  //
2480  // Free any buffer we may have allocated
2481  //
2482 
2483  if ( BootSector != NULL ) { ExFreePool( BootSector ); }
2484  if ( RootDirectory != NULL ) { ExFreePool( RootDirectory ); }
2485 
2486  //
2487  // Show that we are done with this volume.
2488  //
2489 
2490  NT_ASSERT( Vcb->VerifyThread == KeGetCurrentThread() );
2491  Vcb->VerifyThread = NULL;
2492 
2493  if (ReleaseEntireVolume) {
2494 
2495  FatReleaseVolume( IrpContext, Vcb );
2496  }
2497 
2498  FatReleaseVcb( IrpContext, Vcb );
2499  FatReleaseGlobal( IrpContext );
2500 
2501  //
2502  // If this was not an abnormal termination, complete the irp.
2503  //
2504 
2505  if (!_SEH2_AbnormalTermination()) {
2506 
2507  FatCompleteRequest( IrpContext, Irp, Status );
2508  }
2509 
2510  DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status);
2511  } _SEH2_END;
2512 
2513  return Status;
2514 }
2515 
2516 
2517 //
2518 // Local Support Routine
2519 //
2520 
2521 BOOLEAN
2524  )
2525 
2526 /*++
2527 
2528 Routine Description:
2529 
2530  This routine checks if the boot sector is for a fat file volume.
2531 
2532 Arguments:
2533 
2534  BootSector - Supplies the packed boot sector to check
2535 
2536 Return Value:
2537 
2538  BOOLEAN - TRUE if the volume is Fat and FALSE otherwise.
2539 
2540 --*/
2541 
2542 {
2543  BOOLEAN Result;
2544  BIOS_PARAMETER_BLOCK Bpb = {0};
2545 
2546  DebugTrace(+1, Dbg, "FatIsBootSectorFat, BootSector = %p\n", BootSector);
2547 
2548  //
2549  // The result is true unless we decide that it should be false
2550  //
2551 
2552  Result = TRUE;
2553 
2554  //
2555  // Unpack the bios and then test everything
2556  //
2557 
2558  FatUnpackBios( &Bpb, &BootSector->PackedBpb );
2559  if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; }
2560 
2561  if ((BootSector->Jump[0] != 0xe9) &&
2562  (BootSector->Jump[0] != 0xeb) &&
2563  (BootSector->Jump[0] != 0x49)) {
2564 
2565  Result = FALSE;
2566 
2567  //
2568  // Enforce some sanity on the sector size (easy check)
2569  //
2570 
2571  } else if ((Bpb.BytesPerSector != 128) &&
2572  (Bpb.BytesPerSector != 256) &&
2573  (Bpb.BytesPerSector != 512) &&
2574  (Bpb.BytesPerSector != 1024) &&
2575  (Bpb.BytesPerSector != 2048) &&
2576  (Bpb.BytesPerSector != 4096)) {
2577 
2578  Result = FALSE;
2579 
2580  //
2581  // Likewise on the clustering.
2582  //
2583 
2584  } else if ((Bpb.SectorsPerCluster != 1) &&
2585  (Bpb.SectorsPerCluster != 2) &&
2586  (Bpb.SectorsPerCluster != 4) &&
2587  (Bpb.SectorsPerCluster != 8) &&
2588  (Bpb.SectorsPerCluster != 16) &&
2589  (Bpb.SectorsPerCluster != 32) &&
2590  (Bpb.SectorsPerCluster != 64) &&
2591  (Bpb.SectorsPerCluster != 128)) {
2592 
2593  Result = FALSE;
2594 
2595  //
2596  // Likewise on the reserved sectors (must reflect at least the boot sector!)
2597  //
2598 
2599  } else if (Bpb.ReservedSectors == 0) {
2600 
2601  Result = FALSE;
2602 
2603  //
2604  // No FATs? Wrong ...
2605  //
2606 
2607  } else if (Bpb.Fats == 0) {
2608 
2609  Result = FALSE;
2610 
2611  //
2612  // Prior to DOS 3.2 might contains value in both of Sectors and
2613  // Sectors Large.
2614  //
2615 
2616  } else if ((Bpb.Sectors == 0) && (Bpb.LargeSectors == 0)) {
2617 
2618  Result = FALSE;
2619 
2620  //
2621  // Check that FAT32 (SectorsPerFat == 0) claims some FAT space and
2622  // is of a version we recognize, currently Version 0.0.
2623  //
2624 
2625  } else if (Bpb.SectorsPerFat == 0 && ( Bpb.LargeSectorsPerFat == 0 ||
2626  Bpb.FsVersion != 0 )) {
2627 
2628  Result = FALSE;
2629 
2630  } else if ((Bpb.Media != 0xf0) &&
2631  (Bpb.Media != 0xf8) &&
2632  (Bpb.Media != 0xf9) &&
2633  (Bpb.Media != 0xfb) &&
2634  (Bpb.Media != 0xfc) &&
2635  (Bpb.Media != 0xfd) &&
2636  (Bpb.Media != 0xfe) &&
2637  (Bpb.Media != 0xff) &&
2638  (!FatData.FujitsuFMR || ((Bpb.Media != 0x00) &&
2639  (Bpb.Media != 0x01) &&
2640  (Bpb.Media != 0xfa)))) {
2641 
2642  Result = FALSE;
2643 
2644  //
2645  // If this isn't FAT32, then there better be a claimed root directory
2646  // size here ...
2647  //
2648 
2649  } else if (Bpb.SectorsPerFat != 0 && Bpb.RootEntries == 0) {
2650 
2651  Result = FALSE;
2652 
2653  //
2654  // If this is FAT32 (i.e., extended BPB), look for and refuse to mount
2655  // mirror-disabled volumes. If we did, we would need to only write to
2656  // the FAT# indicated in the ActiveFat field. The only user of this is
2657  // the FAT->FAT32 converter after the first pass of protected mode work
2658  // (booting into realmode) and NT should absolutely not be attempting
2659  // to mount such an in-transition volume.
2660  //
2661 
2662  } else if (Bpb.SectorsPerFat == 0 && Bpb.MirrorDisabled) {
2663 
2664  Result = FALSE;
2665  }
2666 
2667  DebugTrace(-1, Dbg, "FatIsBootSectorFat -> %08lx\n", Result);
2668 
2669  return Result;
2670 }
2671 
2672 
2673 //
2674 // Local Support Routine
2675 //
2676 
2677 BOOLEAN
2679  IN PIRP_CONTEXT IrpContext,
2681  )
2682 
2683 /*++
2684 
2685 Routine Description:
2686 
2687  This routine determines if the target media is write protected.
2688 
2689 Arguments:
2690 
2691  TargetDeviceObject - The target of the query
2692 
2693 Return Value:
2694 
2695  NTSTATUS - The return status for the operation
2696 
2697 --*/
2698 
2699 {
2700  PIRP Irp;
2701  KEVENT Event;
2702  NTSTATUS Status;
2704 
2705  PAGED_CODE();
2706  UNREFERENCED_PARAMETER( IrpContext );
2707 
2708  //
2709  // Query the partition table
2710  //
2711 
2713 
2714  //
2715  // See if the media is write protected. On success or any kind
2716  // of error (possibly illegal device function), assume it is
2717  // writeable, and only complain if he tells us he is write protected.
2718  //
2719 
2722  NULL,
2723  0,
2724  NULL,
2725  0,
2726  FALSE,
2727  &Event,
2728  &Iosb );
2729 
2730  //
2731  // Just return FALSE in the unlikely event we couldn't allocate an Irp.
2732  //
2733 
2734  if ( Irp == NULL ) {
2735 
2736  return FALSE;
2737  }
2738 
2740 
2742 
2743  if ( Status == STATUS_PENDING ) {
2744 
2746  Executive,
2747  KernelMode,
2748  FALSE,
2749  (PLARGE_INTEGER)NULL );
2750 
2751  Status = Iosb.Status;
2752  }
2753 
2755 }
2756 
2757 
2758 //
2759 // Local Support Routine
2760 //
2761 
2762 _Requires_lock_held_(_Global_critical_region_)
2763 NTSTATUS
2764 FatUserFsCtrl (
2765  IN PIRP_CONTEXT IrpContext,
2766  IN PIRP Irp
2767  )
2768 
2769 /*++
2770 
2771 Routine Description:
2772 
2773  This is the common routine for implementing the user's requests made
2774  through NtFsControlFile.
2775 
2776 Arguments:
2777 
2778  Irp - Supplies the Irp being processed
2779 
2780 Return Value:
2781 
2782  NTSTATUS - The return status for the operation
2783 
2784 --*/
2785 
2786 {
2787  NTSTATUS Status;
2789 
2791 
2792  PAGED_CODE();
2793 
2794  //
2795  // Save some references to make our life a little easier
2796  //
2797 
2798  FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
2799 
2800  DebugTrace(+1, Dbg,"FatUserFsCtrl...\n", 0);
2801  DebugTrace( 0, Dbg,"FsControlCode = %08lx\n", FsControlCode);
2802 
2803  //
2804  // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode
2805  // of the caller was userspace and this is a METHOD_NEITHER, we have the choice
2806  // of realy buffering the request through so we can possibly post, or making the
2807  // request synchronous. Since the former was not done by design, do the latter.
2808  //
2809 
2810  if (Irp->RequestorMode != KernelMode && (FsControlCode & 3) == METHOD_NEITHER) {
2811 
2812  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2813  }
2814 
2815  //
2816  // Case on the control code.
2817  //
2818 
2819  switch ( FsControlCode ) {
2820 
2829 #if (NTDDI_VERSION >= NTDDI_WIN7)
2830  case FSCTL_REQUEST_OPLOCK:
2831 #endif
2832  Status = FatOplockRequest( IrpContext, Irp );
2833  break;
2834 
2835  case FSCTL_LOCK_VOLUME:
2836 
2837  Status = FatLockVolume( IrpContext, Irp );
2838  break;
2839 
2840  case FSCTL_UNLOCK_VOLUME:
2841 
2842  Status = FatUnlockVolume( IrpContext, Irp );
2843  break;
2844 
2845  case FSCTL_DISMOUNT_VOLUME:
2846 
2847  Status = FatDismountVolume( IrpContext, Irp );
2848  break;
2849 
2851 
2852  Status = FatDirtyVolume( IrpContext, Irp );
2853  break;
2854 
2855  case FSCTL_IS_VOLUME_DIRTY:
2856 
2857  Status = FatIsVolumeDirty( IrpContext, Irp );
2858  break;
2859 
2861 
2862  Status = FatIsVolumeMounted( IrpContext, Irp );
2863  break;
2864 
2866  Status = FatIsPathnameValid( IrpContext, Irp );
2867  break;
2868 
2870  Status = FatQueryRetrievalPointers( IrpContext, Irp );
2871  break;
2872 
2873  case FSCTL_QUERY_FAT_BPB:
2874  Status = FatQueryBpb( IrpContext, Irp );
2875  break;
2876 
2878  Status = FatGetStatistics( IrpContext, Irp );
2879  break;
2880 
2881 #if (NTDDI_VERSION >= NTDDI_WIN7)
2883  Status = FatGetRetrievalPointerBase( IrpContext, Irp );
2884  break;
2885 
2886  case FSCTL_GET_BOOT_AREA_INFO:
2887  Status = FatGetBootAreaInfo( IrpContext, Irp );
2888  break;
2889 #endif
2890 
2892  Status = FatGetVolumeBitmap( IrpContext, Irp );
2893  break;
2894 
2896  Status = FatGetRetrievalPointers( IrpContext, Irp );
2897  break;
2898 
2899  case FSCTL_MOVE_FILE:
2900  Status = FatMoveFile( IrpContext, Irp );
2901  break;
2902 
2904  Status = FatAllowExtendedDasdIo( IrpContext, Irp );
2905  break;
2906 
2907  case FSCTL_MARK_HANDLE:
2908  Status = FatMarkHandle( IrpContext, Irp );
2909  break;
2910 
2911 #if (NTDDI_VERSION >= NTDDI_WIN8)
2912 
2913  case FSCTL_SET_PURGE_FAILURE_MODE:
2914  Status = FatSetPurgeFailureMode( IrpContext, Irp );
2915  break;
2916 
2917 #endif
2918 
2919 
2920 #if (NTDDI_VERSION >= NTDDI_WIN7)
2922  Status = FatSetZeroOnDeallocate( IrpContext, Irp );
2923  break;
2924 #endif
2925 
2926  default :
2927 
2928  DebugTrace(0, Dbg, "Invalid control code -> %08lx\n", FsControlCode );
2929 
2932  break;
2933  }
2934 
2935  DebugTrace(-1, Dbg, "FatUserFsCtrl -> %08lx\n", Status );
2936  return Status;
2937 }
2938 
2939 
2940 
2941 //
2942 // Local support routine
2943 //
2944 
2945 _Requires_lock_held_(_Global_critical_region_)
2946 NTSTATUS
2947 FatOplockRequest (
2948  _In_ PIRP_CONTEXT IrpContext,
2949  _In_ PIRP Irp
2950  )
2951 
2952 /*++
2953 
2954 Routine Description:
2955 
2956  This is the common routine to handle oplock requests made via the
2957  NtFsControlFile call.
2958 
2959 Arguments:
2960 
2961  Irp - Supplies the Irp being processed
2962 
2963 Return Value:
2964 
2965  NTSTATUS - The return status for the operation
2966 
2967 --*/
2968 
2969 {
2972  PFCB Fcb;
2973  PVCB Vcb;
2974  PCCB Ccb;
2975 
2976  ULONG OplockCount = 0;
2977 
2979 
2980  BOOLEAN AcquiredVcb = FALSE;
2981  BOOLEAN AcquiredFcb = FALSE;
2982 
2983 #if (NTDDI_VERSION >= NTDDI_WIN7)
2984  PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL;
2987 #endif
2988 
2990 
2991  PAGED_CODE();
2992 
2993  //
2994  // Save some references to make our life a little easier
2995  //
2996 
2997  FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
2998 
3000 
3001  DebugTrace(+1, Dbg, "FatOplockRequest...\n", 0);
3002  DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode);
3003 
3004  //
3005  // We permit oplock requests on files and directories.
3006  //
3007 
3008  if ((TypeOfOpen != UserFileOpen)
3009 #if (NTDDI_VERSION >= NTDDI_WIN8)
3010  &&
3012 #endif
3013  ) {
3014 
3016  DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
3017  return STATUS_INVALID_PARAMETER;
3018  }
3019 
3020 #if (NTDDI_VERSION >= NTDDI_WIN7)
3021 
3022  //
3023  // Get the input & output buffer lengths and pointers.
3024  //
3025 
3026  if (FsControlCode == FSCTL_REQUEST_OPLOCK) {
3027 
3028  InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
3029  InputBuffer = (PREQUEST_OPLOCK_INPUT_BUFFER) Irp->AssociatedIrp.SystemBuffer;
3030 
3031  OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
3032 
3033  //
3034  // Check for a minimum length on the input and ouput buffers.
3035  //
3036 
3037  if ((InputBufferLength < sizeof( REQUEST_OPLOCK_INPUT_BUFFER )) ||
3038  (OutputBufferLength < sizeof( REQUEST_OPLOCK_OUTPUT_BUFFER ))) {
3039 
3041  DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_BUFFER_TOO_SMALL\n", 0);
3042  return STATUS_BUFFER_TOO_SMALL;
3043  }
3044  }
3045 
3046  //
3047  // If the oplock request is on a directory it must be for a Read or Read-Handle
3048  // oplock only.
3049  //
3050 
3051  if ((TypeOfOpen == UserDirectoryOpen) &&
3052  ((FsControlCode != FSCTL_REQUEST_OPLOCK) ||
3053  !FsRtlOplockIsSharedRequest( Irp ))) {
3054 
3056  DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
3057  return STATUS_INVALID_PARAMETER;
3058  }
3059 
3060 #endif
3061 
3062  //
3063  // Make this a waitable Irpcontext so we don't fail to acquire
3064  // the resources.
3065  //
3066 
3067  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
3068 
3069  //
3070  // Use a try finally to free the Fcb/Vcb
3071  //
3072 
3073  _SEH2_TRY {
3074 
3075  //
3076  // We grab the Fcb exclusively for oplock requests, shared for oplock
3077  // break acknowledgement.
3078  //
3079 
3084 #if (NTDDI_VERSION >= NTDDI_WIN7)
3085  ||
3086  ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_REQUEST ))
3087 #endif
3088  ) {
3089 
3090  FatAcquireSharedVcb( IrpContext, Fcb->Vcb );
3091  AcquiredVcb = TRUE;
3092  FatAcquireExclusiveFcb( IrpContext, Fcb );
3093  AcquiredFcb = TRUE;
3094 
3095 #if (NTDDI_VERSION >= NTDDI_WIN7)
3096  if (FsRtlOplockIsSharedRequest( Irp )) {
3097 #else
3099 #endif
3100 
3101  //
3102  // Byte-range locks are only valid on files.
3103  //
3104 
3105  if (TypeOfOpen == UserFileOpen) {
3106 
3107  //
3108  // Set OplockCount to nonzero if FsRtl denies access
3109  // based on current byte-range lock state.
3110  //
3111 
3112 #if (NTDDI_VERSION >= NTDDI_WIN8)
3113  OplockCount = (ULONG) !FsRtlCheckLockForOplockRequest( &Fcb->Specific.Fcb.FileLock, &Fcb->Header.AllocationSize );
3114 #elif (NTDDI_VERSION >= NTDDI_WIN7)
3115  OplockCount = (ULONG) FsRtlAreThereCurrentOrInProgressFileLocks( &Fcb->Specific.Fcb.FileLock );
3116 #else
3117  OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( &Fcb->Specific.Fcb.FileLock );
3118 #endif
3119 
3120  }
3121 
3122  } else {
3123 
3124  OplockCount = Fcb->UncleanCount;
3125  }
3126 
3131 #if (NTDDI_VERSION >= NTDDI_WIN7)
3132  ||
3133  ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_ACK ))
3134 #endif
3135  ) {
3136 
3137  FatAcquireSharedFcb( IrpContext, Fcb );
3138  AcquiredFcb = TRUE;
3139 #if (NTDDI_VERSION >= NTDDI_WIN7)
3140  } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) {
3141 
3142  //
3143  // The caller didn't provide either REQUEST_OPLOCK_INPUT_FLAG_REQUEST or
3144  // REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer.
3145  //
3146 
3148 
3149  } else {
3150 #else
3151  } else {
3152 #endif
3153 
3154 #ifdef _MSC_VER
3155 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
3156 #endif
3157  FatBugCheck( FsControlCode, 0, 0 );
3158  }
3159 
3160  //
3161  // Fail batch, filter, and handle oplock requests if the file is marked
3162  // for delete.
3163  //
3164 
3167 #if (NTDDI_VERSION >= NTDDI_WIN7)
3168  ||
3169  ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->RequestedOplockLevel, OPLOCK_LEVEL_CACHE_HANDLE ))
3170 #endif
3171  ) &&
3173 
3175  }
3176 
3177  //
3178  // Call the FsRtl routine to grant/acknowledge oplock.
3179  //
3180 
3182  Irp,
3183  OplockCount );
3184 
3185  //
3186  // Once we call FsRtlOplockFsctrl, we no longer own the IRP and we should not complete it.
3187  //
3188 
3189  Irp = NULL;
3190 
3191  //
3192  // Set the flag indicating if Fast I/O is possible
3193  //
3194 
3195  Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
3196 
3197  } _SEH2_FINALLY {
3198 
3199  DebugUnwind( FatOplockRequest );
3200 
3201  //
3202  // Release all of our resources
3203  //
3204 
3205  if (AcquiredVcb) {
3206 
3207  FatReleaseVcb( IrpContext, Fcb->Vcb );
3208  }
3209 
3210  if (AcquiredFcb) {
3211 
3212  FatReleaseFcb( IrpContext, Fcb );
3213  }
3214 
3215  DebugTrace(-1, Dbg, "FatOplockRequest -> %08lx\n", Status );
3216  } _SEH2_END;
3217 
3218  FatCompleteRequest( IrpContext, Irp, Status );
3219 
3220  return Status;
3221 }
3222 
3223 
3224 //
3225 // Local Support Routine
3226 //
3227 
3228 _Requires_lock_held_(_Global_critical_region_)
3229 NTSTATUS
3230 FatLockVolume (
3231  IN PIRP_CONTEXT IrpContext,
3232  IN PIRP Irp
3233  )
3234 
3235 /*++
3236 
3237 Routine Description:
3238 
3239  This routine performs the lock volume operation. It is responsible for
3240  either completing of enqueuing the input Irp.
3241 
3242 Arguments:
3243 
3244  Irp - Supplies the Irp to process
3245 
3246 Return Value:
3247 
3248  NTSTATUS - The return status for the operation
3249 
3250 --*/
3251 
3252 {
3254 
3256 
3257  PVCB Vcb;
3258  PFCB Fcb;
3259  PCCB Ccb;
3260 
3261  PAGED_CODE();
3262 
3264 
3265  DebugTrace(+1, Dbg, "FatLockVolume...\n", 0);
3266 
3267  //
3268  // Decode the file object, the only type of opens we accept are
3269  // user volume opens.
3270  //
3271 
3273 
3275 
3276  DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3277  return STATUS_INVALID_PARAMETER;
3278  }
3279 
3280  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3281 
3283 
3284  DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3285  return STATUS_INVALID_PARAMETER;
3286  }
3287 
3288  //
3289  // Send our notification so that folks that like to hold handles on
3290  // volumes can get out of the way.
3291  //
3292 
3294 
3295  //
3296  // Acquire exclusive access to the Vcb and enqueue the Irp if we
3297  // didn't get access.
3298  //
3299 
3300  if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
3301 
3302  DebugTrace( 0, Dbg, "Cannot acquire Vcb\n", 0);
3303 
3304  Status = FatFsdPostRequest( IrpContext, Irp );
3305 
3306  DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status);
3307  return Status;
3308  }
3309 
3310  _SEH2_TRY {
3311 
3312  Status = FatLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
3313 
3314  } _SEH2_FINALLY {
3315 
3316  //
3317  // Since we drop and release the vcb while trying to punch the volume
3318  // down, it may be the case that we decide the operation should not
3319  // continue if the user raced a CloeseHandle() with us (and it finished
3320  // the cleanup) while we were waiting for our closes to finish.
3321  //
3322  // In this case, we will have been raised out of the acquire logic with
3323  // STATUS_FILE_CLOSED, and the volume will not be held.
3324  //
3325 
3327 
3328  FatReleaseVcb( IrpContext, Vcb );
3329  }
3330 
3332 
3333  //
3334  // The volume lock will be failing.
3335  //
3336 
3338  }
3339  } _SEH2_END;
3340 
3341  FatCompleteRequest( IrpContext, Irp, Status );
3342 
3343  DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", Status);
3344 
3345  return Status;
3346 }
3347 
3348 
3349 //
3350 // Local Support Routine
3351 //
3352 
3353 NTSTATUS
3355  IN PIRP_CONTEXT IrpContext,
3356  IN PIRP Irp
3357  )
3358 
3359 /*++
3360 
3361 Routine Description:
3362 
3363  This routine performs the unlock volume operation. It is responsible for
3364  either completing of enqueuing the input Irp.
3365 
3366 Arguments:
3367 
3368  Irp - Supplies the Irp to process
3369 
3370 Return Value:
3371 
3372  NTSTATUS - The return status for the operation
3373 
3374 --*/
3375 
3376 {
3377  NTSTATUS Status;
3378 
3380 
3381  PVCB Vcb;
3382  PFCB Fcb;
3383  PCCB Ccb;
3384 
3385  PAGED_CODE();
3386 
3388 
3389  DebugTrace(+1, Dbg, "FatUnlockVolume...\n", 0);
3390 
3391  //
3392  // Decode the file object, the only type of opens we accept are
3393  // user volume opens.
3394  //
3395 
3397 
3399 
3400  DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3401  return STATUS_INVALID_PARAMETER;
3402  }
3403 
3404  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3405 
3407 
3408  DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3409  return STATUS_INVALID_PARAMETER;
3410  }
3411 
3412  Status = FatUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
3413 
3414  //
3415  // Send notification that the volume is avaliable.
3416  //
3417 
3418  if (NT_SUCCESS( Status )) {
3419 
3421  }
3422 
3423  FatCompleteRequest( IrpContext, Irp, Status );
3424 
3425  DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status);
3426 
3427  return Status;
3428 }
3429 
3430 
3431 _Requires_lock_held_(_Global_critical_region_)
3432 NTSTATUS
3433 FatLockVolumeInternal (
3434  IN PIRP_CONTEXT IrpContext,
3435  IN PVCB Vcb,
3437  )
3438 
3439 /*++
3440 
3441 Routine Description:
3442 
3443  This routine performs the actual lock volume operation. It will be called
3444  by anyone wishing to try to protect the volume for a long duration. PNP
3445  operations are such a user.
3446 
3447  The volume must be held exclusive by the caller.
3448 
3449 Arguments:
3450 
3451  Vcb - The volume being locked.
3452 
3453  FileObject - File corresponding to the handle locking the volume. If this
3454  is not specified, a system lock is assumed.
3455 
3456 Return Value:
3457 
3458  NTSTATUS - The return status for the operation
3459 
3460 --*/
3461 
3462 {
3464  KIRQL SavedIrql;
3465  ULONG RemainingUserReferences = (FileObject? 1: 0);
3466 
3469  //
3470  // Go synchronous for the rest of the lock operation. It may be
3471  // reasonable to try to revisit this in the future, but for now
3472  // the purge below expects to be able to wait.
3473  //
3474  // We know it is OK to leave the flag up given how we're used at
3475  // the moment.
3476  //
3477 
3478  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
3479 
3480  //
3481  // If there are any open handles, this will fail.
3482  //
3483 
3484  if (!FatIsHandleCountZero( IrpContext, Vcb )) {
3485 
3486  return STATUS_ACCESS_DENIED;
3487  }
3488 
3489  //
3490  // Force Mm to get rid of its referenced file objects.
3491  //
3492 
3493  FatFlushFat( IrpContext, Vcb );
3494 
3495  FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
3496 
3497  FatCloseEaFile( IrpContext, Vcb, TRUE );
3498 
3499  //
3500  // Now back out of our synchronization and wait for the lazy writer
3501  // to finish off any lazy closes that could have been outstanding.
3502  //
3503  // Since we flushed, we know that the lazy writer will issue all
3504  // possible lazy closes in the next tick - if we hadn't, an otherwise
3505  // unopened file with a large amount of dirty data could have hung
3506  // around for a while as the data trickled out to the disk.
3507  //
3508  // This is even more important now since we send notification to
3509  // alert other folks that this style of check is about to happen so
3510  // that they can close their handles. We don't want to enter a fast
3511  // race with the lazy writer tearing down his references to the file.
3512  //
3513 
3514  FatReleaseVcb( IrpContext, Vcb );
3515 
3517 
3518  FatAcquireExclusiveVcb( IrpContext, Vcb );
3519 
3520  if (!NT_SUCCESS( Status )) {
3521 
3522  return Status;
3523  }
3524 
3525  //
3526  // The act of closing and purging may have touched pages in various
3527  // parent DCBs. We handle this by purging a second time.
3528  //
3529 
3530  FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
3531 
3532  FatReleaseVcb( IrpContext, Vcb );
3533 
3535 
3536  FatAcquireExclusiveVcb( IrpContext, Vcb );
3537 
3538  if (!NT_SUCCESS( Status )) {
3539 
3540  return Status;
3541  }
3542 
3543  //
3544  // Now rundown the delayed closes one last time. We appear to be able
3545  // to have additional collisions.
3546  //
3547 
3548  FatFspClose( Vcb );
3549 
3550  //
3551  // Check if the Vcb is already locked, or if the open file count
3552  // is greater than 1 (which implies that someone else also is
3553  // currently using the volume, or a file on the volume), and that the
3554  // VPB reference count only includes our residual and the handle (as
3555  // appropriate).
3556  //
3557  // We used to only check for the vpb refcount. This is unreliable since
3558  // the vpb refcount is dropped immediately before final close, meaning
3559  // that even though we had a good refcount, the close was inflight and
3560  // subsequent operations could get confused. Especially if the PNP path
3561  // was the lock caller, we delete the VCB with an outstanding opencount!
3562  //
3563 
3564  IoAcquireVpbSpinLock( &SavedIrql );
3565 
3566  if (!FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) &&
3567  (Vcb->Vpb->ReferenceCount <= 2 + RemainingUserReferences) &&
3568  (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 ))) {
3569 
3570  SetFlag(Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED));
3571  SetFlag(Vcb->VcbState, VCB_STATE_FLAG_LOCKED);
3572  Vcb->FileObjectWithVcbLocked = FileObject;
3573 
3574  } else {
3575 
3577  }
3578 
3579  IoReleaseVpbSpinLock( SavedIrql );
3580 
3581  //
3582  // If we successully locked the volume, see if it is clean now.
3583  //
3584 
3585  if (NT_SUCCESS( Status ) &&
3586  FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) &&
3587  !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) &&
3588  !CcIsThereDirtyData(Vcb->Vpb)) {
3589 
3590  FatMarkVolume( IrpContext, Vcb, VolumeClean );
3592  }
3593 
3594  NT_ASSERT( !NT_SUCCESS(Status) || (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 )));
3595 
3596  return Status;
3597 }
3598 
3599 
3600 NTSTATUS
3602  IN PIRP_CONTEXT IrpContext,
3603  IN PVCB Vcb,
3605  )
3606 
3607 /*++
3608 
3609 Routine Description:
3610 
3611  This routine performs the actual unlock volume operation.
3612 
3613  The volume must be held exclusive by the caller.
3614 
3615 Arguments:
3616 
3617  Vcb - The volume being locked.
3618 
3619  FileObject - File corresponding to the handle locking the volume. If this
3620  is not specified, a system lock is assumed.
3621 
3622 Return Value:
3623 
3624  NTSTATUS - The return status for the operation
3625 
3626  Attempting to remove a system lock that did not exist is OK.
3627 
3628 --*/
3629 
3630 {
3631  KIRQL SavedIrql;
3633 
3634  UNREFERENCED_PARAMETER( IrpContext );
3635 
3636  IoAcquireVpbSpinLock( &SavedIrql );
3637 
3638  if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && FileObject == Vcb->FileObjectWithVcbLocked) {
3639 
3640  //
3641  // This one locked it, unlock the volume
3642  //
3643 
3644  ClearFlag( Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED) );
3645  ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_LOCKED );
3646  Vcb->FileObjectWithVcbLocked = NULL;
3647 
3649  }
3650 
3651  IoReleaseVpbSpinLock( SavedIrql );
3652 
3653  return Status;
3654 }
3655 
3656 
3657 //
3658 // Local Support Routine
3659 //
3660 
3661 _Requires_lock_held_(_Global_critical_region_)
3662 NTSTATUS
3663 FatDismountVolume (
3664  IN PIRP_CONTEXT IrpContext,
3665  IN PIRP Irp
3666  )
3667 
3668 /*++
3669 
3670 Routine Description:
3671 
3672  This routine performs the dismount volume operation. It is responsible for
3673  either completing of enqueuing the input Irp.
3674 
3675 Arguments:
3676 
3677  Irp - Supplies the Irp to process
3678 
3679 Return Value:
3680 
3681  NTSTATUS - The return status for the operation
3682 
3683 --*/
3684 
3685 {
3688  BOOLEAN VcbHeld = FALSE;
3689  KIRQL SavedIrql;
3690 
3691  PVCB Vcb;
3692  PFCB Fcb;
3693  PCCB Ccb;
3694 
3696 
3697  DebugTrace(+1, Dbg, "FatDismountVolume...\n", 0);
3698 
3699  //
3700  // Decode the file object, the only type of opens we accept are
3701  // user volume opens on media that is not boot/paging and is not
3702  // already dismounted ... (but we need to check that stuff while
3703  // synchronized)
3704  //
3705 
3707 
3709  goto fn_return;
3710  }
3711 
3712  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3713 
3715 
3716  DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3717  return STATUS_INVALID_PARAMETER;
3718  }
3719 
3720  //
3721  // Make some unsynchronized checks to see if this operation is possible.
3722  // We will repeat the appropriate ones inside synchronization, but it is
3723  // good to avoid bogus notifications.
3724  //
3725 
3726  if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE )) {
3727 
3729  goto fn_return;
3730  }
3731 
3732  if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
3733 
3735  goto fn_return;
3736  }
3737 
3738  //
3739  // A bit of historical comment is in order.
3740  //
3741  // In all versions prior to NT5, we only permitted dismount if the volume had
3742  // previously been locked. Now we must permit a forced dismount, meaning that
3743  // we grab ahold of the whole kit-n-kaboodle - regardless of activity, open
3744  // handles, etc. - to flush and invalidate the volume.
3745  //
3746  // Previously, dismount assumed that lock had come along earlier and done some
3747  // of the work that we are now going to do - i.e., flush, tear down the eas. All
3748  // we had to do here is flush the device out and kill off as many of the orphan
3749  // fcbs as possible. This now changes.
3750  //
3751  // In fact, everything is a forced dismount now. This changes one interesting
3752  // aspect, which is that it used to be the case that the handle used to dismount
3753  // could come back, read, and induce a verify/remount. This is just not possible
3754  // now. The point of forced dismount is that very shortly someone will come along
3755  // and be destructive to the possibility of using the media further - format, eject,
3756  // etc. By using this path, callers are expected to tolerate the consequences.
3757  //
3758  // Note that the volume can still be successfully unlocked by this handle.
3759  //
3760 
3761  //
3762  // Send notification.
3763  //
3764 
3766 
3767  //
3768  // Force ourselves to wait and grab everything.
3769  //
3770 
3771  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
3772 
3773 #ifdef _MSC_VER
3774 #pragma prefast( push )
3775 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
3776 #pragma prefast( disable: 28193, "this will always wait" )
3777 #endif
3778 
3779  (VOID)FatAcquireExclusiveGlobal( IrpContext );
3780 
3781 #ifdef _MSC_VER
3782 #pragma prefast( pop )
3783 #endif
3784 
3785  _SEH2_TRY {
3786 
3787  //
3788  // Guess what? This can raise if a cleanup on the fileobject we
3789  // got races in ahead of us.
3790  //
3791 
3792  FatAcquireExclusiveVolume( IrpContext, Vcb );
3793  VcbHeld = TRUE;
3794 
3795  if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
3796 
3798  }
3799 
3800  FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushAndInvalidate );
3801 
3802  //
3803  // We defer the physical dismount until this handle is closed, per symmetric
3804  // implemntation in the other FS. This permits a dismounter to issue IOCTL
3805  // through this handle and perform device manipulation without racing with
3806  // creates attempting to mount the volume again.
3807  //
3808  // Raise a flag to tell the cleanup path to complete the dismount.
3809  //
3810 
3812 
3813  //
3814  // Indicate that the volume was dismounted so that we may return the
3815  // correct error code when operations are attempted via open handles.
3816  //
3817 
3819 
3821 
3822  //
3823  // Set a flag in the VPB to let others know that direct volume access is allowed.
3824  //
3825 
3826  IoAcquireVpbSpinLock( &SavedIrql );
3827  SetFlag( Vcb->Vpb->Flags, VPB_DIRECT_WRITES_ALLOWED );
3828  IoReleaseVpbSpinLock( SavedIrql );
3829 
3831 
3832  try_exit: NOTHING;
3833 
3834  } _SEH2_FINALLY {
3835 
3836 #if (NTDDI_VERSION >= NTDDI_WIN8)
3837 
3838  FsRtlDismountComplete( Vcb->TargetDeviceObject, Status );
3839 
3840 #endif
3841 
3842  if (VcbHeld) {
3843 
3844  FatReleaseVolume( IrpContext, Vcb );
3845  }
3846 
3847  FatReleaseGlobal( IrpContext );
3848 
3849  //
3850  // I do not believe it is possible to raise, but for completeness
3851  // notice and send notification of failure. We absolutely
3852  // cannot have raised in CheckForDismount.
3853  //
3854  // We decline to call an attempt to dismount a dismounted volume
3855  // a failure to do so.
3856  //
3857 
3860 
3862  }
3863  } _SEH2_END;
3864 
3865  fn_return:
3866 
3867  FatCompleteRequest( IrpContext, Irp, Status );
3868  DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", Status);
3869  return Status;
3870 }
3871 
3872 
3873 //
3874 // Local Support Routine
3875 //
3876 
3877 _Requires_lock_held_(_Global_critical_region_)
3878 NTSTATUS
3879 FatDirtyVolume (
3880  IN PIRP_CONTEXT IrpContext,
3881  IN PIRP Irp
3882  )
3883 
3884 /*++
3885 
3886 Routine Description:
3887 
3888  This routine marks the volume as dirty.
3889 
3890 Arguments:
3891 
3892  Irp - Supplies the Irp to process
3893 
3894 Return Value:
3895 
3896  NTSTATUS - The return status for the operation
3897 
3898 --*/
3899 
3900 {
3902 
3903  PVCB Vcb;
3904  PFCB Fcb;
3905  PCCB Ccb;
3906 
3907  PAGED_CODE();
3908 
3910 
3911  DebugTrace(+1, Dbg, "FatDirtyVolume...\n", 0);
3912 
3913  //
3914  // Decode the file object, the only type of opens we accept are
3915  // user volume opens.
3916  //
3917 
3919 
3921 
3922  DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3923  return STATUS_INVALID_PARAMETER;
3924  }
3925 
3926  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
3927 
3929 
3930  DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
3931  return STATUS_INVALID_PARAMETER;
3932  }
3933 
3934 
3935  //
3936  // Disable popups, we will just return any error.
3937  //
3938 
3939  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
3940 
3941  //
3942  // Verify the Vcb. We want to make sure we don't dirty some
3943  // random chunk of media that happens to be in the drive now.
3944  //
3945 
3946  FatVerifyVcb( IrpContext, Vcb );
3947 
3949 
3950  FatMarkVolume( IrpContext, Vcb, VolumeDirty );
3951 
3952  FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
3953 
3954  DebugTrace(-1, Dbg, "FatDirtyVolume -> STATUS_SUCCESS\n", 0);
3955 
3956  return STATUS_SUCCESS;
3957 }
3958 
3959 
3960 //
3961 // Local Support Routine
3962 //
3963 
3964 NTSTATUS
3966  IN PIRP_CONTEXT IrpContext,
3967  IN PIRP Irp
3968  )
3969 
3970 /*++
3971 
3972 Routine Description:
3973 
3974  This routine determines if a volume is currently dirty.
3975 
3976 Arguments:
3977 
3978  Irp - Supplies the Irp to process
3979 
3980 Return Value:
3981 
3982  NTSTATUS - The return status for the operation
3983 
3984 --*/
3985 
3986 {
3988 
3990  PVCB Vcb;
3991  PFCB Fcb;
3992  PCCB Ccb;
3993 
3995 
3996  PAGED_CODE();
3997 
3998  //
3999  // Get the current stack location and extract the output
4000  // buffer information.
4001  //
4002 
4004 
4005  //
4006  // Get a pointer to the output buffer. Look at the system buffer field in the
4007  // irp first. Then the Irp Mdl.
4008  //
4009 
4010  if (Irp->AssociatedIrp.SystemBuffer != NULL) {
4011 
4012  VolumeState = Irp->AssociatedIrp.SystemBuffer;
4013 
4014  } else if (Irp->MdlAddress != NULL) {
4015 
4016  VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, LowPagePriority | MdlMappingNoExecute );
4017 
4018  if (VolumeState == NULL) {
4019 
4022  }
4023 
4024  } else {
4025 
4028  }
4029 
4030  //
4031  // Make sure the output buffer is large enough and then initialize
4032  // the answer to be that the volume isn't dirty.
4033  //
4034 
4035  if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
4036 
4038  return STATUS_INVALID_PARAMETER;
4039  }
4040 
4041  *VolumeState = 0;
4042 
4043  //
4044  // Decode the file object
4045  //
4046 
4048 
4049  if (TypeOfOpen != UserVolumeOpen) {
4050 
4052  return STATUS_INVALID_PARAMETER;
4053  }
4054 
4055  if (Vcb->VcbCondition != VcbGood) {
4056 
4058  return STATUS_VOLUME_DISMOUNTED;
4059  }
4060 
4061  //
4062  // Disable PopUps, we want to return any error.
4063  //
4064 
4065  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
4066 
4067  //
4068  // Verify the Vcb. We want to make double sure that this volume
4069  // is around so that we know our information is good.
4070  //
4071 
4072  FatVerifyVcb( IrpContext, Vcb );
4073 
4074  //
4075  // Now set the returned information. We can avoid probing the disk since
4076  // we know our internal state is in sync.
4077  //
4078 
4079  if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY) ) {
4080 
4082  }
4083 
4084  Irp->IoStatus.Information = sizeof( ULONG );
4085 
4086  FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
4087  return STATUS_SUCCESS;
4088 }
4089 
4090 
4091 //
4092 // Local Support Routine
4093 //
4094 
4095 NTSTATUS
4097  IN PIRP_CONTEXT IrpContext,
4098  IN PIRP Irp
4099  )
4100 
4101 /*++
4102 
4103 Routine Description:
4104 
4105  This routine determines if a volume is currently mounted.
4106 
4107 Arguments:
4108 
4109  Irp - Supplies the Irp to process
4110 
4111 Return Value:
4112 
4113  NTSTATUS - The return status for the operation
4114 
4115 --*/
4116 
4117 {
4118  NTSTATUS Status;
4119 
4121 
4122  PVCB Vcb = NULL;
4123  PFCB Fcb;
4124  PCCB Ccb;
4125 
4126  PAGED_CODE();
4127 
4129 
4131 
4132  DebugTrace(+1, Dbg, "FatIsVolumeMounted...\n", 0);
4133 
4134  //
4135  // Decode the file object.
4136  //
4137 
4139 
4140  NT_ASSERT( Vcb != NULL );
4141  _Analysis_assume_( Vcb != NULL );
4142 
4143  //
4144  // Disable PopUps, we want to return any error.
4145  //
4146 
4147  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
4148 
4149  //
4150  // Verify the Vcb.
4151  //
4152 
4153  FatVerifyVcb( IrpContext, Vcb );
4154 
4155  FatCompleteRequest( IrpContext, Irp, Status );
4156 
4157  DebugTrace(-1, Dbg, "FatIsVolumeMounted -> %08lx\n", Status);
4158 
4159  return Status;
4160 }
4161 
4162 
4163 //
4164 // Local Support Routine
4165 //
4166 
4167 NTSTATUS
4169  IN PIRP_CONTEXT IrpContext,
4170  IN PIRP Irp
4171  )
4172 
4173 /*++
4174 
4175 Routine Description:
4176 
4177  This routine determines if a pathname is a-priori illegal by inspecting
4178  the the characters used. It is required to be correct on a FALSE return.
4179 
4180  N.B.: current implementation is intentioanlly a no-op. This may change
4181  in the future. A careful reader of the previous implementation of this
4182  FSCTL in FAT would discover that it violated the requirement stated above
4183  and could return FALSE for a valid (createable) pathname.
4184 
4185 Arguments:
4186 
4187  Irp - Supplies the Irp to process
4188 
4189 Return Value:
4190 
4191  NTSTATUS - The return status for the operation
4192 
4193 --*/
4194 
4195 {
4196  PAGED_CODE();
4197 
4198  DebugTrace(+1, Dbg, "FatIsPathnameValid...\n", 0);
4199 
4200  FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
4201 
4202  DebugTrace(-1, Dbg, "FatIsPathnameValid -> %08lx\n", STATUS_SUCCESS);
4203 
4204  return STATUS_SUCCESS;
4205 }
4206 
4207 
4208 //
4209 // Local Support Routine
4210 //
4211 
4212 NTSTATUS
4214  IN PIRP_CONTEXT IrpContext,
4215  IN PIRP Irp
4216  )
4217 
4218 /*++
4219 
4220 Routine Description:
4221 
4222  This routine simply returns the first 0x24 bytes of sector 0.
4223 
4224 Arguments:
4225 
4226  Irp - Supplies the Irp to process
4227 
4228 Return Value:
4229 
4230  NTSTATUS - The return status for the operation
4231 
4232 --*/
4233 
4234 {
4236 
4237  PVCB Vcb;
4238 
4239  PFSCTL_QUERY_FAT_BPB_BUFFER BpbBuffer;
4240 
4241  PAGED_CODE();
4242 
4244 
4245  DebugTrace(+1, Dbg, "FatQueryBpb...\n", 0);
4246 
4247  //
4248  // Get the Vcb. If we didn't keep the information needed for this call,
4249  // we had a reason ...
4250  //
4251 
4253 
4254  if (Vcb->First0x24BytesOfBootSector == NULL) {
4255 
4257  DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST );
4259  }
4260 
4261  //
4262  // Extract the buffer
4263  //
4264 
4265  BpbBuffer = (PFSCTL_QUERY_FAT_BPB_BUFFER)Irp->AssociatedIrp.SystemBuffer;
4266 
4267  //
4268  // Make sure the buffer is big enough.
4269  //
4270 
4271  if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < 0x24) {
4272 
4274  DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
4275  return STATUS_BUFFER_TOO_SMALL;
4276  }
4277 
4278  //
4279  // Fill in the output buffer
4280  //
4281 
4283  Vcb->First0x24BytesOfBootSector,
4284  0x24 );
4285 
4286  Irp->IoStatus.Information = 0x24;
4287 
4288  FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
4289  DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_SUCCESS);
4290  return STATUS_SUCCESS;
4291 }
4292 
4293 
4294 //
4295 // Local Support Routine
4296 //
4297 
4298 _Requires_lock_held_(_Global_critical_region_)
4299 NTSTATUS
4300 FatInvalidateVolumes (
4301  IN PIRP Irp
4302  )
4303 
4304 /*++
4305 
4306 Routine Description:
4307 
4308  This routine searches for all the volumes mounted on the same real device
4309  of the current DASD handle, and marks them all bad. The only operation
4310  that can be done on such handles is cleanup and close.
4311 
4312 Arguments:
4313 
4314  Irp - Supplies the Irp to process
4315 
4316 Return Value:
4317 
4318  NTSTATUS - The return status for the operation
4319 
4320 --*/
4321 
4322 {
4323  NTSTATUS Status;
4324  IRP_CONTEXT IrpContext;
4326 
4327  LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
4328 
4329  HANDLE Handle;
4330 
4331  PLIST_ENTRY Links;
4332 
4333  PFILE_OBJECT FileToMarkBad;
4334  PDEVICE_OBJECT DeviceToMarkBad;
4335 
4337 
4338  DebugTrace(+1, Dbg, "FatInvalidateVolumes...\n", 0);
4339 
4340  //
4341  // Check for the correct security access.
4342  // The caller must have the SeTcbPrivilege.
4343  //
4344 
4345  if (!SeSinglePrivilegeCheck(TcbPrivilege, Irp->RequestorMode)) {
4346 
4348 
4349  DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_PRIVILEGE_NOT_HELD);
4351  }
4352 
4353  //
4354  // Try to get a pointer to the device object from the handle passed in.
4355  //
4356 
4357 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
4358  if (IoIs32bitProcess( Irp )) {
4359 
4360  if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(UINT32)) {
4361 
4363 
4364  DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER);
4365  return STATUS_INVALID_PARAMETER;
4366  }
4367 
4368  Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
4369  } else {
4370 #endif
4371  if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(HANDLE)) {
4372 
4374 
4375  DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER);
4376  return STATUS_INVALID_PARAMETER;
4377  }
4378 
4379  Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
4380 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
4381  }
4382 #endif
4383 
4384 
4386  0,
4388  KernelMode,
4389 #ifndef __REACTOS__
4390  &FileToMarkBad,
4391 #else
4392  (PVOID *)&FileToMarkBad,
4393 #endif
4394  NULL );
4395 
4396  if (!NT_SUCCESS(Status)) {
4397 
4399 
4400  DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", Status);
4401  return Status;
4402 
4403  } else {
4404 
4405  //
4406  // We only needed the pointer, not a reference.
4407  //
4408 
4409  ObDereferenceObject( FileToMarkBad );
4410 
4411  //
4412  // Grab the DeviceObject from the FileObject.
4413  //
4414 
4415  DeviceToMarkBad = FileToMarkBad->DeviceObject;
4416  }
4417 
4418  RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
4419 
4420  SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
4421  IrpContext.MajorFunction = IrpSp->MajorFunction;
4422  IrpContext.MinorFunction = IrpSp->MinorFunction;
4423 
4424 #ifdef _MSC_VER
4425 #pragma prefast( push )
4426 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
4427 #pragma prefast( disable: 28193, "this will always wait" )
4428 #endif
4429 
4430  FatAcquireExclusiveGlobal( &IrpContext );
4431 
4432 #ifdef _MSC_VER
4433 #pragma prefast( pop )
4434 #endif
4435 
4436  //
4437  // First acquire the FatData resource shared, then walk through all the
4438  // mounted VCBs looking for candidates to mark BAD.
4439  //
4440  // On volumes we mark bad, check for dismount possibility (which is
4441  // why we have to get the next link early).
4442  //
4443 
4444  Links = FatData.VcbQueue.Flink;
4445 
4446  while (Links != &FatData.VcbQueue) {
4447 
4448  PVCB ExistingVcb;
4449 
4450  ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
4451 
4452  Links = Links->Flink;
4453 
4454  //
4455  // If we get a match, mark the volume Bad, and also check to
4456  // see if the volume should go away.
4457  //
4458 
4459  if (ExistingVcb->Vpb->RealDevice == DeviceToMarkBad) {
4460 
4461  BOOLEAN VcbDeleted = FALSE;
4462 
4463  //
4464  // Here we acquire the Vcb exclusive and try to purge
4465  // all the open files. The idea is to have as little as
4466  // possible stale data visible and to hasten the volume
4467  // going away.
4468  //
4469 
4470  (VOID)FatAcquireExclusiveVcb( &IrpContext, ExistingVcb );
4471 
4472 #ifdef _MSC_VER
4473 #pragma prefast( push )
4474 #pragma prefast( disable: 28175, "touching Vpb is ok for a filesystem" )
4475 #endif
4476 
4477  if (ExistingVcb->Vpb == DeviceToMarkBad->Vpb) {
4478 
4479  KIRQL OldIrql;
4480 
4482 
4483  if (FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_MOUNTED )) {
4484 
4485  PVPB NewVpb;
4486 
4487  NewVpb = ExistingVcb->SwapVpb;
4488  ExistingVcb->SwapVpb = NULL;
4490 
4491  RtlZeroMemory( NewVpb, sizeof( VPB ) );
4492  NewVpb->Type = IO_TYPE_VPB;
4493  NewVpb->Size = sizeof( VPB );
4494  NewVpb->RealDevice = DeviceToMarkBad;
4495  NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING );
4496 
4497  DeviceToMarkBad->Vpb = NewVpb;
4498  }
4499 
4500  NT_ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL );
4501 
4502 #ifdef _MSC_VER
4503 #pragma prefast( pop )
4504 #endif
4505 
4507  }
4508 
4509  FatSetVcbCondition( ExistingVcb, VcbBad );
4510 
4511  //
4512  // Process the root directory, if it is present.
4513  //
4514 
4515  if (ExistingVcb->RootDcb != NULL) {
4516 
4517  //
4518  // In order to safely mark all FCBs bad, we must acquire everything.
4519  //
4520 
4521  FatAcquireExclusiveVolume(&IrpContext, ExistingVcb);
4522  FatMarkFcbCondition( &IrpContext, ExistingVcb->RootDcb, FcbBad, TRUE );
4523  FatReleaseVolume(&IrpContext, ExistingVcb);
4524 
4525  //
4526  // Purging the file objects on this volume could result in the memory manager
4527  // dereferencing it's file pointer which could be the last reference and
4528  // trigger object deletion and VCB deletion. Protect against that here by
4529  // temporarily biasing the file count, and later checking for dismount.
4530  //
4531 
4532  ExistingVcb->OpenFileCount += 1;
4533 
4534  FatPurgeReferencedFileObjects( &IrpContext,
4535  ExistingVcb->RootDcb,
4536  NoFlush );
4537 
4538  ExistingVcb->OpenFileCount -= 1;
4539 
4540  VcbDeleted = FatCheckForDismount( &IrpContext, ExistingVcb, FALSE );
4541  }
4542 
4543  //
4544  // Only release the VCB if it did not go away.
4545  //
4546 
4547  if (!VcbDeleted) {
4548 
4549  FatReleaseVcb( &IrpContext, ExistingVcb );
4550  }
4551  }
4552  }
4553 
4554  FatReleaseGlobal( &IrpContext );
4555 
4557 
4558  DebugTrace(-1, Dbg, "FatInvalidateVolumes -> STATUS_SUCCESS\n", 0);
4559 
4560  return STATUS_SUCCESS;
4561 }
4562 
4563 
4564 //
4565 // Local Support routine
4566 //
4567 
4568 BOOLEAN
4570  IN PIRP_CONTEXT IrpContext,
4571  IN PVCB Vcb,
4572  IN PVOID Buffer,
4573  IN LBO Lbo,
4574  IN ULONG NumberOfBytesToRead,
4575  IN BOOLEAN ReturnOnError
4576  )
4577 
4578 /*++
4579 
4580 Routine Description:
4581 
4582  This routine is used to read in a range of bytes from the disk. It
4583  bypasses all of the caching and regular I/O logic, and builds and issues
4584  the requests itself. It does this operation overriding the verify
4585  volume flag in the device object.
4586 
4587 Arguments:
4588 
4589  Vcb - Supplies the target device object for this operation.
4590 
4591  Buffer - Supplies the buffer that will recieve the results of this operation
4592 
4593  Lbo - Supplies the byte offset of where to start reading
4594 
4595  NumberOfBytesToRead - Supplies the number of bytes to read, this must
4596  be in multiple of bytes units acceptable to the disk driver.
4597 
4598  ReturnOnError - Indicates that we should return on an error, instead
4599  of raising.
4600 
4601 Return Value:
4602 
4603  BOOLEAN - TRUE if the operation succeded, FALSE otherwise.
4604 
4605 --*/
4606 
4607 {
4608  KEVENT Event;
4609  PIRP Irp;
4611  NTSTATUS Status;
4613 
4614  PAGED_CODE();
4615 
4616  DebugTrace(0, Dbg, "FatPerformVerifyDiskRead, Lbo = %08lx\n", Lbo );
4617 
4618  //
4619  // Initialize the event we're going to use
4620  //
4621 
4623 
4624  //
4625  // Build the irp for the operation and also set the overrride flag
4626  //
4627 
4628  ByteOffset.QuadPart = Lbo;
4629 
4631  Vcb->TargetDeviceObject,
4632  Buffer,
4633  NumberOfBytesToRead,
4634  &ByteOffset,
4635  &Event,
4636  &Iosb );
4637 
4638  if ( Irp == NULL ) {
4639 
4641  }
4642 
4644 
4645  //
4646  // Call the device to do the read and wait for it to finish.
4647  //
4648 
4649  Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
4650 
4651  if (Status == STATUS_PENDING) {
4652 
4654 
4655  Status = Iosb.Status;
4656  }
4657 
4659 
4660  //
4661  // Special case this error code because this probably means we used
4662  // the wrong sector size and we want to reject STATUS_WRONG_VOLUME.
4663  //
4664 
4666 
4667  return FALSE;
4668  }
4669 
4670  //
4671  // If it doesn't succeed then either return or raise the error.
4672  //
4673 
4674  if (!NT_SUCCESS(Status)) {
4675 
4676  if (ReturnOnError) {
4677 
4678  return FALSE;
4679 
4680  } else {
4681 
4682  FatNormalizeAndRaiseStatus( IrpContext, Status );
4683  }
4684  }
4685 
4686  //
4687  // And return to our caller
4688  //
4689 
4690  return TRUE;
4691 }
4692 
4693 
4694 //
4695 // Local Support Routine
4696 //
4697 
4698 _Requires_lock_held_(_Global_critical_region_)
4699 NTSTATUS
4700 FatQueryRetrievalPointers (
4701  IN PIRP_CONTEXT IrpContext,
4702  IN PIRP Irp
4703  )
4704 
4705 /*++
4706 
4707 Routine Description:
4708 
4709  This routine performs the query retrieval pointers operation.
4710  It returns the retrieval pointers for the specified input
4711  file from the start of the file to the request map size specified
4712  in the input buffer.
4713 
4714 Arguments:
4715 
4716  Irp - Supplies the Irp to process
4717 
4718 Return Value:
4719 
4720  NTSTATUS - The return status for the operation
4721 
4722 --*/
4723 
4724 {
4726 
4728 
4729  PVCB Vcb;
4730  PFCB Fcb;
4731  PCCB Ccb;
4732 
4733  PLARGE_INTEGER RequestedMapSize;
4734  PLARGE_INTEGER *MappingPairs;
4735 
4736  ULONG Index;
4737  ULONG i;
4739  LBO Lbo;
4740  ULONG Vbo;
4741  ULONG MapSize;
4742  BOOLEAN Result;
4743 
4744  PAGED_CODE();
4745 
4746  //
4747  // Get the current stack location
4748  //
4749 
4751 
4752  //
4753  // Make this a synchronous IRP because we need access to the input buffer and
4754  // this Irp is marked METHOD_NEITHER.
4755  //
4756 
4757  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
4758 
4759  //
4760  // Decode the file object and ensure that it is the paging file
4761  //
4762  // Only Kernel mode clients may query retrieval pointer information about
4763  // a file. Ensure that this is the case for this caller.
4764  //
4765 
4767 
4768  if (Irp->RequestorMode != KernelMode ||
4769  Fcb == NULL ||
4771 
4773  return STATUS_INVALID_PARAMETER;
4774  }
4775 
4776  //
4777  // Extract the input and output buffer information. The input contains
4778  // the requested size of the mappings in terms of VBO. The output
4779  // parameter will receive a pointer to nonpaged pool where the mapping
4780  // pairs are stored.
4781  //
4782 
4783  NT_ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof(LARGE_INTEGER) );
4784  NT_ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength == sizeof(PVOID) );
4785 
4786  RequestedMapSize = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
4787  MappingPairs = Irp->UserBuffer;
4788 
4789  //
4790  // Acquire exclusive access to the Fcb
4791  //
4792 
4793  FatAcquireExclusiveFcb( IrpContext, Fcb );
4794 
4795  _SEH2_TRY {
4796 
4797  //
4798  // Verify the Fcb is still OK
4799  //
4800 
4801  FatVerifyFcb( IrpContext, Fcb );
4802 
4803  //
4804  // Check if the mapping the caller requested is too large
4805  //
4806 
4807  if ((*RequestedMapSize).QuadPart > Fcb->Header.FileSize.QuadPart) {
4808 
4810  }
4811 
4812  //
4813  // Now get the index for the mcb entry that will contain the
4814  // callers request and allocate enough pool to hold the
4815  // output mapping pairs. Mapping should always be present, but handle
4816  // the case where it isn't.
4817  //
4818 
4820  &Fcb->Mcb,
4821  RequestedMapSize->LowPart - 1,
4822  &Lbo,
4823  NULL,
4824  &Index );
4825 
4826  if (!Result) {
4827 
4828  NT_ASSERT(FALSE);
4830  }
4831 
4832  *MappingPairs = FsRtlAllocatePoolWithTag( NonPagedPoolNx,
4833  (Index + 2) * (2 * sizeof(LARGE_INTEGER)),
4835 
4836  //
4837  // Now copy over the mapping pairs from the mcb
4838  // to the output buffer. We store in [sector count, lbo]
4839  // mapping pairs and end with a zero sector count.
4840  //
4841 
4842  MapSize = RequestedMapSize->LowPart;
4843 
4844  for (i = 0; i <= Index; i += 1) {
4845 
4847 
4848  if (SectorCount > MapSize) {
4849  SectorCount = MapSize;
4850  }
4851 
4852  (*MappingPairs)[ i*2 + 0 ].QuadPart = SectorCount;
4853  (*MappingPairs)[ i*2 + 1 ].QuadPart = Lbo;
4854 
4855  MapSize -= SectorCount;
4856  }
4857 
4858  (*MappingPairs)[ i*2 + 0 ].QuadPart = 0;
4859 
4861  }
4862  _SEH2_FINALLY {
4863 
4864  DebugUnwind( FatQueryRetrievalPointers );
4865 
4866  //
4867  // Release all of our resources
4868  //
4869 
4870  FatReleaseFcb( IrpContext, Fcb );
4871 
4872  //
4873  // If this is an abnormal termination then undo our work, otherwise
4874  // complete the irp
4875  //
4876 
4877  if (!_SEH2_AbnormalTermination()) {
4878 
4879  FatCompleteRequest( IrpContext, Irp, Status );
4880  }
4881  } _SEH2_END;
4882 
4883  return Status;
4884 }
4885 
4886 
4887 //
4888 // Local Support Routine
4889 //
4890 
4891 NTSTATUS
4893  IN PIRP_CONTEXT IrpContext,
4894  IN PIRP Irp
4895  )
4896 
4897 /*++
4898 
4899 Routine Description:
4900 
4901  This routine returns the filesystem performance counters from the
4902  appropriate VCB.
4903 
4904 Arguments:
4905 
4906  Irp - Supplies the Irp to process
4907 
4908 Return Value:
4909 
4910  NTSTATUS - The return status for the operation
4911 
4912 --*/
4913 
4914 {
4916  NTSTATUS Status;
4917  PVCB Vcb;
4918 
4921  ULONG StatsSize;
4923 
4924  PAGED_CODE();
4925 
4927 
4928  DebugTrace(+1, Dbg, "FatGetStatistics...\n", 0);
4929 
4930  //
4931  // Extract the buffer
4932  //
4933 
4934  BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
4935 
4936  //
4937  // Get a pointer to the output buffer.
4938  //
4939 
4940  Buffer = Irp->AssociatedIrp.SystemBuffer;
4941 
4942  //
4943  // Make sure the buffer is big enough for at least the common part.
4944  //
4945 
4946  if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) {
4947 
4949 
4950  DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
4951 
4952  return STATUS_BUFFER_TOO_SMALL;
4953  }
4954 
4955  //
4956  // Now see how many bytes we can copy.
4957  //
4958 
4959  StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * FatData.NumberProcessors;
4960 
4961  if (BufferLength < StatsSize) {
4962 
4965 
4966  } else {
4967 
4968  BytesToCopy = StatsSize;
4970  }
4971 
4972  //
4973  // Get the Vcb.
4974  //
4975 
4977 
4978  //
4979  // Fill in the output buffer
4980  //
4981 
4982  RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
4983 
4984  Irp->IoStatus.Information = BytesToCopy;
4985 
4986  FatCompleteRequest( IrpContext, Irp, Status );
4987 
4988  DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", Status);
4989 
4990  return Status;
4991 }
4992 
4993 //
4994 // Local Support Routine
4995 //
4996 
4997 _Requires_lock_held_(_Global_critical_region_)
4998 NTSTATUS
4999 FatGetVolumeBitmap(
5000  IN PIRP_CONTEXT IrpContext,
5001  IN PIRP Irp
5002  )
5003 
5004 /*++
5005 
5006 Routine Description:
5007 
5008  This routine returns the volume allocation bitmap.
5009 
5010  Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in
5011  through the input buffer.
5012  Output = the VOLUME_BITMAP_BUFFER data structure is returned through
5013  the output buffer.
5014 
5015  We return as much as the user buffer allows starting the specified input
5016  LCN (trucated to a byte). If there is no input buffer, we start at zero.
5017 
5018 Arguments:
5019 
5020  Irp - Supplies the Irp being processed.
5021 
5022 Return Value:
5023 
5024  NTSTATUS - The return status for the operation.
5025 
5026 --*/
5027 {
5028  NTSTATUS Status;
5030 
5031  PVCB Vcb;
5032  PFCB Fcb;
5033  PCCB Ccb;
5034 
5036  ULONG TotalClusters;
5037  ULONG DesiredClusters;
5038  ULONG StartingCluster;
5039  ULONG EndingCluster;
5042  LARGE_INTEGER StartingLcn;
5044 
5045  PAGED_CODE();
5046 
5047  //
5048  // Get the current Irp stack location and save some references.
5049  //
5050 
5052 
5053  DebugTrace(+1, Dbg, "FatGetVolumeBitmap, FsControlCode = %08lx\n",
5054  IrpSp->Parameters.FileSystemControl.FsControlCode);
5055 
5056  //
5057  // Make this a synchronous IRP because we need access to the input buffer and
5058  // this Irp is marked METHOD_NEITHER.
5059  //
5060 
5061  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
5062 
5063  //
5064  // Extract and decode the file object and check for type of open.
5065  //
5066 
5068 
5070  return STATUS_INVALID_PARAMETER;
5071  }
5072 
5073  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
5074 
5076 
5077  DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> %08lx\n", STATUS_INVALID_PARAMETER);
5078  return STATUS_INVALID_PARAMETER;
5079  }
5080 
5081  InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
5082  OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
5083 
5085 
5086  //
5087  // Check for a minimum length on the input and output buffers.
5088  //
5089 
5090  if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) ||
5092 
5094  return STATUS_BUFFER_TOO_SMALL;
5095  }
5096 
5097  //
5098  // Check if a starting cluster was specified.
5099  //
5100 
5101  TotalClusters = Vcb->AllocationSupport.NumberOfClusters;
5102 
5103  //
5104  // Check for valid buffers
5105  //
5106 
5107  _SEH2_TRY {
5108 
5109  if (Irp->RequestorMode != KernelMode) {
5110 
5111  ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
5113  sizeof(UCHAR) );
5114 
5116  }
5117 
5118  StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn;
5119 
5121 
5123 
5124  FatRaiseStatus( IrpContext,
5127  } _SEH2_END;
5128 
5129  if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) {
5130 
5132  return STATUS_INVALID_PARAMETER;
5133 
5134  } else {
5135 
5136  StartingCluster = StartingLcn.LowPart & ~7;
5137  }
5138 
5139  (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
5140 
5141  //
5142  // Only return what will fit in the user buffer.
5143  //
5144 
5146  DesiredClusters = TotalClusters - StartingCluster;
5147 
5148  if (OutputBufferLength < (DesiredClusters + 7) / 8) {
5149 
5152 
5153  } else {
5154 
5155  BytesToCopy = (DesiredClusters + 7) / 8;
5157  }
5158 
5159  //
5160  // Use try/finally for cleanup.
5161  //
5162 
5163  _SEH2_TRY {
5164 
5165  _SEH2_TRY {
5166 
5167  //
5168  // Verify the Vcb is still OK
5169  //
5170 
5171  FatQuickVerifyVcb( IrpContext, Vcb );
5172 
5173  //
5174  // Fill in the fixed part of the output buffer
5175  //
5176 
5177  OutputBuffer->StartingLcn.QuadPart = StartingCluster;
5178  OutputBuffer->BitmapSize.QuadPart = DesiredClusters;
5179 
5180  if (Vcb->NumberOfWindows == 1) {
5181 
5182  //
5183  // Just copy the volume bitmap into the user buffer.
5184  //
5185 
5186  NT_ASSERT( Vcb->FreeClusterBitMap.Buffer != NULL );
5187 
5188  RtlCopyMemory( &OutputBuffer->Buffer[0],
5189  (PUCHAR)Vcb->FreeClusterBitMap.Buffer + StartingCluster/8,
5190  BytesToCopy );
5191  } else {
5192 
5193  //
5194  // Call out to analyze the FAT. We must bias by two to account for
5195  // the zero base of this API and FAT's physical reality of starting
5196  // the file heap at cluster 2.
5197  //
5198  // Note that the end index is inclusive - we need to subtract one to
5199  // calculcate it.
5200  //
5201  // I.e.: StartingCluster 0 for one byte of bitmap means a start cluster
5202  // of 2 and end cluster of 9, a run of eight clusters.
5203  //
5204 
5205  EndingCluster = StartingCluster + (BytesToCopy * 8);
5206 
5207  //
5208  // Make sure we do not read past the end of the entries.
5209  //
5210 
5211  if (EndingCluster > TotalClusters) {
5212 
5213  EndingCluster = TotalClusters;
5214  }
5215 
5216  FatExamineFatEntries( IrpContext,
5217  Vcb,
5218  StartingCluster + 2,
5219  EndingCluster + 2 - 1,
5220  FALSE,
5221  NULL,
5222  (PULONG)&OutputBuffer->Buffer[0] );
5223  }
5224 
5226 
5228 
5229  FatRaiseStatus( IrpContext,
5232  } _SEH2_END;
5233 
5234  } _SEH2_FINALLY {
5235 
5236  FatReleaseVcb( IrpContext, Vcb );
5237  } _SEH2_END;
5238 
5239  Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) +
5240  BytesToCopy;
5241 
5242  FatCompleteRequest( IrpContext, Irp, Status );
5243 
5244  DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> VOID\n", 0);
5245 
5246  return Status;
5247 }
5248 
5249 
5250 //
5251 // Local Support Routine
5252 //
5253 
5254 _Requires_lock_held_(_Global_critical_region_)
5255 NTSTATUS
5256 FatGetRetrievalPointers (
5257  IN PIRP_CONTEXT IrpContext,
5258  IN PIRP Irp
5259  )
5260 
5261 /*++
5262 
5263 Routine Description:
5264 
5265  This routine scans the MCB and builds an extent list. The first run in
5266  the output extent list will start at the begining of the contiguous
5267  run specified by the input parameter.
5268 
5269  Input = STARTING_VCN_INPUT_BUFFER;
5270  Output = RETRIEVAL_POINTERS_BUFFER.
5271 
5272 Arguments:
5273 
5274  Irp - Supplies the Irp being processed.
5275 
5276 Return Value:
5277 
5278  NTSTATUS - The return status for the operation.
5279 
5280 --*/
5281 {
5284 
5285  PVCB Vcb;
5286  PFCB FcbOrDcb;
5287  PCCB Ccb;
5288  PLARGE_MCB McbToUse = NULL;
5290 
5291  ULONG Index;
5292  ULONG ClusterShift = 0;
5295 
5296  ULONG Run;
5297  ULONG RunCount;
5298  ULONG StartingRun;
5299  LARGE_INTEGER StartingVcn;
5300 
5303 
5304  VBO LastVbo;
5305  LBO LastLbo;
5306  ULONG LastIndex;
5307 
5309 
5310  PAGED_CODE();
5311 
5312  //
5313  // Get the current Irp stack location and save some references.
5314  //
5315 
5317 
5318  DebugTrace(+1, Dbg, "FatGetRetrievalPointers, FsControlCode = %08lx\n",
5319  IrpSp->Parameters.FileSystemControl.FsControlCode);
5320 
5321  //
5322  // Make this a synchronous IRP because we need access to the input buffer and
5323  // this Irp is marked METHOD_NEITHER.
5324  //
5325 
5326  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
5327 
5328  //
5329  // Extract and decode the file object and check for type of open.
5330  //
5331 
5333 
5335 
5337  return STATUS_INVALID_PARAMETER;
5338  }
5339 
5340  //
5341  // Get the input and output buffer lengths and pointers.
5342  // Initialize some variables.
5343  //
5344 
5345  InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
5346  OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
5347 
5349 
5350  //
5351  // Check for a minimum length on the input and ouput buffers.
5352  //
5353 
5354  if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) ||
5356 
5358  return STATUS_BUFFER_TOO_SMALL;
5359  }
5360 
5361  //
5362  // Acquire the Fcb and enqueue the Irp if we didn't get access. Go for
5363  // shared on read-only media so we can allow prototype XIP to get
5364  // recursive, as well as recognizing this is safe anyway.
5365  //
5367 
5369 
5370  (VOID)FatAcquireSharedFcb( IrpContext, FcbOrDcb );
5371 
5372  } else {
5373 
5374  (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
5375  }
5376  } else if ((TypeOfOpen == UserVolumeOpen )) {
5377 
5378  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
5379 
5381 
5382  DebugTrace(-1, Dbg, "FatMoveFile -> 0x%x\n", STATUS_ACCESS_DENIED);
5383  return STATUS_ACCESS_DENIED;
5384  }
5385 
5386  (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
5387  }
5388 
5389  _SEH2_TRY {
5390 
5391  //
5392  // Verify the Fcb is still OK, or if it is a volume handle, the VCB.
5393  //
5394 
5396 
5397  FatVerifyFcb( IrpContext, FcbOrDcb );
5398 
5399  //
5400  // If we haven't yet set the correct AllocationSize, do so.
5401  //
5402 
5403  if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
5404 
5405  FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
5406 
5407  //
5408  // If this is a non-root directory, we have a bit more to
5409  // do since it has not gone through FatOpenDirectoryFile().
5410  //
5411 
5412  if (NodeType(FcbOrDcb) == FAT_NTC_DCB ||
5414 
5415  FcbOrDcb->Header.FileSize.LowPart =
5416  FcbOrDcb->Header.AllocationSize.LowPart;
5417  }
5418  }
5419 
5420 
5421  ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
5422 
5423 #ifdef _MSC_VER
5424 #pragma prefast( suppress:28931, "calculate it anyway, in case someone adds code that uses this in the future" )
5425 #endif
5426  ClusterSize = 1 << ClusterShift;
5427 
5428  AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
5429  McbToUse = &FcbOrDcb->Mcb;
5430 
5431  } else if ((TypeOfOpen == UserVolumeOpen )) {
5432 
5433  FatQuickVerifyVcb( IrpContext, Vcb );
5434 
5435  if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BAD_BLOCKS_POPULATED)) {
5436 
5437  //
5438  // If the bad cluster mcb isn't populated, something is wrong. (It should have been
5439  // populated during mount when we scanned the FAT.
5440  //
5441 
5443  }
5444 
5445  ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
5446  ClusterSize = 1 << ClusterShift;
5447 
5448  if (!FatLookupLastMcbEntry(Vcb, &Vcb->BadBlockMcb, &LastVbo, &LastLbo, &LastIndex)) {
5449  AllocationSize = 0;
5450  } else {
5451 
5452  //
5453  // Round the allocation size to a multiple of of the cluster size.
5454  //
5455 
5456  AllocationSize = (LastVbo + ((LONGLONG)ClusterSize-1)) & ~((LONGLONG)ClusterSize-1);
5457  }
5458 
5459  McbToUse = &Vcb->BadBlockMcb;
5460 
5461  }
5462 
5463  //
5464  // Check if a starting cluster was specified.
5465  //
5466 
5467  _SEH2_TRY {
5468 
5469  if (Irp->RequestorMode != KernelMode) {
5470 
5471  ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
5473  sizeof(UCHAR) );
5474 
5476  }
5477 
5478  StartingVcn = ((PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingVcn;
5479 
5481 
5483 
5484  FatRaiseStatus( IrpContext,
5487  } _SEH2_END;
5488 
5489  if (StartingVcn.HighPart ||
5490  StartingVcn.LowPart >= (AllocationSize >> ClusterShift)) {
5491 
5493 
5494  } else {
5495 
5496  //
5497  // If we don't find the run, something is very wrong.
5498  //
5499 
5500  LBO Lbo;
5501 
5502  if (!FatLookupMcbEntry( Vcb, McbToUse,
5503  StartingVcn.LowPart << ClusterShift,
5504  &Lbo,
5505  NULL,
5506  &StartingRun)) {
5507 
5508 #ifdef _MSC_VER
5509 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
5510 #endif
5511  FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)McbToUse, StartingVcn.LowPart );
5512  }
5513  }
5514 
5515  //
5516  // Now go fill in the ouput buffer with run information
5517  //
5518 
5519  RunCount = FsRtlNumberOfRunsInLargeMcb( McbToUse );
5520 
5521  for (Index = 0, Run = StartingRun; Run < RunCount; Index++, Run++) {
5522 
5523  ULONG Vcn;
5524  LBO Lbo;
5525  ULONG ByteLength;
5526 
5527  //
5528  // Check for an exhausted output buffer.
5529  //
5530 
5532 
5533 
5534  //
5535  // We've run out of space, so we won't be storing as many runs to the
5536  // user's buffer as we had originally planned. We need to return the
5537  // number of runs that we did have room for.
5538  //
5539 
5540  _SEH2_TRY {
5541 
5542  OutputBuffer->ExtentCount = Index;
5543 
5545 
5547 
5548  FatRaiseStatus( IrpContext,
5551  } _SEH2_END;
5552 
5553  Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]);
5555  }
5556 
5557  //
5558  // Get the extent. If it's not there or malformed, something is very wrong.
5559  //
5560 
5561  if (!FatGetNextMcbEntry(Vcb, McbToUse, Run, (PVBO)&Vcn, &Lbo, &ByteLength)) {
5562 
5563 #ifdef _MSC_VER
5564 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
5565 #endif
5566  FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)McbToUse, Run );
5567  }
5568 
5569  //
5570  // Fill in the next array element.
5571  //
5572 
5573  _SEH2_TRY {
5574 
5575  OutputBuffer->Extents[Index].NextVcn.QuadPart = ((LONGLONG)Vcn + ByteLength) >> ClusterShift;
5576  OutputBuffer->Extents[Index].Lcn.QuadPart = FatGetIndexFromLbo( Vcb, Lbo ) - 2;
5577 
5578  //
5579  // If this is the first run, fill in the starting Vcn
5580  //
5581 
5582  if (Index == 0) {
5583  OutputBuffer->ExtentCount = RunCount - StartingRun;
5584  OutputBuffer->StartingVcn.QuadPart = Vcn >> ClusterShift;
5585  }
5586 
5588 
5590 
5591  FatRaiseStatus( IrpContext,
5594  } _SEH2_END;
5595  }
5596 
5597  //
5598  // We successfully retrieved extent info to the end of the allocation.
5599  //
5600 
5601  Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]);
5603 
5604  try_exit: NOTHING;
5605 
5606  } _SEH2_FINALLY {
5607 
5608  DebugUnwind( FatGetRetrievalPointers );
5609 
5610  //
5611  // Release resources
5612  //
5613 
5615 
5616  FatReleaseFcb( IrpContext, FcbOrDcb );
5617  } else if ((TypeOfOpen == UserVolumeOpen )) {
5618 
5619  FatReleaseVcb(IrpContext, Vcb);
5620  }
5621 
5622  //
5623  // If nothing raised then complete the irp.
5624  //
5625 
5626  if (!_SEH2_AbnormalTermination()) {
5627 
5628  FatCompleteRequest( IrpContext, Irp, Status );
5629  }
5630 
5631  DebugTrace(-1, Dbg, "FatGetRetrievalPointers -> VOID\n", 0);
5632  } _SEH2_END;
5633 
5634  return Status;
5635 }
5636 
5637 
5638 //
5639 // Local Support Routine
5640 //
5641 
5642 _Requires_lock_held_(_Global_critical_region_)
5643 VOID
5644 FatMoveFileNeedsWriteThrough (
5645  _In_ PIRP_CONTEXT IrpContext,
5646  _In_ PFCB FcbOrDcb,
5647  _In_ ULONG OldWriteThroughFlags
5648  )
5649 {
5650  PAGED_CODE();
5651 
5652  if (NodeType(FcbOrDcb) == FAT_NTC_FCB) {
5653 
5654 
5655  if (FcbOrDcb->Header.ValidDataLength.QuadPart == 0) {
5656 
5657 
5658  ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
5659  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH );
5660 
5661  } else {
5662 
5664  IrpContext->Flags |= OldWriteThroughFlags;
5665&#