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