1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     VolInfo.c
8 
9 Abstract:
10 
11     This module implements the volume information routines for Fat called by
12     the dispatch driver.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 //  The local debug trace level
21 //
22 
23 #define Dbg                              (DEBUG_TRACE_VOLINFO)
24 
25 NTSTATUS
26 FatQueryFsVolumeInfo (
27     IN PIRP_CONTEXT IrpContext,
28     IN PVCB Vcb,
29     IN PFILE_FS_VOLUME_INFORMATION Buffer,
30     IN OUT PULONG Length
31     );
32 
33 NTSTATUS
34 FatQueryFsSizeInfo (
35     IN PIRP_CONTEXT IrpContext,
36     IN PVCB Vcb,
37     IN PFILE_FS_SIZE_INFORMATION Buffer,
38     IN OUT PULONG Length
39     );
40 
41 NTSTATUS
42 FatQueryFsDeviceInfo (
43     IN PIRP_CONTEXT IrpContext,
44     IN PVCB Vcb,
45     IN PFILE_FS_DEVICE_INFORMATION Buffer,
46     IN OUT PULONG Length
47     );
48 
49 NTSTATUS
50 FatQueryFsAttributeInfo (
51     IN PIRP_CONTEXT IrpContext,
52     IN PVCB Vcb,
53     IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
54     IN OUT PULONG Length
55     );
56 
57 NTSTATUS
58 FatQueryFsFullSizeInfo (
59     IN PIRP_CONTEXT IrpContext,
60     IN PVCB Vcb,
61     IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
62     IN OUT PULONG Length
63     );
64 
65 NTSTATUS
66 FatSetFsLabelInfo (
67     IN PIRP_CONTEXT IrpContext,
68     IN PVCB Vcb,
69     IN PFILE_FS_LABEL_INFORMATION Buffer
70     );
71 
72 #if (NTDDI_VERSION >= NTDDI_WIN8)
73 NTSTATUS
74 FatQueryFsSectorSizeInfo (
75     _In_ PIRP_CONTEXT IrpContext,
76     _In_ PVCB Vcb,
77     _Out_writes_bytes_(*Length) PFILE_FS_SECTOR_SIZE_INFORMATION Buffer,
78     _Inout_ PULONG Length
79     );
80 #endif
81 
82 #ifdef ALLOC_PRAGMA
83 #pragma alloc_text(PAGE, FatCommonQueryVolumeInfo)
84 #pragma alloc_text(PAGE, FatCommonSetVolumeInfo)
85 #pragma alloc_text(PAGE, FatFsdQueryVolumeInformation)
86 #pragma alloc_text(PAGE, FatFsdSetVolumeInformation)
87 #pragma alloc_text(PAGE, FatQueryFsAttributeInfo)
88 #pragma alloc_text(PAGE, FatQueryFsDeviceInfo)
89 #pragma alloc_text(PAGE, FatQueryFsSizeInfo)
90 #pragma alloc_text(PAGE, FatQueryFsVolumeInfo)
91 #pragma alloc_text(PAGE, FatQueryFsFullSizeInfo)
92 #pragma alloc_text(PAGE, FatSetFsLabelInfo)
93 #if (NTDDI_VERSION >= NTDDI_WIN8)
94 #pragma alloc_text(PAGE, FatQueryFsSectorSizeInfo)
95 #endif
96 #endif
97 
98 
99 _Function_class_(IRP_MJ_QUERY_VOLUME_INFORMATION)
100 _Function_class_(DRIVER_DISPATCH)
101 NTSTATUS
102 NTAPI
103 FatFsdQueryVolumeInformation (
104     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
105     _Inout_ PIRP Irp
106     )
107 
108 /*++
109 
110 Routine Description:
111 
112     This routine implements the Fsd part of the NtQueryVolumeInformation API
113     call.
114 
115 Arguments:
116 
117     VolumeDeviceObject - Supplies the volume device object where the file
118         being queried exists.
119 
120     Irp - Supplies the Irp being processed.
121 
122 Return Value:
123 
124     NTSTATUS - The FSD status for the Irp.
125 
126 --*/
127 
128 {
129     NTSTATUS Status;
130     PIRP_CONTEXT IrpContext = NULL;
131 
132     BOOLEAN TopLevel;
133 
134     PAGED_CODE();
135 
136     DebugTrace(+1, Dbg, "FatFsdQueryVolumeInformation\n", 0);
137 
138     //
139     //  Call the common query routine, with blocking allowed if synchronous
140     //
141 
142     FsRtlEnterFileSystem();
143 
144     TopLevel = FatIsIrpTopLevel( Irp );
145 
146     _SEH2_TRY {
147 
148         IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
149 
150         Status = FatCommonQueryVolumeInfo( IrpContext, Irp );
151 
152     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
153 
154         //
155         //  We had some trouble trying to perform the requested
156         //  operation, so we'll abort the I/O request with
157         //  the error status that we get back from the
158         //  exception code
159         //
160 
161         Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
162     } _SEH2_END;
163 
164     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
165 
166     FsRtlExitFileSystem();
167 
168     //
169     //  And return to our caller
170     //
171 
172     DebugTrace(-1, Dbg, "FatFsdQueryVolumeInformation -> %08lx\n", Status);
173 
174     UNREFERENCED_PARAMETER( VolumeDeviceObject );
175 
176     return Status;
177 }
178 
179 
180 _Function_class_(IRP_MJ_SET_VOLUME_INFORMATION)
181 _Function_class_(DRIVER_DISPATCH)
182 NTSTATUS
183 NTAPI
184 FatFsdSetVolumeInformation (
185     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
186     _Inout_ PIRP Irp
187     )
188 
189 /*++
190 
191 Routine Description:
192 
193     This routine implements the FSD part of the NtSetVolumeInformation API
194     call.
195 
196 Arguments:
197 
198     VolumeDeviceObject - Supplies the volume device object where the file
199         being set exists.
200 
201     Irp - Supplies the Irp being processed.
202 
203 Return Value:
204 
205     NTSTATUS - The FSD status for the Irp.
206 
207 --*/
208 
209 {
210     NTSTATUS Status;
211     PIRP_CONTEXT IrpContext = NULL;
212 
213     BOOLEAN TopLevel;
214 
215     PAGED_CODE();
216 
217     DebugTrace(+1, Dbg, "FatFsdSetVolumeInformation\n", 0);
218 
219     //
220     //  Call the common set routine
221     //
222 
223     FsRtlEnterFileSystem();
224 
225     TopLevel = FatIsIrpTopLevel( Irp );
226 
227     _SEH2_TRY {
228 
229         IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
230 
231         Status = FatCommonSetVolumeInfo( IrpContext, Irp );
232 
233     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
234 
235         //
236         //  We had some trouble trying to perform the requested
237         //  operation, so we'll abort the I/O request with
238         //  the error status that we get back from the
239         //  exception code
240         //
241 
242         Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
243     } _SEH2_END;
244 
245     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
246 
247     FsRtlExitFileSystem();
248 
249     //
250     //  And return to our caller
251     //
252 
253     DebugTrace(-1, Dbg, "FatFsdSetVolumeInformation -> %08lx\n", Status);
254 
255     UNREFERENCED_PARAMETER( VolumeDeviceObject );
256 
257     return Status;
258 }
259 
260 
261 _Requires_lock_held_(_Global_critical_region_)
262 NTSTATUS
263 FatCommonQueryVolumeInfo (
264     IN PIRP_CONTEXT IrpContext,
265     IN PIRP Irp
266     )
267 
268 /*++
269 
270 Routine Description:
271 
272     This is the common routine for querying volume information called by both
273     the fsd and fsp threads.
274 
275 Arguments:
276 
277     Irp - Supplies the Irp being processed
278 
279 Return Value:
280 
281     NTSTATUS - The return status for the operation
282 
283 --*/
284 
285 {
286     NTSTATUS Status = STATUS_SUCCESS;
287     PIO_STACK_LOCATION IrpSp;
288 
289     PVCB Vcb;
290     PFCB Fcb;
291     PCCB Ccb;
292 
293     ULONG Length;
294     FS_INFORMATION_CLASS FsInformationClass;
295     PVOID Buffer;
296 
297     BOOLEAN WeAcquiredVcb = FALSE;
298 
299     PAGED_CODE();
300 
301     //
302     //  Get the current stack location
303     //
304 
305     IrpSp = IoGetCurrentIrpStackLocation( Irp );
306 
307     DebugTrace(+1, Dbg, "FatCommonQueryVolumeInfo...\n", 0);
308     DebugTrace( 0, Dbg, "Irp                  = %p\n", Irp );
309     DebugTrace( 0, Dbg, "->Length             = %08lx\n", IrpSp->Parameters.QueryVolume.Length);
310     DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
311     DebugTrace( 0, Dbg, "->Buffer             = %p\n", Irp->AssociatedIrp.SystemBuffer);
312 
313     //
314     //  Reference our input parameters to make things easier
315     //
316 
317     Length = IrpSp->Parameters.QueryVolume.Length;
318     FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
319     Buffer = Irp->AssociatedIrp.SystemBuffer;
320 
321     //
322     //  Decode the file object to get the Vcb
323     //
324 
325     (VOID) FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
326 
327     NT_ASSERT( Vcb != NULL );
328     _Analysis_assume_( Vcb != NULL );
329 
330     _SEH2_TRY {
331 
332         //
333         //  Make sure the vcb is in a usable condition.  This will raise
334         //  an error condition if the volume is unusable
335         //
336         //  Also verify the Root Dcb since we need info from there.
337         //
338 
339         FatVerifyFcb( IrpContext, Vcb->RootDcb );
340 
341         //
342         //  Based on the information class we'll do different actions.  Each
343         //  of the procedures that we're calling fills up the output buffer
344         //  if possible and returns true if it successfully filled the buffer
345         //  and false if it couldn't wait for any I/O to complete.
346         //
347 
348         switch (FsInformationClass) {
349 
350         case FileFsVolumeInformation:
351 
352             //
353             //  This is the only routine we need the Vcb shared because of
354             //  copying the volume label.  All other routines copy fields that
355             //  cannot change or are just manifest constants.
356             //
357 
358             if (!FatAcquireSharedVcb( IrpContext, Vcb )) {
359 
360                 DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
361 
362                 Status = FatFsdPostRequest( IrpContext, Irp );
363                 IrpContext = NULL;
364                 Irp = NULL;
365 
366             } else {
367 
368                 WeAcquiredVcb = TRUE;
369 
370                 Status = FatQueryFsVolumeInfo( IrpContext, Vcb, Buffer, &Length );
371             }
372 
373             break;
374 
375         case FileFsSizeInformation:
376 
377             Status = FatQueryFsSizeInfo( IrpContext, Vcb, Buffer, &Length );
378             break;
379 
380         case FileFsDeviceInformation:
381 
382             Status = FatQueryFsDeviceInfo( IrpContext, Vcb, Buffer, &Length );
383             break;
384 
385         case FileFsAttributeInformation:
386 
387             Status = FatQueryFsAttributeInfo( IrpContext, Vcb, Buffer, &Length );
388             break;
389 
390         case FileFsFullSizeInformation:
391 
392             Status = FatQueryFsFullSizeInfo( IrpContext, Vcb, Buffer, &Length );
393             break;
394 
395 #if (NTDDI_VERSION >= NTDDI_WIN8)
396         case FileFsSectorSizeInformation:
397 
398             Status = FatQueryFsSectorSizeInfo( IrpContext, Vcb, Buffer, &Length );
399             break;
400 #endif
401 
402         default:
403 
404             Status = STATUS_INVALID_PARAMETER;
405             break;
406         }
407 
408         //
409         //  Set the information field to the number of bytes actually filled in.
410         //
411 
412         if (Irp != NULL) {
413 
414             Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
415         }
416 
417     } _SEH2_FINALLY {
418 
419         DebugUnwind( FatCommonQueryVolumeInfo );
420 
421         if (WeAcquiredVcb) {
422 
423             FatReleaseVcb( IrpContext, Vcb );
424         }
425 
426         if (!_SEH2_AbnormalTermination()) {
427 
428             FatCompleteRequest( IrpContext, Irp, Status );
429         }
430 
431         DebugTrace(-1, Dbg, "FatCommonQueryVolumeInfo -> %08lx\n", Status);
432     } _SEH2_END;
433 
434     return Status;
435 }
436 
437 
438 _Requires_lock_held_(_Global_critical_region_)
439 NTSTATUS
440 FatCommonSetVolumeInfo (
441     IN PIRP_CONTEXT IrpContext,
442     IN PIRP Irp
443     )
444 
445 /*++
446 
447 Routine Description:
448 
449     This is the common routine for setting Volume Information called by both
450     the fsd and fsp threads.
451 
452 Arguments:
453 
454     Irp - Supplies the Irp being processed
455 
456 Return Value:
457 
458     NTSTATUS - The return status for the operation
459 
460 --*/
461 
462 {
463     NTSTATUS Status = STATUS_SUCCESS;
464     PIO_STACK_LOCATION IrpSp;
465 
466     PVCB Vcb;
467     PFCB Fcb;
468     PCCB Ccb;
469     TYPE_OF_OPEN TypeOfOpen;
470 
471     FS_INFORMATION_CLASS FsInformationClass;
472     PVOID Buffer;
473 
474     PAGED_CODE();
475 
476     //
477     //  Get the current stack location
478     //
479 
480     IrpSp = IoGetCurrentIrpStackLocation( Irp );
481 
482     DebugTrace(+1, Dbg, "FatCommonSetVolumeInfo...\n", 0);
483     DebugTrace( 0, Dbg, "Irp                  = %p\n", Irp );
484     DebugTrace( 0, Dbg, "->Length             = %08lx\n", IrpSp->Parameters.SetVolume.Length);
485     DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.SetVolume.FsInformationClass);
486     DebugTrace( 0, Dbg, "->Buffer             = %p\n", Irp->AssociatedIrp.SystemBuffer);
487 
488     //
489     //  Reference our input parameters to make things easier
490     //
491 
492     FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
493     Buffer = Irp->AssociatedIrp.SystemBuffer;
494 
495     //
496     //  Decode the file object to get the Vcb
497     //
498 
499     TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
500 
501     if (TypeOfOpen != UserVolumeOpen) {
502 
503         FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
504 
505         DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> STATUS_ACCESS_DENIED\n", 0);
506 
507         return STATUS_ACCESS_DENIED;
508     }
509 
510     //
511     //  Acquire exclusive access to the Vcb and enqueue the Irp if we didn't
512     //  get access
513     //
514 
515     if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
516 
517         DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
518 
519         Status = FatFsdPostRequest( IrpContext, Irp );
520 
521         DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status );
522         return Status;
523     }
524 
525     _SEH2_TRY {
526 
527         //
528         //  Make sure the vcb is in a usable condition.  This will raise
529         //  an error condition if the volume is unusable
530         //
531         //  Also verify the Root Dcb since we need info from there.
532         //
533 
534         FatVerifyFcb( IrpContext, Vcb->RootDcb );
535 
536         //
537         //  Based on the information class we'll do different actions.  Each
538         //  of the procedures that we're calling performs the action if
539         //  possible and returns true if it successful and false if it couldn't
540         //  wait for any I/O to complete.
541         //
542 
543         switch (FsInformationClass) {
544 
545         case FileFsLabelInformation:
546 
547             Status = FatSetFsLabelInfo( IrpContext, Vcb, Buffer );
548             break;
549 
550         default:
551 
552             Status = STATUS_INVALID_PARAMETER;
553             break;
554         }
555 
556         FatUnpinRepinnedBcbs( IrpContext );
557 
558     } _SEH2_FINALLY {
559 
560         DebugUnwind( FatCommonSetVolumeInfo );
561 
562         FatReleaseVcb( IrpContext, Vcb );
563 
564         if (!_SEH2_AbnormalTermination()) {
565 
566             FatCompleteRequest( IrpContext, Irp, Status );
567         }
568 
569         DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status);
570     } _SEH2_END;
571 
572     return Status;
573 }
574 
575 
576 //
577 //  Internal support routine
578 //
579 
580 NTSTATUS
581 FatQueryFsVolumeInfo (
582     IN PIRP_CONTEXT IrpContext,
583     IN PVCB Vcb,
584     IN PFILE_FS_VOLUME_INFORMATION Buffer,
585     IN OUT PULONG Length
586     )
587 
588 /*++
589 
590 Routine Description:
591 
592     This routine implements the query volume info call
593 
594 Arguments:
595 
596     Vcb - Supplies the Vcb being queried
597 
598     Buffer - Supplies a pointer to the output buffer where the information
599         is to be returned
600 
601     Length - Supplies the length of the buffer in bytes.  This variable
602         upon return receives the remaining bytes free in the buffer
603 
604 Return Value:
605 
606     NTSTATUS - Returns the status for the query
607 
608 --*/
609 
610 {
611     ULONG BytesToCopy;
612 
613     NTSTATUS Status;
614 
615     PAGED_CODE();
616 
617     DebugTrace(0, Dbg, "FatQueryFsVolumeInfo...\n", 0);
618 
619     //
620     //  Zero out the buffer, then extract and fill up the non zero fields.
621     //
622 
623     RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION) );
624 
625     Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
626 
627     Buffer->SupportsObjects = FALSE;
628 
629     *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
630 
631     //
632     //  Check if the buffer we're given is long enough
633     //
634 
635     if ( *Length >= (ULONG)Vcb->Vpb->VolumeLabelLength ) {
636 
637         BytesToCopy = Vcb->Vpb->VolumeLabelLength;
638 
639         Status = STATUS_SUCCESS;
640 
641     } else {
642 
643         BytesToCopy = *Length;
644 
645         Status = STATUS_BUFFER_OVERFLOW;
646     }
647 
648     //
649     //  Copy over what we can of the volume label, and adjust *Length
650     //
651 
652     Buffer->VolumeLabelLength = Vcb->Vpb->VolumeLabelLength;
653 
654     RtlCopyMemory( &Buffer->VolumeLabel[0],
655                    &Vcb->Vpb->VolumeLabel[0],
656                    BytesToCopy );
657 
658     *Length -= BytesToCopy;
659 
660     //
661     //  Set our status and return to our caller
662     //
663 
664     UNREFERENCED_PARAMETER( IrpContext );
665 
666     return Status;
667 }
668 
669 
670 //
671 //  Internal support routine
672 //
673 
674 NTSTATUS
675 FatQueryFsSizeInfo (
676     IN PIRP_CONTEXT IrpContext,
677     IN PVCB Vcb,
678     IN PFILE_FS_SIZE_INFORMATION Buffer,
679     IN OUT PULONG Length
680     )
681 
682 /*++
683 
684 Routine Description:
685 
686     This routine implements the query volume size call
687 
688 Arguments:
689 
690     Vcb - Supplies the Vcb being queried
691 
692     Buffer - Supplies a pointer to the output buffer where the information
693         is to be returned
694 
695     Length - Supplies the length of the buffer in bytes.  This variable
696         upon return receives the remaining bytes free in the buffer
697 
698 Return Value:
699 
700     Status - Returns the status for the query
701 
702 --*/
703 
704 {
705     PAGED_CODE();
706 
707     DebugTrace(0, Dbg, "FatQueryFsSizeInfo...\n", 0);
708 
709     RtlZeroMemory( Buffer, sizeof(FILE_FS_SIZE_INFORMATION) );
710 
711     //
712     //  Set the output buffer.
713     //
714 
715     Buffer->TotalAllocationUnits.LowPart =
716                                     Vcb->AllocationSupport.NumberOfClusters;
717     Buffer->AvailableAllocationUnits.LowPart =
718                                     Vcb->AllocationSupport.NumberOfFreeClusters;
719 
720     Buffer->SectorsPerAllocationUnit = Vcb->Bpb.SectorsPerCluster;
721     Buffer->BytesPerSector = Vcb->Bpb.BytesPerSector;
722 
723     //
724     //  Adjust the length variable
725     //
726 
727     *Length -= sizeof(FILE_FS_SIZE_INFORMATION);
728 
729     //
730     //  And return success to our caller
731     //
732 
733     UNREFERENCED_PARAMETER( IrpContext );
734 
735     return STATUS_SUCCESS;
736 }
737 
738 
739 //
740 //  Internal support routine
741 //
742 
743 NTSTATUS
744 FatQueryFsDeviceInfo (
745     IN PIRP_CONTEXT IrpContext,
746     IN PVCB Vcb,
747     IN PFILE_FS_DEVICE_INFORMATION Buffer,
748     IN OUT PULONG Length
749     )
750 
751 /*++
752 
753 Routine Description:
754 
755     This routine implements the query volume device call
756 
757 Arguments:
758 
759     Vcb - Supplies the Vcb being queried
760 
761     Buffer - Supplies a pointer to the output buffer where the information
762         is to be returned
763 
764     Length - Supplies the length of the buffer in bytes.  This variable
765         upon return receives the remaining bytes free in the buffer
766 
767 Return Value:
768 
769     Status - Returns the status for the query
770 
771 --*/
772 
773 {
774     PAGED_CODE();
775 
776     DebugTrace(0, Dbg, "FatQueryFsDeviceInfo...\n", 0);
777 
778     RtlZeroMemory( Buffer, sizeof(FILE_FS_DEVICE_INFORMATION) );
779 
780     //
781     //  Set the output buffer
782     //
783 
784     Buffer->DeviceType = FILE_DEVICE_DISK;
785 
786     Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
787 
788     //
789     //  Adjust the length variable
790     //
791 
792     *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
793 
794     //
795     //  And return success to our caller
796     //
797 
798     UNREFERENCED_PARAMETER( IrpContext );
799 
800     return STATUS_SUCCESS;
801 }
802 
803 
804 //
805 //  Internal support routine
806 //
807 
808 NTSTATUS
809 FatQueryFsAttributeInfo (
810     IN PIRP_CONTEXT IrpContext,
811     IN PVCB Vcb,
812     IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
813     IN OUT PULONG Length
814     )
815 
816 /*++
817 
818 Routine Description:
819 
820     This routine implements the query volume attribute call
821 
822 Arguments:
823 
824     Vcb - Supplies the Vcb being queried
825 
826     Buffer - Supplies a pointer to the output buffer where the information
827         is to be returned
828 
829     Length - Supplies the length of the buffer in bytes.  This variable
830         upon return receives the remaining bytes free in the buffer
831 
832 Return Value:
833 
834     Status - Returns the status for the query
835 
836 --*/
837 
838 {
839     ULONG BytesToCopy;
840 
841     NTSTATUS Status;
842 
843     PAGED_CODE();
844 
845     DebugTrace(0, Dbg, "FatQueryFsAttributeInfo...\n", 0);
846 
847     //
848     //  Set the output buffer
849     //
850 
851     Buffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES |
852                                    FILE_UNICODE_ON_DISK;
853 
854     if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED )) {
855 
856         SetFlag( Buffer->FileSystemAttributes, FILE_READ_ONLY_VOLUME );
857     }
858 
859 
860     Buffer->MaximumComponentNameLength = FatData.ChicagoMode ? 255 : 12;
861 
862     if (FatIsFat32(Vcb)) {
863 
864         //
865         //  Determine how much of the file system name will fit.
866         //
867 
868         if ( (*Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
869                                       FileSystemName[0] )) >= 10 ) {
870 
871             BytesToCopy = 10;
872             *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
873                                      FileSystemName[0] ) + 10;
874             Status = STATUS_SUCCESS;
875 
876         } else {
877 
878             BytesToCopy = *Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
879                                                   FileSystemName[0]);
880             *Length = 0;
881 
882             Status = STATUS_BUFFER_OVERFLOW;
883         }
884 
885         RtlCopyMemory( &Buffer->FileSystemName[0], L"FAT32", BytesToCopy );
886 
887     } else {
888 
889         //
890         //  Determine how much of the file system name will fit.
891         //
892 
893         if ( (*Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
894                                       FileSystemName[0] )) >= 6 ) {
895 
896             BytesToCopy = 6;
897             *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
898                                      FileSystemName[0] ) + 6;
899             Status = STATUS_SUCCESS;
900 
901         } else {
902 
903             BytesToCopy = *Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
904                                                   FileSystemName[0]);
905             *Length = 0;
906 
907             Status = STATUS_BUFFER_OVERFLOW;
908         }
909 
910 
911         RtlCopyMemory( &Buffer->FileSystemName[0], L"FAT", BytesToCopy );
912     }
913 
914     Buffer->FileSystemNameLength       = BytesToCopy;
915 
916     //
917     //  And return success to our caller
918     //
919 
920     UNREFERENCED_PARAMETER( IrpContext );
921     UNREFERENCED_PARAMETER( Vcb );
922 
923     return Status;
924 }
925 
926 
927 //
928 //  Internal support routine
929 //
930 
931 NTSTATUS
932 FatQueryFsFullSizeInfo (
933     IN PIRP_CONTEXT IrpContext,
934     IN PVCB Vcb,
935     IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
936     IN OUT PULONG Length
937     )
938 
939 /*++
940 
941 Routine Description:
942 
943     This routine implements the query volume full size call
944 
945 Arguments:
946 
947     Vcb - Supplies the Vcb being queried
948 
949     Buffer - Supplies a pointer to the output buffer where the information
950         is to be returned
951 
952     Length - Supplies the length of the buffer in bytes.  This variable
953         upon return receives the remaining bytes free in the buffer
954 
955 Return Value:
956 
957     Status - Returns the status for the query
958 
959 --*/
960 
961 {
962     PAGED_CODE();
963 
964     DebugTrace(0, Dbg, "FatQueryFsSizeInfo...\n", 0);
965 
966     RtlZeroMemory( Buffer, sizeof(FILE_FS_FULL_SIZE_INFORMATION) );
967 
968     Buffer->TotalAllocationUnits.LowPart =
969                                 Vcb->AllocationSupport.NumberOfClusters;
970     Buffer->CallerAvailableAllocationUnits.LowPart =
971                                 Vcb->AllocationSupport.NumberOfFreeClusters;
972     Buffer->ActualAvailableAllocationUnits.LowPart =
973         Buffer->CallerAvailableAllocationUnits.LowPart;
974     Buffer->SectorsPerAllocationUnit = Vcb->Bpb.SectorsPerCluster;
975     Buffer->BytesPerSector = Vcb->Bpb.BytesPerSector;
976 
977     //
978     //  Adjust the length variable
979     //
980 
981     *Length -= sizeof(FILE_FS_FULL_SIZE_INFORMATION);
982 
983     //
984     //  And return success to our caller
985     //
986 
987     UNREFERENCED_PARAMETER( IrpContext );
988 
989     return STATUS_SUCCESS;
990 }
991 
992 
993 //
994 //  Internal support routine
995 //
996 
997 NTSTATUS
998 FatSetFsLabelInfo (
999     IN PIRP_CONTEXT IrpContext,
1000     IN PVCB Vcb,
1001     IN PFILE_FS_LABEL_INFORMATION Buffer
1002     )
1003 
1004 /*++
1005 
1006 Routine Description:
1007 
1008     This routine implements the set volume label call
1009 
1010 Arguments:
1011 
1012     Vcb - Supplies the Vcb being queried
1013 
1014     Buffer - Supplies the input where the information is stored.
1015 
1016 Return Value:
1017 
1018     NTSTATUS - Returns the status for the operation
1019 
1020 --*/
1021 
1022 {
1023     NTSTATUS Status;
1024 
1025     PDIRENT Dirent;
1026     PBCB DirentBcb = NULL;
1027     ULONG ByteOffset;
1028 
1029     WCHAR TmpBuffer[11];
1030     UCHAR OemBuffer[11];
1031     OEM_STRING OemLabel;
1032     UNICODE_STRING UnicodeString;
1033     UNICODE_STRING UpcasedLabel;
1034 
1035     PAGED_CODE();
1036 
1037     DebugTrace(+1, Dbg, "FatSetFsLabelInfo...\n", 0);
1038 
1039     //
1040     //  Setup our local variable
1041     //
1042 
1043     UnicodeString.Length = (USHORT)Buffer->VolumeLabelLength;
1044     UnicodeString.MaximumLength = UnicodeString.Length;
1045     UnicodeString.Buffer = (PWSTR) &Buffer->VolumeLabel[0];
1046 
1047     //
1048     //  Make sure the name can fit into the stack buffer
1049     //
1050 
1051     if ( UnicodeString.Length > 11*sizeof(WCHAR) ) {
1052 
1053         return STATUS_INVALID_VOLUME_LABEL;
1054     }
1055 
1056     //
1057     //  Upcase the name and convert it to the Oem code page.
1058     //
1059 
1060     OemLabel.Buffer = (PCHAR)&OemBuffer[0];
1061     OemLabel.Length = 0;
1062     OemLabel.MaximumLength = 11;
1063 
1064     Status = RtlUpcaseUnicodeStringToCountedOemString( &OemLabel,
1065                                                        &UnicodeString,
1066                                                        FALSE );
1067 
1068     //
1069     //  Volume label that fits in 11 unicode character length limit
1070     //  is not necessarily within 11 characters in OEM character set.
1071     //
1072 
1073     if (!NT_SUCCESS( Status )) {
1074 
1075         DebugTrace(-1, Dbg, "FatSetFsLabelInfo:  Label must be too long. %08lx\n", Status );
1076 
1077         return STATUS_INVALID_VOLUME_LABEL;
1078     }
1079 
1080     //
1081     //  Strip spaces off of the label.
1082     //
1083 
1084     if (OemLabel.Length > 0) {
1085 
1086         USHORT i;
1087         USHORT LastSpaceIndex = MAXUSHORT;
1088 
1089         //
1090         //  Check the label for illegal characters
1091         //
1092 
1093         for ( i = 0; i < (ULONG)OemLabel.Length; i += 1 ) {
1094 
1095             if ( FsRtlIsLeadDbcsCharacter( OemLabel.Buffer[i] ) ) {
1096 
1097                 LastSpaceIndex = MAXUSHORT;
1098                 i += 1;
1099                 continue;
1100             }
1101 
1102             if (!FsRtlIsAnsiCharacterLegalFat(OemLabel.Buffer[i], FALSE) ||
1103                 (OemLabel.Buffer[i] == '.')) {
1104 
1105                 return STATUS_INVALID_VOLUME_LABEL;
1106             }
1107 
1108             //
1109             //  Watch for the last run of spaces, so we can strip them.
1110             //
1111 
1112             if (OemLabel.Buffer[i] == ' ' &&
1113                 LastSpaceIndex == MAXUSHORT) {
1114                 LastSpaceIndex = i;
1115             } else {
1116                 LastSpaceIndex = MAXUSHORT;
1117             }
1118         }
1119 
1120         if (LastSpaceIndex != MAXUSHORT) {
1121             OemLabel.Length = LastSpaceIndex;
1122         }
1123     }
1124 
1125     //
1126     //  Get the Unicode upcased string to store in the VPB.
1127     //
1128 
1129     UpcasedLabel.Length = UnicodeString.Length;
1130     UpcasedLabel.MaximumLength = 11*sizeof(WCHAR);
1131     UpcasedLabel.Buffer = &TmpBuffer[0];
1132 
1133     Status = RtlOemStringToCountedUnicodeString( &UpcasedLabel,
1134                                                  &OemLabel,
1135                                                  FALSE );
1136 
1137     if (!NT_SUCCESS( Status )) {
1138 
1139         DebugTrace(-1, Dbg, "FatSetFsLabelInfo:  Label must be too long. %08lx\n", Status );
1140 
1141         return STATUS_INVALID_VOLUME_LABEL;
1142     }
1143 
1144     DirentBcb = NULL;
1145 
1146     //
1147     //  Make this look like a write through to disk.  This is important to
1148     //  avoid a unpleasant window where it looks like we have the wrong volume.
1149     //
1150 
1151     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
1152 
1153     _SEH2_TRY {
1154 
1155         //
1156         //  Are we setting or removing the label?  Note that shaving spaces could
1157         //  make this different than wondering if the input buffer is non-zero length.
1158         //
1159 
1160         if (OemLabel.Length > 0) {
1161 
1162             //
1163             //  Translate the first character from 0xe5 to 0x5.
1164             //
1165 
1166             if ((UCHAR)OemLabel.Buffer[0] == 0xe5) {
1167 
1168                 OemLabel.Buffer[0] = FAT_DIRENT_REALLY_0E5;
1169             }
1170 
1171             //
1172             //  Locate the volume label if there already is one
1173             //
1174 
1175             FatLocateVolumeLabel( IrpContext,
1176                                   Vcb,
1177                                   &Dirent,
1178                                   &DirentBcb,
1179                                   (PVBO)&ByteOffset );
1180 
1181             //
1182             //  Check that we really got one, if not then we need to create
1183             //  a new one.  The procedure we call will raise an appropriate
1184             //  status if we are not able to allocate a new dirent
1185             //
1186 
1187             if (Dirent == NULL) {
1188 
1189                 ByteOffset = FatCreateNewDirent( IrpContext,
1190                                                  Vcb->RootDcb,
1191                                                  1,
1192                                                  FALSE );
1193 
1194                 FatPrepareWriteDirectoryFile( IrpContext,
1195                                               Vcb->RootDcb,
1196                                               ByteOffset,
1197                                               sizeof(DIRENT),
1198                                               &DirentBcb,
1199 #ifndef __REACTOS__
1200                                               &Dirent,
1201 #else
1202                                               (PVOID *)&Dirent,
1203 #endif
1204                                               FALSE,
1205                                               TRUE,
1206                                               &Status );
1207 
1208                 NT_ASSERT( NT_SUCCESS( Status ));
1209 
1210             } else {
1211 
1212                 //
1213                 //  Just mark this guy dirty now.
1214                 //
1215 
1216                 FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
1217             }
1218 
1219             //
1220             //  Now reconstruct the volume label dirent.
1221             //
1222 
1223             FatConstructLabelDirent( IrpContext,
1224                                      Dirent,
1225                                      &OemLabel );
1226 
1227             //
1228             //  Unpin the Bcb here so that we will get any IO errors
1229             //  here before changing the VPB label.
1230             //
1231 
1232             FatUnpinBcb( IrpContext, DirentBcb );
1233             FatUnpinRepinnedBcbs( IrpContext );
1234 
1235             //
1236             //  Now set the upcased label in the VPB
1237             //
1238 
1239             RtlCopyMemory( &Vcb->Vpb->VolumeLabel[0],
1240                            &UpcasedLabel.Buffer[0],
1241                            UpcasedLabel.Length );
1242 
1243             Vcb->Vpb->VolumeLabelLength = UpcasedLabel.Length;
1244 
1245         } else {
1246 
1247             //
1248             //  Otherwise we're trying to delete the label
1249             //  Locate the current volume label if there already is one
1250             //
1251 
1252             FatLocateVolumeLabel( IrpContext,
1253                                   Vcb,
1254                                   &Dirent,
1255                                   &DirentBcb,
1256                                   (PVBO)&ByteOffset );
1257 
1258             //
1259             //  Check that we really got one
1260             //
1261 
1262             if (Dirent == NULL) {
1263 
1264                 try_return( Status = STATUS_SUCCESS );
1265             }
1266 
1267             //
1268             //  Now delete the current label.
1269             //
1270 
1271             Dirent->FileName[0] = FAT_DIRENT_DELETED;
1272 
1273             NT_ASSERT( (Vcb->RootDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
1274                     RtlAreBitsSet( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap,
1275                                    ByteOffset / sizeof(DIRENT),
1276                                    1 ) );
1277 
1278             RtlClearBits( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap,
1279                           ByteOffset / sizeof(DIRENT),
1280                           1 );
1281 
1282             FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
1283 
1284             //
1285             //  Unpin the Bcb here so that we will get any IO errors
1286             //  here before changing the VPB label.
1287             //
1288 
1289             FatUnpinBcb( IrpContext, DirentBcb );
1290             FatUnpinRepinnedBcbs( IrpContext );
1291 
1292             //
1293             //  Now set the label in the VPB
1294             //
1295 
1296             Vcb->Vpb->VolumeLabelLength = 0;
1297         }
1298 
1299         Status = STATUS_SUCCESS;
1300 
1301     try_exit: NOTHING;
1302     } _SEH2_FINALLY {
1303 
1304         DebugUnwind( FatSetFsALabelInfo );
1305 
1306         FatUnpinBcb( IrpContext, DirentBcb );
1307 
1308         DebugTrace(-1, Dbg, "FatSetFsALabelInfo -> STATUS_SUCCESS\n", 0);
1309     } _SEH2_END;
1310 
1311     return Status;
1312 }
1313 
1314 #if (NTDDI_VERSION >= NTDDI_WIN8)
1315 
1316 NTSTATUS
1317 FatQueryFsSectorSizeInfo (
1318     _In_ PIRP_CONTEXT IrpContext,
1319     _In_ PVCB Vcb,
1320     _Out_writes_bytes_(*Length) PFILE_FS_SECTOR_SIZE_INFORMATION Buffer,
1321     _Inout_ PULONG Length
1322     )
1323 
1324 /*++
1325 
1326 Routine Description:
1327 
1328     This routine implements the query sector size information call
1329     This operation will work on any handle and requires no privilege.
1330 
1331 Arguments:
1332 
1333     Vcb - Supplies the Vcb being queried
1334 
1335     Buffer - Supplies a pointer to the output buffer where the information
1336         is to be returned
1337 
1338     Length - Supplies the length of the buffer in bytes.  This variable
1339         upon return receives the remaining bytes free in the buffer
1340 
1341 Return Value:
1342 
1343     NTSTATUS - Returns the status for the query
1344 
1345 --*/
1346 
1347 {
1348     NTSTATUS Status;
1349 
1350     PAGED_CODE();
1351     UNREFERENCED_PARAMETER( IrpContext );
1352 
1353     //
1354     //  Sufficient buffer size is guaranteed by the I/O manager or the
1355     //  originating kernel mode driver.
1356     //
1357 
1358     ASSERT( *Length >= sizeof( FILE_FS_SECTOR_SIZE_INFORMATION ));
1359     _Analysis_assume_( *Length >= sizeof( FILE_FS_SECTOR_SIZE_INFORMATION ));
1360 
1361     //
1362     //  Retrieve the sector size information
1363     //
1364 
1365     Status = FsRtlGetSectorSizeInformation( Vcb->Vpb->RealDevice,
1366                                             Buffer );
1367 
1368     //
1369     //  Adjust the length variable
1370     //
1371 
1372     if (NT_SUCCESS( Status )) {
1373 
1374         *Length -= sizeof( FILE_FS_SECTOR_SIZE_INFORMATION );
1375     }
1376 
1377     return Status;
1378 }
1379 
1380 #endif
1381 
1382