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)
_Function_class_(DRIVER_DISPATCH)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)
_Function_class_(DRIVER_DISPATCH)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
FatQueryFsVolumeInfo(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN PFILE_FS_VOLUME_INFORMATION Buffer,IN OUT PULONG Length)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
FatQueryFsSizeInfo(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN PFILE_FS_SIZE_INFORMATION Buffer,IN OUT PULONG Length)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
FatQueryFsDeviceInfo(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN PFILE_FS_DEVICE_INFORMATION Buffer,IN OUT PULONG Length)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
FatQueryFsAttributeInfo(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,IN OUT PULONG Length)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
FatQueryFsFullSizeInfo(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,IN OUT PULONG Length)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
FatSetFsLabelInfo(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN PFILE_FS_LABEL_INFORMATION Buffer)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
FatQueryFsSectorSizeInfo(_In_ PIRP_CONTEXT IrpContext,_In_ PVCB Vcb,_Out_writes_bytes_ (* Length)PFILE_FS_SECTOR_SIZE_INFORMATION Buffer,_Inout_ PULONG Length)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