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