1 /*++ 2 3 4 Copyright (c) 1989-2000 Microsoft Corporation 5 6 Module Name: 7 8 FsCtrl.c 9 10 Abstract: 11 12 This module implements the File System Control routines for Fat called 13 by the dispatch driver. 14 15 16 --*/ 17 18 #include "fatprocs.h" 19 20 // 21 // The Bug check file id for this module 22 // 23 24 #define BugCheckFileId (FAT_BUG_CHECK_FSCTRL) 25 26 // 27 // The local debug trace level 28 // 29 30 #define Dbg (DEBUG_TRACE_FSCTRL) 31 32 // 33 // Local procedure prototypes 34 // 35 36 _Requires_lock_held_(_Global_critical_region_) 37 NTSTATUS 38 FatMountVolume ( 39 IN PIRP_CONTEXT IrpContext, 40 IN PDEVICE_OBJECT TargetDeviceObject, 41 IN PVPB Vpb, 42 IN PDEVICE_OBJECT FsDeviceObject 43 ); 44 45 _Requires_lock_held_(_Global_critical_region_) 46 NTSTATUS 47 FatVerifyVolume ( 48 IN PIRP_CONTEXT IrpContext, 49 IN PIRP Irp 50 ); 51 52 BOOLEAN 53 FatIsMediaWriteProtected ( 54 IN PIRP_CONTEXT IrpContext, 55 IN PDEVICE_OBJECT TargetDeviceObject 56 ); 57 58 _Requires_lock_held_(_Global_critical_region_) 59 NTSTATUS 60 FatUserFsCtrl ( 61 IN PIRP_CONTEXT IrpContext, 62 IN PIRP Irp 63 ); 64 65 _Requires_lock_held_(_Global_critical_region_) 66 NTSTATUS 67 FatOplockRequest ( 68 _In_ PIRP_CONTEXT IrpContext, 69 _In_ PIRP Irp 70 ); 71 72 _Requires_lock_held_(_Global_critical_region_) 73 NTSTATUS 74 FatLockVolume ( 75 IN PIRP_CONTEXT IrpContext, 76 IN PIRP Irp 77 ); 78 79 NTSTATUS 80 FatUnlockVolume ( 81 IN PIRP_CONTEXT IrpContext, 82 IN PIRP Irp 83 ); 84 85 _Requires_lock_held_(_Global_critical_region_) 86 NTSTATUS 87 FatDismountVolume ( 88 IN PIRP_CONTEXT IrpContext, 89 IN PIRP Irp 90 ); 91 92 _Requires_lock_held_(_Global_critical_region_) 93 NTSTATUS 94 FatDirtyVolume ( 95 IN PIRP_CONTEXT IrpContext, 96 IN PIRP Irp 97 ); 98 99 NTSTATUS 100 FatIsVolumeDirty ( 101 IN PIRP_CONTEXT IrpContext, 102 IN PIRP Irp 103 ); 104 105 NTSTATUS 106 FatIsVolumeMounted ( 107 IN PIRP_CONTEXT IrpContext, 108 IN PIRP Irp 109 ); 110 111 NTSTATUS 112 FatIsPathnameValid ( 113 IN PIRP_CONTEXT IrpContext, 114 IN PIRP Irp 115 ); 116 117 _Requires_lock_held_(_Global_critical_region_) 118 NTSTATUS 119 FatInvalidateVolumes ( 120 IN PIRP Irp 121 ); 122 123 _Requires_lock_held_(_Global_critical_region_) 124 VOID 125 FatScanForDismountedVcb ( 126 IN PIRP_CONTEXT IrpContext 127 ); 128 129 BOOLEAN 130 FatPerformVerifyDiskRead ( 131 IN PIRP_CONTEXT IrpContext, 132 IN PVCB Vcb, 133 IN PVOID Buffer, 134 IN LBO Lbo, 135 IN ULONG NumberOfBytesToRead, 136 IN BOOLEAN ReturnOnError 137 ); 138 139 _Requires_lock_held_(_Global_critical_region_) 140 NTSTATUS 141 FatQueryRetrievalPointers ( 142 IN PIRP_CONTEXT IrpContext, 143 IN PIRP Irp 144 ); 145 146 NTSTATUS 147 FatQueryBpb ( 148 IN PIRP_CONTEXT IrpContext, 149 IN PIRP Irp 150 ); 151 152 NTSTATUS 153 FatGetStatistics ( 154 IN PIRP_CONTEXT IrpContext, 155 IN PIRP Irp 156 ); 157 158 NTSTATUS 159 FatAllowExtendedDasdIo ( 160 IN PIRP_CONTEXT IrpContext, 161 IN PIRP Irp 162 ); 163 164 _Requires_lock_held_(_Global_critical_region_) 165 NTSTATUS 166 FatGetBootAreaInfo ( 167 _In_ PIRP_CONTEXT IrpContext, 168 _In_ PIRP Irp 169 ); 170 171 _Requires_lock_held_(_Global_critical_region_) 172 NTSTATUS 173 FatGetRetrievalPointerBase ( 174 _In_ PIRP_CONTEXT IrpContext, 175 _In_ PIRP Irp 176 ); 177 178 _Requires_lock_held_(_Global_critical_region_) 179 NTSTATUS 180 FatMarkHandle( 181 _In_ PIRP_CONTEXT IrpContext, 182 _In_ PIRP Irp 183 ); 184 185 NTSTATUS 186 FatSetZeroOnDeallocate ( 187 __in PIRP_CONTEXT IrpContext, 188 __in PIRP Irp 189 ); 190 191 _Requires_lock_held_(_Global_critical_region_) 192 NTSTATUS 193 FatSetPurgeFailureMode ( 194 _In_ PIRP_CONTEXT IrpContext, 195 _In_ PIRP Irp 196 ); 197 198 // 199 // Local support routine prototypes 200 // 201 202 _Requires_lock_held_(_Global_critical_region_) 203 NTSTATUS 204 FatGetVolumeBitmap ( 205 IN PIRP_CONTEXT IrpContext, 206 IN PIRP Irp 207 ); 208 209 _Requires_lock_held_(_Global_critical_region_) 210 NTSTATUS 211 FatGetRetrievalPointers ( 212 IN PIRP_CONTEXT IrpContext, 213 IN PIRP Irp 214 ); 215 216 _Requires_lock_held_(_Global_critical_region_) 217 VOID 218 FatMoveFileNeedsWriteThrough ( 219 _In_ PIRP_CONTEXT IrpContext, 220 _In_ PFCB FcbOrDcb, 221 _In_ ULONG OldWriteThroughFlags 222 ); 223 224 _Requires_lock_held_(_Global_critical_region_) 225 NTSTATUS 226 FatMoveFile ( 227 IN PIRP_CONTEXT IrpContext, 228 IN PIRP Irp 229 ); 230 231 VOID 232 FatComputeMoveFileSplicePoints ( 233 PIRP_CONTEXT IrpContext, 234 PFCB FcbOrDcb, 235 ULONG FileOffset, 236 ULONG TargetCluster, 237 ULONG BytesToReallocate, 238 PULONG FirstSpliceSourceCluster, 239 PULONG FirstSpliceTargetCluster, 240 PULONG SecondSpliceSourceCluster, 241 PULONG SecondSpliceTargetCluster, 242 PLARGE_MCB SourceMcb 243 ); 244 245 _Requires_lock_held_(_Global_critical_region_) 246 VOID 247 FatComputeMoveFileParameter ( 248 IN PIRP_CONTEXT IrpContext, 249 IN PFCB FcbOrDcb, 250 IN ULONG BufferSize, 251 IN ULONG FileOffset, 252 IN OUT PULONG ByteCount, 253 OUT PULONG BytesToReallocate, 254 OUT PULONG BytesToWrite, 255 OUT PLARGE_INTEGER SourceLbo 256 ); 257 258 NTSTATUS 259 FatSearchBufferForLabel( 260 IN PIRP_CONTEXT IrpContext, 261 IN PVPB Vpb, 262 IN PVOID Buffer, 263 IN ULONG Size, 264 OUT PBOOLEAN LabelFound 265 ); 266 267 VOID 268 FatVerifyLookupFatEntry ( 269 IN PIRP_CONTEXT IrpContext, 270 IN PVCB Vcb, 271 IN ULONG FatIndex, 272 IN OUT PULONG FatEntry 273 ); 274 275 #ifdef ALLOC_PRAGMA 276 #pragma alloc_text(PAGE, FatAddMcbEntry) 277 #pragma alloc_text(PAGE, FatAllowExtendedDasdIo) 278 #pragma alloc_text(PAGE, FatCommonFileSystemControl) 279 #pragma alloc_text(PAGE, FatComputeMoveFileParameter) 280 #pragma alloc_text(PAGE, FatComputeMoveFileSplicePoints) 281 #pragma alloc_text(PAGE, FatDirtyVolume) 282 #pragma alloc_text(PAGE, FatFsdFileSystemControl) 283 #pragma alloc_text(PAGE, FatGetRetrievalPointerBase) 284 #pragma alloc_text(PAGE, FatGetBootAreaInfo) 285 #pragma alloc_text(PAGE, FatMarkHandle) 286 #pragma alloc_text(PAGE, FatGetRetrievalPointers) 287 #pragma alloc_text(PAGE, FatGetStatistics) 288 #pragma alloc_text(PAGE, FatGetVolumeBitmap) 289 #pragma alloc_text(PAGE, FatIsMediaWriteProtected) 290 #pragma alloc_text(PAGE, FatIsPathnameValid) 291 #pragma alloc_text(PAGE, FatIsVolumeDirty) 292 #pragma alloc_text(PAGE, FatIsVolumeMounted) 293 #pragma alloc_text(PAGE, FatLockVolume) 294 #pragma alloc_text(PAGE, FatLookupLastMcbEntry) 295 #pragma alloc_text(PAGE, FatGetNextMcbEntry) 296 #pragma alloc_text(PAGE, FatMountVolume) 297 #pragma alloc_text(PAGE, FatMoveFileNeedsWriteThrough) 298 #pragma alloc_text(PAGE, FatMoveFile) 299 #pragma alloc_text(PAGE, FatOplockRequest) 300 #pragma alloc_text(PAGE, FatPerformVerifyDiskRead) 301 #pragma alloc_text(PAGE, FatQueryBpb) 302 #pragma alloc_text(PAGE, FatQueryRetrievalPointers) 303 #pragma alloc_text(PAGE, FatRemoveMcbEntry) 304 #pragma alloc_text(PAGE, FatScanForDismountedVcb) 305 #pragma alloc_text(PAGE, FatFlushAndCleanVolume) 306 #pragma alloc_text(PAGE, FatSearchBufferForLabel) 307 #pragma alloc_text(PAGE, FatSetPurgeFailureMode) 308 #pragma alloc_text(PAGE, FatUnlockVolume) 309 #pragma alloc_text(PAGE, FatUserFsCtrl) 310 #pragma alloc_text(PAGE, FatVerifyLookupFatEntry) 311 #pragma alloc_text(PAGE, FatVerifyVolume) 312 #endif 313 314 #if DBG 315 316 BOOLEAN FatMoveFileDebug = 0; 317 318 #endif 319 320 // 321 // These wrappers go around the MCB package; we scale the LBO's passed 322 // in (which can be bigger than 32 bits on fat32) by the volume's sector 323 // size. 324 // 325 // Note we now use the real large mcb package. This means these shims 326 // now also convert the -1 unused LBN number to the 0 of the original 327 // mcb package. 328 // 329 330 #define MCB_SCALE_LOG2 (Vcb->AllocationSupport.LogOfBytesPerSector) 331 #define MCB_SCALE (1 << MCB_SCALE_LOG2) 332 #define MCB_SCALE_MODULO (MCB_SCALE - 1) 333 334 BOOLEAN 335 FatNonSparseMcb( 336 _In_ PVCB Vcb, 337 _In_ PLARGE_MCB Mcb, 338 _Out_ PVBO Vbo, 339 _Out_ PLONGLONG ByteCount 340 ) 341 { 342 LBO Lbo; 343 ULONG Index = 0; 344 LONGLONG llVbo = 0; 345 346 UNREFERENCED_PARAMETER(Vcb); 347 348 while (FsRtlGetNextLargeMcbEntry(Mcb, Index, &llVbo, &Lbo, ByteCount)) { 349 *Vbo = (VBO)llVbo; 350 if (((ULONG)Lbo) == -1) { 351 return FALSE; 352 } 353 354 Index++; 355 } 356 357 *Vbo = (VBO)llVbo; 358 359 return TRUE; 360 } 361 362 363 BOOLEAN 364 FatAddMcbEntry ( 365 IN PVCB Vcb, 366 IN PLARGE_MCB Mcb, 367 IN VBO Vbo, 368 IN LBO Lbo, 369 IN ULONG SectorCount 370 ) 371 372 { 373 BOOLEAN Result; 374 #if DBG 375 VBO SparseVbo; 376 LONGLONG SparseByteCount; 377 #endif 378 379 PAGED_CODE(); 380 381 if (SectorCount) { 382 383 // 384 // Round up sectors, but be careful as SectorCount approaches 4Gb. 385 // Note that for x>0, (x+m-1)/m = ((x-1)/m)+(m/m) = ((x-1)/m)+1 386 // 387 388 SectorCount--; 389 SectorCount >>= MCB_SCALE_LOG2; 390 SectorCount++; 391 } 392 393 Vbo >>= MCB_SCALE_LOG2; 394 Lbo >>= MCB_SCALE_LOG2; 395 396 NT_ASSERT( SectorCount != 0 ); 397 398 if (Mcb != &Vcb->DirtyFatMcb) { 399 NT_ASSERT( FatNonSparseMcb( Vcb, Mcb, &SparseVbo, &SparseByteCount ) || 400 ((SparseVbo == Vbo) && (SparseByteCount == SectorCount )) ); 401 } 402 403 Result = FsRtlAddLargeMcbEntry( Mcb, 404 ((LONGLONG) Vbo), 405 ((LONGLONG) Lbo), 406 ((LONGLONG) SectorCount) ); 407 408 if (Mcb != &Vcb->DirtyFatMcb) { 409 NT_ASSERT( FatNonSparseMcb( Vcb, Mcb, &SparseVbo, &SparseByteCount ) || 410 ((SparseVbo == Vbo) && (SparseByteCount == SectorCount )) ); 411 } 412 413 return Result; 414 } 415 416 417 BOOLEAN 418 FatLookupMcbEntry ( 419 IN PVCB Vcb, 420 IN PLARGE_MCB Mcb, 421 IN VBO Vbo, 422 OUT PLBO Lbo, 423 OUT PULONG ByteCount OPTIONAL, 424 OUT PULONG Index OPTIONAL 425 ) 426 { 427 BOOLEAN Results; 428 LONGLONG LiLbo; 429 LONGLONG LiSectorCount; 430 ULONG Remainder; 431 432 LiLbo = 0; 433 LiSectorCount = 0; 434 435 Remainder = Vbo & MCB_SCALE_MODULO; 436 437 Results = FsRtlLookupLargeMcbEntry( Mcb, 438 (Vbo >> MCB_SCALE_LOG2), 439 &LiLbo, 440 ARGUMENT_PRESENT(ByteCount) ? &LiSectorCount : NULL, 441 NULL, 442 NULL, 443 Index ); 444 445 if ((ULONG) LiLbo != -1) { 446 447 *Lbo = (((LBO) LiLbo) << MCB_SCALE_LOG2); 448 449 if (Results) { 450 451 *Lbo += Remainder; 452 } 453 454 } else { 455 456 *Lbo = 0; 457 } 458 459 if (ARGUMENT_PRESENT(ByteCount)) { 460 461 *ByteCount = (ULONG) LiSectorCount; 462 463 if (*ByteCount) { 464 465 *ByteCount <<= MCB_SCALE_LOG2; 466 467 // 468 // If ByteCount overflows, then this is likely the case of 469 // a file of max-supported size (4GiB - 1), allocated in a 470 // single continuous run. 471 // 472 473 if (*ByteCount == 0) { 474 475 *ByteCount = 0xFFFFFFFF; 476 } 477 478 if (Results) { 479 480 *ByteCount -= Remainder; 481 } 482 } 483 484 } 485 486 return Results; 487 } 488 489 // 490 // NOTE: Vbo/Lbn undefined if MCB is empty & return code false. 491 // 492 493 BOOLEAN 494 FatLookupLastMcbEntry ( 495 IN PVCB Vcb, 496 IN PLARGE_MCB Mcb, 497 OUT PVBO Vbo, 498 OUT PLBO Lbo, 499 OUT PULONG Index 500 ) 501 502 { 503 BOOLEAN Results; 504 LONGLONG LiVbo; 505 LONGLONG LiLbo; 506 ULONG LocalIndex; 507 508 PAGED_CODE(); 509 510 LiVbo = LiLbo = 0; 511 LocalIndex = 0; 512 513 Results = FsRtlLookupLastLargeMcbEntryAndIndex( Mcb, 514 &LiVbo, 515 &LiLbo, 516 &LocalIndex ); 517 518 *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2; 519 520 if (((ULONG) LiLbo) != -1) { 521 522 *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2; 523 524 *Lbo += (MCB_SCALE - 1); 525 *Vbo += (MCB_SCALE - 1); 526 527 } else { 528 529 *Lbo = 0; 530 } 531 532 if (Index) { 533 *Index = LocalIndex; 534 } 535 536 return Results; 537 } 538 539 540 BOOLEAN 541 FatGetNextMcbEntry ( 542 IN PVCB Vcb, 543 IN PLARGE_MCB Mcb, 544 IN ULONG RunIndex, 545 OUT PVBO Vbo, 546 OUT PLBO Lbo, 547 OUT PULONG ByteCount 548 ) 549 550 { 551 BOOLEAN Results; 552 LONGLONG LiVbo; 553 LONGLONG LiLbo; 554 LONGLONG LiSectorCount; 555 556 PAGED_CODE(); 557 558 LiVbo = LiLbo = 0; 559 560 Results = FsRtlGetNextLargeMcbEntry( Mcb, 561 RunIndex, 562 &LiVbo, 563 &LiLbo, 564 &LiSectorCount ); 565 566 if (Results) { 567 568 *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2; 569 570 if (((ULONG) LiLbo) != -1) { 571 572 *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2; 573 574 } else { 575 576 *Lbo = 0; 577 } 578 579 *ByteCount = ((ULONG) LiSectorCount) << MCB_SCALE_LOG2; 580 581 if ((*ByteCount == 0) && (LiSectorCount != 0)) { 582 583 // 584 // If 'ByteCount' overflows, then this is likely a file of 585 // max supported size (2^32 - 1) in one contiguous run. 586 // 587 588 NT_ASSERT( RunIndex == 0 ); 589 590 *ByteCount = 0xFFFFFFFF; 591 } 592 } 593 594 return Results; 595 } 596 597 598 VOID 599 FatRemoveMcbEntry ( 600 IN PVCB Vcb, 601 IN PLARGE_MCB Mcb, 602 IN VBO Vbo, 603 IN ULONG SectorCount 604 ) 605 { 606 PAGED_CODE(); 607 608 if ((SectorCount) && (SectorCount != 0xFFFFFFFF)) { 609 610 SectorCount--; 611 SectorCount >>= MCB_SCALE_LOG2; 612 SectorCount++; 613 } 614 615 Vbo >>= MCB_SCALE_LOG2; 616 617 #if DBG 618 _SEH2_TRY { 619 #endif 620 621 FsRtlRemoveLargeMcbEntry( Mcb, 622 (LONGLONG) Vbo, 623 (LONGLONG) SectorCount); 624 625 #if DBG 626 } _SEH2_EXCEPT(FatBugCheckExceptionFilter( _SEH2_GetExceptionInformation() )) { 627 628 NOTHING; 629 } _SEH2_END; 630 #endif 631 632 } 633 634 635 _Function_class_(IRP_MJ_FILE_SYSTEM_CONTROL) 636 _Function_class_(DRIVER_DISPATCH) 637 NTSTATUS 638 NTAPI 639 FatFsdFileSystemControl ( 640 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, 641 _Inout_ PIRP Irp 642 ) 643 644 /*++ 645 646 Routine Description: 647 648 This routine implements the FSD part of FileSystem control operations 649 650 Arguments: 651 652 VolumeDeviceObject - Supplies the volume device object where the 653 file exists 654 655 Irp - Supplies the Irp being processed 656 657 Return Value: 658 659 NTSTATUS - The FSD status for the IRP 660 661 --*/ 662 663 { 664 BOOLEAN Wait; 665 NTSTATUS Status; 666 PIRP_CONTEXT IrpContext = NULL; 667 668 BOOLEAN TopLevel; 669 670 PAGED_CODE(); 671 UNREFERENCED_PARAMETER( VolumeDeviceObject ); 672 673 DebugTrace(+1, Dbg,"FatFsdFileSystemControl\n", 0); 674 675 // 676 // Call the common FileSystem Control routine, with blocking allowed if 677 // synchronous. This opeation needs to special case the mount 678 // and verify suboperations because we know they are allowed to block. 679 // We identify these suboperations by looking at the file object field 680 // and seeing if its null. 681 // 682 683 if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) { 684 685 Wait = TRUE; 686 687 } else { 688 689 Wait = CanFsdWait( Irp ); 690 } 691 692 FsRtlEnterFileSystem(); 693 694 TopLevel = FatIsIrpTopLevel( Irp ); 695 696 _SEH2_TRY { 697 698 PIO_STACK_LOCATION IrpSp; 699 700 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 701 702 // 703 // We need to made a special check here for the InvalidateVolumes 704 // FSCTL as that comes in with a FileSystem device object instead 705 // of a volume device object. 706 // 707 708 if (FatDeviceIsFatFsdo( IrpSp->DeviceObject) && 709 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && 710 (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST) && 711 (IrpSp->Parameters.FileSystemControl.FsControlCode == 712 FSCTL_INVALIDATE_VOLUMES)) { 713 714 Status = FatInvalidateVolumes( Irp ); 715 716 } else { 717 718 IrpContext = FatCreateIrpContext( Irp, Wait ); 719 720 Status = FatCommonFileSystemControl( IrpContext, Irp ); 721 } 722 723 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 724 725 // 726 // We had some trouble trying to perform the requested 727 // operation, so we'll abort the I/O request with 728 // the error status that we get back from the 729 // execption code 730 // 731 732 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 733 } _SEH2_END; 734 735 if (TopLevel) { IoSetTopLevelIrp( NULL ); } 736 737 FsRtlExitFileSystem(); 738 739 // 740 // And return to our caller 741 // 742 743 DebugTrace(-1, Dbg, "FatFsdFileSystemControl -> %08lx\n", Status); 744 745 return Status; 746 } 747 748 749 _Requires_lock_held_(_Global_critical_region_) 750 NTSTATUS 751 FatCommonFileSystemControl ( 752 IN PIRP_CONTEXT IrpContext, 753 IN PIRP Irp 754 ) 755 756 /*++ 757 758 Routine Description: 759 760 This is the common routine for doing FileSystem control operations called 761 by both the fsd and fsp threads 762 763 Arguments: 764 765 Irp - Supplies the Irp to process 766 767 Return Value: 768 769 NTSTATUS - The return status for the operation 770 771 --*/ 772 773 { 774 NTSTATUS Status; 775 PIO_STACK_LOCATION IrpSp; 776 777 PAGED_CODE(); 778 779 // 780 // Get a pointer to the current Irp stack location 781 // 782 783 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 784 785 DebugTrace(+1, Dbg,"FatCommonFileSystemControl\n", 0); 786 DebugTrace( 0, Dbg,"Irp = %p\n", Irp); 787 DebugTrace( 0, Dbg,"MinorFunction = %08lx\n", IrpSp->MinorFunction); 788 789 // 790 // We know this is a file system control so we'll case on the 791 // minor function, and call a internal worker routine to complete 792 // the irp. 793 // 794 795 switch (IrpSp->MinorFunction) { 796 797 case IRP_MN_USER_FS_REQUEST: 798 799 Status = FatUserFsCtrl( IrpContext, Irp ); 800 break; 801 802 case IRP_MN_MOUNT_VOLUME: 803 804 Status = FatMountVolume( IrpContext, 805 IrpSp->Parameters.MountVolume.DeviceObject, 806 IrpSp->Parameters.MountVolume.Vpb, 807 IrpSp->DeviceObject ); 808 809 // 810 // Complete the request. 811 // 812 // We do this here because FatMountVolume can be called recursively, 813 // but the Irp is only to be completed once. 814 // 815 // NOTE: I don't think this is true anymore (danlo 3/15/1999). Probably 816 // an artifact of the old doublespace attempt. 817 // 818 819 FatCompleteRequest( IrpContext, Irp, Status ); 820 break; 821 822 case IRP_MN_VERIFY_VOLUME: 823 824 Status = FatVerifyVolume( IrpContext, Irp ); 825 break; 826 827 default: 828 829 DebugTrace( 0, Dbg, "Invalid FS Control Minor Function %08lx\n", IrpSp->MinorFunction); 830 831 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 832 Status = STATUS_INVALID_DEVICE_REQUEST; 833 break; 834 } 835 836 DebugTrace(-1, Dbg, "FatCommonFileSystemControl -> %08lx\n", Status); 837 838 return Status; 839 } 840 841 842 // 843 // Local Support Routine 844 // 845 846 _Requires_lock_held_(_Global_critical_region_) 847 NTSTATUS 848 FatMountVolume ( 849 IN PIRP_CONTEXT IrpContext, 850 IN PDEVICE_OBJECT TargetDeviceObject, 851 IN PVPB Vpb, 852 IN PDEVICE_OBJECT FsDeviceObject 853 ) 854 855 /*++ 856 857 Routine Description: 858 859 This routine performs the mount volume operation. It is responsible for 860 either completing of enqueuing the input Irp. 861 862 Its job is to verify that the volume denoted in the IRP is a Fat volume, 863 and create the VCB and root DCB structures. The algorithm it uses is 864 essentially as follows: 865 866 1. Create a new Vcb Structure, and initialize it enough to do cached 867 volume file I/O. 868 869 2. Read the disk and check if it is a Fat volume. 870 871 3. If it is not a Fat volume then free the cached volume file, delete 872 the VCB, and complete the IRP with STATUS_UNRECOGNIZED_VOLUME 873 874 4. Check if the volume was previously mounted and if it was then do a 875 remount operation. This involves reinitializing the cached volume 876 file, checking the dirty bit, resetting up the allocation support, 877 deleting the VCB, hooking in the old VCB, and completing the IRP. 878 879 5. Otherwise create a root DCB, create Fsp threads as necessary, and 880 complete the IRP. 881 882 Arguments: 883 884 TargetDeviceObject - This is where we send all of our requests. 885 886 Vpb - This gives us additional information needed to complete the mount. 887 888 Return Value: 889 890 NTSTATUS - The return status for the operation 891 892 --*/ 893 894 { 895 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); 896 NTSTATUS Status = STATUS_INVALID_PARAMETER; 897 898 PBCB BootBcb; 899 PPACKED_BOOT_SECTOR BootSector = NULL; 900 901 PBCB DirentBcb; 902 PDIRENT Dirent; 903 ULONG ByteOffset; 904 905 BOOLEAN MountNewVolume = FALSE; 906 BOOLEAN WeClearedVerifyRequiredBit = FALSE; 907 BOOLEAN DoARemount = FALSE; 908 909 PVCB OldVcb = NULL; 910 PVPB OldVpb = NULL; 911 912 PDEVICE_OBJECT RealDevice = NULL; 913 PVOLUME_DEVICE_OBJECT VolDo = NULL; 914 PVCB Vcb = NULL; 915 PFILE_OBJECT RootDirectoryFile = NULL; 916 917 PLIST_ENTRY Links; 918 919 IO_STATUS_BLOCK Iosb = {0}; 920 ULONG ChangeCount = 0; 921 922 DISK_GEOMETRY Geometry; 923 924 PARTITION_INFORMATION_EX PartitionInformation; 925 NTSTATUS StatusPartInfo; 926 927 #if (NTDDI_VERSION > NTDDI_WIN8) 928 GUID VolumeGuid = {0}; 929 #endif 930 931 932 PAGED_CODE(); 933 934 DebugTrace(+1, Dbg, "FatMountVolume\n", 0); 935 DebugTrace( 0, Dbg, "TargetDeviceObject = %p\n", TargetDeviceObject); 936 DebugTrace( 0, Dbg, "Vpb = %p\n", Vpb); 937 938 NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); 939 NT_ASSERT( FatDeviceIsFatFsdo( FsDeviceObject)); 940 941 // 942 // Only send down IOCTL_DISK_CHECK_VERIFY if it is removable media. 943 // 944 945 if (FlagOn(TargetDeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { 946 947 // 948 // Verify that there is a disk here and pick up the change count. 949 // 950 951 Status = FatPerformDevIoCtrl( IrpContext, 952 IOCTL_DISK_CHECK_VERIFY, 953 TargetDeviceObject, 954 NULL, 955 0, 956 &ChangeCount, 957 sizeof(ULONG), 958 FALSE, 959 TRUE, 960 &Iosb ); 961 962 if (!NT_SUCCESS( Status )) { 963 964 // 965 // If we will allow a raw mount then avoid sending the popup. 966 // 967 // Only send this on "true" disk devices to handle the accidental 968 // legacy of FAT. No other FS will throw a harderror on empty 969 // drives. 970 // 971 // Cmd should really handle this per 9x. 972 // 973 974 if (!FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT ) && 975 Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK) { 976 977 FatNormalizeAndRaiseStatus( IrpContext, Status ); 978 } 979 980 return Status; 981 } 982 983 } 984 985 if (Iosb.Information != sizeof(ULONG)) { 986 987 // 988 // Be safe about the count in case the driver didn't fill it in 989 // 990 991 ChangeCount = 0; 992 } 993 994 // 995 // If this is a CD class device, then check to see if there is a 996 // 'data track' or not. This is to avoid issuing paging reads which will 997 // fail later in the mount process (e.g. CD-DA or blank CD media) 998 // 999 1000 if ((TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) && 1001 !FatScanForDataTrack( IrpContext, TargetDeviceObject)) { 1002 1003 return STATUS_UNRECOGNIZED_VOLUME; 1004 } 1005 1006 // 1007 // Ping the volume with a partition query and pick up the partition 1008 // type. We'll check this later to avoid some scurrilous volumes. 1009 // 1010 1011 StatusPartInfo = FatPerformDevIoCtrl( IrpContext, 1012 IOCTL_DISK_GET_PARTITION_INFO_EX, 1013 TargetDeviceObject, 1014 NULL, 1015 0, 1016 &PartitionInformation, 1017 sizeof(PARTITION_INFORMATION_EX), 1018 FALSE, 1019 TRUE, 1020 &Iosb ); 1021 1022 // 1023 // Make sure we can wait. 1024 // 1025 1026 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 1027 1028 // 1029 // Do a quick check to see if there any Vcb's which can be removed. 1030 // 1031 1032 FatScanForDismountedVcb( IrpContext ); 1033 1034 // 1035 // Initialize the Bcbs and our final state so that the termination 1036 // handlers will know what to free or unpin 1037 // 1038 1039 BootBcb = NULL; 1040 DirentBcb = NULL; 1041 1042 Vcb = NULL; 1043 VolDo = NULL; 1044 MountNewVolume = FALSE; 1045 1046 _SEH2_TRY { 1047 1048 // 1049 // Synchronize with FatCheckForDismount(), which modifies the vpb. 1050 // 1051 1052 #ifdef _MSC_VER 1053 #pragma prefast( push ) 1054 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 1055 #pragma prefast( disable: 28193, "this will always wait" ) 1056 #endif 1057 1058 (VOID)FatAcquireExclusiveGlobal( IrpContext ); 1059 1060 #ifdef _MSC_VER 1061 #pragma prefast( pop ) 1062 #endif 1063 1064 // 1065 // Create a new volume device object. This will have the Vcb 1066 // hanging off of its end, and set its alignment requirement 1067 // from the device we talk to. 1068 // 1069 1070 if (!NT_SUCCESS(Status = IoCreateDevice( FatData.DriverObject, 1071 sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT), 1072 NULL, 1073 FILE_DEVICE_DISK_FILE_SYSTEM, 1074 0, 1075 FALSE, 1076 (PDEVICE_OBJECT *)&VolDo))) { 1077 1078 try_return( Status ); 1079 } 1080 1081 // 1082 // Our alignment requirement is the larger of the processor alignment requirement 1083 // already in the volume device object and that in the TargetDeviceObject 1084 // 1085 1086 if (TargetDeviceObject->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) { 1087 1088 VolDo->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; 1089 } 1090 1091 // 1092 // Initialize the overflow queue for the volume 1093 // 1094 1095 VolDo->OverflowQueueCount = 0; 1096 InitializeListHead( &VolDo->OverflowQueue ); 1097 1098 VolDo->PostedRequestCount = 0; 1099 KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock ); 1100 1101 // 1102 // We must initialize the stack size in our device object before 1103 // the following reads, because the I/O system has not done it yet. 1104 // This must be done before we clear the device initializing flag 1105 // otherwise a filter could attach and copy the wrong stack size into 1106 // it's device object. 1107 // 1108 1109 VolDo->DeviceObject.StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); 1110 1111 // 1112 // We must also set the sector size correctly in our device object 1113 // before clearing the device initializing flag. 1114 // 1115 1116 Status = FatPerformDevIoCtrl( IrpContext, 1117 IOCTL_DISK_GET_DRIVE_GEOMETRY, 1118 TargetDeviceObject, 1119 NULL, 1120 0, 1121 &Geometry, 1122 sizeof( DISK_GEOMETRY ), 1123 FALSE, 1124 TRUE, 1125 NULL ); 1126 1127 if (!NT_SUCCESS( Status )) { 1128 1129 try_return( Status ); 1130 } 1131 1132 #ifdef _MSC_VER 1133 #pragma prefast( suppress: 28175, "this is a filesystem driver, touching SectorSize is fine" ) 1134 #endif 1135 VolDo->DeviceObject.SectorSize = (USHORT)Geometry.BytesPerSector; 1136 1137 // 1138 // Indicate that this device object is now completely initialized 1139 // 1140 1141 ClearFlag(VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING); 1142 1143 // 1144 // Now Before we can initialize the Vcb we need to set up the device 1145 // object field in the Vpb to point to our new volume device object. 1146 // This is needed when we create the virtual volume file's file object 1147 // in initialize vcb. 1148 // 1149 1150 Vpb->DeviceObject = (PDEVICE_OBJECT)VolDo; 1151 1152 // 1153 // If the real device needs verification, temporarily clear the 1154 // field. 1155 // 1156 1157 RealDevice = Vpb->RealDevice; 1158 1159 if ( FlagOn(RealDevice->Flags, DO_VERIFY_VOLUME) ) { 1160 1161 ClearFlag(RealDevice->Flags, DO_VERIFY_VOLUME); 1162 1163 WeClearedVerifyRequiredBit = TRUE; 1164 } 1165 1166 // 1167 // Initialize the new vcb 1168 // 1169 1170 FatInitializeVcb( IrpContext, 1171 &VolDo->Vcb, 1172 TargetDeviceObject, 1173 Vpb, 1174 FsDeviceObject); 1175 // 1176 // Get a reference to the Vcb hanging off the end of the device object 1177 // 1178 1179 Vcb = &VolDo->Vcb; 1180 1181 // 1182 // Read in the boot sector, and have the read be the minumum size 1183 // needed. We know we can wait. 1184 // 1185 1186 // 1187 // We need to commute errors on CD so that CDFS will get its crack. Audio 1188 // and even data media may not be universally readable on sector zero. 1189 // 1190 1191 _SEH2_TRY { 1192 1193 FatReadVolumeFile( IrpContext, 1194 Vcb, 1195 0, // Starting Byte 1196 sizeof(PACKED_BOOT_SECTOR), 1197 &BootBcb, 1198 (PVOID *)&BootSector ); 1199 1200 } _SEH2_EXCEPT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ? 1201 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { 1202 1203 NOTHING; 1204 } _SEH2_END; 1205 1206 // 1207 // Call a routine to check the boot sector to see if it is fat 1208 // 1209 1210 if (BootBcb == NULL || !FatIsBootSectorFat( BootSector)) { 1211 1212 DebugTrace(0, Dbg, "Not a Fat Volume\n", 0); 1213 1214 // 1215 // Complete the request and return to our caller 1216 // 1217 1218 try_return( Status = STATUS_UNRECOGNIZED_VOLUME ); 1219 } 1220 1221 #if (NTDDI_VERSION > NTDDI_WIN8) 1222 // 1223 // Initialize the volume guid. 1224 // 1225 1226 if (NT_SUCCESS( IoVolumeDeviceToGuid( Vcb->TargetDeviceObject, &VolumeGuid ))) { 1227 1228 1229 // 1230 // Stash a copy away in the VCB. 1231 // 1232 1233 RtlCopyMemory( &Vcb->VolumeGuid, &VolumeGuid, sizeof(GUID)); 1234 1235 } 1236 1237 1238 // 1239 // Stash away a copy of the volume GUID path in our VCB. 1240 // 1241 1242 if (Vcb->VolumeGuidPath.Buffer) { 1243 ExFreePool( Vcb->VolumeGuidPath.Buffer ); 1244 Vcb->VolumeGuidPath.Buffer = NULL; 1245 Vcb->VolumeGuidPath.Length = Vcb->VolumeGuidPath.MaximumLength = 0; 1246 } 1247 1248 IoVolumeDeviceToGuidPath( Vcb->TargetDeviceObject, &Vcb->VolumeGuidPath ); 1249 #endif 1250 1251 // 1252 // Unpack the BPB. We used to do some sanity checking of the FATs at 1253 // this point, but authoring errors on third-party devices prevent 1254 // us from continuing to safeguard ourselves. We can only hope the 1255 // boot sector check is good enough. 1256 // 1257 // (read: digital cameras) 1258 // 1259 // Win9x does the same. 1260 // 1261 1262 FatUnpackBios( &Vcb->Bpb, &BootSector->PackedBpb ); 1263 1264 // 1265 // Check if we have an OS/2 Boot Manager partition and treat it as an 1266 // unknown file system. We'll check the partition type in from the 1267 // partition table and we ensure that it has less than 0x80 sectors, 1268 // which is just a heuristic that will capture all real OS/2 BM partitions 1269 // and avoid the chance we'll discover partitions which erroneously 1270 // (but to this point, harmlessly) put down the OS/2 BM type. 1271 // 1272 // Note that this is only conceivable on good old MBR media. 1273 // 1274 // The OS/2 Boot Manager boot format mimics a FAT16 partition in sector 1275 // zero but does is not a real FAT16 file system. For example, the boot 1276 // sector indicates it has 2 FATs but only really has one, with the boot 1277 // manager code overlaying the second FAT. If we then set clean bits in 1278 // FAT[0] we'll corrupt that code. 1279 // 1280 1281 if (NT_SUCCESS( StatusPartInfo ) && 1282 (PartitionInformation.PartitionStyle == PARTITION_STYLE_MBR && 1283 PartitionInformation.Mbr.PartitionType == PARTITION_OS2BOOTMGR) && 1284 (Vcb->Bpb.Sectors != 0 && 1285 Vcb->Bpb.Sectors < 0x80)) { 1286 1287 DebugTrace( 0, Dbg, "OS/2 Boot Manager volume detected, volume not mounted. \n", 0 ); 1288 1289 // 1290 // Complete the request and return to our caller 1291 // 1292 1293 try_return( Status = STATUS_UNRECOGNIZED_VOLUME ); 1294 } 1295 1296 // 1297 // Verify that the sector size recorded in the Bpb matches what the 1298 // device currently reports it's sector size to be. 1299 // 1300 1301 if ( !NT_SUCCESS( Status) || 1302 (Geometry.BytesPerSector != Vcb->Bpb.BytesPerSector)) { 1303 1304 try_return( Status = STATUS_UNRECOGNIZED_VOLUME ); 1305 } 1306 1307 // 1308 // This is a fat volume, so extract the bpb, serial number. The 1309 // label we'll get later after we've created the root dcb. 1310 // 1311 // Note that the way data caching is done, we set neither the 1312 // direct I/O or Buffered I/O bit in the device object flags. 1313 // 1314 1315 if (Vcb->Bpb.Sectors != 0) { Vcb->Bpb.LargeSectors = 0; } 1316 1317 if (IsBpbFat32(&BootSector->PackedBpb)) { 1318 1319 CopyUchar4( &Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id ); 1320 1321 } else { 1322 1323 CopyUchar4( &Vpb->SerialNumber, BootSector->Id ); 1324 1325 // 1326 // Allocate space for the stashed boot sector chunk. This only has meaning on 1327 // FAT12/16 volumes since this only is kept for the FSCTL_QUERY_FAT_BPB and it and 1328 // its users are a bit wierd, thinking that a BPB exists wholly in the first 0x24 1329 // bytes. 1330 // 1331 1332 Vcb->First0x24BytesOfBootSector = 1333 FsRtlAllocatePoolWithTag( PagedPool, 1334 0x24, 1335 TAG_STASHED_BPB ); 1336 1337 // 1338 // Stash a copy of the first 0x24 bytes 1339 // 1340 1341 RtlCopyMemory( Vcb->First0x24BytesOfBootSector, 1342 BootSector, 1343 0x24 ); 1344 } 1345 1346 // 1347 // Now unpin the boot sector, so when we set up allocation eveything 1348 // works. 1349 // 1350 1351 FatUnpinBcb( IrpContext, BootBcb ); 1352 1353 // 1354 // Compute a number of fields for Vcb.AllocationSupport 1355 // 1356 1357 FatSetupAllocationSupport( IrpContext, Vcb ); 1358 1359 // 1360 // Sanity check the FsInfo information for FAT32 volumes. Silently deal 1361 // with messed up information by effectively disabling FsInfo updates. 1362 // 1363 1364 if (FatIsFat32( Vcb )) { 1365 1366 if (Vcb->Bpb.FsInfoSector >= Vcb->Bpb.ReservedSectors) { 1367 1368 Vcb->Bpb.FsInfoSector = 0; 1369 } 1370 } 1371 1372 1373 // 1374 // Create a root Dcb so we can read in the volume label. If this is FAT32, we can 1375 // discover corruption in the FAT chain. 1376 // 1377 // NOTE: this exception handler presumes that this is the only spot where we can 1378 // discover corruption in the mount process. If this ever changes, this handler 1379 // MUST be expanded. The reason we have this guy here is because we have to rip 1380 // the structures down now (in the finally below) and can't wait for the outer 1381 // exception handling to do it for us, at which point everything will have vanished. 1382 // 1383 1384 _SEH2_TRY { 1385 1386 FatCreateRootDcb( IrpContext, Vcb ); 1387 1388 } _SEH2_EXCEPT (_SEH2_GetExceptionCode() == STATUS_FILE_CORRUPT_ERROR ? EXCEPTION_EXECUTE_HANDLER : 1389 EXCEPTION_CONTINUE_SEARCH) { 1390 1391 // 1392 // The volume needs to be dirtied, do it now. Note that at this point we have built 1393 // enough of the Vcb to pull this off. 1394 // 1395 1396 FatCheckDirtyBit( IrpContext, 1397 Vcb ); 1398 1399 // 1400 // Set the dirty bit if it is not set already 1401 // 1402 1403 if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { 1404 1405 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNT_IN_PROGRESS ); 1406 FatMarkVolume( IrpContext, Vcb, VolumeDirty ); 1407 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNT_IN_PROGRESS ); 1408 } 1409 1410 // 1411 // Now keep bailing out ... 1412 // 1413 1414 FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 1415 } _SEH2_END; 1416 1417 FatLocateVolumeLabel( IrpContext, 1418 Vcb, 1419 &Dirent, 1420 &DirentBcb, 1421 (PVBO)&ByteOffset ); 1422 1423 if (Dirent != NULL) { 1424 1425 UCHAR OemBuffer[11]; 1426 OEM_STRING OemString; 1427 UNICODE_STRING UnicodeString; 1428 1429 OemString.Buffer = (PCHAR)&OemBuffer[0]; 1430 OemString.MaximumLength = 11; 1431 1432 RtlCopyMemory( OemString.Buffer, Dirent->FileName, 11 ); 1433 1434 // 1435 // Translate the first character from 0x5 to 0xe5. 1436 // 1437 1438 if (OemString.Buffer[0] == FAT_DIRENT_REALLY_0E5) { 1439 1440 OemString.Buffer[0] = 0xe5; 1441 } 1442 1443 // 1444 // Compute the length of the volume name 1445 // 1446 1447 for ( OemString.Length = 11; 1448 OemString.Length > 0; 1449 OemString.Length -= 1) { 1450 1451 if ( (OemString.Buffer[OemString.Length-1] != 0x00) && 1452 (OemString.Buffer[OemString.Length-1] != 0x20) ) { break; } 1453 } 1454 1455 UnicodeString.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH; 1456 UnicodeString.Buffer = &Vcb->Vpb->VolumeLabel[0]; 1457 1458 Status = RtlOemStringToCountedUnicodeString( &UnicodeString, 1459 &OemString, 1460 FALSE ); 1461 1462 if ( !NT_SUCCESS( Status ) ) { 1463 1464 try_return( Status ); 1465 } 1466 1467 Vpb->VolumeLabelLength = UnicodeString.Length; 1468 1469 } else { 1470 1471 Vpb->VolumeLabelLength = 0; 1472 } 1473 1474 // 1475 // Use the change count we noted initially *before* doing any work. 1476 // If something came along in the midst of this operation, we'll 1477 // verify and discover the problem. 1478 // 1479 1480 Vcb->ChangeCount = ChangeCount; 1481 1482 // 1483 // Now scan the list of previously mounted volumes and compare 1484 // serial numbers and volume labels off not currently mounted 1485 // volumes to see if we have a match. 1486 // 1487 1488 for (Links = FatData.VcbQueue.Flink; 1489 Links != &FatData.VcbQueue; 1490 Links = Links->Flink) { 1491 1492 OldVcb = CONTAINING_RECORD( Links, VCB, VcbLinks ); 1493 OldVpb = OldVcb->Vpb; 1494 1495 // 1496 // Skip over ourselves since we're already in the VcbQueue 1497 // 1498 1499 if (OldVpb == Vpb) { continue; } 1500 1501 // 1502 // Check for a match: 1503 // 1504 // Serial Number, VolumeLabel and Bpb must all be the same. 1505 // Also the volume must have failed a verify before (ie. 1506 // VolumeNotMounted), and it must be in the same physical 1507 // drive than it was mounted in before. 1508 // 1509 1510 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) && 1511 (OldVcb->VcbCondition == VcbNotMounted) && 1512 (OldVpb->RealDevice == RealDevice) && 1513 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) && 1514 (RtlEqualMemory(&OldVpb->VolumeLabel[0], 1515 &Vpb->VolumeLabel[0], 1516 Vpb->VolumeLabelLength)) && 1517 (RtlEqualMemory(&OldVcb->Bpb, 1518 &Vcb->Bpb, 1519 IsBpbFat32(&Vcb->Bpb) ? 1520 sizeof(BIOS_PARAMETER_BLOCK) : 1521 FIELD_OFFSET(BIOS_PARAMETER_BLOCK, 1522 LargeSectorsPerFat) ))) { 1523 1524 DoARemount = TRUE; 1525 1526 break; 1527 } 1528 } 1529 1530 if ( DoARemount ) { 1531 1532 PVPB *IrpVpb; 1533 1534 DebugTrace(0, Dbg, "Doing a remount\n", 0); 1535 DebugTrace(0, Dbg, "Vcb = %p\n", Vcb); 1536 DebugTrace(0, Dbg, "Vpb = %p\n", Vpb); 1537 DebugTrace(0, Dbg, "OldVcb = %p\n", OldVcb); 1538 DebugTrace(0, Dbg, "OldVpb = %p\n", OldVpb); 1539 1540 // 1541 // Swap target device objects between the VCBs. That way 1542 // the old VCB will start using the new target device object, 1543 // and the new VCB will be torn down and deference the old 1544 // target device object. 1545 // 1546 1547 Vcb->TargetDeviceObject = OldVcb->TargetDeviceObject; 1548 OldVcb->TargetDeviceObject = TargetDeviceObject; 1549 1550 // 1551 // This is a remount, so link the old vpb in place 1552 // of the new vpb. 1553 // 1554 1555 NT_ASSERT( !FlagOn( OldVcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED ) ); 1556 1557 FatSetVcbCondition( OldVcb, VcbGood); 1558 OldVpb->RealDevice = Vpb->RealDevice; 1559 ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE); 1560 1561 #ifdef _MSC_VER 1562 #pragma prefast( suppress: 28175, "touching Vpb is ok for a filesystem" ) 1563 #endif 1564 OldVpb->RealDevice->Vpb = OldVpb; 1565 1566 // 1567 // Use the new changecount. 1568 // 1569 1570 OldVcb->ChangeCount = Vcb->ChangeCount; 1571 1572 // 1573 // If the new VPB is the VPB referenced in the original Irp, set 1574 // that reference back to the old VPB. 1575 // 1576 1577 IrpVpb = &IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->Parameters.MountVolume.Vpb; 1578 1579 if (*IrpVpb == Vpb) { 1580 1581 *IrpVpb = OldVpb; 1582 } 1583 1584 // 1585 // We do not want to touch this VPB again. It will get cleaned up when 1586 // the new VCB is cleaned up. 1587 // 1588 1589 NT_ASSERT( Vcb->Vpb == Vpb ); 1590 1591 Vpb = NULL; 1592 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED ); 1593 FatSetVcbCondition( Vcb, VcbBad ); 1594 1595 // 1596 // Reinitialize the volume file cache and allocation support. 1597 // 1598 1599 { 1600 CC_FILE_SIZES FileSizes; 1601 1602 FileSizes.AllocationSize.QuadPart = 1603 FileSizes.FileSize.QuadPart = ( 0x40000 + 0x1000 ); 1604 FileSizes.ValidDataLength = FatMaxLarge; 1605 1606 DebugTrace(0, Dbg, "Truncate and reinitialize the volume file\n", 0); 1607 1608 FatInitializeCacheMap( OldVcb->VirtualVolumeFile, 1609 &FileSizes, 1610 TRUE, 1611 &FatData.CacheManagerNoOpCallbacks, 1612 Vcb ); 1613 1614 // 1615 // Redo the allocation support 1616 // 1617 1618 FatSetupAllocationSupport( IrpContext, OldVcb ); 1619 1620 // 1621 // Get the state of the dirty bit. 1622 // 1623 1624 FatCheckDirtyBit( IrpContext, OldVcb ); 1625 1626 // 1627 // Check for write protected media. 1628 // 1629 1630 if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) { 1631 1632 SetFlag( OldVcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ); 1633 1634 } else { 1635 1636 ClearFlag( OldVcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ); 1637 } 1638 } 1639 1640 // 1641 // Complete the request and return to our caller 1642 // 1643 1644 try_return( Status = STATUS_SUCCESS ); 1645 } 1646 1647 DebugTrace(0, Dbg, "Mount a new volume\n", 0); 1648 1649 // 1650 // This is a new mount 1651 // 1652 // Create a blank ea data file fcb, just not for Fat32. 1653 // 1654 1655 if (!FatIsFat32(Vcb)) { 1656 1657 DIRENT TempDirent; 1658 PFCB EaFcb; 1659 1660 RtlZeroMemory( &TempDirent, sizeof(DIRENT) ); 1661 RtlCopyMemory( &TempDirent.FileName[0], "EA DATA SF", 11 ); 1662 1663 EaFcb = FatCreateFcb( IrpContext, 1664 Vcb, 1665 Vcb->RootDcb, 1666 0, 1667 0, 1668 &TempDirent, 1669 NULL, 1670 NULL, 1671 FALSE, 1672 TRUE ); 1673 1674 // 1675 // Deny anybody who trys to open the file. 1676 // 1677 1678 SetFlag( EaFcb->FcbState, FCB_STATE_SYSTEM_FILE ); 1679 1680 Vcb->EaFcb = EaFcb; 1681 } 1682 1683 // 1684 // Get the state of the dirty bit. 1685 // 1686 1687 FatCheckDirtyBit( IrpContext, Vcb ); 1688 1689 1690 // 1691 // Check for write protected media. 1692 // 1693 1694 if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) { 1695 1696 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ); 1697 1698 } else { 1699 1700 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ); 1701 } 1702 1703 1704 // 1705 // Lock volume in drive if we just mounted the boot drive. 1706 // 1707 1708 if (FlagOn(RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION)) { 1709 1710 SetFlag(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE); 1711 1712 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) { 1713 1714 FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE ); 1715 } 1716 } 1717 1718 1719 // 1720 // Indicate to our termination handler that we have mounted 1721 // a new volume. 1722 // 1723 1724 MountNewVolume = TRUE; 1725 1726 // 1727 // Complete the request 1728 // 1729 1730 Status = STATUS_SUCCESS; 1731 1732 // 1733 // Ref the root dir stream object so we can send mount notification. 1734 // 1735 1736 RootDirectoryFile = Vcb->RootDcb->Specific.Dcb.DirectoryFile; 1737 ObReferenceObject( RootDirectoryFile ); 1738 1739 // 1740 // Remove the extra reference to this target DO made on behalf of us 1741 // by the IO system. In the remount case, we permit regular Vcb 1742 // deletion to do this work. 1743 // 1744 1745 ObDereferenceObject( TargetDeviceObject ); 1746 1747 1748 try_exit: NOTHING; 1749 1750 } _SEH2_FINALLY { 1751 1752 DebugUnwind( FatMountVolume ); 1753 1754 FatUnpinBcb( IrpContext, BootBcb ); 1755 FatUnpinBcb( IrpContext, DirentBcb ); 1756 1757 // 1758 // Check if a volume was mounted. If not then we need to 1759 // mark the Vpb not mounted again. 1760 // 1761 1762 if ( !MountNewVolume ) { 1763 1764 if ( Vcb != NULL ) { 1765 1766 // 1767 // A VCB was created and initialized. We need to try to tear it down. 1768 // 1769 1770 FatCheckForDismount( IrpContext, 1771 Vcb, 1772 TRUE ); 1773 1774 IrpContext->Vcb = NULL; 1775 1776 } else if (VolDo != NULL) { 1777 1778 // 1779 // The VCB was never initialized, so we need to delete the 1780 // device right here. 1781 // 1782 1783 IoDeleteDevice( &VolDo->DeviceObject ); 1784 } 1785 1786 // 1787 // See if a remount failed. 1788 // 1789 1790 if (DoARemount && _SEH2_AbnormalTermination()) { 1791 1792 // 1793 // The remount failed. Try to tear down the old VCB as well. 1794 // 1795 1796 FatCheckForDismount( IrpContext, 1797 OldVcb, 1798 TRUE ); 1799 } 1800 } 1801 1802 if ( WeClearedVerifyRequiredBit == TRUE ) { 1803 1804 SetFlag(RealDevice->Flags, DO_VERIFY_VOLUME); 1805 } 1806 1807 FatReleaseGlobal( IrpContext ); 1808 1809 DebugTrace(-1, Dbg, "FatMountVolume -> %08lx\n", Status); 1810 } _SEH2_END; 1811 1812 // 1813 // Now send mount notification. Note that since this is outside of any 1814 // synchronization since the synchronous delivery of this may go to 1815 // folks that provoke re-entrance to the FS. 1816 // 1817 1818 if (RootDirectoryFile != NULL) { 1819 1820 #if (NTDDI_VERSION >= NTDDI_WIN8) 1821 if (FatDiskAccountingEnabled) { 1822 1823 CcSetAdditionalCacheAttributesEx( RootDirectoryFile, CC_ENABLE_DISK_IO_ACCOUNTING ); 1824 } 1825 #endif 1826 1827 FsRtlNotifyVolumeEvent( RootDirectoryFile, FSRTL_VOLUME_MOUNT ); 1828 ObDereferenceObject( RootDirectoryFile ); 1829 } 1830 1831 return Status; 1832 } 1833 1834 1835 // 1836 // Local Support Routine 1837 // 1838 1839 _Requires_lock_held_(_Global_critical_region_) 1840 NTSTATUS 1841 FatVerifyVolume ( 1842 IN PIRP_CONTEXT IrpContext, 1843 IN PIRP Irp 1844 ) 1845 1846 /*++ 1847 1848 Routine Description: 1849 1850 This routine performs the verify volume operation by checking the volume 1851 label and serial number physically on the media with the the Vcb 1852 currently claiming to have the volume mounted. It is responsible for 1853 either completing or enqueuing the input Irp. 1854 1855 Regardless of whether the verify operation succeeds, the following 1856 operations are performed: 1857 1858 - Set Vcb->VirtualEaFile back to its initial state. 1859 - Purge all cached data (flushing first if verify succeeds) 1860 - Mark all Fcbs as needing verification 1861 1862 If the volumes verifies correctly we also must: 1863 1864 - Check the volume dirty bit. 1865 - Reinitialize the allocation support 1866 - Flush any dirty data 1867 1868 If the volume verify fails, it may never be mounted again. If it is 1869 mounted again, it will happen as a remount operation. In preparation 1870 for that, and to leave the volume in a state that can be "lazy deleted" 1871 the following operations are performed: 1872 1873 - Set the Vcb condition to VcbNotMounted 1874 - Uninitialize the volume file cachemap 1875 - Tear down the allocation support 1876 1877 In the case of an abnormal termination we haven't determined the state 1878 of the volume, so we set the Device Object as needing verification again. 1879 1880 Arguments: 1881 1882 Irp - Supplies the Irp to process 1883 1884 Return Value: 1885 1886 NTSTATUS - If the verify operation completes, it will return either 1887 STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. If an IO or 1888 other error is encountered, that status will be returned. 1889 1890 --*/ 1891 1892 { 1893 NTSTATUS Status = STATUS_SUCCESS; 1894 1895 PIO_STACK_LOCATION IrpSp; 1896 1897 PDIRENT RootDirectory = NULL; 1898 PPACKED_BOOT_SECTOR BootSector = NULL; 1899 1900 BIOS_PARAMETER_BLOCK Bpb; 1901 1902 PVOLUME_DEVICE_OBJECT VolDo; 1903 PVCB Vcb; 1904 PVPB Vpb; 1905 1906 ULONG SectorSize; 1907 BOOLEAN ClearVerify = FALSE; 1908 BOOLEAN ReleaseEntireVolume = FALSE; 1909 BOOLEAN VerifyAlreadyDone = FALSE; 1910 1911 DISK_GEOMETRY DiskGeometry; 1912 1913 LBO RootDirectoryLbo; 1914 ULONG RootDirectorySize; 1915 BOOLEAN LabelFound; 1916 1917 ULONG ChangeCount = 0; 1918 IO_STATUS_BLOCK Iosb = {0}; 1919 1920 PAGED_CODE(); 1921 1922 // 1923 // Get the current Irp stack location 1924 // 1925 1926 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 1927 1928 DebugTrace(+1, Dbg, "FatVerifyVolume\n", 0); 1929 DebugTrace( 0, Dbg, "DeviceObject = %p\n", IrpSp->Parameters.VerifyVolume.DeviceObject); 1930 DebugTrace( 0, Dbg, "Vpb = %p\n", IrpSp->Parameters.VerifyVolume.Vpb); 1931 1932 // 1933 // Save some references to make our life a little easier. Note the Vcb for the purposes 1934 // of exception handling. 1935 // 1936 1937 VolDo = (PVOLUME_DEVICE_OBJECT)IrpSp->Parameters.VerifyVolume.DeviceObject; 1938 1939 Vpb = IrpSp->Parameters.VerifyVolume.Vpb; 1940 IrpContext->Vcb = Vcb = &VolDo->Vcb; 1941 1942 // 1943 // If we cannot wait then enqueue the irp to the fsp and 1944 // return the status to our caller. 1945 // 1946 1947 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { 1948 1949 DebugTrace(0, Dbg, "Cannot wait for verify.\n", 0); 1950 1951 Status = FatFsdPostRequest( IrpContext, Irp ); 1952 1953 DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status ); 1954 return Status; 1955 } 1956 1957 // 1958 // We are serialized at this point allowing only one thread to 1959 // actually perform the verify operation. Any others will just 1960 // wait and then no-op when checking if the volume still needs 1961 // verification. 1962 // 1963 1964 #ifdef _MSC_VER 1965 #pragma prefast( push ) 1966 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 1967 #pragma prefast( disable: 28193, "this will always wait" ) 1968 #endif 1969 1970 (VOID)FatAcquireExclusiveGlobal( IrpContext ); 1971 1972 #ifdef _MSC_VER 1973 #pragma prefast( pop ) 1974 #endif 1975 1976 (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb ); 1977 1978 _SEH2_TRY { 1979 1980 BOOLEAN AllowRawMount = BooleanFlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT ); 1981 1982 // 1983 // Mark ourselves as verifying this volume so that recursive I/Os 1984 // will be able to complete. 1985 // 1986 1987 NT_ASSERT( Vcb->VerifyThread == NULL ); 1988 Vcb->VerifyThread = KeGetCurrentThread(); 1989 1990 // 1991 // Check if the real device still needs to be verified. If it doesn't 1992 // then obviously someone beat us here and already did the work 1993 // so complete the verify irp with success. Otherwise reenable 1994 // the real device and get to work. 1995 // 1996 1997 if (!FlagOn(Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) { 1998 1999 DebugTrace(0, Dbg, "RealDevice has already been verified\n", 0); 2000 2001 VerifyAlreadyDone = TRUE; 2002 try_return( Status = STATUS_SUCCESS ); 2003 } 2004 2005 // 2006 // Ping the volume with a partition query to make Jeff happy. 2007 // 2008 2009 { 2010 PARTITION_INFORMATION_EX PartitionInformation; 2011 2012 (VOID) FatPerformDevIoCtrl( IrpContext, 2013 IOCTL_DISK_GET_PARTITION_INFO_EX, 2014 Vcb->TargetDeviceObject, 2015 NULL, 2016 0, 2017 &PartitionInformation, 2018 sizeof(PARTITION_INFORMATION_EX), 2019 FALSE, 2020 TRUE, 2021 &Iosb ); 2022 } 2023 2024 // 2025 // Only send down IOCTL_DISK_CHECK_VERIFY if it is removable media. 2026 // 2027 2028 if (FlagOn(Vcb->TargetDeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { 2029 2030 // 2031 // Verify that there is a disk here and pick up the change count. 2032 // 2033 2034 Status = FatPerformDevIoCtrl( IrpContext, 2035 IOCTL_DISK_CHECK_VERIFY, 2036 Vcb->TargetDeviceObject, 2037 NULL, 2038 0, 2039 &ChangeCount, 2040 sizeof(ULONG), 2041 FALSE, 2042 TRUE, 2043 &Iosb ); 2044 2045 if (!NT_SUCCESS( Status )) { 2046 2047 // 2048 // If we will allow a raw mount then return WRONG_VOLUME to 2049 // allow the volume to be mounted by raw. 2050 // 2051 2052 if (AllowRawMount) { 2053 2054 try_return( Status = STATUS_WRONG_VOLUME ); 2055 } 2056 2057 FatNormalizeAndRaiseStatus( IrpContext, Status ); 2058 } 2059 2060 } 2061 2062 if (Iosb.Information != sizeof(ULONG)) { 2063 2064 // 2065 // Be safe about the count in case the driver didn't fill it in 2066 // 2067 2068 ChangeCount = 0; 2069 } 2070 2071 // 2072 // Whatever happens we will have verified this volume at this change 2073 // count, so record that fact. 2074 // 2075 2076 Vcb->ChangeCount = ChangeCount; 2077 2078 // 2079 // If this is a CD class device, then check to see if there is a 2080 // 'data track' or not. This is to avoid issuing paging reads which will 2081 // fail later in the mount process (e.g. CD-DA or blank CD media) 2082 // 2083 2084 if ((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) && 2085 !FatScanForDataTrack( IrpContext, Vcb->TargetDeviceObject)) { 2086 2087 try_return( Status = STATUS_WRONG_VOLUME); 2088 } 2089 2090 // 2091 // Some devices can change sector sizes on the fly. Obviously, it 2092 // isn't the same volume if that happens. 2093 // 2094 2095 Status = FatPerformDevIoCtrl( IrpContext, 2096 IOCTL_DISK_GET_DRIVE_GEOMETRY, 2097 Vcb->TargetDeviceObject, 2098 NULL, 2099 0, 2100 &DiskGeometry, 2101 sizeof( DISK_GEOMETRY ), 2102 FALSE, 2103 TRUE, 2104 NULL ); 2105 2106 if (!NT_SUCCESS( Status )) { 2107 2108 // 2109 // If we will allow a raw mount then return WRONG_VOLUME to 2110 // allow the volume to be mounted by raw. 2111 // 2112 2113 if (AllowRawMount) { 2114 2115 try_return( Status = STATUS_WRONG_VOLUME ); 2116 } 2117 2118 FatNormalizeAndRaiseStatus( IrpContext, Status ); 2119 } 2120 2121 // 2122 // Read in the boot sector 2123 // 2124 2125 SectorSize = (ULONG)Vcb->Bpb.BytesPerSector; 2126 2127 if (SectorSize != DiskGeometry.BytesPerSector) { 2128 2129 try_return( Status = STATUS_WRONG_VOLUME ); 2130 } 2131 2132 BootSector = FsRtlAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 2133 (ULONG) ROUND_TO_PAGES( SectorSize ), 2134 TAG_VERIFY_BOOTSECTOR); 2135 2136 // 2137 // If this verify is on behalf of a DASD open, allow a RAW mount. 2138 // 2139 2140 if (!FatPerformVerifyDiskRead( IrpContext, 2141 Vcb, 2142 BootSector, 2143 0, 2144 SectorSize, 2145 AllowRawMount )) { 2146 2147 try_return( Status = STATUS_WRONG_VOLUME ); 2148 } 2149 2150 // 2151 // Call a routine to check the boot sector to see if it is fat. 2152 // If it is not fat then mark the vcb as not mounted tell our 2153 // caller its the wrong volume 2154 // 2155 2156 if (!FatIsBootSectorFat( BootSector )) { 2157 2158 DebugTrace(0, Dbg, "Not a Fat Volume\n", 0); 2159 2160 try_return( Status = STATUS_WRONG_VOLUME ); 2161 } 2162 2163 // 2164 // This is a fat volume, so extract serial number and see if it is 2165 // ours. 2166 // 2167 2168 { 2169 ULONG SerialNumber; 2170 2171 if (IsBpbFat32(&BootSector->PackedBpb)) { 2172 CopyUchar4( &SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id ); 2173 } else { 2174 CopyUchar4( &SerialNumber, BootSector->Id ); 2175 } 2176 2177 if (SerialNumber != Vpb->SerialNumber) { 2178 2179 DebugTrace(0, Dbg, "Not our serial number\n", 0); 2180 2181 try_return( Status = STATUS_WRONG_VOLUME ); 2182 } 2183 } 2184 2185 // 2186 // Make sure the Bpbs are not different. We have to zero out our 2187 // stack version of the Bpb since unpacking leaves holes. 2188 // 2189 2190 RtlZeroMemory( &Bpb, sizeof(BIOS_PARAMETER_BLOCK) ); 2191 2192 FatUnpackBios( &Bpb, &BootSector->PackedBpb ); 2193 if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; } 2194 2195 if ( !RtlEqualMemory( &Bpb, 2196 &Vcb->Bpb, 2197 IsBpbFat32(&Bpb) ? 2198 sizeof(BIOS_PARAMETER_BLOCK) : 2199 FIELD_OFFSET(BIOS_PARAMETER_BLOCK, 2200 LargeSectorsPerFat) )) { 2201 2202 DebugTrace(0, Dbg, "Bpb is different\n", 0); 2203 2204 try_return( Status = STATUS_WRONG_VOLUME ); 2205 } 2206 2207 // 2208 // Check the volume label. We do this by trying to locate the 2209 // volume label, making two strings one for the saved volume label 2210 // and the other for the new volume label and then we compare the 2211 // two labels. 2212 // 2213 2214 if (FatRootDirectorySize(&Bpb) > 0) { 2215 2216 RootDirectorySize = FatRootDirectorySize(&Bpb); 2217 2218 } else { 2219 2220 RootDirectorySize = FatBytesPerCluster(&Bpb); 2221 } 2222 2223 RootDirectory = FsRtlAllocatePoolWithTag( NonPagedPoolNxCacheAligned, 2224 (ULONG) ROUND_TO_PAGES( RootDirectorySize ), 2225 TAG_VERIFY_ROOTDIR); 2226 2227 if (!IsBpbFat32(&BootSector->PackedBpb)) { 2228 2229 // 2230 // The Fat12/16 case is simple -- read the root directory in and 2231 // search it. 2232 // 2233 2234 RootDirectoryLbo = FatRootDirectoryLbo(&Bpb); 2235 2236 if (!FatPerformVerifyDiskRead( IrpContext, 2237 Vcb, 2238 RootDirectory, 2239 RootDirectoryLbo, 2240 RootDirectorySize, 2241 AllowRawMount )) { 2242 2243 try_return( Status = STATUS_WRONG_VOLUME ); 2244 } 2245 2246 Status = FatSearchBufferForLabel(IrpContext, Vpb, 2247 RootDirectory, RootDirectorySize, 2248 &LabelFound); 2249 2250 if (!NT_SUCCESS(Status)) { 2251 2252 try_return( Status ); 2253 } 2254 2255 if (!LabelFound && Vpb->VolumeLabelLength > 0) { 2256 2257 try_return( Status = STATUS_WRONG_VOLUME ); 2258 } 2259 2260 } else { 2261 2262 ULONG RootDirectoryCluster; 2263 2264 RootDirectoryCluster = Bpb.RootDirFirstCluster; 2265 2266 while (RootDirectoryCluster != FAT_CLUSTER_LAST) { 2267 2268 RootDirectoryLbo = FatGetLboFromIndex(Vcb, RootDirectoryCluster); 2269 2270 if (!FatPerformVerifyDiskRead( IrpContext, 2271 Vcb, 2272 RootDirectory, 2273 RootDirectoryLbo, 2274 RootDirectorySize, 2275 AllowRawMount )) { 2276 2277 try_return( Status = STATUS_WRONG_VOLUME ); 2278 } 2279 2280 Status = FatSearchBufferForLabel(IrpContext, Vpb, 2281 RootDirectory, RootDirectorySize, 2282 &LabelFound); 2283 2284 if (!NT_SUCCESS(Status)) { 2285 2286 try_return( Status ); 2287 } 2288 2289 if (LabelFound) { 2290 2291 // 2292 // Found a matching label. 2293 // 2294 2295 break; 2296 } 2297 2298 // 2299 // Set ourselves up for the next loop iteration. 2300 // 2301 2302 FatVerifyLookupFatEntry( IrpContext, Vcb, 2303 RootDirectoryCluster, 2304 &RootDirectoryCluster ); 2305 2306 switch (FatInterpretClusterType(Vcb, RootDirectoryCluster)) { 2307 2308 case FatClusterAvailable: 2309 case FatClusterReserved: 2310 case FatClusterBad: 2311 2312 // 2313 // Bail all the way out if we have a bad root. 2314 // 2315 2316 FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 2317 break; 2318 2319 default: 2320 2321 break; 2322 } 2323 2324 } 2325 2326 if (RootDirectoryCluster == FAT_CLUSTER_LAST && 2327 Vpb->VolumeLabelLength > 0) { 2328 2329 // 2330 // Should have found a label, didn't find any. 2331 // 2332 2333 try_return( Status = STATUS_WRONG_VOLUME ); 2334 } 2335 } 2336 2337 2338 try_exit: NOTHING; 2339 2340 // 2341 // Note that we have previously acquired the Vcb to serialize 2342 // the EA file stuff the marking all the Fcbs as NeedToBeVerified. 2343 // 2344 // Put the Ea file back in a initial state. 2345 // 2346 2347 FatCloseEaFile( IrpContext, Vcb, (BOOLEAN)(Status == STATUS_SUCCESS) ); 2348 2349 // 2350 // Mark all Fcbs as needing verification, but only if we really have 2351 // to do it. 2352 // 2353 2354 if (!VerifyAlreadyDone) { 2355 2356 FatAcquireExclusiveVolume( IrpContext, Vcb ); 2357 ReleaseEntireVolume = TRUE; 2358 2359 FatMarkFcbCondition( IrpContext, Vcb->RootDcb, FcbNeedsToBeVerified, TRUE ); 2360 } 2361 2362 // 2363 // If the verify didn't succeed, get the volume ready for a 2364 // remount or eventual deletion. 2365 // 2366 2367 if (Vcb->VcbCondition == VcbNotMounted) { 2368 2369 // 2370 // If the volume was already in an unmounted state, just bail 2371 // and make sure we return STATUS_WRONG_VOLUME. 2372 // 2373 2374 Status = STATUS_WRONG_VOLUME; 2375 2376 } else if ( Status == STATUS_WRONG_VOLUME ) { 2377 2378 // 2379 // Grab everything so we can safely transition the volume state without 2380 // having a thread stumble into the torn-down allocation engine. 2381 // 2382 2383 if (!ReleaseEntireVolume) { 2384 FatAcquireExclusiveVolume( IrpContext, Vcb ); 2385 ReleaseEntireVolume = TRUE; 2386 } 2387 2388 // 2389 // Get rid of any cached data, without flushing 2390 // 2391 2392 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush ); 2393 2394 // 2395 // Uninitialize the volume file cache map. Note that we cannot 2396 // do a "FatSyncUninit" because of deadlock problems. However, 2397 // since this FileObject is referenced by us, and thus included 2398 // in the Vpb residual count, it is OK to do a normal CcUninit. 2399 // 2400 2401 CcUninitializeCacheMap( Vcb->VirtualVolumeFile, 2402 &FatLargeZero, 2403 NULL ); 2404 2405 FatTearDownAllocationSupport( IrpContext, Vcb ); 2406 2407 FatSetVcbCondition( Vcb, VcbNotMounted); 2408 2409 ClearVerify = TRUE; 2410 2411 } else if (!VerifyAlreadyDone) { 2412 2413 // 2414 // Grab everything so we can safely transition the volume state without 2415 // having a thread stumble into the torn-down allocation engine. 2416 // 2417 2418 if (!ReleaseEntireVolume) { 2419 FatAcquireExclusiveVolume( IrpContext, Vcb ); 2420 ReleaseEntireVolume = TRUE; 2421 } 2422 2423 // 2424 // Get rid of any cached data, flushing first. 2425 // 2426 // Future work (and for bonus points, around the other flush points) 2427 // could address the possibility that the dirent filesize hasn't been 2428 // updated yet, causing us to fail the re-verification of a file in 2429 // DetermineAndMark. This is pretty subtle and very very uncommon. 2430 // 2431 2432 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush ); 2433 2434 // 2435 // Flush and Purge the volume file. 2436 // 2437 2438 (VOID)FatFlushFat( IrpContext, Vcb ); 2439 CcPurgeCacheSection( &Vcb->SectionObjectPointers, NULL, 0, FALSE ); 2440 2441 // 2442 // Redo the allocation support with newly paged stuff. 2443 // 2444 2445 FatTearDownAllocationSupport( IrpContext, Vcb ); 2446 FatSetupAllocationSupport( IrpContext, Vcb ); 2447 2448 FatCheckDirtyBit( IrpContext, Vcb ); 2449 2450 // 2451 // Check for write protected media. 2452 // 2453 2454 if (FatIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) { 2455 2456 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ); 2457 2458 } else { 2459 2460 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED ); 2461 } 2462 2463 ClearVerify = TRUE; 2464 } 2465 2466 if (ClearVerify) { 2467 2468 // 2469 // Mark the device as no longer needing verification. 2470 // 2471 2472 ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME ); 2473 } 2474 2475 } _SEH2_FINALLY { 2476 2477 DebugUnwind( FatVerifyVolume ); 2478 2479 // 2480 // Free any buffer we may have allocated 2481 // 2482 2483 if ( BootSector != NULL ) { ExFreePool( BootSector ); } 2484 if ( RootDirectory != NULL ) { ExFreePool( RootDirectory ); } 2485 2486 // 2487 // Show that we are done with this volume. 2488 // 2489 2490 NT_ASSERT( Vcb->VerifyThread == KeGetCurrentThread() ); 2491 Vcb->VerifyThread = NULL; 2492 2493 if (ReleaseEntireVolume) { 2494 2495 FatReleaseVolume( IrpContext, Vcb ); 2496 } 2497 2498 FatReleaseVcb( IrpContext, Vcb ); 2499 FatReleaseGlobal( IrpContext ); 2500 2501 // 2502 // If this was not an abnormal termination, complete the irp. 2503 // 2504 2505 if (!_SEH2_AbnormalTermination()) { 2506 2507 FatCompleteRequest( IrpContext, Irp, Status ); 2508 } 2509 2510 DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status); 2511 } _SEH2_END; 2512 2513 return Status; 2514 } 2515 2516 2517 // 2518 // Local Support Routine 2519 // 2520 2521 BOOLEAN 2522 FatIsBootSectorFat ( 2523 IN PPACKED_BOOT_SECTOR BootSector 2524 ) 2525 2526 /*++ 2527 2528 Routine Description: 2529 2530 This routine checks if the boot sector is for a fat file volume. 2531 2532 Arguments: 2533 2534 BootSector - Supplies the packed boot sector to check 2535 2536 Return Value: 2537 2538 BOOLEAN - TRUE if the volume is Fat and FALSE otherwise. 2539 2540 --*/ 2541 2542 { 2543 BOOLEAN Result; 2544 BIOS_PARAMETER_BLOCK Bpb = {0}; 2545 2546 DebugTrace(+1, Dbg, "FatIsBootSectorFat, BootSector = %p\n", BootSector); 2547 2548 // 2549 // The result is true unless we decide that it should be false 2550 // 2551 2552 Result = TRUE; 2553 2554 // 2555 // Unpack the bios and then test everything 2556 // 2557 2558 FatUnpackBios( &Bpb, &BootSector->PackedBpb ); 2559 if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; } 2560 2561 if ((BootSector->Jump[0] != 0xe9) && 2562 (BootSector->Jump[0] != 0xeb) && 2563 (BootSector->Jump[0] != 0x49)) { 2564 2565 Result = FALSE; 2566 2567 // 2568 // Enforce some sanity on the sector size (easy check) 2569 // 2570 2571 } else if ((Bpb.BytesPerSector != 128) && 2572 (Bpb.BytesPerSector != 256) && 2573 (Bpb.BytesPerSector != 512) && 2574 (Bpb.BytesPerSector != 1024) && 2575 (Bpb.BytesPerSector != 2048) && 2576 (Bpb.BytesPerSector != 4096)) { 2577 2578 Result = FALSE; 2579 2580 // 2581 // Likewise on the clustering. 2582 // 2583 2584 } else if ((Bpb.SectorsPerCluster != 1) && 2585 (Bpb.SectorsPerCluster != 2) && 2586 (Bpb.SectorsPerCluster != 4) && 2587 (Bpb.SectorsPerCluster != 8) && 2588 (Bpb.SectorsPerCluster != 16) && 2589 (Bpb.SectorsPerCluster != 32) && 2590 (Bpb.SectorsPerCluster != 64) && 2591 (Bpb.SectorsPerCluster != 128)) { 2592 2593 Result = FALSE; 2594 2595 // 2596 // Likewise on the reserved sectors (must reflect at least the boot sector!) 2597 // 2598 2599 } else if (Bpb.ReservedSectors == 0) { 2600 2601 Result = FALSE; 2602 2603 // 2604 // No FATs? Wrong ... 2605 // 2606 2607 } else if (Bpb.Fats == 0) { 2608 2609 Result = FALSE; 2610 2611 // 2612 // Prior to DOS 3.2 might contains value in both of Sectors and 2613 // Sectors Large. 2614 // 2615 2616 } else if ((Bpb.Sectors == 0) && (Bpb.LargeSectors == 0)) { 2617 2618 Result = FALSE; 2619 2620 // 2621 // Check that FAT32 (SectorsPerFat == 0) claims some FAT space and 2622 // is of a version we recognize, currently Version 0.0. 2623 // 2624 2625 } else if (Bpb.SectorsPerFat == 0 && ( Bpb.LargeSectorsPerFat == 0 || 2626 Bpb.FsVersion != 0 )) { 2627 2628 Result = FALSE; 2629 2630 } else if ((Bpb.Media != 0xf0) && 2631 (Bpb.Media != 0xf8) && 2632 (Bpb.Media != 0xf9) && 2633 (Bpb.Media != 0xfb) && 2634 (Bpb.Media != 0xfc) && 2635 (Bpb.Media != 0xfd) && 2636 (Bpb.Media != 0xfe) && 2637 (Bpb.Media != 0xff) && 2638 (!FatData.FujitsuFMR || ((Bpb.Media != 0x00) && 2639 (Bpb.Media != 0x01) && 2640 (Bpb.Media != 0xfa)))) { 2641 2642 Result = FALSE; 2643 2644 // 2645 // If this isn't FAT32, then there better be a claimed root directory 2646 // size here ... 2647 // 2648 2649 } else if (Bpb.SectorsPerFat != 0 && Bpb.RootEntries == 0) { 2650 2651 Result = FALSE; 2652 2653 // 2654 // If this is FAT32 (i.e., extended BPB), look for and refuse to mount 2655 // mirror-disabled volumes. If we did, we would need to only write to 2656 // the FAT# indicated in the ActiveFat field. The only user of this is 2657 // the FAT->FAT32 converter after the first pass of protected mode work 2658 // (booting into realmode) and NT should absolutely not be attempting 2659 // to mount such an in-transition volume. 2660 // 2661 2662 } else if (Bpb.SectorsPerFat == 0 && Bpb.MirrorDisabled) { 2663 2664 Result = FALSE; 2665 } 2666 2667 DebugTrace(-1, Dbg, "FatIsBootSectorFat -> %08lx\n", Result); 2668 2669 return Result; 2670 } 2671 2672 2673 // 2674 // Local Support Routine 2675 // 2676 2677 BOOLEAN 2678 FatIsMediaWriteProtected ( 2679 IN PIRP_CONTEXT IrpContext, 2680 IN PDEVICE_OBJECT TargetDeviceObject 2681 ) 2682 2683 /*++ 2684 2685 Routine Description: 2686 2687 This routine determines if the target media is write protected. 2688 2689 Arguments: 2690 2691 TargetDeviceObject - The target of the query 2692 2693 Return Value: 2694 2695 NTSTATUS - The return status for the operation 2696 2697 --*/ 2698 2699 { 2700 PIRP Irp; 2701 KEVENT Event; 2702 NTSTATUS Status; 2703 IO_STATUS_BLOCK Iosb; 2704 2705 PAGED_CODE(); 2706 UNREFERENCED_PARAMETER( IrpContext ); 2707 2708 // 2709 // Query the partition table 2710 // 2711 2712 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 2713 2714 // 2715 // See if the media is write protected. On success or any kind 2716 // of error (possibly illegal device function), assume it is 2717 // writeable, and only complain if he tells us he is write protected. 2718 // 2719 2720 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE, 2721 TargetDeviceObject, 2722 NULL, 2723 0, 2724 NULL, 2725 0, 2726 FALSE, 2727 &Event, 2728 &Iosb ); 2729 2730 // 2731 // Just return FALSE in the unlikely event we couldn't allocate an Irp. 2732 // 2733 2734 if ( Irp == NULL ) { 2735 2736 return FALSE; 2737 } 2738 2739 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); 2740 2741 Status = IoCallDriver( TargetDeviceObject, Irp ); 2742 2743 if ( Status == STATUS_PENDING ) { 2744 2745 (VOID) KeWaitForSingleObject( &Event, 2746 Executive, 2747 KernelMode, 2748 FALSE, 2749 (PLARGE_INTEGER)NULL ); 2750 2751 Status = Iosb.Status; 2752 } 2753 2754 return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED); 2755 } 2756 2757 2758 // 2759 // Local Support Routine 2760 // 2761 2762 _Requires_lock_held_(_Global_critical_region_) 2763 NTSTATUS 2764 FatUserFsCtrl ( 2765 IN PIRP_CONTEXT IrpContext, 2766 IN PIRP Irp 2767 ) 2768 2769 /*++ 2770 2771 Routine Description: 2772 2773 This is the common routine for implementing the user's requests made 2774 through NtFsControlFile. 2775 2776 Arguments: 2777 2778 Irp - Supplies the Irp being processed 2779 2780 Return Value: 2781 2782 NTSTATUS - The return status for the operation 2783 2784 --*/ 2785 2786 { 2787 NTSTATUS Status; 2788 ULONG FsControlCode; 2789 2790 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2791 2792 PAGED_CODE(); 2793 2794 // 2795 // Save some references to make our life a little easier 2796 // 2797 2798 FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; 2799 2800 DebugTrace(+1, Dbg,"FatUserFsCtrl...\n", 0); 2801 DebugTrace( 0, Dbg,"FsControlCode = %08lx\n", FsControlCode); 2802 2803 // 2804 // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode 2805 // of the caller was userspace and this is a METHOD_NEITHER, we have the choice 2806 // of realy buffering the request through so we can possibly post, or making the 2807 // request synchronous. Since the former was not done by design, do the latter. 2808 // 2809 2810 if (Irp->RequestorMode != KernelMode && (FsControlCode & 3) == METHOD_NEITHER) { 2811 2812 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 2813 } 2814 2815 // 2816 // Case on the control code. 2817 // 2818 2819 switch ( FsControlCode ) { 2820 2821 case FSCTL_REQUEST_OPLOCK_LEVEL_1: 2822 case FSCTL_REQUEST_OPLOCK_LEVEL_2: 2823 case FSCTL_REQUEST_BATCH_OPLOCK: 2824 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: 2825 case FSCTL_OPBATCH_ACK_CLOSE_PENDING: 2826 case FSCTL_OPLOCK_BREAK_NOTIFY: 2827 case FSCTL_OPLOCK_BREAK_ACK_NO_2: 2828 case FSCTL_REQUEST_FILTER_OPLOCK: 2829 #if (NTDDI_VERSION >= NTDDI_WIN7) 2830 case FSCTL_REQUEST_OPLOCK: 2831 #endif 2832 Status = FatOplockRequest( IrpContext, Irp ); 2833 break; 2834 2835 case FSCTL_LOCK_VOLUME: 2836 2837 Status = FatLockVolume( IrpContext, Irp ); 2838 break; 2839 2840 case FSCTL_UNLOCK_VOLUME: 2841 2842 Status = FatUnlockVolume( IrpContext, Irp ); 2843 break; 2844 2845 case FSCTL_DISMOUNT_VOLUME: 2846 2847 Status = FatDismountVolume( IrpContext, Irp ); 2848 break; 2849 2850 case FSCTL_MARK_VOLUME_DIRTY: 2851 2852 Status = FatDirtyVolume( IrpContext, Irp ); 2853 break; 2854 2855 case FSCTL_IS_VOLUME_DIRTY: 2856 2857 Status = FatIsVolumeDirty( IrpContext, Irp ); 2858 break; 2859 2860 case FSCTL_IS_VOLUME_MOUNTED: 2861 2862 Status = FatIsVolumeMounted( IrpContext, Irp ); 2863 break; 2864 2865 case FSCTL_IS_PATHNAME_VALID: 2866 Status = FatIsPathnameValid( IrpContext, Irp ); 2867 break; 2868 2869 case FSCTL_QUERY_RETRIEVAL_POINTERS: 2870 Status = FatQueryRetrievalPointers( IrpContext, Irp ); 2871 break; 2872 2873 case FSCTL_QUERY_FAT_BPB: 2874 Status = FatQueryBpb( IrpContext, Irp ); 2875 break; 2876 2877 case FSCTL_FILESYSTEM_GET_STATISTICS: 2878 Status = FatGetStatistics( IrpContext, Irp ); 2879 break; 2880 2881 #if (NTDDI_VERSION >= NTDDI_WIN7) 2882 case FSCTL_GET_RETRIEVAL_POINTER_BASE: 2883 Status = FatGetRetrievalPointerBase( IrpContext, Irp ); 2884 break; 2885 2886 case FSCTL_GET_BOOT_AREA_INFO: 2887 Status = FatGetBootAreaInfo( IrpContext, Irp ); 2888 break; 2889 #endif 2890 2891 case FSCTL_GET_VOLUME_BITMAP: 2892 Status = FatGetVolumeBitmap( IrpContext, Irp ); 2893 break; 2894 2895 case FSCTL_GET_RETRIEVAL_POINTERS: 2896 Status = FatGetRetrievalPointers( IrpContext, Irp ); 2897 break; 2898 2899 case FSCTL_MOVE_FILE: 2900 Status = FatMoveFile( IrpContext, Irp ); 2901 break; 2902 2903 case FSCTL_ALLOW_EXTENDED_DASD_IO: 2904 Status = FatAllowExtendedDasdIo( IrpContext, Irp ); 2905 break; 2906 2907 case FSCTL_MARK_HANDLE: 2908 Status = FatMarkHandle( IrpContext, Irp ); 2909 break; 2910 2911 #if (NTDDI_VERSION >= NTDDI_WIN8) 2912 2913 case FSCTL_SET_PURGE_FAILURE_MODE: 2914 Status = FatSetPurgeFailureMode( IrpContext, Irp ); 2915 break; 2916 2917 #endif 2918 2919 2920 #if (NTDDI_VERSION >= NTDDI_WIN7) 2921 case FSCTL_SET_ZERO_ON_DEALLOCATION: 2922 Status = FatSetZeroOnDeallocate( IrpContext, Irp ); 2923 break; 2924 #endif 2925 2926 default : 2927 2928 DebugTrace(0, Dbg, "Invalid control code -> %08lx\n", FsControlCode ); 2929 2930 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 2931 Status = STATUS_INVALID_DEVICE_REQUEST; 2932 break; 2933 } 2934 2935 DebugTrace(-1, Dbg, "FatUserFsCtrl -> %08lx\n", Status ); 2936 return Status; 2937 } 2938 2939 2940 2941 // 2942 // Local support routine 2943 // 2944 2945 _Requires_lock_held_(_Global_critical_region_) 2946 NTSTATUS 2947 FatOplockRequest ( 2948 _In_ PIRP_CONTEXT IrpContext, 2949 _In_ PIRP Irp 2950 ) 2951 2952 /*++ 2953 2954 Routine Description: 2955 2956 This is the common routine to handle oplock requests made via the 2957 NtFsControlFile call. 2958 2959 Arguments: 2960 2961 Irp - Supplies the Irp being processed 2962 2963 Return Value: 2964 2965 NTSTATUS - The return status for the operation 2966 2967 --*/ 2968 2969 { 2970 NTSTATUS Status = STATUS_SUCCESS; 2971 ULONG FsControlCode; 2972 PFCB Fcb; 2973 PVCB Vcb; 2974 PCCB Ccb; 2975 2976 ULONG OplockCount = 0; 2977 2978 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 2979 2980 BOOLEAN AcquiredVcb = FALSE; 2981 BOOLEAN AcquiredFcb = FALSE; 2982 2983 #if (NTDDI_VERSION >= NTDDI_WIN7) 2984 PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL; 2985 ULONG InputBufferLength; 2986 ULONG OutputBufferLength; 2987 #endif 2988 2989 TYPE_OF_OPEN TypeOfOpen; 2990 2991 PAGED_CODE(); 2992 2993 // 2994 // Save some references to make our life a little easier 2995 // 2996 2997 FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; 2998 2999 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); 3000 3001 DebugTrace(+1, Dbg, "FatOplockRequest...\n", 0); 3002 DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode); 3003 3004 // 3005 // We permit oplock requests on files and directories. 3006 // 3007 3008 if ((TypeOfOpen != UserFileOpen) 3009 #if (NTDDI_VERSION >= NTDDI_WIN8) 3010 && 3011 (TypeOfOpen != UserDirectoryOpen) 3012 #endif 3013 ) { 3014 3015 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3016 DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0); 3017 return STATUS_INVALID_PARAMETER; 3018 } 3019 3020 #if (NTDDI_VERSION >= NTDDI_WIN7) 3021 3022 // 3023 // Get the input & output buffer lengths and pointers. 3024 // 3025 3026 if (FsControlCode == FSCTL_REQUEST_OPLOCK) { 3027 3028 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; 3029 InputBuffer = (PREQUEST_OPLOCK_INPUT_BUFFER) Irp->AssociatedIrp.SystemBuffer; 3030 3031 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 3032 3033 // 3034 // Check for a minimum length on the input and ouput buffers. 3035 // 3036 3037 if ((InputBufferLength < sizeof( REQUEST_OPLOCK_INPUT_BUFFER )) || 3038 (OutputBufferLength < sizeof( REQUEST_OPLOCK_OUTPUT_BUFFER ))) { 3039 3040 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 3041 DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_BUFFER_TOO_SMALL\n", 0); 3042 return STATUS_BUFFER_TOO_SMALL; 3043 } 3044 } 3045 3046 // 3047 // If the oplock request is on a directory it must be for a Read or Read-Handle 3048 // oplock only. 3049 // 3050 3051 if ((TypeOfOpen == UserDirectoryOpen) && 3052 ((FsControlCode != FSCTL_REQUEST_OPLOCK) || 3053 !FsRtlOplockIsSharedRequest( Irp ))) { 3054 3055 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3056 DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0); 3057 return STATUS_INVALID_PARAMETER; 3058 } 3059 3060 #endif 3061 3062 // 3063 // Make this a waitable Irpcontext so we don't fail to acquire 3064 // the resources. 3065 // 3066 3067 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 3068 3069 // 3070 // Use a try finally to free the Fcb/Vcb 3071 // 3072 3073 _SEH2_TRY { 3074 3075 // 3076 // We grab the Fcb exclusively for oplock requests, shared for oplock 3077 // break acknowledgement. 3078 // 3079 3080 if ((FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1) || 3081 (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) || 3082 (FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || 3083 (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) 3084 #if (NTDDI_VERSION >= NTDDI_WIN7) 3085 || 3086 ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_REQUEST )) 3087 #endif 3088 ) { 3089 3090 FatAcquireSharedVcb( IrpContext, Fcb->Vcb ); 3091 AcquiredVcb = TRUE; 3092 FatAcquireExclusiveFcb( IrpContext, Fcb ); 3093 AcquiredFcb = TRUE; 3094 3095 #if (NTDDI_VERSION >= NTDDI_WIN7) 3096 if (FsRtlOplockIsSharedRequest( Irp )) { 3097 #else 3098 if (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) { 3099 #endif 3100 3101 // 3102 // Byte-range locks are only valid on files. 3103 // 3104 3105 if (TypeOfOpen == UserFileOpen) { 3106 3107 // 3108 // Set OplockCount to nonzero if FsRtl denies access 3109 // based on current byte-range lock state. 3110 // 3111 3112 #if (NTDDI_VERSION >= NTDDI_WIN8) 3113 OplockCount = (ULONG) !FsRtlCheckLockForOplockRequest( &Fcb->Specific.Fcb.FileLock, &Fcb->Header.AllocationSize ); 3114 #elif (NTDDI_VERSION >= NTDDI_WIN7) 3115 OplockCount = (ULONG) FsRtlAreThereCurrentOrInProgressFileLocks( &Fcb->Specific.Fcb.FileLock ); 3116 #else 3117 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( &Fcb->Specific.Fcb.FileLock ); 3118 #endif 3119 3120 } 3121 3122 } else { 3123 3124 OplockCount = Fcb->UncleanCount; 3125 } 3126 3127 } else if ((FsControlCode == FSCTL_OPLOCK_BREAK_ACKNOWLEDGE) || 3128 (FsControlCode == FSCTL_OPBATCH_ACK_CLOSE_PENDING) || 3129 (FsControlCode == FSCTL_OPLOCK_BREAK_NOTIFY) || 3130 (FsControlCode == FSCTL_OPLOCK_BREAK_ACK_NO_2) 3131 #if (NTDDI_VERSION >= NTDDI_WIN7) 3132 || 3133 ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_ACK )) 3134 #endif 3135 ) { 3136 3137 FatAcquireSharedFcb( IrpContext, Fcb ); 3138 AcquiredFcb = TRUE; 3139 #if (NTDDI_VERSION >= NTDDI_WIN7) 3140 } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) { 3141 3142 // 3143 // The caller didn't provide either REQUEST_OPLOCK_INPUT_FLAG_REQUEST or 3144 // REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer. 3145 // 3146 3147 try_leave( Status = STATUS_INVALID_PARAMETER ); 3148 3149 } else { 3150 #else 3151 } else { 3152 #endif 3153 3154 #ifdef _MSC_VER 3155 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 3156 #endif 3157 FatBugCheck( FsControlCode, 0, 0 ); 3158 } 3159 3160 // 3161 // Fail batch, filter, and handle oplock requests if the file is marked 3162 // for delete. 3163 // 3164 3165 if (((FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || 3166 (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) 3167 #if (NTDDI_VERSION >= NTDDI_WIN7) 3168 || 3169 ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn( InputBuffer->RequestedOplockLevel, OPLOCK_LEVEL_CACHE_HANDLE )) 3170 #endif 3171 ) && 3172 FlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE )) { 3173 3174 try_leave( Status = STATUS_DELETE_PENDING ); 3175 } 3176 3177 // 3178 // Call the FsRtl routine to grant/acknowledge oplock. 3179 // 3180 3181 Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), 3182 Irp, 3183 OplockCount ); 3184 3185 // 3186 // Once we call FsRtlOplockFsctrl, we no longer own the IRP and we should not complete it. 3187 // 3188 3189 Irp = NULL; 3190 3191 // 3192 // Set the flag indicating if Fast I/O is possible 3193 // 3194 3195 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 3196 3197 } _SEH2_FINALLY { 3198 3199 DebugUnwind( FatOplockRequest ); 3200 3201 // 3202 // Release all of our resources 3203 // 3204 3205 if (AcquiredVcb) { 3206 3207 FatReleaseVcb( IrpContext, Fcb->Vcb ); 3208 } 3209 3210 if (AcquiredFcb) { 3211 3212 FatReleaseFcb( IrpContext, Fcb ); 3213 } 3214 3215 DebugTrace(-1, Dbg, "FatOplockRequest -> %08lx\n", Status ); 3216 } _SEH2_END; 3217 3218 FatCompleteRequest( IrpContext, Irp, Status ); 3219 3220 return Status; 3221 } 3222 3223 3224 // 3225 // Local Support Routine 3226 // 3227 3228 _Requires_lock_held_(_Global_critical_region_) 3229 NTSTATUS 3230 FatLockVolume ( 3231 IN PIRP_CONTEXT IrpContext, 3232 IN PIRP Irp 3233 ) 3234 3235 /*++ 3236 3237 Routine Description: 3238 3239 This routine performs the lock volume operation. It is responsible for 3240 either completing of enqueuing the input Irp. 3241 3242 Arguments: 3243 3244 Irp - Supplies the Irp to process 3245 3246 Return Value: 3247 3248 NTSTATUS - The return status for the operation 3249 3250 --*/ 3251 3252 { 3253 NTSTATUS Status = STATUS_SUCCESS; 3254 3255 PIO_STACK_LOCATION IrpSp; 3256 3257 PVCB Vcb; 3258 PFCB Fcb; 3259 PCCB Ccb; 3260 3261 PAGED_CODE(); 3262 3263 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 3264 3265 DebugTrace(+1, Dbg, "FatLockVolume...\n", 0); 3266 3267 // 3268 // Decode the file object, the only type of opens we accept are 3269 // user volume opens. 3270 // 3271 3272 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 3273 3274 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3275 3276 DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3277 return STATUS_INVALID_PARAMETER; 3278 } 3279 3280 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 3281 3282 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3283 3284 DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3285 return STATUS_INVALID_PARAMETER; 3286 } 3287 3288 // 3289 // Send our notification so that folks that like to hold handles on 3290 // volumes can get out of the way. 3291 // 3292 3293 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK ); 3294 3295 // 3296 // Acquire exclusive access to the Vcb and enqueue the Irp if we 3297 // didn't get access. 3298 // 3299 3300 if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) { 3301 3302 DebugTrace( 0, Dbg, "Cannot acquire Vcb\n", 0); 3303 3304 Status = FatFsdPostRequest( IrpContext, Irp ); 3305 3306 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status); 3307 return Status; 3308 } 3309 3310 _SEH2_TRY { 3311 3312 Status = FatLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject ); 3313 3314 } _SEH2_FINALLY { 3315 3316 // 3317 // Since we drop and release the vcb while trying to punch the volume 3318 // down, it may be the case that we decide the operation should not 3319 // continue if the user raced a CloeseHandle() with us (and it finished 3320 // the cleanup) while we were waiting for our closes to finish. 3321 // 3322 // In this case, we will have been raised out of the acquire logic with 3323 // STATUS_FILE_CLOSED, and the volume will not be held. 3324 // 3325 3326 if (!_SEH2_AbnormalTermination() || ExIsResourceAcquiredExclusiveLite( &Vcb->Resource )) { 3327 3328 FatReleaseVcb( IrpContext, Vcb ); 3329 } 3330 3331 if (!NT_SUCCESS( Status ) || _SEH2_AbnormalTermination()) { 3332 3333 // 3334 // The volume lock will be failing. 3335 // 3336 3337 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED ); 3338 } 3339 } _SEH2_END; 3340 3341 FatCompleteRequest( IrpContext, Irp, Status ); 3342 3343 DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", Status); 3344 3345 return Status; 3346 } 3347 3348 3349 // 3350 // Local Support Routine 3351 // 3352 3353 NTSTATUS 3354 FatUnlockVolume ( 3355 IN PIRP_CONTEXT IrpContext, 3356 IN PIRP Irp 3357 ) 3358 3359 /*++ 3360 3361 Routine Description: 3362 3363 This routine performs the unlock volume operation. It is responsible for 3364 either completing of enqueuing the input Irp. 3365 3366 Arguments: 3367 3368 Irp - Supplies the Irp to process 3369 3370 Return Value: 3371 3372 NTSTATUS - The return status for the operation 3373 3374 --*/ 3375 3376 { 3377 NTSTATUS Status; 3378 3379 PIO_STACK_LOCATION IrpSp; 3380 3381 PVCB Vcb; 3382 PFCB Fcb; 3383 PCCB Ccb; 3384 3385 PAGED_CODE(); 3386 3387 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 3388 3389 DebugTrace(+1, Dbg, "FatUnlockVolume...\n", 0); 3390 3391 // 3392 // Decode the file object, the only type of opens we accept are 3393 // user volume opens. 3394 // 3395 3396 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 3397 3398 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3399 3400 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3401 return STATUS_INVALID_PARAMETER; 3402 } 3403 3404 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 3405 3406 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3407 3408 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3409 return STATUS_INVALID_PARAMETER; 3410 } 3411 3412 Status = FatUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject ); 3413 3414 // 3415 // Send notification that the volume is avaliable. 3416 // 3417 3418 if (NT_SUCCESS( Status )) { 3419 3420 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK ); 3421 } 3422 3423 FatCompleteRequest( IrpContext, Irp, Status ); 3424 3425 DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status); 3426 3427 return Status; 3428 } 3429 3430 3431 _Requires_lock_held_(_Global_critical_region_) 3432 NTSTATUS 3433 FatLockVolumeInternal ( 3434 IN PIRP_CONTEXT IrpContext, 3435 IN PVCB Vcb, 3436 IN PFILE_OBJECT FileObject OPTIONAL 3437 ) 3438 3439 /*++ 3440 3441 Routine Description: 3442 3443 This routine performs the actual lock volume operation. It will be called 3444 by anyone wishing to try to protect the volume for a long duration. PNP 3445 operations are such a user. 3446 3447 The volume must be held exclusive by the caller. 3448 3449 Arguments: 3450 3451 Vcb - The volume being locked. 3452 3453 FileObject - File corresponding to the handle locking the volume. If this 3454 is not specified, a system lock is assumed. 3455 3456 Return Value: 3457 3458 NTSTATUS - The return status for the operation 3459 3460 --*/ 3461 3462 { 3463 NTSTATUS Status = STATUS_SUCCESS; 3464 KIRQL SavedIrql; 3465 ULONG RemainingUserReferences = (FileObject? 1: 0); 3466 3467 NT_ASSERT( ExIsResourceAcquiredExclusiveLite( &Vcb->Resource ) && 3468 !ExIsResourceAcquiredExclusiveLite( &FatData.Resource )); 3469 // 3470 // Go synchronous for the rest of the lock operation. It may be 3471 // reasonable to try to revisit this in the future, but for now 3472 // the purge below expects to be able to wait. 3473 // 3474 // We know it is OK to leave the flag up given how we're used at 3475 // the moment. 3476 // 3477 3478 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 3479 3480 // 3481 // If there are any open handles, this will fail. 3482 // 3483 3484 if (!FatIsHandleCountZero( IrpContext, Vcb )) { 3485 3486 return STATUS_ACCESS_DENIED; 3487 } 3488 3489 // 3490 // Force Mm to get rid of its referenced file objects. 3491 // 3492 3493 FatFlushFat( IrpContext, Vcb ); 3494 3495 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush ); 3496 3497 FatCloseEaFile( IrpContext, Vcb, TRUE ); 3498 3499 // 3500 // Now back out of our synchronization and wait for the lazy writer 3501 // to finish off any lazy closes that could have been outstanding. 3502 // 3503 // Since we flushed, we know that the lazy writer will issue all 3504 // possible lazy closes in the next tick - if we hadn't, an otherwise 3505 // unopened file with a large amount of dirty data could have hung 3506 // around for a while as the data trickled out to the disk. 3507 // 3508 // This is even more important now since we send notification to 3509 // alert other folks that this style of check is about to happen so 3510 // that they can close their handles. We don't want to enter a fast 3511 // race with the lazy writer tearing down his references to the file. 3512 // 3513 3514 FatReleaseVcb( IrpContext, Vcb ); 3515 3516 Status = CcWaitForCurrentLazyWriterActivity(); 3517 3518 FatAcquireExclusiveVcb( IrpContext, Vcb ); 3519 3520 if (!NT_SUCCESS( Status )) { 3521 3522 return Status; 3523 } 3524 3525 // 3526 // The act of closing and purging may have touched pages in various 3527 // parent DCBs. We handle this by purging a second time. 3528 // 3529 3530 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush ); 3531 3532 FatReleaseVcb( IrpContext, Vcb ); 3533 3534 Status = CcWaitForCurrentLazyWriterActivity(); 3535 3536 FatAcquireExclusiveVcb( IrpContext, Vcb ); 3537 3538 if (!NT_SUCCESS( Status )) { 3539 3540 return Status; 3541 } 3542 3543 // 3544 // Now rundown the delayed closes one last time. We appear to be able 3545 // to have additional collisions. 3546 // 3547 3548 FatFspClose( Vcb ); 3549 3550 // 3551 // Check if the Vcb is already locked, or if the open file count 3552 // is greater than 1 (which implies that someone else also is 3553 // currently using the volume, or a file on the volume), and that the 3554 // VPB reference count only includes our residual and the handle (as 3555 // appropriate). 3556 // 3557 // We used to only check for the vpb refcount. This is unreliable since 3558 // the vpb refcount is dropped immediately before final close, meaning 3559 // that even though we had a good refcount, the close was inflight and 3560 // subsequent operations could get confused. Especially if the PNP path 3561 // was the lock caller, we delete the VCB with an outstanding opencount! 3562 // 3563 3564 IoAcquireVpbSpinLock( &SavedIrql ); 3565 3566 if (!FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && 3567 (Vcb->Vpb->ReferenceCount <= 2 + RemainingUserReferences) && 3568 (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 ))) { 3569 3570 SetFlag(Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED)); 3571 SetFlag(Vcb->VcbState, VCB_STATE_FLAG_LOCKED); 3572 Vcb->FileObjectWithVcbLocked = FileObject; 3573 3574 } else { 3575 3576 Status = STATUS_ACCESS_DENIED; 3577 } 3578 3579 IoReleaseVpbSpinLock( SavedIrql ); 3580 3581 // 3582 // If we successully locked the volume, see if it is clean now. 3583 // 3584 3585 if (NT_SUCCESS( Status ) && 3586 FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) && 3587 !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) && 3588 !CcIsThereDirtyData(Vcb->Vpb)) { 3589 3590 FatMarkVolume( IrpContext, Vcb, VolumeClean ); 3591 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); 3592 } 3593 3594 NT_ASSERT( !NT_SUCCESS(Status) || (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 ))); 3595 3596 return Status; 3597 } 3598 3599 3600 NTSTATUS 3601 FatUnlockVolumeInternal ( 3602 IN PIRP_CONTEXT IrpContext, 3603 IN PVCB Vcb, 3604 IN PFILE_OBJECT FileObject OPTIONAL 3605 ) 3606 3607 /*++ 3608 3609 Routine Description: 3610 3611 This routine performs the actual unlock volume operation. 3612 3613 The volume must be held exclusive by the caller. 3614 3615 Arguments: 3616 3617 Vcb - The volume being locked. 3618 3619 FileObject - File corresponding to the handle locking the volume. If this 3620 is not specified, a system lock is assumed. 3621 3622 Return Value: 3623 3624 NTSTATUS - The return status for the operation 3625 3626 Attempting to remove a system lock that did not exist is OK. 3627 3628 --*/ 3629 3630 { 3631 KIRQL SavedIrql; 3632 NTSTATUS Status = STATUS_NOT_LOCKED; 3633 3634 UNREFERENCED_PARAMETER( IrpContext ); 3635 3636 IoAcquireVpbSpinLock( &SavedIrql ); 3637 3638 if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && FileObject == Vcb->FileObjectWithVcbLocked) { 3639 3640 // 3641 // This one locked it, unlock the volume 3642 // 3643 3644 ClearFlag( Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED) ); 3645 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ); 3646 Vcb->FileObjectWithVcbLocked = NULL; 3647 3648 Status = STATUS_SUCCESS; 3649 } 3650 3651 IoReleaseVpbSpinLock( SavedIrql ); 3652 3653 return Status; 3654 } 3655 3656 3657 // 3658 // Local Support Routine 3659 // 3660 3661 _Requires_lock_held_(_Global_critical_region_) 3662 NTSTATUS 3663 FatDismountVolume ( 3664 IN PIRP_CONTEXT IrpContext, 3665 IN PIRP Irp 3666 ) 3667 3668 /*++ 3669 3670 Routine Description: 3671 3672 This routine performs the dismount volume operation. It is responsible for 3673 either completing of enqueuing the input Irp. 3674 3675 Arguments: 3676 3677 Irp - Supplies the Irp to process 3678 3679 Return Value: 3680 3681 NTSTATUS - The return status for the operation 3682 3683 --*/ 3684 3685 { 3686 PIO_STACK_LOCATION IrpSp; 3687 NTSTATUS Status = STATUS_SUCCESS; 3688 BOOLEAN VcbHeld = FALSE; 3689 KIRQL SavedIrql; 3690 3691 PVCB Vcb; 3692 PFCB Fcb; 3693 PCCB Ccb; 3694 3695 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 3696 3697 DebugTrace(+1, Dbg, "FatDismountVolume...\n", 0); 3698 3699 // 3700 // Decode the file object, the only type of opens we accept are 3701 // user volume opens on media that is not boot/paging and is not 3702 // already dismounted ... (but we need to check that stuff while 3703 // synchronized) 3704 // 3705 3706 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 3707 3708 Status = STATUS_INVALID_PARAMETER; 3709 goto fn_return; 3710 } 3711 3712 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 3713 3714 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3715 3716 DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3717 return STATUS_INVALID_PARAMETER; 3718 } 3719 3720 // 3721 // Make some unsynchronized checks to see if this operation is possible. 3722 // We will repeat the appropriate ones inside synchronization, but it is 3723 // good to avoid bogus notifications. 3724 // 3725 3726 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE )) { 3727 3728 Status = STATUS_ACCESS_DENIED; 3729 goto fn_return; 3730 } 3731 3732 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) { 3733 3734 Status = STATUS_VOLUME_DISMOUNTED; 3735 goto fn_return; 3736 } 3737 3738 // 3739 // A bit of historical comment is in order. 3740 // 3741 // In all versions prior to NT5, we only permitted dismount if the volume had 3742 // previously been locked. Now we must permit a forced dismount, meaning that 3743 // we grab ahold of the whole kit-n-kaboodle - regardless of activity, open 3744 // handles, etc. - to flush and invalidate the volume. 3745 // 3746 // Previously, dismount assumed that lock had come along earlier and done some 3747 // of the work that we are now going to do - i.e., flush, tear down the eas. All 3748 // we had to do here is flush the device out and kill off as many of the orphan 3749 // fcbs as possible. This now changes. 3750 // 3751 // In fact, everything is a forced dismount now. This changes one interesting 3752 // aspect, which is that it used to be the case that the handle used to dismount 3753 // could come back, read, and induce a verify/remount. This is just not possible 3754 // now. The point of forced dismount is that very shortly someone will come along 3755 // and be destructive to the possibility of using the media further - format, eject, 3756 // etc. By using this path, callers are expected to tolerate the consequences. 3757 // 3758 // Note that the volume can still be successfully unlocked by this handle. 3759 // 3760 3761 // 3762 // Send notification. 3763 // 3764 3765 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT ); 3766 3767 // 3768 // Force ourselves to wait and grab everything. 3769 // 3770 3771 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 3772 3773 #ifdef _MSC_VER 3774 #pragma prefast( push ) 3775 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 3776 #pragma prefast( disable: 28193, "this will always wait" ) 3777 #endif 3778 3779 (VOID)FatAcquireExclusiveGlobal( IrpContext ); 3780 3781 #ifdef _MSC_VER 3782 #pragma prefast( pop ) 3783 #endif 3784 3785 _SEH2_TRY { 3786 3787 // 3788 // Guess what? This can raise if a cleanup on the fileobject we 3789 // got races in ahead of us. 3790 // 3791 3792 FatAcquireExclusiveVolume( IrpContext, Vcb ); 3793 VcbHeld = TRUE; 3794 3795 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) { 3796 3797 try_return( Status = STATUS_VOLUME_DISMOUNTED ); 3798 } 3799 3800 FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushAndInvalidate ); 3801 3802 // 3803 // We defer the physical dismount until this handle is closed, per symmetric 3804 // implemntation in the other FS. This permits a dismounter to issue IOCTL 3805 // through this handle and perform device manipulation without racing with 3806 // creates attempting to mount the volume again. 3807 // 3808 // Raise a flag to tell the cleanup path to complete the dismount. 3809 // 3810 3811 SetFlag( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT ); 3812 3813 // 3814 // Indicate that the volume was dismounted so that we may return the 3815 // correct error code when operations are attempted via open handles. 3816 // 3817 3818 FatSetVcbCondition( Vcb, VcbBad); 3819 3820 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED ); 3821 3822 // 3823 // Set a flag in the VPB to let others know that direct volume access is allowed. 3824 // 3825 3826 IoAcquireVpbSpinLock( &SavedIrql ); 3827 SetFlag( Vcb->Vpb->Flags, VPB_DIRECT_WRITES_ALLOWED ); 3828 IoReleaseVpbSpinLock( SavedIrql ); 3829 3830 Status = STATUS_SUCCESS; 3831 3832 try_exit: NOTHING; 3833 3834 } _SEH2_FINALLY { 3835 3836 #if (NTDDI_VERSION >= NTDDI_WIN8) 3837 3838 FsRtlDismountComplete( Vcb->TargetDeviceObject, Status ); 3839 3840 #endif 3841 3842 if (VcbHeld) { 3843 3844 FatReleaseVolume( IrpContext, Vcb ); 3845 } 3846 3847 FatReleaseGlobal( IrpContext ); 3848 3849 // 3850 // I do not believe it is possible to raise, but for completeness 3851 // notice and send notification of failure. We absolutely 3852 // cannot have raised in CheckForDismount. 3853 // 3854 // We decline to call an attempt to dismount a dismounted volume 3855 // a failure to do so. 3856 // 3857 3858 if ((!NT_SUCCESS( Status ) && Status != STATUS_VOLUME_DISMOUNTED) 3859 || _SEH2_AbnormalTermination()) { 3860 3861 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED ); 3862 } 3863 } _SEH2_END; 3864 3865 fn_return: 3866 3867 FatCompleteRequest( IrpContext, Irp, Status ); 3868 DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", Status); 3869 return Status; 3870 } 3871 3872 3873 // 3874 // Local Support Routine 3875 // 3876 3877 _Requires_lock_held_(_Global_critical_region_) 3878 NTSTATUS 3879 FatDirtyVolume ( 3880 IN PIRP_CONTEXT IrpContext, 3881 IN PIRP Irp 3882 ) 3883 3884 /*++ 3885 3886 Routine Description: 3887 3888 This routine marks the volume as dirty. 3889 3890 Arguments: 3891 3892 Irp - Supplies the Irp to process 3893 3894 Return Value: 3895 3896 NTSTATUS - The return status for the operation 3897 3898 --*/ 3899 3900 { 3901 PIO_STACK_LOCATION IrpSp; 3902 3903 PVCB Vcb; 3904 PFCB Fcb; 3905 PCCB Ccb; 3906 3907 PAGED_CODE(); 3908 3909 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 3910 3911 DebugTrace(+1, Dbg, "FatDirtyVolume...\n", 0); 3912 3913 // 3914 // Decode the file object, the only type of opens we accept are 3915 // user volume opens. 3916 // 3917 3918 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 3919 3920 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3921 3922 DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3923 return STATUS_INVALID_PARAMETER; 3924 } 3925 3926 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 3927 3928 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 3929 3930 DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER); 3931 return STATUS_INVALID_PARAMETER; 3932 } 3933 3934 3935 // 3936 // Disable popups, we will just return any error. 3937 // 3938 3939 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS); 3940 3941 // 3942 // Verify the Vcb. We want to make sure we don't dirty some 3943 // random chunk of media that happens to be in the drive now. 3944 // 3945 3946 FatVerifyVcb( IrpContext, Vcb ); 3947 3948 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); 3949 3950 FatMarkVolume( IrpContext, Vcb, VolumeDirty ); 3951 3952 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 3953 3954 DebugTrace(-1, Dbg, "FatDirtyVolume -> STATUS_SUCCESS\n", 0); 3955 3956 return STATUS_SUCCESS; 3957 } 3958 3959 3960 // 3961 // Local Support Routine 3962 // 3963 3964 NTSTATUS 3965 FatIsVolumeDirty ( 3966 IN PIRP_CONTEXT IrpContext, 3967 IN PIRP Irp 3968 ) 3969 3970 /*++ 3971 3972 Routine Description: 3973 3974 This routine determines if a volume is currently dirty. 3975 3976 Arguments: 3977 3978 Irp - Supplies the Irp to process 3979 3980 Return Value: 3981 3982 NTSTATUS - The return status for the operation 3983 3984 --*/ 3985 3986 { 3987 PIO_STACK_LOCATION IrpSp; 3988 3989 TYPE_OF_OPEN TypeOfOpen; 3990 PVCB Vcb; 3991 PFCB Fcb; 3992 PCCB Ccb; 3993 3994 PULONG VolumeState; 3995 3996 PAGED_CODE(); 3997 3998 // 3999 // Get the current stack location and extract the output 4000 // buffer information. 4001 // 4002 4003 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4004 4005 // 4006 // Get a pointer to the output buffer. Look at the system buffer field in the 4007 // irp first. Then the Irp Mdl. 4008 // 4009 4010 if (Irp->AssociatedIrp.SystemBuffer != NULL) { 4011 4012 VolumeState = Irp->AssociatedIrp.SystemBuffer; 4013 4014 } else if (Irp->MdlAddress != NULL) { 4015 4016 VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, LowPagePriority | MdlMappingNoExecute ); 4017 4018 if (VolumeState == NULL) { 4019 4020 FatCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES ); 4021 return STATUS_INSUFFICIENT_RESOURCES; 4022 } 4023 4024 } else { 4025 4026 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER ); 4027 return STATUS_INVALID_USER_BUFFER; 4028 } 4029 4030 // 4031 // Make sure the output buffer is large enough and then initialize 4032 // the answer to be that the volume isn't dirty. 4033 // 4034 4035 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) { 4036 4037 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 4038 return STATUS_INVALID_PARAMETER; 4039 } 4040 4041 *VolumeState = 0; 4042 4043 // 4044 // Decode the file object 4045 // 4046 4047 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); 4048 4049 if (TypeOfOpen != UserVolumeOpen) { 4050 4051 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 4052 return STATUS_INVALID_PARAMETER; 4053 } 4054 4055 if (Vcb->VcbCondition != VcbGood) { 4056 4057 FatCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED ); 4058 return STATUS_VOLUME_DISMOUNTED; 4059 } 4060 4061 // 4062 // Disable PopUps, we want to return any error. 4063 // 4064 4065 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS); 4066 4067 // 4068 // Verify the Vcb. We want to make double sure that this volume 4069 // is around so that we know our information is good. 4070 // 4071 4072 FatVerifyVcb( IrpContext, Vcb ); 4073 4074 // 4075 // Now set the returned information. We can avoid probing the disk since 4076 // we know our internal state is in sync. 4077 // 4078 4079 if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY) ) { 4080 4081 SetFlag( *VolumeState, VOLUME_IS_DIRTY ); 4082 } 4083 4084 Irp->IoStatus.Information = sizeof( ULONG ); 4085 4086 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 4087 return STATUS_SUCCESS; 4088 } 4089 4090 4091 // 4092 // Local Support Routine 4093 // 4094 4095 NTSTATUS 4096 FatIsVolumeMounted ( 4097 IN PIRP_CONTEXT IrpContext, 4098 IN PIRP Irp 4099 ) 4100 4101 /*++ 4102 4103 Routine Description: 4104 4105 This routine determines if a volume is currently mounted. 4106 4107 Arguments: 4108 4109 Irp - Supplies the Irp to process 4110 4111 Return Value: 4112 4113 NTSTATUS - The return status for the operation 4114 4115 --*/ 4116 4117 { 4118 NTSTATUS Status; 4119 4120 PIO_STACK_LOCATION IrpSp; 4121 4122 PVCB Vcb = NULL; 4123 PFCB Fcb; 4124 PCCB Ccb; 4125 4126 PAGED_CODE(); 4127 4128 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4129 4130 Status = STATUS_SUCCESS; 4131 4132 DebugTrace(+1, Dbg, "FatIsVolumeMounted...\n", 0); 4133 4134 // 4135 // Decode the file object. 4136 // 4137 4138 (VOID)FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); 4139 4140 NT_ASSERT( Vcb != NULL ); 4141 _Analysis_assume_( Vcb != NULL ); 4142 4143 // 4144 // Disable PopUps, we want to return any error. 4145 // 4146 4147 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS); 4148 4149 // 4150 // Verify the Vcb. 4151 // 4152 4153 FatVerifyVcb( IrpContext, Vcb ); 4154 4155 FatCompleteRequest( IrpContext, Irp, Status ); 4156 4157 DebugTrace(-1, Dbg, "FatIsVolumeMounted -> %08lx\n", Status); 4158 4159 return Status; 4160 } 4161 4162 4163 // 4164 // Local Support Routine 4165 // 4166 4167 NTSTATUS 4168 FatIsPathnameValid ( 4169 IN PIRP_CONTEXT IrpContext, 4170 IN PIRP Irp 4171 ) 4172 4173 /*++ 4174 4175 Routine Description: 4176 4177 This routine determines if a pathname is a-priori illegal by inspecting 4178 the the characters used. It is required to be correct on a FALSE return. 4179 4180 N.B.: current implementation is intentioanlly a no-op. This may change 4181 in the future. A careful reader of the previous implementation of this 4182 FSCTL in FAT would discover that it violated the requirement stated above 4183 and could return FALSE for a valid (createable) pathname. 4184 4185 Arguments: 4186 4187 Irp - Supplies the Irp to process 4188 4189 Return Value: 4190 4191 NTSTATUS - The return status for the operation 4192 4193 --*/ 4194 4195 { 4196 PAGED_CODE(); 4197 4198 DebugTrace(+1, Dbg, "FatIsPathnameValid...\n", 0); 4199 4200 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 4201 4202 DebugTrace(-1, Dbg, "FatIsPathnameValid -> %08lx\n", STATUS_SUCCESS); 4203 4204 return STATUS_SUCCESS; 4205 } 4206 4207 4208 // 4209 // Local Support Routine 4210 // 4211 4212 NTSTATUS 4213 FatQueryBpb ( 4214 IN PIRP_CONTEXT IrpContext, 4215 IN PIRP Irp 4216 ) 4217 4218 /*++ 4219 4220 Routine Description: 4221 4222 This routine simply returns the first 0x24 bytes of sector 0. 4223 4224 Arguments: 4225 4226 Irp - Supplies the Irp to process 4227 4228 Return Value: 4229 4230 NTSTATUS - The return status for the operation 4231 4232 --*/ 4233 4234 { 4235 PIO_STACK_LOCATION IrpSp; 4236 4237 PVCB Vcb; 4238 4239 PFSCTL_QUERY_FAT_BPB_BUFFER BpbBuffer; 4240 4241 PAGED_CODE(); 4242 4243 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4244 4245 DebugTrace(+1, Dbg, "FatQueryBpb...\n", 0); 4246 4247 // 4248 // Get the Vcb. If we didn't keep the information needed for this call, 4249 // we had a reason ... 4250 // 4251 4252 Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb; 4253 4254 if (Vcb->First0x24BytesOfBootSector == NULL) { 4255 4256 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 4257 DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST ); 4258 return STATUS_INVALID_DEVICE_REQUEST; 4259 } 4260 4261 // 4262 // Extract the buffer 4263 // 4264 4265 BpbBuffer = (PFSCTL_QUERY_FAT_BPB_BUFFER)Irp->AssociatedIrp.SystemBuffer; 4266 4267 // 4268 // Make sure the buffer is big enough. 4269 // 4270 4271 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < 0x24) { 4272 4273 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 4274 DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_BUFFER_TOO_SMALL ); 4275 return STATUS_BUFFER_TOO_SMALL; 4276 } 4277 4278 // 4279 // Fill in the output buffer 4280 // 4281 4282 RtlCopyMemory( BpbBuffer->First0x24BytesOfBootSector, 4283 Vcb->First0x24BytesOfBootSector, 4284 0x24 ); 4285 4286 Irp->IoStatus.Information = 0x24; 4287 4288 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 4289 DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_SUCCESS); 4290 return STATUS_SUCCESS; 4291 } 4292 4293 4294 // 4295 // Local Support Routine 4296 // 4297 4298 _Requires_lock_held_(_Global_critical_region_) 4299 NTSTATUS 4300 FatInvalidateVolumes ( 4301 IN PIRP Irp 4302 ) 4303 4304 /*++ 4305 4306 Routine Description: 4307 4308 This routine searches for all the volumes mounted on the same real device 4309 of the current DASD handle, and marks them all bad. The only operation 4310 that can be done on such handles is cleanup and close. 4311 4312 Arguments: 4313 4314 Irp - Supplies the Irp to process 4315 4316 Return Value: 4317 4318 NTSTATUS - The return status for the operation 4319 4320 --*/ 4321 4322 { 4323 NTSTATUS Status; 4324 IRP_CONTEXT IrpContext; 4325 PIO_STACK_LOCATION IrpSp; 4326 4327 LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0}; 4328 4329 HANDLE Handle; 4330 4331 PLIST_ENTRY Links; 4332 4333 PFILE_OBJECT FileToMarkBad; 4334 PDEVICE_OBJECT DeviceToMarkBad; 4335 4336 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4337 4338 DebugTrace(+1, Dbg, "FatInvalidateVolumes...\n", 0); 4339 4340 // 4341 // Check for the correct security access. 4342 // The caller must have the SeTcbPrivilege. 4343 // 4344 4345 if (!SeSinglePrivilegeCheck(TcbPrivilege, Irp->RequestorMode)) { 4346 4347 FatCompleteRequest( FatNull, Irp, STATUS_PRIVILEGE_NOT_HELD ); 4348 4349 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_PRIVILEGE_NOT_HELD); 4350 return STATUS_PRIVILEGE_NOT_HELD; 4351 } 4352 4353 // 4354 // Try to get a pointer to the device object from the handle passed in. 4355 // 4356 4357 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 4358 if (IoIs32bitProcess( Irp )) { 4359 4360 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(UINT32)) { 4361 4362 FatCompleteRequest( FatNull, Irp, STATUS_INVALID_PARAMETER ); 4363 4364 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER); 4365 return STATUS_INVALID_PARAMETER; 4366 } 4367 4368 Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) ); 4369 } else { 4370 #endif 4371 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(HANDLE)) { 4372 4373 FatCompleteRequest( FatNull, Irp, STATUS_INVALID_PARAMETER ); 4374 4375 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER); 4376 return STATUS_INVALID_PARAMETER; 4377 } 4378 4379 Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; 4380 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 4381 } 4382 #endif 4383 4384 4385 Status = ObReferenceObjectByHandle( Handle, 4386 0, 4387 *IoFileObjectType, 4388 KernelMode, 4389 #ifndef __REACTOS__ 4390 &FileToMarkBad, 4391 #else 4392 (PVOID *)&FileToMarkBad, 4393 #endif 4394 NULL ); 4395 4396 if (!NT_SUCCESS(Status)) { 4397 4398 FatCompleteRequest( FatNull, Irp, Status ); 4399 4400 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", Status); 4401 return Status; 4402 4403 } else { 4404 4405 // 4406 // We only needed the pointer, not a reference. 4407 // 4408 4409 ObDereferenceObject( FileToMarkBad ); 4410 4411 // 4412 // Grab the DeviceObject from the FileObject. 4413 // 4414 4415 DeviceToMarkBad = FileToMarkBad->DeviceObject; 4416 } 4417 4418 RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); 4419 4420 SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); 4421 IrpContext.MajorFunction = IrpSp->MajorFunction; 4422 IrpContext.MinorFunction = IrpSp->MinorFunction; 4423 4424 #ifdef _MSC_VER 4425 #pragma prefast( push ) 4426 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 4427 #pragma prefast( disable: 28193, "this will always wait" ) 4428 #endif 4429 4430 FatAcquireExclusiveGlobal( &IrpContext ); 4431 4432 #ifdef _MSC_VER 4433 #pragma prefast( pop ) 4434 #endif 4435 4436 // 4437 // First acquire the FatData resource shared, then walk through all the 4438 // mounted VCBs looking for candidates to mark BAD. 4439 // 4440 // On volumes we mark bad, check for dismount possibility (which is 4441 // why we have to get the next link early). 4442 // 4443 4444 Links = FatData.VcbQueue.Flink; 4445 4446 while (Links != &FatData.VcbQueue) { 4447 4448 PVCB ExistingVcb; 4449 4450 ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks); 4451 4452 Links = Links->Flink; 4453 4454 // 4455 // If we get a match, mark the volume Bad, and also check to 4456 // see if the volume should go away. 4457 // 4458 4459 if (ExistingVcb->Vpb->RealDevice == DeviceToMarkBad) { 4460 4461 BOOLEAN VcbDeleted = FALSE; 4462 4463 // 4464 // Here we acquire the Vcb exclusive and try to purge 4465 // all the open files. The idea is to have as little as 4466 // possible stale data visible and to hasten the volume 4467 // going away. 4468 // 4469 4470 (VOID)FatAcquireExclusiveVcb( &IrpContext, ExistingVcb ); 4471 4472 #ifdef _MSC_VER 4473 #pragma prefast( push ) 4474 #pragma prefast( disable: 28175, "touching Vpb is ok for a filesystem" ) 4475 #endif 4476 4477 if (ExistingVcb->Vpb == DeviceToMarkBad->Vpb) { 4478 4479 KIRQL OldIrql; 4480 4481 IoAcquireVpbSpinLock( &OldIrql ); 4482 4483 if (FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_MOUNTED )) { 4484 4485 PVPB NewVpb; 4486 4487 NewVpb = ExistingVcb->SwapVpb; 4488 ExistingVcb->SwapVpb = NULL; 4489 SetFlag( ExistingVcb->VcbState, VCB_STATE_FLAG_VPB_MUST_BE_FREED ); 4490 4491 RtlZeroMemory( NewVpb, sizeof( VPB ) ); 4492 NewVpb->Type = IO_TYPE_VPB; 4493 NewVpb->Size = sizeof( VPB ); 4494 NewVpb->RealDevice = DeviceToMarkBad; 4495 NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING ); 4496 4497 DeviceToMarkBad->Vpb = NewVpb; 4498 } 4499 4500 NT_ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL ); 4501 4502 #ifdef _MSC_VER 4503 #pragma prefast( pop ) 4504 #endif 4505 4506 IoReleaseVpbSpinLock( OldIrql ); 4507 } 4508 4509 FatSetVcbCondition( ExistingVcb, VcbBad ); 4510 4511 // 4512 // Process the root directory, if it is present. 4513 // 4514 4515 if (ExistingVcb->RootDcb != NULL) { 4516 4517 // 4518 // In order to safely mark all FCBs bad, we must acquire everything. 4519 // 4520 4521 FatAcquireExclusiveVolume(&IrpContext, ExistingVcb); 4522 FatMarkFcbCondition( &IrpContext, ExistingVcb->RootDcb, FcbBad, TRUE ); 4523 FatReleaseVolume(&IrpContext, ExistingVcb); 4524 4525 // 4526 // Purging the file objects on this volume could result in the memory manager 4527 // dereferencing it's file pointer which could be the last reference and 4528 // trigger object deletion and VCB deletion. Protect against that here by 4529 // temporarily biasing the file count, and later checking for dismount. 4530 // 4531 4532 ExistingVcb->OpenFileCount += 1; 4533 4534 FatPurgeReferencedFileObjects( &IrpContext, 4535 ExistingVcb->RootDcb, 4536 NoFlush ); 4537 4538 ExistingVcb->OpenFileCount -= 1; 4539 4540 VcbDeleted = FatCheckForDismount( &IrpContext, ExistingVcb, FALSE ); 4541 } 4542 4543 // 4544 // Only release the VCB if it did not go away. 4545 // 4546 4547 if (!VcbDeleted) { 4548 4549 FatReleaseVcb( &IrpContext, ExistingVcb ); 4550 } 4551 } 4552 } 4553 4554 FatReleaseGlobal( &IrpContext ); 4555 4556 FatCompleteRequest( FatNull, Irp, STATUS_SUCCESS ); 4557 4558 DebugTrace(-1, Dbg, "FatInvalidateVolumes -> STATUS_SUCCESS\n", 0); 4559 4560 return STATUS_SUCCESS; 4561 } 4562 4563 4564 // 4565 // Local Support routine 4566 // 4567 4568 BOOLEAN 4569 FatPerformVerifyDiskRead ( 4570 IN PIRP_CONTEXT IrpContext, 4571 IN PVCB Vcb, 4572 IN PVOID Buffer, 4573 IN LBO Lbo, 4574 IN ULONG NumberOfBytesToRead, 4575 IN BOOLEAN ReturnOnError 4576 ) 4577 4578 /*++ 4579 4580 Routine Description: 4581 4582 This routine is used to read in a range of bytes from the disk. It 4583 bypasses all of the caching and regular I/O logic, and builds and issues 4584 the requests itself. It does this operation overriding the verify 4585 volume flag in the device object. 4586 4587 Arguments: 4588 4589 Vcb - Supplies the target device object for this operation. 4590 4591 Buffer - Supplies the buffer that will recieve the results of this operation 4592 4593 Lbo - Supplies the byte offset of where to start reading 4594 4595 NumberOfBytesToRead - Supplies the number of bytes to read, this must 4596 be in multiple of bytes units acceptable to the disk driver. 4597 4598 ReturnOnError - Indicates that we should return on an error, instead 4599 of raising. 4600 4601 Return Value: 4602 4603 BOOLEAN - TRUE if the operation succeded, FALSE otherwise. 4604 4605 --*/ 4606 4607 { 4608 KEVENT Event; 4609 PIRP Irp; 4610 LARGE_INTEGER ByteOffset; 4611 NTSTATUS Status; 4612 IO_STATUS_BLOCK Iosb; 4613 4614 PAGED_CODE(); 4615 4616 DebugTrace(0, Dbg, "FatPerformVerifyDiskRead, Lbo = %08lx\n", Lbo ); 4617 4618 // 4619 // Initialize the event we're going to use 4620 // 4621 4622 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 4623 4624 // 4625 // Build the irp for the operation and also set the overrride flag 4626 // 4627 4628 ByteOffset.QuadPart = Lbo; 4629 4630 Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 4631 Vcb->TargetDeviceObject, 4632 Buffer, 4633 NumberOfBytesToRead, 4634 &ByteOffset, 4635 &Event, 4636 &Iosb ); 4637 4638 if ( Irp == NULL ) { 4639 4640 FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 4641 } 4642 4643 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); 4644 4645 // 4646 // Call the device to do the read and wait for it to finish. 4647 // 4648 4649 Status = IoCallDriver( Vcb->TargetDeviceObject, Irp ); 4650 4651 if (Status == STATUS_PENDING) { 4652 4653 (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); 4654 4655 Status = Iosb.Status; 4656 } 4657 4658 NT_ASSERT( Status != STATUS_VERIFY_REQUIRED ); 4659 4660 // 4661 // Special case this error code because this probably means we used 4662 // the wrong sector size and we want to reject STATUS_WRONG_VOLUME. 4663 // 4664 4665 if (Status == STATUS_INVALID_PARAMETER) { 4666 4667 return FALSE; 4668 } 4669 4670 // 4671 // If it doesn't succeed then either return or raise the error. 4672 // 4673 4674 if (!NT_SUCCESS(Status)) { 4675 4676 if (ReturnOnError) { 4677 4678 return FALSE; 4679 4680 } else { 4681 4682 FatNormalizeAndRaiseStatus( IrpContext, Status ); 4683 } 4684 } 4685 4686 // 4687 // And return to our caller 4688 // 4689 4690 return TRUE; 4691 } 4692 4693 4694 // 4695 // Local Support Routine 4696 // 4697 4698 _Requires_lock_held_(_Global_critical_region_) 4699 NTSTATUS 4700 FatQueryRetrievalPointers ( 4701 IN PIRP_CONTEXT IrpContext, 4702 IN PIRP Irp 4703 ) 4704 4705 /*++ 4706 4707 Routine Description: 4708 4709 This routine performs the query retrieval pointers operation. 4710 It returns the retrieval pointers for the specified input 4711 file from the start of the file to the request map size specified 4712 in the input buffer. 4713 4714 Arguments: 4715 4716 Irp - Supplies the Irp to process 4717 4718 Return Value: 4719 4720 NTSTATUS - The return status for the operation 4721 4722 --*/ 4723 4724 { 4725 NTSTATUS Status = STATUS_SUCCESS; 4726 4727 PIO_STACK_LOCATION IrpSp; 4728 4729 PVCB Vcb; 4730 PFCB Fcb; 4731 PCCB Ccb; 4732 4733 PLARGE_INTEGER RequestedMapSize; 4734 PLARGE_INTEGER *MappingPairs; 4735 4736 ULONG Index; 4737 ULONG i; 4738 ULONG SectorCount; 4739 LBO Lbo; 4740 ULONG Vbo; 4741 ULONG MapSize; 4742 BOOLEAN Result; 4743 4744 PAGED_CODE(); 4745 4746 // 4747 // Get the current stack location 4748 // 4749 4750 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4751 4752 // 4753 // Make this a synchronous IRP because we need access to the input buffer and 4754 // this Irp is marked METHOD_NEITHER. 4755 // 4756 4757 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 4758 4759 // 4760 // Decode the file object and ensure that it is the paging file 4761 // 4762 // Only Kernel mode clients may query retrieval pointer information about 4763 // a file. Ensure that this is the case for this caller. 4764 // 4765 4766 (VOID)FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); 4767 4768 if (Irp->RequestorMode != KernelMode || 4769 Fcb == NULL || 4770 !FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ) { 4771 4772 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 4773 return STATUS_INVALID_PARAMETER; 4774 } 4775 4776 // 4777 // Extract the input and output buffer information. The input contains 4778 // the requested size of the mappings in terms of VBO. The output 4779 // parameter will receive a pointer to nonpaged pool where the mapping 4780 // pairs are stored. 4781 // 4782 4783 NT_ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof(LARGE_INTEGER) ); 4784 NT_ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength == sizeof(PVOID) ); 4785 4786 RequestedMapSize = IrpSp->Parameters.FileSystemControl.Type3InputBuffer; 4787 MappingPairs = Irp->UserBuffer; 4788 4789 // 4790 // Acquire exclusive access to the Fcb 4791 // 4792 4793 FatAcquireExclusiveFcb( IrpContext, Fcb ); 4794 4795 _SEH2_TRY { 4796 4797 // 4798 // Verify the Fcb is still OK 4799 // 4800 4801 FatVerifyFcb( IrpContext, Fcb ); 4802 4803 // 4804 // Check if the mapping the caller requested is too large 4805 // 4806 4807 if ((*RequestedMapSize).QuadPart > Fcb->Header.FileSize.QuadPart) { 4808 4809 try_leave( Status = STATUS_INVALID_PARAMETER ); 4810 } 4811 4812 // 4813 // Now get the index for the mcb entry that will contain the 4814 // callers request and allocate enough pool to hold the 4815 // output mapping pairs. Mapping should always be present, but handle 4816 // the case where it isn't. 4817 // 4818 4819 Result = FatLookupMcbEntry( Fcb->Vcb, 4820 &Fcb->Mcb, 4821 RequestedMapSize->LowPart - 1, 4822 &Lbo, 4823 NULL, 4824 &Index ); 4825 4826 if (!Result) { 4827 4828 NT_ASSERT(FALSE); 4829 try_leave( Status = STATUS_FILE_CORRUPT_ERROR); 4830 } 4831 4832 *MappingPairs = FsRtlAllocatePoolWithTag( NonPagedPoolNx, 4833 (Index + 2) * (2 * sizeof(LARGE_INTEGER)), 4834 TAG_OUTPUT_MAPPINGPAIRS ); 4835 4836 // 4837 // Now copy over the mapping pairs from the mcb 4838 // to the output buffer. We store in [sector count, lbo] 4839 // mapping pairs and end with a zero sector count. 4840 // 4841 4842 MapSize = RequestedMapSize->LowPart; 4843 4844 for (i = 0; i <= Index; i += 1) { 4845 4846 (VOID)FatGetNextMcbEntry( Fcb->Vcb, &Fcb->Mcb, i, (PVBO)&Vbo, &Lbo, &SectorCount ); 4847 4848 if (SectorCount > MapSize) { 4849 SectorCount = MapSize; 4850 } 4851 4852 (*MappingPairs)[ i*2 + 0 ].QuadPart = SectorCount; 4853 (*MappingPairs)[ i*2 + 1 ].QuadPart = Lbo; 4854 4855 MapSize -= SectorCount; 4856 } 4857 4858 (*MappingPairs)[ i*2 + 0 ].QuadPart = 0; 4859 4860 Status = STATUS_SUCCESS; 4861 } 4862 _SEH2_FINALLY { 4863 4864 DebugUnwind( FatQueryRetrievalPointers ); 4865 4866 // 4867 // Release all of our resources 4868 // 4869 4870 FatReleaseFcb( IrpContext, Fcb ); 4871 4872 // 4873 // If this is an abnormal termination then undo our work, otherwise 4874 // complete the irp 4875 // 4876 4877 if (!_SEH2_AbnormalTermination()) { 4878 4879 FatCompleteRequest( IrpContext, Irp, Status ); 4880 } 4881 } _SEH2_END; 4882 4883 return Status; 4884 } 4885 4886 4887 // 4888 // Local Support Routine 4889 // 4890 4891 NTSTATUS 4892 FatGetStatistics ( 4893 IN PIRP_CONTEXT IrpContext, 4894 IN PIRP Irp 4895 ) 4896 4897 /*++ 4898 4899 Routine Description: 4900 4901 This routine returns the filesystem performance counters from the 4902 appropriate VCB. 4903 4904 Arguments: 4905 4906 Irp - Supplies the Irp to process 4907 4908 Return Value: 4909 4910 NTSTATUS - The return status for the operation 4911 4912 --*/ 4913 4914 { 4915 PIO_STACK_LOCATION IrpSp; 4916 NTSTATUS Status; 4917 PVCB Vcb; 4918 4919 PFILE_SYSTEM_STATISTICS Buffer; 4920 ULONG BufferLength; 4921 ULONG StatsSize; 4922 ULONG BytesToCopy; 4923 4924 PAGED_CODE(); 4925 4926 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4927 4928 DebugTrace(+1, Dbg, "FatGetStatistics...\n", 0); 4929 4930 // 4931 // Extract the buffer 4932 // 4933 4934 BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 4935 4936 // 4937 // Get a pointer to the output buffer. 4938 // 4939 4940 Buffer = Irp->AssociatedIrp.SystemBuffer; 4941 4942 // 4943 // Make sure the buffer is big enough for at least the common part. 4944 // 4945 4946 if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) { 4947 4948 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 4949 4950 DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", STATUS_BUFFER_TOO_SMALL ); 4951 4952 return STATUS_BUFFER_TOO_SMALL; 4953 } 4954 4955 // 4956 // Now see how many bytes we can copy. 4957 // 4958 4959 StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * FatData.NumberProcessors; 4960 4961 if (BufferLength < StatsSize) { 4962 4963 BytesToCopy = BufferLength; 4964 Status = STATUS_BUFFER_OVERFLOW; 4965 4966 } else { 4967 4968 BytesToCopy = StatsSize; 4969 Status = STATUS_SUCCESS; 4970 } 4971 4972 // 4973 // Get the Vcb. 4974 // 4975 4976 Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb; 4977 4978 // 4979 // Fill in the output buffer 4980 // 4981 4982 RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy ); 4983 4984 Irp->IoStatus.Information = BytesToCopy; 4985 4986 FatCompleteRequest( IrpContext, Irp, Status ); 4987 4988 DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", Status); 4989 4990 return Status; 4991 } 4992 4993 // 4994 // Local Support Routine 4995 // 4996 4997 _Requires_lock_held_(_Global_critical_region_) 4998 NTSTATUS 4999 FatGetVolumeBitmap( 5000 IN PIRP_CONTEXT IrpContext, 5001 IN PIRP Irp 5002 ) 5003 5004 /*++ 5005 5006 Routine Description: 5007 5008 This routine returns the volume allocation bitmap. 5009 5010 Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in 5011 through the input buffer. 5012 Output = the VOLUME_BITMAP_BUFFER data structure is returned through 5013 the output buffer. 5014 5015 We return as much as the user buffer allows starting the specified input 5016 LCN (trucated to a byte). If there is no input buffer, we start at zero. 5017 5018 Arguments: 5019 5020 Irp - Supplies the Irp being processed. 5021 5022 Return Value: 5023 5024 NTSTATUS - The return status for the operation. 5025 5026 --*/ 5027 { 5028 NTSTATUS Status; 5029 PIO_STACK_LOCATION IrpSp; 5030 5031 PVCB Vcb; 5032 PFCB Fcb; 5033 PCCB Ccb; 5034 5035 ULONG BytesToCopy; 5036 ULONG TotalClusters; 5037 ULONG DesiredClusters; 5038 ULONG StartingCluster; 5039 ULONG EndingCluster; 5040 ULONG InputBufferLength; 5041 ULONG OutputBufferLength; 5042 LARGE_INTEGER StartingLcn; 5043 PVOLUME_BITMAP_BUFFER OutputBuffer; 5044 5045 PAGED_CODE(); 5046 5047 // 5048 // Get the current Irp stack location and save some references. 5049 // 5050 5051 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 5052 5053 DebugTrace(+1, Dbg, "FatGetVolumeBitmap, FsControlCode = %08lx\n", 5054 IrpSp->Parameters.FileSystemControl.FsControlCode); 5055 5056 // 5057 // Make this a synchronous IRP because we need access to the input buffer and 5058 // this Irp is marked METHOD_NEITHER. 5059 // 5060 5061 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 5062 5063 // 5064 // Extract and decode the file object and check for type of open. 5065 // 5066 5067 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 5068 5069 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5070 return STATUS_INVALID_PARAMETER; 5071 } 5072 5073 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 5074 5075 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5076 5077 DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> %08lx\n", STATUS_INVALID_PARAMETER); 5078 return STATUS_INVALID_PARAMETER; 5079 } 5080 5081 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; 5082 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 5083 5084 OutputBuffer = (PVOLUME_BITMAP_BUFFER)FatMapUserBuffer( IrpContext, Irp ); 5085 5086 // 5087 // Check for a minimum length on the input and output buffers. 5088 // 5089 5090 if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) || 5091 (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) { 5092 5093 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 5094 return STATUS_BUFFER_TOO_SMALL; 5095 } 5096 5097 // 5098 // Check if a starting cluster was specified. 5099 // 5100 5101 TotalClusters = Vcb->AllocationSupport.NumberOfClusters; 5102 5103 // 5104 // Check for valid buffers 5105 // 5106 5107 _SEH2_TRY { 5108 5109 if (Irp->RequestorMode != KernelMode) { 5110 5111 ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer, 5112 InputBufferLength, 5113 sizeof(UCHAR) ); 5114 5115 ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) ); 5116 } 5117 5118 StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn; 5119 5120 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) { 5121 5122 Status = _SEH2_GetExceptionCode(); 5123 5124 FatRaiseStatus( IrpContext, 5125 FsRtlIsNtstatusExpected(Status) ? 5126 Status : STATUS_INVALID_USER_BUFFER ); 5127 } _SEH2_END; 5128 5129 if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) { 5130 5131 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5132 return STATUS_INVALID_PARAMETER; 5133 5134 } else { 5135 5136 StartingCluster = StartingLcn.LowPart & ~7; 5137 } 5138 5139 (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb ); 5140 5141 // 5142 // Only return what will fit in the user buffer. 5143 // 5144 5145 OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); 5146 DesiredClusters = TotalClusters - StartingCluster; 5147 5148 if (OutputBufferLength < (DesiredClusters + 7) / 8) { 5149 5150 BytesToCopy = OutputBufferLength; 5151 Status = STATUS_BUFFER_OVERFLOW; 5152 5153 } else { 5154 5155 BytesToCopy = (DesiredClusters + 7) / 8; 5156 Status = STATUS_SUCCESS; 5157 } 5158 5159 // 5160 // Use try/finally for cleanup. 5161 // 5162 5163 _SEH2_TRY { 5164 5165 _SEH2_TRY { 5166 5167 // 5168 // Verify the Vcb is still OK 5169 // 5170 5171 FatQuickVerifyVcb( IrpContext, Vcb ); 5172 5173 // 5174 // Fill in the fixed part of the output buffer 5175 // 5176 5177 OutputBuffer->StartingLcn.QuadPart = StartingCluster; 5178 OutputBuffer->BitmapSize.QuadPart = DesiredClusters; 5179 5180 if (Vcb->NumberOfWindows == 1) { 5181 5182 // 5183 // Just copy the volume bitmap into the user buffer. 5184 // 5185 5186 NT_ASSERT( Vcb->FreeClusterBitMap.Buffer != NULL ); 5187 5188 RtlCopyMemory( &OutputBuffer->Buffer[0], 5189 (PUCHAR)Vcb->FreeClusterBitMap.Buffer + StartingCluster/8, 5190 BytesToCopy ); 5191 } else { 5192 5193 // 5194 // Call out to analyze the FAT. We must bias by two to account for 5195 // the zero base of this API and FAT's physical reality of starting 5196 // the file heap at cluster 2. 5197 // 5198 // Note that the end index is inclusive - we need to subtract one to 5199 // calculcate it. 5200 // 5201 // I.e.: StartingCluster 0 for one byte of bitmap means a start cluster 5202 // of 2 and end cluster of 9, a run of eight clusters. 5203 // 5204 5205 EndingCluster = StartingCluster + (BytesToCopy * 8); 5206 5207 // 5208 // Make sure we do not read past the end of the entries. 5209 // 5210 5211 if (EndingCluster > TotalClusters) { 5212 5213 EndingCluster = TotalClusters; 5214 } 5215 5216 FatExamineFatEntries( IrpContext, 5217 Vcb, 5218 StartingCluster + 2, 5219 EndingCluster + 2 - 1, 5220 FALSE, 5221 NULL, 5222 (PULONG)&OutputBuffer->Buffer[0] ); 5223 } 5224 5225 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) { 5226 5227 Status = _SEH2_GetExceptionCode(); 5228 5229 FatRaiseStatus( IrpContext, 5230 FsRtlIsNtstatusExpected(Status) ? 5231 Status : STATUS_INVALID_USER_BUFFER ); 5232 } _SEH2_END; 5233 5234 } _SEH2_FINALLY { 5235 5236 FatReleaseVcb( IrpContext, Vcb ); 5237 } _SEH2_END; 5238 5239 Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + 5240 BytesToCopy; 5241 5242 FatCompleteRequest( IrpContext, Irp, Status ); 5243 5244 DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> VOID\n", 0); 5245 5246 return Status; 5247 } 5248 5249 5250 // 5251 // Local Support Routine 5252 // 5253 5254 _Requires_lock_held_(_Global_critical_region_) 5255 NTSTATUS 5256 FatGetRetrievalPointers ( 5257 IN PIRP_CONTEXT IrpContext, 5258 IN PIRP Irp 5259 ) 5260 5261 /*++ 5262 5263 Routine Description: 5264 5265 This routine scans the MCB and builds an extent list. The first run in 5266 the output extent list will start at the begining of the contiguous 5267 run specified by the input parameter. 5268 5269 Input = STARTING_VCN_INPUT_BUFFER; 5270 Output = RETRIEVAL_POINTERS_BUFFER. 5271 5272 Arguments: 5273 5274 Irp - Supplies the Irp being processed. 5275 5276 Return Value: 5277 5278 NTSTATUS - The return status for the operation. 5279 5280 --*/ 5281 { 5282 NTSTATUS Status = STATUS_SUCCESS; 5283 PIO_STACK_LOCATION IrpSp; 5284 5285 PVCB Vcb; 5286 PFCB FcbOrDcb; 5287 PCCB Ccb; 5288 PLARGE_MCB McbToUse = NULL; 5289 TYPE_OF_OPEN TypeOfOpen; 5290 5291 ULONG Index; 5292 ULONG ClusterShift = 0; 5293 ULONG ClusterSize; 5294 LONGLONG AllocationSize = 0; 5295 5296 ULONG Run; 5297 ULONG RunCount; 5298 ULONG StartingRun; 5299 LARGE_INTEGER StartingVcn; 5300 5301 ULONG InputBufferLength; 5302 ULONG OutputBufferLength; 5303 5304 VBO LastVbo; 5305 LBO LastLbo; 5306 ULONG LastIndex; 5307 5308 PRETRIEVAL_POINTERS_BUFFER OutputBuffer; 5309 5310 PAGED_CODE(); 5311 5312 // 5313 // Get the current Irp stack location and save some references. 5314 // 5315 5316 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 5317 5318 DebugTrace(+1, Dbg, "FatGetRetrievalPointers, FsControlCode = %08lx\n", 5319 IrpSp->Parameters.FileSystemControl.FsControlCode); 5320 5321 // 5322 // Make this a synchronous IRP because we need access to the input buffer and 5323 // this Irp is marked METHOD_NEITHER. 5324 // 5325 5326 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 5327 5328 // 5329 // Extract and decode the file object and check for type of open. 5330 // 5331 5332 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ); 5333 5334 if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen) && (TypeOfOpen != UserVolumeOpen) ) { 5335 5336 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5337 return STATUS_INVALID_PARAMETER; 5338 } 5339 5340 // 5341 // Get the input and output buffer lengths and pointers. 5342 // Initialize some variables. 5343 // 5344 5345 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; 5346 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 5347 5348 OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)FatMapUserBuffer( IrpContext, Irp ); 5349 5350 // 5351 // Check for a minimum length on the input and ouput buffers. 5352 // 5353 5354 if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) || 5355 (OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))) { 5356 5357 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 5358 return STATUS_BUFFER_TOO_SMALL; 5359 } 5360 5361 // 5362 // Acquire the Fcb and enqueue the Irp if we didn't get access. Go for 5363 // shared on read-only media so we can allow prototype XIP to get 5364 // recursive, as well as recognizing this is safe anyway. 5365 // 5366 if( (TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen) ) { 5367 5368 if (FlagOn( FcbOrDcb->Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED )) { 5369 5370 (VOID)FatAcquireSharedFcb( IrpContext, FcbOrDcb ); 5371 5372 } else { 5373 5374 (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb ); 5375 } 5376 } else if ((TypeOfOpen == UserVolumeOpen )) { 5377 5378 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 5379 5380 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); 5381 5382 DebugTrace(-1, Dbg, "FatMoveFile -> 0x%x\n", STATUS_ACCESS_DENIED); 5383 return STATUS_ACCESS_DENIED; 5384 } 5385 5386 (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb); 5387 } 5388 5389 _SEH2_TRY { 5390 5391 // 5392 // Verify the Fcb is still OK, or if it is a volume handle, the VCB. 5393 // 5394 5395 if( (TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen) ) { 5396 5397 FatVerifyFcb( IrpContext, FcbOrDcb ); 5398 5399 // 5400 // If we haven't yet set the correct AllocationSize, do so. 5401 // 5402 5403 if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) { 5404 5405 FatLookupFileAllocationSize( IrpContext, FcbOrDcb ); 5406 5407 // 5408 // If this is a non-root directory, we have a bit more to 5409 // do since it has not gone through FatOpenDirectoryFile(). 5410 // 5411 5412 if (NodeType(FcbOrDcb) == FAT_NTC_DCB || 5413 (NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && FatIsFat32(Vcb))) { 5414 5415 FcbOrDcb->Header.FileSize.LowPart = 5416 FcbOrDcb->Header.AllocationSize.LowPart; 5417 } 5418 } 5419 5420 5421 ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster; 5422 5423 #ifdef _MSC_VER 5424 #pragma prefast( suppress:28931, "calculate it anyway, in case someone adds code that uses this in the future" ) 5425 #endif 5426 ClusterSize = 1 << ClusterShift; 5427 5428 AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart; 5429 McbToUse = &FcbOrDcb->Mcb; 5430 5431 } else if ((TypeOfOpen == UserVolumeOpen )) { 5432 5433 FatQuickVerifyVcb( IrpContext, Vcb ); 5434 5435 if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BAD_BLOCKS_POPULATED)) { 5436 5437 // 5438 // If the bad cluster mcb isn't populated, something is wrong. (It should have been 5439 // populated during mount when we scanned the FAT. 5440 // 5441 5442 FatRaiseStatus(IrpContext, STATUS_FILE_CORRUPT_ERROR ); 5443 } 5444 5445 ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster; 5446 ClusterSize = 1 << ClusterShift; 5447 5448 if (!FatLookupLastMcbEntry(Vcb, &Vcb->BadBlockMcb, &LastVbo, &LastLbo, &LastIndex)) { 5449 AllocationSize = 0; 5450 } else { 5451 5452 // 5453 // Round the allocation size to a multiple of of the cluster size. 5454 // 5455 5456 AllocationSize = (LastVbo + ((LONGLONG)ClusterSize-1)) & ~((LONGLONG)ClusterSize-1); 5457 } 5458 5459 McbToUse = &Vcb->BadBlockMcb; 5460 5461 } 5462 5463 // 5464 // Check if a starting cluster was specified. 5465 // 5466 5467 _SEH2_TRY { 5468 5469 if (Irp->RequestorMode != KernelMode) { 5470 5471 ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer, 5472 InputBufferLength, 5473 sizeof(UCHAR) ); 5474 5475 ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) ); 5476 } 5477 5478 StartingVcn = ((PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingVcn; 5479 5480 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) { 5481 5482 Status = _SEH2_GetExceptionCode(); 5483 5484 FatRaiseStatus( IrpContext, 5485 FsRtlIsNtstatusExpected(Status) ? 5486 Status : STATUS_INVALID_USER_BUFFER ); 5487 } _SEH2_END; 5488 5489 if (StartingVcn.HighPart || 5490 StartingVcn.LowPart >= (AllocationSize >> ClusterShift)) { 5491 5492 try_return( Status = STATUS_END_OF_FILE ); 5493 5494 } else { 5495 5496 // 5497 // If we don't find the run, something is very wrong. 5498 // 5499 5500 LBO Lbo; 5501 5502 if (!FatLookupMcbEntry( Vcb, McbToUse, 5503 StartingVcn.LowPart << ClusterShift, 5504 &Lbo, 5505 NULL, 5506 &StartingRun)) { 5507 5508 #ifdef _MSC_VER 5509 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 5510 #endif 5511 FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)McbToUse, StartingVcn.LowPart ); 5512 } 5513 } 5514 5515 // 5516 // Now go fill in the ouput buffer with run information 5517 // 5518 5519 RunCount = FsRtlNumberOfRunsInLargeMcb( McbToUse ); 5520 5521 for (Index = 0, Run = StartingRun; Run < RunCount; Index++, Run++) { 5522 5523 ULONG Vcn; 5524 LBO Lbo; 5525 ULONG ByteLength; 5526 5527 // 5528 // Check for an exhausted output buffer. 5529 // 5530 5531 if ((ULONG)FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index+1]) > OutputBufferLength) { 5532 5533 5534 // 5535 // We've run out of space, so we won't be storing as many runs to the 5536 // user's buffer as we had originally planned. We need to return the 5537 // number of runs that we did have room for. 5538 // 5539 5540 _SEH2_TRY { 5541 5542 OutputBuffer->ExtentCount = Index; 5543 5544 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) { 5545 5546 Status = _SEH2_GetExceptionCode(); 5547 5548 FatRaiseStatus( IrpContext, 5549 FsRtlIsNtstatusExpected(Status) ? 5550 Status : STATUS_INVALID_USER_BUFFER ); 5551 } _SEH2_END; 5552 5553 Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]); 5554 try_return( Status = STATUS_BUFFER_OVERFLOW ); 5555 } 5556 5557 // 5558 // Get the extent. If it's not there or malformed, something is very wrong. 5559 // 5560 5561 if (!FatGetNextMcbEntry(Vcb, McbToUse, Run, (PVBO)&Vcn, &Lbo, &ByteLength)) { 5562 5563 #ifdef _MSC_VER 5564 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 5565 #endif 5566 FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)McbToUse, Run ); 5567 } 5568 5569 // 5570 // Fill in the next array element. 5571 // 5572 5573 _SEH2_TRY { 5574 5575 OutputBuffer->Extents[Index].NextVcn.QuadPart = ((LONGLONG)Vcn + ByteLength) >> ClusterShift; 5576 OutputBuffer->Extents[Index].Lcn.QuadPart = FatGetIndexFromLbo( Vcb, Lbo ) - 2; 5577 5578 // 5579 // If this is the first run, fill in the starting Vcn 5580 // 5581 5582 if (Index == 0) { 5583 OutputBuffer->ExtentCount = RunCount - StartingRun; 5584 OutputBuffer->StartingVcn.QuadPart = Vcn >> ClusterShift; 5585 } 5586 5587 } _SEH2_EXCEPT( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) { 5588 5589 Status = _SEH2_GetExceptionCode(); 5590 5591 FatRaiseStatus( IrpContext, 5592 FsRtlIsNtstatusExpected(Status) ? 5593 Status : STATUS_INVALID_USER_BUFFER ); 5594 } _SEH2_END; 5595 } 5596 5597 // 5598 // We successfully retrieved extent info to the end of the allocation. 5599 // 5600 5601 Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]); 5602 Status = STATUS_SUCCESS; 5603 5604 try_exit: NOTHING; 5605 5606 } _SEH2_FINALLY { 5607 5608 DebugUnwind( FatGetRetrievalPointers ); 5609 5610 // 5611 // Release resources 5612 // 5613 5614 if( (TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen) ) { 5615 5616 FatReleaseFcb( IrpContext, FcbOrDcb ); 5617 } else if ((TypeOfOpen == UserVolumeOpen )) { 5618 5619 FatReleaseVcb(IrpContext, Vcb); 5620 } 5621 5622 // 5623 // If nothing raised then complete the irp. 5624 // 5625 5626 if (!_SEH2_AbnormalTermination()) { 5627 5628 FatCompleteRequest( IrpContext, Irp, Status ); 5629 } 5630 5631 DebugTrace(-1, Dbg, "FatGetRetrievalPointers -> VOID\n", 0); 5632 } _SEH2_END; 5633 5634 return Status; 5635 } 5636 5637 5638 // 5639 // Local Support Routine 5640 // 5641 5642 _Requires_lock_held_(_Global_critical_region_) 5643 VOID 5644 FatMoveFileNeedsWriteThrough ( 5645 _In_ PIRP_CONTEXT IrpContext, 5646 _In_ PFCB FcbOrDcb, 5647 _In_ ULONG OldWriteThroughFlags 5648 ) 5649 { 5650 PAGED_CODE(); 5651 5652 if (NodeType(FcbOrDcb) == FAT_NTC_FCB) { 5653 5654 5655 if (FcbOrDcb->Header.ValidDataLength.QuadPart == 0) { 5656 5657 5658 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH ); 5659 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH ); 5660 5661 } else { 5662 5663 IrpContext->Flags &= ~(IRP_CONTEXT_FLAG_WRITE_THROUGH|IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH); 5664 IrpContext->Flags |= OldWriteThroughFlags; 5665 5666 } 5667 } 5668 } 5669 5670 _Requires_lock_held_(_Global_critical_region_) 5671 NTSTATUS 5672 FatMoveFile ( 5673 IN PIRP_CONTEXT IrpContext, 5674 IN PIRP Irp 5675 ) 5676 5677 /*++ 5678 5679 Routine Description: 5680 5681 Routine moves a file to the requested Starting Lcn from Starting Vcn for the length 5682 of cluster count. These values are passed in through the the input buffer as a 5683 MOVE_DATA structure. 5684 5685 The call must be made with a DASD handle. The file to move is passed in as a 5686 parameter. 5687 5688 Arguments: 5689 5690 Irp - Supplies the Irp being processed. 5691 5692 Return Value: 5693 5694 NTSTATUS - The return status for the operation. 5695 5696 --*/ 5697 5698 { 5699 NTSTATUS Status; 5700 PIO_STACK_LOCATION IrpSp; 5701 5702 PFILE_OBJECT FileObject; 5703 TYPE_OF_OPEN TypeOfOpen; 5704 PVCB Vcb; 5705 PFCB FcbOrDcb; 5706 PCCB Ccb; 5707 5708 ULONG InputBufferLength; 5709 PMOVE_FILE_DATA InputBuffer; 5710 5711 ULONG ClusterShift; 5712 ULONG MaxClusters; 5713 5714 ULONG FileOffset; 5715 5716 LBO TargetLbo; 5717 ULONG TargetCluster; 5718 LARGE_INTEGER LargeSourceLbo; 5719 LARGE_INTEGER LargeTargetLbo; 5720 5721 ULONG ByteCount; 5722 ULONG BytesToWrite; 5723 ULONG BytesToReallocate; 5724 5725 ULONG FirstSpliceSourceCluster; 5726 ULONG FirstSpliceTargetCluster; 5727 ULONG SecondSpliceSourceCluster; 5728 ULONG SecondSpliceTargetCluster; 5729 5730 LARGE_MCB SourceMcb; 5731 LARGE_MCB TargetMcb; 5732 5733 KEVENT StackEvent; 5734 5735 PVOID Buffer = NULL; 5736 ULONG BufferSize; 5737 5738 BOOLEAN SourceMcbInitialized = FALSE; 5739 BOOLEAN TargetMcbInitialized = FALSE; 5740 5741 BOOLEAN FcbAcquired = FALSE; 5742 BOOLEAN EventArmed = FALSE; 5743 BOOLEAN DiskSpaceAllocated = FALSE; 5744 5745 PDIRENT Dirent; 5746 PBCB DirentBcb = NULL; 5747 5748 ULONG OldWriteThroughFlags = (IrpContext->Flags & (IRP_CONTEXT_FLAG_WRITE_THROUGH|IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH)); 5749 5750 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 5751 MOVE_FILE_DATA LocalMoveFileData; 5752 PMOVE_FILE_DATA32 MoveFileData32; 5753 #endif 5754 5755 ULONG LocalAbnormalTermination = 0; 5756 5757 PAGED_CODE(); 5758 5759 // 5760 // Get the current Irp stack location and save some references. 5761 // 5762 5763 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 5764 5765 DebugTrace(+1, Dbg, "FatMoveFile, FsControlCode = %08lx\n", 5766 IrpSp->Parameters.FileSystemControl.FsControlCode); 5767 5768 // 5769 // Force WAIT to true. We have a handle in the input buffer which can only 5770 // be referenced within the originating process. 5771 // 5772 5773 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 5774 5775 // 5776 // Extract and decode the file object and check for type of open. 5777 // 5778 5779 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ) != UserVolumeOpen) { 5780 5781 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5782 5783 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER); 5784 return STATUS_INVALID_PARAMETER; 5785 } 5786 5787 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 5788 5789 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5790 5791 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER); 5792 return STATUS_INVALID_PARAMETER; 5793 } 5794 5795 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; 5796 InputBuffer = (PMOVE_FILE_DATA)Irp->AssociatedIrp.SystemBuffer; 5797 5798 // 5799 // Do a quick check on the input buffer. 5800 // 5801 5802 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 5803 if (IoIs32bitProcess( Irp )) { 5804 5805 if (InputBuffer == NULL || InputBufferLength < sizeof(MOVE_FILE_DATA32)) { 5806 5807 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 5808 return STATUS_BUFFER_TOO_SMALL; 5809 } 5810 5811 MoveFileData32 = (PMOVE_FILE_DATA32) InputBuffer; 5812 5813 LocalMoveFileData.FileHandle = (HANDLE) LongToHandle( MoveFileData32->FileHandle ); 5814 LocalMoveFileData.StartingVcn = MoveFileData32->StartingVcn; 5815 LocalMoveFileData.StartingLcn = MoveFileData32->StartingLcn; 5816 LocalMoveFileData.ClusterCount = MoveFileData32->ClusterCount; 5817 5818 InputBuffer = &LocalMoveFileData; 5819 5820 } else { 5821 #endif 5822 if (InputBuffer == NULL || InputBufferLength < sizeof(MOVE_FILE_DATA)) { 5823 5824 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 5825 return STATUS_BUFFER_TOO_SMALL; 5826 } 5827 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 5828 } 5829 #endif 5830 5831 MaxClusters = Vcb->AllocationSupport.NumberOfClusters; 5832 TargetCluster = InputBuffer->StartingLcn.LowPart + 2; 5833 5834 if (InputBuffer->StartingVcn.HighPart || 5835 InputBuffer->StartingLcn.HighPart || 5836 (TargetCluster < 2) || 5837 (TargetCluster + InputBuffer->ClusterCount < TargetCluster) || 5838 (TargetCluster + InputBuffer->ClusterCount > MaxClusters + 2) || 5839 (InputBuffer->StartingVcn.LowPart >= MaxClusters) || 5840 InputBuffer->ClusterCount == 0 5841 ) { 5842 5843 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5844 5845 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER); 5846 return STATUS_INVALID_PARAMETER; 5847 } 5848 5849 // 5850 // Try to get a pointer to the file object from the handle passed in. 5851 // 5852 5853 Status = ObReferenceObjectByHandle( InputBuffer->FileHandle, 5854 0, 5855 *IoFileObjectType, 5856 Irp->RequestorMode, 5857 #ifndef __REACTOS__ 5858 &FileObject, 5859 #else 5860 (PVOID *)&FileObject, 5861 #endif 5862 NULL ); 5863 5864 if (!NT_SUCCESS(Status)) { 5865 5866 FatCompleteRequest( IrpContext, Irp, Status ); 5867 5868 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", Status); 5869 return Status; 5870 } 5871 5872 // 5873 // There are three basic ways this could be an invalid attempt, so 5874 // we need to 5875 // 5876 // - check that this file object is opened on the same volume as the 5877 // DASD handle used to call this routine. 5878 // 5879 // - extract and decode the file object and check for type of open. 5880 // 5881 // - if this is a directory, verify that it's not the root and that 5882 // we are not trying to move the first cluster. We cannot move the 5883 // first cluster because sub-directories have this cluster number 5884 // in them and there is no safe way to simultaneously update them 5885 // all. 5886 // 5887 // We'll allow movefile on the root dir if its fat32, since the root dir 5888 // is a real chained file there. 5889 // 5890 5891 if (FileObject->Vpb != Vcb->Vpb) { 5892 5893 ObDereferenceObject( FileObject ); 5894 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5895 5896 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER); 5897 return STATUS_INVALID_PARAMETER; 5898 } 5899 5900 TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &FcbOrDcb, &Ccb ); 5901 5902 if ((TypeOfOpen != UserFileOpen && 5903 TypeOfOpen != UserDirectoryOpen) || 5904 5905 ((TypeOfOpen == UserDirectoryOpen) && 5906 ((NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && !FatIsFat32(Vcb)) || 5907 (InputBuffer->StartingVcn.QuadPart == 0)))) { 5908 5909 ObDereferenceObject( FileObject ); 5910 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 5911 5912 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER); 5913 return STATUS_INVALID_PARAMETER; 5914 } 5915 5916 // 5917 // If the VDL of the file is zero, it has no valid data in it anyway. 5918 // So it should be safe to avoid flushing the FAT entries and let them be 5919 // lazily written out. 5920 // 5921 // This is done so that bitlocker's cover file doesn't cause 5922 // unnecessary FAT table I/O when it's moved around. 5923 // (See Win8 bug 106505) 5924 // 5925 5926 // 5927 // If this is a file, and the VDL is zero, clear write through. 5928 // 5929 5930 FatMoveFileNeedsWriteThrough(IrpContext, FcbOrDcb, OldWriteThroughFlags); 5931 5932 5933 // 5934 // Indicate we're getting to parents of this fcb by their child, and that 5935 // this is a sufficient assertion of our ability to by synchronized 5936 // with respect to the parent directory going away. 5937 // 5938 // The defrag path is an example of one which arrives at an Fcb by 5939 // a means which would be unreasonable to duplicate in the assertion 5940 // code. See FatOpenDirectoryFile. 5941 // 5942 5943 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD ); 5944 5945 ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster; 5946 5947 _SEH2_TRY { 5948 5949 // 5950 // Initialize our state variables and the event. 5951 // 5952 5953 FileOffset = InputBuffer->StartingVcn.LowPart << ClusterShift; 5954 5955 ByteCount = InputBuffer->ClusterCount << ClusterShift; 5956 5957 TargetLbo = FatGetLboFromIndex( Vcb, TargetCluster ); 5958 LargeTargetLbo.QuadPart = TargetLbo; 5959 5960 Buffer = NULL; 5961 5962 // 5963 // Do a quick check on parameters here 5964 // 5965 5966 if (FileOffset + ByteCount < FileOffset) { 5967 5968 try_return( Status = STATUS_INVALID_PARAMETER ); 5969 } 5970 5971 KeInitializeEvent( &StackEvent, NotificationEvent, FALSE ); 5972 5973 // 5974 // Initialize two MCBs we will be using 5975 // 5976 5977 FsRtlInitializeLargeMcb( &SourceMcb, PagedPool ); 5978 SourceMcbInitialized = TRUE; 5979 5980 FsRtlInitializeLargeMcb( &TargetMcb, PagedPool ); 5981 TargetMcbInitialized = TRUE; 5982 5983 // 5984 // Ok, now if this is a directory open we need to switch to the internal 5985 // stream fileobject since it is set up for caching. The top-level 5986 // fileobject has no section object pointers in order prevent folks from 5987 // mapping it. 5988 // 5989 5990 if (TypeOfOpen == UserDirectoryOpen) { 5991 5992 PFILE_OBJECT DirStreamFileObject; 5993 5994 // 5995 // Open the stream fileobject if neccesary. We must acquire the Fcb 5996 // now to synchronize with other operations (such as dismount ripping 5997 // apart the allocator). 5998 // 5999 6000 (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb ); 6001 FcbAcquired = TRUE; 6002 6003 FatVerifyFcb( IrpContext, FcbOrDcb ); 6004 6005 FatOpenDirectoryFile( IrpContext, FcbOrDcb ); 6006 DirStreamFileObject = FcbOrDcb->Specific.Dcb.DirectoryFile; 6007 6008 // 6009 // Transfer our reference to the internal stream and proceed. Note that 6010 // if we dereferenced first, the user could sneak a teardown through since 6011 // we'd have no references. 6012 // 6013 6014 ObReferenceObject( DirStreamFileObject ); 6015 ObDereferenceObject( FileObject ); 6016 FileObject = DirStreamFileObject; 6017 6018 // 6019 // We've referenced the DirStreamFileObject, so it should be ok to drop 6020 // the Dcb now. 6021 // 6022 6023 FatReleaseFcb( IrpContext, FcbOrDcb ); 6024 FcbAcquired = FALSE; 6025 } 6026 6027 // 6028 // Determine the size of the buffer we will use to move data. 6029 // 6030 6031 BufferSize = FAT_DEFAULT_DEFRAG_CHUNK_IN_BYTES; 6032 6033 if (BufferSize < (ULONG)(1 << ClusterShift)) { 6034 6035 BufferSize = (1 << ClusterShift); 6036 } 6037 6038 while (ByteCount) { 6039 6040 VBO TempVbo; 6041 LBO TempLbo; 6042 ULONG TempByteCount; 6043 6044 // 6045 // We must throttle our writes. 6046 // 6047 6048 CcCanIWrite( FileObject, 6049 BufferSize, 6050 TRUE, 6051 FALSE ); 6052 6053 // 6054 // Aqcuire file resource exclusive to freeze FileSize and block 6055 // user non-cached I/O. Verify the integrity of the fcb - the 6056 // media may have changed (or been dismounted) on us. 6057 // 6058 6059 if (FcbAcquired == FALSE) { 6060 6061 (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb ); 6062 FcbAcquired = TRUE; 6063 6064 FatVerifyFcb( IrpContext, FcbOrDcb ); 6065 } 6066 6067 // 6068 // Check if the handle indicates we're allowed to move the file. 6069 // 6070 // FCB_STATE_DENY_DEFRAG indicates that someone blocked move file on this FCB. 6071 // CCB_FLAG_DENY_DEFRAG indicates that this handle was the one that blocked move file, and hence 6072 // it still gets to move the file around. 6073 // 6074 6075 if ((FcbOrDcb->FcbState & FCB_STATE_DENY_DEFRAG) && !(Ccb->Flags & CCB_FLAG_DENY_DEFRAG)) { 6076 DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_ACCESS_DENIED); 6077 try_return( Status = STATUS_ACCESS_DENIED ); 6078 } 6079 6080 // 6081 // Allocate our buffer, if we need to. 6082 // 6083 6084 if (Buffer == NULL) { 6085 6086 Buffer = FsRtlAllocatePoolWithTag( NonPagedPoolNx, 6087 BufferSize, 6088 TAG_DEFRAG_BUFFER ); 6089 } 6090 6091 // 6092 // Analyzes the range of file allocation we are moving 6093 // and determines the actual amount of allocation to be 6094 // moved and how much needs to be written. In addition 6095 // it guarantees that the Mcb in the file is large enough 6096 // so that later MCB operations cannot fail. 6097 // 6098 6099 FatComputeMoveFileParameter( IrpContext, 6100 FcbOrDcb, 6101 BufferSize, 6102 FileOffset, 6103 &ByteCount, 6104 &BytesToReallocate, 6105 &BytesToWrite, 6106 &LargeSourceLbo ); 6107 6108 // 6109 // If ByteCount comes back zero, break here. 6110 // 6111 6112 if (ByteCount == 0) { 6113 break; 6114 } 6115 6116 // 6117 // At this point (before actually doing anything with the disk 6118 // meta data), calculate the FAT splice clusters and build an 6119 // MCB describing the space to be deallocated. 6120 // 6121 6122 FatComputeMoveFileSplicePoints( IrpContext, 6123 FcbOrDcb, 6124 FileOffset, 6125 TargetCluster, 6126 BytesToReallocate, 6127 &FirstSpliceSourceCluster, 6128 &FirstSpliceTargetCluster, 6129 &SecondSpliceSourceCluster, 6130 &SecondSpliceTargetCluster, 6131 &SourceMcb ); 6132 6133 // 6134 // Now attempt to allocate the new disk storage using the 6135 // Target Lcn as a hint. 6136 // 6137 6138 TempByteCount = BytesToReallocate; 6139 FatAllocateDiskSpace( IrpContext, 6140 Vcb, 6141 TargetCluster, 6142 &TempByteCount, 6143 TRUE, 6144 &TargetMcb ); 6145 6146 DiskSpaceAllocated = TRUE; 6147 6148 // 6149 // If we didn't get EXACTLY what we wanted, return immediately. 6150 // 6151 6152 if ((FsRtlNumberOfRunsInLargeMcb( &TargetMcb ) != 1) || 6153 !FatGetNextMcbEntry( Vcb, &TargetMcb, 0, &TempVbo, &TempLbo, &TempByteCount ) || 6154 (FatGetIndexFromLbo( Vcb, TempLbo) != TargetCluster ) || 6155 (TempByteCount != BytesToReallocate)) { 6156 6157 // 6158 // It would be nice if we could be more specific, but such is life. 6159 // 6160 try_return( Status = STATUS_INVALID_PARAMETER ); 6161 } 6162 6163 #if DBG 6164 // 6165 // We are going to attempt a move, note it. 6166 // 6167 6168 if (FatMoveFileDebug) { 6169 DbgPrint("0x%p: Vcn 0x%lx, Lcn 0x%lx, Count 0x%lx.\n", 6170 PsGetCurrentThread(), 6171 FileOffset >> ClusterShift, 6172 TargetCluster, 6173 BytesToReallocate >> ClusterShift ); 6174 } 6175 #endif 6176 6177 // 6178 // Now attempt to commit the new allocation to disk. If this 6179 // raises, the allocation will be deallocated. 6180 // 6181 // If the VDL of the file is zero, it has no valid data in it anyway. 6182 // So it should be safe to avoid flushing the FAT entries and let them be 6183 // lazily written out. 6184 // 6185 // This is done so that bitlocker's cover file doesn't cause 6186 // unnecessary FAT table I/O when it's moved around. 6187 // (See Win8 bug 106505) 6188 // 6189 6190 if ((FcbOrDcb->Header.ValidDataLength.QuadPart != 0) || (NodeType(FcbOrDcb) != FAT_NTC_FCB)) { 6191 6192 FatFlushFatEntries( IrpContext, 6193 Vcb, 6194 TargetCluster, 6195 BytesToReallocate >> ClusterShift ); 6196 } 6197 6198 // 6199 // Aqcuire both resources exclusive now, guaranteeing that NOBODY 6200 // is in either the read or write paths. 6201 // 6202 6203 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE ); 6204 6205 // 6206 // This is the first part of some tricky synchronization. 6207 // 6208 // Set the Event pointer in the FCB. Any paging I/O will block on 6209 // this event (if set in FCB) after acquiring the PagingIo resource. 6210 // 6211 // This is how I keep ALL I/O out of this path without holding the 6212 // PagingIo resource exclusive for an extended time. 6213 // 6214 6215 FcbOrDcb->MoveFileEvent = &StackEvent; 6216 EventArmed = TRUE; 6217 6218 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource ); 6219 6220 // 6221 // Now write out the data, but only if we have to. We don't have 6222 // to copy any file data if the range being reallocated is wholly 6223 // beyond valid data length. 6224 // 6225 6226 if (BytesToWrite) { 6227 6228 PIRP IoIrp; 6229 KEVENT IoEvent; 6230 IO_STATUS_BLOCK Iosb; 6231 6232 KeInitializeEvent( &IoEvent, 6233 NotificationEvent, 6234 FALSE ); 6235 6236 NT_ASSERT( LargeTargetLbo.QuadPart >= Vcb->AllocationSupport.FileAreaLbo ); 6237 6238 // 6239 // Read in the data that is being moved. 6240 // 6241 6242 IoIrp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 6243 Vcb->TargetDeviceObject, 6244 Buffer, 6245 BytesToWrite, 6246 &LargeSourceLbo, 6247 &IoEvent, 6248 &Iosb ); 6249 6250 if (IoIrp == NULL) { 6251 6252 FatRaiseStatus( IrpContext, 6253 STATUS_INSUFFICIENT_RESOURCES ); 6254 } 6255 6256 Status = IoCallDriver( Vcb->TargetDeviceObject, IoIrp ); 6257 6258 if (Status == STATUS_PENDING) { 6259 6260 (VOID)KeWaitForSingleObject( &IoEvent, 6261 Executive, 6262 KernelMode, 6263 FALSE, 6264 (PLARGE_INTEGER)NULL ); 6265 6266 Status = Iosb.Status; 6267 } 6268 6269 if (!NT_SUCCESS( Status )) { 6270 6271 FatNormalizeAndRaiseStatus( IrpContext, 6272 Status ); 6273 } 6274 6275 // 6276 // Write the data to its new location. 6277 // 6278 6279 KeClearEvent( &IoEvent ); 6280 6281 IoIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, 6282 Vcb->TargetDeviceObject, 6283 Buffer, 6284 BytesToWrite, 6285 &LargeTargetLbo, 6286 &IoEvent, 6287 &Iosb ); 6288 6289 if (IoIrp == NULL) { 6290 6291 FatRaiseStatus( IrpContext, 6292 STATUS_INSUFFICIENT_RESOURCES ); 6293 } 6294 6295 // 6296 // Set a flag indicating that we want to write through any 6297 // cache on the controller. This eliminates the need for 6298 // an explicit flush-device after the write. 6299 // 6300 6301 SetFlag( IoGetNextIrpStackLocation(IoIrp)->Flags, SL_WRITE_THROUGH ); 6302 6303 Status = IoCallDriver( Vcb->TargetDeviceObject, IoIrp ); 6304 6305 if (Status == STATUS_PENDING) { 6306 6307 (VOID)KeWaitForSingleObject( &IoEvent, 6308 Executive, 6309 KernelMode, 6310 FALSE, 6311 (PLARGE_INTEGER)NULL ); 6312 6313 Status = Iosb.Status; 6314 } 6315 6316 if (!NT_SUCCESS( Status )) { 6317 6318 FatNormalizeAndRaiseStatus( IrpContext, 6319 Status ); 6320 } 6321 } 6322 6323 // 6324 // Now that the file data has been moved successfully, we'll go 6325 // to fix up the links in the FAT table and perhaps change the 6326 // entry in the parent directory. 6327 // 6328 // First we'll do the second splice and commit it. At that point, 6329 // while the volume is in an inconsistent state, the file is 6330 // still OK. 6331 // 6332 6333 FatSetFatEntry( IrpContext, 6334 Vcb, 6335 SecondSpliceSourceCluster, 6336 (FAT_ENTRY)SecondSpliceTargetCluster ); 6337 6338 if ((FcbOrDcb->Header.ValidDataLength.QuadPart != 0) || (NodeType(FcbOrDcb) != FAT_NTC_FCB)) { 6339 6340 FatFlushFatEntries( IrpContext, Vcb, SecondSpliceSourceCluster, 1 ); 6341 } 6342 6343 // 6344 // Now do the first splice OR update the dirent in the parent 6345 // and flush the respective object. After this flush the file 6346 // now points to the new allocation. 6347 // 6348 6349 if (FirstSpliceSourceCluster == 0) { 6350 6351 NT_ASSERT( NodeType(FcbOrDcb) == FAT_NTC_FCB ); 6352 6353 // 6354 // We are moving the first cluster of the file, so we need 6355 // to update our parent directory. 6356 // 6357 6358 FatGetDirentFromFcbOrDcb( IrpContext, 6359 FcbOrDcb, 6360 FALSE, 6361 &Dirent, 6362 &DirentBcb ); 6363 6364 Dirent->FirstClusterOfFile = (USHORT)FirstSpliceTargetCluster; 6365 6366 if (FatIsFat32(Vcb)) { 6367 6368 Dirent->FirstClusterOfFileHi = 6369 (USHORT)(FirstSpliceTargetCluster >> 16); 6370 6371 } 6372 6373 FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE ); 6374 6375 FatUnpinBcb( IrpContext, DirentBcb ); 6376 DirentBcb = NULL; 6377 6378 FatFlushDirentForFile( IrpContext, FcbOrDcb ); 6379 6380 FcbOrDcb->FirstClusterOfFile = FirstSpliceTargetCluster; 6381 6382 } else { 6383 6384 FatSetFatEntry( IrpContext, 6385 Vcb, 6386 FirstSpliceSourceCluster, 6387 (FAT_ENTRY)FirstSpliceTargetCluster ); 6388 6389 if ((FcbOrDcb->Header.ValidDataLength.QuadPart != 0) || (NodeType(FcbOrDcb) != FAT_NTC_FCB)) { 6390 6391 FatFlushFatEntries( IrpContext, Vcb, FirstSpliceSourceCluster, 1 ); 6392 } 6393 } 6394 6395 // 6396 // This was successfully committed. We no longer want to free 6397 // this allocation on error. 6398 // 6399 6400 DiskSpaceAllocated = FALSE; 6401 6402 // 6403 // Check if we need to turn off write through for this file. 6404 // 6405 6406 FatMoveFileNeedsWriteThrough(IrpContext, FcbOrDcb, OldWriteThroughFlags); 6407 6408 // 6409 // Now we just have to free the orphaned space. We don't have 6410 // to commit this right now as the integrity of the file doesn't 6411 // depend on it. 6412 // 6413 6414 FatDeallocateDiskSpace( IrpContext, Vcb, &SourceMcb, FALSE ); 6415 6416 FatUnpinRepinnedBcbs( IrpContext ); 6417 6418 Status = FatHijackIrpAndFlushDevice( IrpContext, 6419 Irp, 6420 Vcb->TargetDeviceObject ); 6421 6422 if (!NT_SUCCESS(Status)) { 6423 FatNormalizeAndRaiseStatus( IrpContext, Status ); 6424 } 6425 6426 // 6427 // Finally we must replace the old MCB extent information with 6428 // the new. If this fails from pool allocation, we fix it in 6429 // the finally clause by resetting the file's Mcb. 6430 // 6431 6432 FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 6433 FileOffset, 6434 BytesToReallocate ); 6435 6436 FatAddMcbEntry( Vcb, &FcbOrDcb->Mcb, 6437 FileOffset, 6438 TargetLbo, 6439 BytesToReallocate ); 6440 6441 // 6442 // Now this is the second part of the tricky synchronization. 6443 // 6444 // We drop the paging I/O here and signal the notification 6445 // event which allows all waiters (present or future) to proceed. 6446 // Then we block again on the PagingIo exclusive. When 6447 // we have it, we again know that there can be nobody in the 6448 // read/write path and thus nobody touching the event, so we 6449 // NULL the pointer to it and then drop the PagingIo resource. 6450 // 6451 // This combined with our synchronization before the write above 6452 // guarantees that while we were moving the allocation, there 6453 // was no other I/O to this file and because we do not hold 6454 // the paging resource across a flush, we are not exposed to 6455 // a deadlock. 6456 // 6457 6458 KeSetEvent( &StackEvent, 0, FALSE ); 6459 6460 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE ); 6461 6462 FcbOrDcb->MoveFileEvent = NULL; 6463 EventArmed = FALSE; 6464 6465 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource ); 6466 6467 // 6468 // Release the resources and let anyone else access the file before 6469 // looping back. 6470 // 6471 6472 FatReleaseFcb( IrpContext, FcbOrDcb ); 6473 FcbAcquired = FALSE; 6474 6475 // 6476 // Advance the state variables. 6477 // 6478 6479 TargetCluster += BytesToReallocate >> ClusterShift; 6480 6481 FileOffset += BytesToReallocate; 6482 TargetLbo += BytesToReallocate; 6483 ByteCount -= BytesToReallocate; 6484 6485 LargeTargetLbo.QuadPart += BytesToReallocate; 6486 6487 // 6488 // Clear the two Mcbs 6489 // 6490 6491 FatRemoveMcbEntry( Vcb, &SourceMcb, 0, 0xFFFFFFFF ); 6492 FatRemoveMcbEntry( Vcb, &TargetMcb, 0, 0xFFFFFFFF ); 6493 6494 // 6495 // Make the event blockable again. 6496 // 6497 6498 KeClearEvent( &StackEvent ); 6499 } 6500 6501 Status = STATUS_SUCCESS; 6502 6503 try_exit: NOTHING; 6504 6505 } _SEH2_FINALLY { 6506 6507 DebugUnwind( FatMoveFile ); 6508 6509 LocalAbnormalTermination |= _SEH2_AbnormalTermination(); 6510 6511 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD ); 6512 6513 // 6514 // Free the data buffer, if it was allocated. 6515 // 6516 6517 if (Buffer != NULL) { 6518 6519 ExFreePool( Buffer ); 6520 } 6521 6522 // 6523 // Use a nested try-finally for cleanup if our unpinrepinned 6524 // encounters write-through errors. This may even be a re-raise. 6525 // 6526 6527 _SEH2_TRY { 6528 6529 // 6530 // If we have some new allocation hanging around, remove it. The 6531 // pages needed to do this are guaranteed to be resident because 6532 // we have already repinned them. 6533 // 6534 6535 if (DiskSpaceAllocated) { 6536 FatDeallocateDiskSpace( IrpContext, Vcb, &TargetMcb, FALSE ); 6537 FatUnpinRepinnedBcbs( IrpContext ); 6538 } 6539 6540 } _SEH2_FINALLY { 6541 6542 LocalAbnormalTermination |= _SEH2_AbnormalTermination(); 6543 6544 // 6545 // Check on the directory Bcb 6546 // 6547 6548 if (DirentBcb != NULL) { 6549 FatUnpinBcb( IrpContext, DirentBcb ); 6550 } 6551 6552 // 6553 // Uninitialize our MCBs 6554 // 6555 6556 if (SourceMcbInitialized) { 6557 FsRtlUninitializeLargeMcb( &SourceMcb ); 6558 } 6559 6560 if (TargetMcbInitialized) { 6561 FsRtlUninitializeLargeMcb( &TargetMcb ); 6562 } 6563 6564 // 6565 // If this is an abnormal termination then presumably something 6566 // bad happened. Set the Allocation size to unknown and clear 6567 // the Mcb, but only if we still own the Fcb. 6568 // 6569 // It is important to make sure we use a 64bit form of -1. This is 6570 // what will convince the fastIO path that it cannot extend the file 6571 // in the cache until we have picked up the mapping pairs again. 6572 // 6573 // Also, we have to do this while owning PagingIo or we can tear the 6574 // Mcb down in the midst of the noncached IO path looking up extents 6575 // (after we drop it and let them all in). 6576 // 6577 6578 if (LocalAbnormalTermination && FcbAcquired) { 6579 6580 if (FcbOrDcb->FirstClusterOfFile == 0) { 6581 6582 FcbOrDcb->Header.AllocationSize.QuadPart = 0; 6583 6584 } else { 6585 6586 FcbOrDcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT; 6587 } 6588 6589 FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF ); 6590 } 6591 6592 // 6593 // If we broke out of the loop with the Event armed, defuse it 6594 // in the same way we do it after a write. 6595 // 6596 6597 if (EventArmed) { 6598 KeSetEvent( &StackEvent, 0, FALSE ); 6599 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE ); 6600 FcbOrDcb->MoveFileEvent = NULL; 6601 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource ); 6602 } 6603 6604 // 6605 // Finally release the main file resource. 6606 // 6607 6608 if (FcbAcquired) { 6609 6610 FatReleaseFcb( IrpContext, FcbOrDcb ); 6611 } 6612 6613 // 6614 // Now dereference the fileobject. If the user was a wacko they could have 6615 // tried to nail us by closing the handle right after they threw this move 6616 // down, so we had to keep the fileobject referenced across the entire 6617 // operation. 6618 // 6619 6620 ObDereferenceObject( FileObject ); 6621 6622 } _SEH2_END; 6623 } _SEH2_END; 6624 6625 // 6626 // Complete the irp if we terminated normally. 6627 // 6628 6629 FatCompleteRequest( IrpContext, Irp, Status ); 6630 6631 return Status; 6632 } 6633 6634 6635 // 6636 // Local Support Routine 6637 // 6638 6639 _Requires_lock_held_(_Global_critical_region_) 6640 VOID 6641 FatComputeMoveFileParameter ( 6642 IN PIRP_CONTEXT IrpContext, 6643 IN PFCB FcbOrDcb, 6644 IN ULONG BufferSize, 6645 IN ULONG FileOffset, 6646 IN OUT PULONG ByteCount, 6647 OUT PULONG BytesToReallocate, 6648 OUT PULONG BytesToWrite, 6649 OUT PLARGE_INTEGER SourceLbo 6650 ) 6651 6652 /*++ 6653 6654 Routine Description: 6655 6656 This is a helper routine for FatMoveFile that analyses the range of 6657 file allocation we are moving and determines the actual amount 6658 of allocation to be moved and how much needs to be written. 6659 6660 Arguments: 6661 6662 FcbOrDcb - Supplies the file and its various sizes. 6663 6664 BufferSize - Supplies the size of the buffer we are using to store the data 6665 being moved. 6666 6667 FileOffset - Supplies the beginning Vbo of the reallocation zone. 6668 6669 ByteCount - Supplies the request length to reallocate. This will 6670 be bounded by allocation size on return. 6671 6672 BytesToReallocate - Receives ByteCount bounded by the file allocation size 6673 and buffer size. 6674 6675 BytesToWrite - Receives BytesToReallocate bounded by ValidDataLength. 6676 6677 SourceLbo - Receives the logical byte offset of the source data on the volume. 6678 6679 Return Value: 6680 6681 VOID 6682 6683 --*/ 6684 6685 { 6686 ULONG ClusterSize; 6687 6688 ULONG AllocationSize; 6689 ULONG ValidDataLength; 6690 ULONG ClusterAlignedVDL; 6691 LBO RunLbo; 6692 ULONG RunByteCount; 6693 ULONG RunIndex; 6694 BOOLEAN RunAllocated; 6695 BOOLEAN RunEndOnMax; 6696 6697 PAGED_CODE(); 6698 6699 // 6700 // If we haven't yet set the correct AllocationSize, do so. 6701 // 6702 6703 if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) { 6704 6705 FatLookupFileAllocationSize( IrpContext, FcbOrDcb ); 6706 6707 // 6708 // If this is a non-root directory, we have a bit more to 6709 // do since it has not gone through FatOpenDirectoryFile(). 6710 // 6711 6712 if (NodeType(FcbOrDcb) == FAT_NTC_DCB || 6713 (NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && FatIsFat32(FcbOrDcb->Vcb))) { 6714 6715 FcbOrDcb->Header.FileSize.LowPart = 6716 FcbOrDcb->Header.AllocationSize.LowPart; 6717 } 6718 } 6719 6720 // 6721 // Get the number of bytes left to write and ensure that it does 6722 // not extend beyond allocation size. We return here if FileOffset 6723 // is beyond AllocationSize which can happn on a truncation. 6724 // 6725 6726 AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart; 6727 ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart; 6728 6729 if (FileOffset + *ByteCount > AllocationSize) { 6730 6731 if (FileOffset >= AllocationSize) { 6732 *ByteCount = 0; 6733 *BytesToReallocate = 0; 6734 *BytesToWrite = 0; 6735 6736 return; 6737 } 6738 6739 *ByteCount = AllocationSize - FileOffset; 6740 } 6741 6742 // 6743 // If there is more than our max, then reduce the byte count for this 6744 // pass to our maximum. We must also align the file offset to a 6745 // buffer size byte boundary. 6746 // 6747 6748 if ((FileOffset & (BufferSize - 1)) + *ByteCount > BufferSize) { 6749 6750 *BytesToReallocate = BufferSize - (FileOffset & (BufferSize - 1)); 6751 6752 } else { 6753 6754 *BytesToReallocate = *ByteCount; 6755 } 6756 6757 // 6758 // Find where this data exists on the volume. 6759 // 6760 6761 FatLookupFileAllocation( IrpContext, 6762 FcbOrDcb, 6763 FileOffset, 6764 &RunLbo, 6765 &RunByteCount, 6766 &RunAllocated, 6767 &RunEndOnMax, 6768 &RunIndex ); 6769 6770 NT_ASSERT( RunAllocated ); 6771 6772 // 6773 // Limit this run to the contiguous length. 6774 // 6775 6776 if (RunByteCount < *BytesToReallocate) { 6777 6778 *BytesToReallocate = RunByteCount; 6779 } 6780 6781 // 6782 // Set the starting offset of the source. 6783 // 6784 6785 SourceLbo->QuadPart = RunLbo; 6786 6787 // 6788 // We may be able to skip some (or all) of the write 6789 // if allocation size is significantly greater than valid data length. 6790 // 6791 6792 ClusterSize = 1 << FcbOrDcb->Vcb->AllocationSupport.LogOfBytesPerCluster; 6793 6794 NT_ASSERT( ClusterSize <= BufferSize ); 6795 6796 ClusterAlignedVDL = (ValidDataLength + (ClusterSize - 1)) & ~(ClusterSize - 1); 6797 6798 if ((NodeType(FcbOrDcb) == FAT_NTC_FCB) && 6799 (FileOffset + *BytesToReallocate > ClusterAlignedVDL)) { 6800 6801 if (FileOffset > ClusterAlignedVDL) { 6802 6803 *BytesToWrite = 0; 6804 6805 } else { 6806 6807 *BytesToWrite = ClusterAlignedVDL - FileOffset; 6808 } 6809 6810 } else { 6811 6812 *BytesToWrite = *BytesToReallocate; 6813 } 6814 } 6815 6816 6817 // 6818 // Local Support Routine 6819 // 6820 6821 VOID 6822 FatComputeMoveFileSplicePoints ( 6823 IN PIRP_CONTEXT IrpContext, 6824 IN PFCB FcbOrDcb, 6825 IN ULONG FileOffset, 6826 IN ULONG TargetCluster, 6827 IN ULONG BytesToReallocate, 6828 OUT PULONG FirstSpliceSourceCluster, 6829 OUT PULONG FirstSpliceTargetCluster, 6830 OUT PULONG SecondSpliceSourceCluster, 6831 OUT PULONG SecondSpliceTargetCluster, 6832 IN OUT PLARGE_MCB SourceMcb 6833 ) 6834 6835 /*++ 6836 6837 Routine Description: 6838 6839 This is a helper routine for FatMoveFile that analyzes the range of 6840 file allocation we are moving and generates the splice points in the 6841 FAT table. 6842 6843 Arguments: 6844 6845 FcbOrDcb - Supplies the file and thus Mcb. 6846 6847 FileOffset - Supplies the beginning Vbo of the reallocation zone. 6848 6849 TargetCluster - Supplies the beginning cluster of the reallocation target. 6850 6851 BytesToReallocate - Suppies the length of the reallocation zone. 6852 6853 FirstSpliceSourceCluster - Receives the last cluster in previous allocation 6854 or zero if we are reallocating from VBO 0. 6855 6856 FirstSpliceTargetCluster - Receives the target cluster (i.e. new allocation) 6857 6858 SecondSpliceSourceCluster - Receives the final target cluster. 6859 6860 SecondSpliceTargetCluster - Receives the first cluster of the remaining 6861 source allocation or FAT_CLUSTER_LAST if the reallocation zone 6862 extends to the end of the file. 6863 6864 SourceMcb - This supplies an MCB that will be filled in with run 6865 information describing the file allocation being replaced. The Mcb 6866 must be initialized by the caller. 6867 6868 Return Value: 6869 6870 VOID 6871 6872 --*/ 6873 6874 { 6875 VBO SourceVbo; 6876 LBO SourceLbo; 6877 ULONG SourceIndex; 6878 ULONG SourceBytesInRun; 6879 ULONG SourceBytesRemaining; 6880 6881 ULONG SourceMcbVbo = 0; 6882 ULONG SourceMcbBytesInRun = 0; 6883 6884 PVCB Vcb; 6885 BOOLEAN Result; 6886 6887 PAGED_CODE(); 6888 6889 Vcb = FcbOrDcb->Vcb; 6890 6891 // 6892 // Get information on the final cluster in the previous allocation and 6893 // prepare to enumerate it in the follow loop. 6894 // 6895 6896 if (FileOffset == 0) { 6897 6898 SourceIndex = 0; 6899 *FirstSpliceSourceCluster = 0; 6900 Result = FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb, 6901 0, 6902 &SourceVbo, 6903 &SourceLbo, 6904 &SourceBytesInRun ); 6905 6906 } else { 6907 6908 Result = FatLookupMcbEntry( Vcb, &FcbOrDcb->Mcb, 6909 FileOffset-1, 6910 &SourceLbo, 6911 &SourceBytesInRun, 6912 &SourceIndex); 6913 6914 *FirstSpliceSourceCluster = FatGetIndexFromLbo( Vcb, SourceLbo ); 6915 6916 if ((Result) && (SourceBytesInRun == 1)) { 6917 6918 SourceIndex += 1; 6919 Result = FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb, 6920 SourceIndex, 6921 &SourceVbo, 6922 &SourceLbo, 6923 &SourceBytesInRun); 6924 6925 } else { 6926 6927 SourceVbo = FileOffset; 6928 SourceLbo += 1; 6929 SourceBytesInRun -= 1; 6930 } 6931 } 6932 6933 // 6934 // Run should always be present, but don't bugcheck in the case where it's not. 6935 // 6936 6937 if (!Result) { 6938 6939 NT_ASSERT( FALSE); 6940 FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR); 6941 } 6942 6943 // 6944 // At this point the variables: 6945 // 6946 // - SourceIndex - SourceLbo - SourceBytesInRun - 6947 // 6948 // all correctly decribe the allocation to be removed. In the loop 6949 // below we will start here and continue enumerating the Mcb runs 6950 // until we are finished with the allocation to be relocated. 6951 // 6952 6953 *FirstSpliceTargetCluster = TargetCluster; 6954 6955 *SecondSpliceSourceCluster = 6956 *FirstSpliceTargetCluster + 6957 (BytesToReallocate >> Vcb->AllocationSupport.LogOfBytesPerCluster) - 1; 6958 6959 for (SourceBytesRemaining = BytesToReallocate, SourceMcbVbo = 0; 6960 6961 SourceBytesRemaining > 0; 6962 6963 SourceIndex += 1, 6964 SourceBytesRemaining -= SourceMcbBytesInRun, 6965 SourceMcbVbo += SourceMcbBytesInRun) { 6966 6967 if (SourceMcbVbo != 0) { 6968 #ifdef _MSC_VER 6969 #pragma prefast( suppress:28931, "needed for debug build" ) 6970 #endif 6971 Result = FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb, 6972 SourceIndex, 6973 &SourceVbo, 6974 &SourceLbo, 6975 &SourceBytesInRun ); 6976 NT_ASSERT( Result); 6977 } 6978 6979 NT_ASSERT( SourceVbo == SourceMcbVbo + FileOffset ); 6980 6981 SourceMcbBytesInRun = 6982 SourceBytesInRun < SourceBytesRemaining ? 6983 SourceBytesInRun : SourceBytesRemaining; 6984 6985 FatAddMcbEntry( Vcb, SourceMcb, 6986 SourceMcbVbo, 6987 SourceLbo, 6988 SourceMcbBytesInRun ); 6989 } 6990 6991 // 6992 // Now compute the cluster of the target of the second 6993 // splice. If the final run in the above loop was 6994 // more than we needed, then we can just do arithmetic, 6995 // otherwise we have to look up the next run. 6996 // 6997 6998 if (SourceMcbBytesInRun < SourceBytesInRun) { 6999 7000 *SecondSpliceTargetCluster = 7001 FatGetIndexFromLbo( Vcb, SourceLbo + SourceMcbBytesInRun ); 7002 7003 } else { 7004 7005 if (FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb, 7006 SourceIndex, 7007 &SourceVbo, 7008 &SourceLbo, 7009 &SourceBytesInRun )) { 7010 7011 *SecondSpliceTargetCluster = FatGetIndexFromLbo( Vcb, SourceLbo ); 7012 7013 } else { 7014 7015 *SecondSpliceTargetCluster = FAT_CLUSTER_LAST; 7016 } 7017 } 7018 } 7019 7020 7021 NTSTATUS 7022 FatAllowExtendedDasdIo( 7023 IN PIRP_CONTEXT IrpContext, 7024 IN PIRP Irp 7025 ) 7026 /*++ 7027 7028 Routine Description: 7029 7030 This routine marks the CCB to indicate that the handle 7031 may be used to read past the end of the volume file. The 7032 handle must be a dasd handle. 7033 7034 Arguments: 7035 7036 Irp - Supplies the Irp being processed. 7037 7038 Return Value: 7039 7040 NTSTATUS - The return status for the operation. 7041 7042 --*/ 7043 { 7044 PIO_STACK_LOCATION IrpSp; 7045 PVCB Vcb; 7046 PFCB Fcb; 7047 PCCB Ccb; 7048 7049 PAGED_CODE(); 7050 7051 // 7052 // Get the current Irp stack location and save some references. 7053 // 7054 7055 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 7056 7057 // 7058 // Extract and decode the file object and check for type of open. 7059 // 7060 7061 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 7062 7063 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7064 return STATUS_INVALID_PARAMETER; 7065 } 7066 7067 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 7068 7069 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7070 7071 DebugTrace(-1, Dbg, "FatAllowExtendedDasdIo -> %08lx\n", STATUS_INVALID_PARAMETER); 7072 return STATUS_INVALID_PARAMETER; 7073 } 7074 7075 SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO ); 7076 7077 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 7078 return STATUS_SUCCESS; 7079 } 7080 7081 #if (NTDDI_VERSION >= NTDDI_WIN7) 7082 7083 _Requires_lock_held_(_Global_critical_region_) 7084 NTSTATUS 7085 FatGetRetrievalPointerBase ( 7086 _In_ PIRP_CONTEXT IrpContext, 7087 _In_ PIRP Irp 7088 ) 7089 /*++ 7090 7091 Routine Description: 7092 7093 This routine retrieves the sector offset to the first allocation unit. 7094 7095 Arguments: 7096 7097 IrpContext - Supplies the Irp Context. 7098 Irp - Supplies the Irp being processed. 7099 7100 Return Value: 7101 7102 NTSTATUS - The return status for the operation. 7103 7104 --*/ 7105 { 7106 PIO_STACK_LOCATION IrpSp = NULL; 7107 PVCB Vcb = NULL; 7108 PFCB Fcb = NULL; 7109 PCCB Ccb = NULL; 7110 ULONG BufferLength = 0; 7111 PRETRIEVAL_POINTER_BASE RetrievalPointerBase = NULL; 7112 7113 PAGED_CODE(); 7114 7115 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 7116 7117 // 7118 // Force WAIT to true. 7119 // 7120 7121 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 7122 7123 // 7124 // Extract and decode the file object and check for type of open. 7125 // 7126 7127 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 7128 7129 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7130 return STATUS_INVALID_PARAMETER; 7131 } 7132 7133 // 7134 // Extract the buffer 7135 // 7136 7137 RetrievalPointerBase = Irp->AssociatedIrp.SystemBuffer; 7138 BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 7139 7140 // 7141 // Verify the handle has manage volume access. 7142 // 7143 7144 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 7145 7146 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7147 return STATUS_INVALID_PARAMETER; 7148 } 7149 7150 // 7151 // Validate the output buffer is the right size. 7152 // 7153 // Note that the default size of BOOT_AREA_INFO has enough room for 2 boot sectors, so we're fine. 7154 // 7155 7156 if (BufferLength < sizeof(RETRIEVAL_POINTER_BASE)) { 7157 7158 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 7159 return STATUS_BUFFER_TOO_SMALL; 7160 } 7161 7162 // 7163 // Fill out the offset to the file area. 7164 // 7165 7166 RtlZeroMemory( RetrievalPointerBase, BufferLength ); 7167 7168 try { 7169 7170 FatAcquireSharedVcb(IrpContext, Vcb); 7171 FatQuickVerifyVcb(IrpContext, Vcb); 7172 7173 RetrievalPointerBase->FileAreaOffset.QuadPart = Vcb->AllocationSupport.FileAreaLbo >> Vcb->AllocationSupport.LogOfBytesPerSector; 7174 Irp->IoStatus.Information = sizeof( RETRIEVAL_POINTER_BASE ); 7175 7176 } finally { 7177 7178 FatReleaseVcb(IrpContext, Vcb); 7179 7180 } 7181 7182 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 7183 7184 return STATUS_SUCCESS; 7185 7186 } 7187 7188 7189 _Requires_lock_held_(_Global_critical_region_) 7190 NTSTATUS 7191 FatGetBootAreaInfo ( 7192 _In_ PIRP_CONTEXT IrpContext, 7193 _In_ PIRP Irp 7194 ) 7195 /*++ 7196 7197 Routine Description: 7198 7199 This routine retrieves information about the boot areas of the filesystem. 7200 7201 Arguments: 7202 7203 IrpContext - Supplies the Irp Context. 7204 Irp - Supplies the Irp being processed. 7205 7206 Return Value: 7207 7208 NTSTATUS - The return status for the operation. 7209 7210 --*/ 7211 { 7212 PIO_STACK_LOCATION IrpSp = NULL; 7213 PVCB Vcb = NULL; 7214 PFCB Fcb = NULL; 7215 PCCB Ccb = NULL; 7216 ULONG BufferLength = 0; 7217 PBOOT_AREA_INFO BootAreaInfo = NULL; 7218 7219 PAGED_CODE(); 7220 7221 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 7222 7223 // 7224 // Force WAIT to true. 7225 // 7226 7227 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 7228 7229 // 7230 // Extract and decode the file object and check for type of open. 7231 // 7232 7233 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 7234 7235 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7236 return STATUS_INVALID_PARAMETER; 7237 } 7238 7239 // 7240 // Extract the buffer 7241 // 7242 7243 BootAreaInfo = Irp->AssociatedIrp.SystemBuffer; 7244 BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 7245 7246 // 7247 // Verify the handle has manage volume access. 7248 // 7249 7250 if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 7251 7252 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7253 return STATUS_INVALID_PARAMETER; 7254 } 7255 7256 // 7257 // Validate the output buffer is the right size. 7258 // 7259 // Note that the default size of BOOT_AREA_INFO has enough room for 2 boot sectors, so we're fine. 7260 // 7261 7262 if (BufferLength < sizeof(BOOT_AREA_INFO)) { 7263 7264 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 7265 return STATUS_BUFFER_TOO_SMALL; 7266 } 7267 7268 // 7269 // Fill out our boot areas. 7270 // 7271 7272 RtlZeroMemory( BootAreaInfo, BufferLength ); 7273 7274 try { 7275 7276 FatAcquireSharedVcb(IrpContext, Vcb); 7277 FatQuickVerifyVcb(IrpContext, Vcb); 7278 7279 if (FatIsFat32( Vcb )) { 7280 7281 BootAreaInfo->BootSectorCount = 2; 7282 BootAreaInfo->BootSectors[0].Offset.QuadPart = 0; 7283 BootAreaInfo->BootSectors[1].Offset.QuadPart = 6; 7284 } else { 7285 7286 BootAreaInfo->BootSectorCount = 1; 7287 BootAreaInfo->BootSectors[0].Offset.QuadPart = 0; 7288 } 7289 7290 Irp->IoStatus.Information = sizeof( BOOT_AREA_INFO ); 7291 7292 } finally { 7293 7294 FatReleaseVcb(IrpContext, Vcb); 7295 } 7296 7297 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 7298 return STATUS_SUCCESS; 7299 } 7300 7301 #endif 7302 7303 7304 _Requires_lock_held_(_Global_critical_region_) 7305 NTSTATUS 7306 FatMarkHandle ( 7307 _In_ PIRP_CONTEXT IrpContext, 7308 _In_ PIRP Irp 7309 ) 7310 /*++ 7311 7312 Routine Description: 7313 7314 This routine is used to attach special properties to a user handle. 7315 7316 Arguments: 7317 7318 IrpContext - Supplies the Irp Context. 7319 Irp - Supplies the Irp being processed. 7320 7321 Return Value: 7322 7323 NTSTATUS - The return status for the operation. 7324 7325 --*/ 7326 { 7327 NTSTATUS Status = STATUS_SUCCESS; 7328 PIO_STACK_LOCATION IrpSp = NULL; 7329 PVCB Vcb = NULL; 7330 PFCB Fcb = NULL; 7331 PCCB Ccb = NULL; 7332 PFCB DasdFcb = NULL; 7333 PCCB DasdCcb = NULL; 7334 TYPE_OF_OPEN TypeOfOpen; 7335 PMARK_HANDLE_INFO HandleInfo = NULL; 7336 PFILE_OBJECT DasdFileObject = NULL; 7337 BOOLEAN ReleaseFcb = FALSE; 7338 7339 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 7340 MARK_HANDLE_INFO LocalMarkHandleInfo = {0}; 7341 #endif 7342 7343 PAGED_CODE(); 7344 7345 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 7346 7347 // 7348 // Always make this a synchronous IRP. 7349 // 7350 7351 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 7352 7353 // 7354 // Extract and decode the file object and check for type of open. 7355 // 7356 7357 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) ; 7358 7359 // 7360 // We currently support this call for files and directories only. 7361 // 7362 7363 if ((TypeOfOpen != UserFileOpen) && 7364 (TypeOfOpen != UserDirectoryOpen)) { 7365 7366 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7367 return STATUS_INVALID_PARAMETER; 7368 } 7369 7370 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 7371 7372 // 7373 // Win32/64 thunking code 7374 // 7375 7376 if (IoIs32bitProcess( Irp )) { 7377 7378 PMARK_HANDLE_INFO32 MarkHandle32; 7379 7380 if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO32 )) { 7381 7382 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 7383 return STATUS_BUFFER_TOO_SMALL; 7384 } 7385 7386 MarkHandle32 = (PMARK_HANDLE_INFO32) Irp->AssociatedIrp.SystemBuffer; 7387 LocalMarkHandleInfo.HandleInfo = MarkHandle32->HandleInfo; 7388 LocalMarkHandleInfo.UsnSourceInfo = MarkHandle32->UsnSourceInfo; 7389 LocalMarkHandleInfo.VolumeHandle = (HANDLE)(ULONG_PTR)(LONG) MarkHandle32->VolumeHandle; 7390 7391 HandleInfo = &LocalMarkHandleInfo; 7392 7393 } else { 7394 7395 #endif 7396 7397 // 7398 // Get the input buffer pointer and check its length. 7399 // 7400 7401 if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO )) { 7402 7403 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 7404 return STATUS_BUFFER_TOO_SMALL; 7405 } 7406 7407 HandleInfo = (PMARK_HANDLE_INFO) Irp->AssociatedIrp.SystemBuffer; 7408 7409 #if defined(_WIN64) && defined(BUILD_WOW64_ENABLED) 7410 } 7411 #endif 7412 7413 // 7414 // Check that only legal bits are being set. 7415 // We currently only support two bits: protect clusters and unprotect clusters. 7416 // 7417 // Note that we don't actually support the USN journal, but we must ignore the flags in order 7418 // to preserve compatibility. 7419 // 7420 7421 if (FlagOn( HandleInfo->HandleInfo, 7422 ~(MARK_HANDLE_PROTECT_CLUSTERS)) || 7423 (FlagOn( HandleInfo->HandleInfo, 7424 0 ) && 7425 (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL)) || 7426 FlagOn(HandleInfo->UsnSourceInfo, 7427 ~(USN_SOURCE_DATA_MANAGEMENT | 7428 USN_SOURCE_AUXILIARY_DATA | 7429 USN_SOURCE_REPLICATION_MANAGEMENT) ) ) { 7430 7431 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7432 return STATUS_INVALID_PARAMETER; 7433 } 7434 7435 // 7436 // Check that the user has a valid volume handle or the manage volume 7437 // privilege or is a kernel mode caller 7438 // 7439 // NOTE: the kernel mode check is only valid because the rdr doesn't support this 7440 // FSCTL. 7441 // 7442 7443 if ((Irp->RequestorMode != KernelMode) && 7444 (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL) && 7445 !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ) && 7446 ( FlagOn( HandleInfo->HandleInfo, MARK_HANDLE_PROTECT_CLUSTERS ) || (HandleInfo->UsnSourceInfo != 0) )) { 7447 7448 if (HandleInfo->VolumeHandle == 0) { 7449 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); 7450 return STATUS_ACCESS_DENIED; 7451 } 7452 7453 Status = ObReferenceObjectByHandle( HandleInfo->VolumeHandle, 7454 0, 7455 *IoFileObjectType, 7456 UserMode, 7457 #ifndef __REACTOS__ 7458 &DasdFileObject, 7459 #else 7460 (PVOID *)&DasdFileObject, 7461 #endif 7462 NULL ); 7463 7464 if (!NT_SUCCESS(Status)) { 7465 7466 FatCompleteRequest( IrpContext, Irp, Status ); 7467 return Status; 7468 } 7469 7470 // 7471 // Check that this file object is opened on the same volume as the 7472 // handle used to call this routine. 7473 // 7474 7475 if (DasdFileObject->Vpb != Vcb->Vpb) { 7476 7477 ObDereferenceObject( DasdFileObject ); 7478 7479 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7480 return STATUS_INVALID_PARAMETER; 7481 } 7482 7483 // 7484 // Now decode this FileObject and verify it is a volume handle. 7485 // We don't care to raise on dismounts here because 7486 // we check for that further down anyway. So send FALSE. 7487 // 7488 7489 #ifdef _MSC_VER 7490 #pragma prefast( suppress:28931, "convenient for debugging" ) 7491 #endif 7492 TypeOfOpen = FatDecodeFileObject( DasdFileObject, &Vcb, &DasdFcb, &DasdCcb ) ; 7493 7494 ObDereferenceObject( DasdFileObject ); 7495 7496 if ((DasdCcb == NULL) || !FlagOn( DasdCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) { 7497 7498 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); 7499 return STATUS_ACCESS_DENIED; 7500 } 7501 7502 } 7503 7504 _SEH2_TRY { 7505 7506 FatAcquireExclusiveFcb(IrpContext, Fcb); 7507 ReleaseFcb = TRUE; 7508 7509 FatVerifyFcb( IrpContext, Fcb ); 7510 7511 if (HandleInfo->HandleInfo & MARK_HANDLE_PROTECT_CLUSTERS) { 7512 7513 if (Fcb->FcbState & FCB_STATE_DENY_DEFRAG) { 7514 7515 // 7516 // It's already set, bail out. 7517 // 7518 7519 try_return( Status = STATUS_ACCESS_DENIED ); 7520 } 7521 7522 Ccb->Flags |= CCB_FLAG_DENY_DEFRAG; 7523 Fcb->FcbState|= FCB_STATE_DENY_DEFRAG; 7524 7525 } 7526 7527 try_exit: NOTHING; 7528 7529 } _SEH2_FINALLY { 7530 7531 if (ReleaseFcb) { 7532 7533 FatReleaseFcb(IrpContext, Fcb); 7534 } 7535 7536 } _SEH2_END; 7537 7538 FatCompleteRequest( IrpContext, Irp, Status ); 7539 return Status; 7540 } 7541 7542 7543 _Requires_lock_held_(_Global_critical_region_) 7544 VOID 7545 FatFlushAndCleanVolume( 7546 IN PIRP_CONTEXT IrpContext, 7547 IN PIRP Irp, 7548 IN PVCB Vcb, 7549 IN FAT_FLUSH_TYPE FlushType 7550 ) 7551 /*++ 7552 7553 Routine Description: 7554 7555 This routine flushes and otherwise preparse a volume to be eligible 7556 for deletion. The dismount and PNP paths share the need for this 7557 common work. 7558 7559 The Vcb will always be valid on return from this function. It is the 7560 caller's responsibility to attempt the dismount/deletion, and to setup 7561 allocation support again if the volume will be brought back from the 7562 brink. 7563 7564 Arguments: 7565 7566 Irp - Irp for the overlying request 7567 7568 Vcb - the volume being operated on 7569 7570 FlushType - specifies the kind of flushing desired 7571 7572 Return Value: 7573 7574 NTSTATUS - The return status for the operation. 7575 7576 --*/ 7577 { 7578 PAGED_CODE(); 7579 7580 // 7581 // The volume must be held exclusive. 7582 // 7583 7584 NT_ASSERT( FatVcbAcquiredExclusive( IrpContext, Vcb )); 7585 7586 // 7587 // There is no fail, flush everything. If invalidating, it is important 7588 // that we invalidate as we flush (eventually, w/ paging io held) so that we 7589 // error out the maximum number of late writes. 7590 // 7591 7592 if (FlushType != NoFlush) { 7593 7594 (VOID) FatFlushVolume( IrpContext, Vcb, FlushType ); 7595 } 7596 7597 FatCloseEaFile( IrpContext, Vcb, FALSE ); 7598 7599 // 7600 // Now, tell the device to flush its buffers. 7601 // 7602 7603 if (FlushType != NoFlush) { 7604 7605 (VOID)FatHijackIrpAndFlushDevice( IrpContext, Irp, Vcb->TargetDeviceObject ); 7606 } 7607 7608 // 7609 // Now purge everything in sight. We're trying to provoke as many closes as 7610 // soon as possible, this volume may be on its way out. 7611 // 7612 7613 if (FlushType != FlushWithoutPurge) { 7614 7615 CcPurgeCacheSection( &Vcb->SectionObjectPointers, 7616 NULL, 7617 0, 7618 FALSE ); 7619 7620 (VOID) FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush ); 7621 } 7622 7623 // 7624 // If the volume was dirty and we were allowed to flush, do the processing that 7625 // the delayed callback would have done. 7626 // 7627 7628 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) { 7629 7630 // 7631 // Cancel any pending clean volumes. 7632 // 7633 7634 (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); 7635 (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc ); 7636 7637 7638 if (FlushType != NoFlush) { 7639 7640 // 7641 // The volume is now clean, note it. 7642 // 7643 7644 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { 7645 7646 FatMarkVolume( IrpContext, Vcb, VolumeClean ); 7647 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); 7648 } 7649 7650 // 7651 // Unlock the volume if it is removable. 7652 // 7653 7654 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && 7655 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { 7656 7657 FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); 7658 } 7659 } 7660 } 7661 7662 } 7663 7664 #if (NTDDI_VERSION >= NTDDI_WIN8) 7665 7666 7667 _Requires_lock_held_(_Global_critical_region_) 7668 NTSTATUS 7669 FatSetPurgeFailureMode ( 7670 _In_ PIRP_CONTEXT IrpContext, 7671 _In_ PIRP Irp 7672 ) 7673 /*++ 7674 7675 This routine is used to enable or disable the purge failure mode 7676 on a file. When in this mode the file system will propagate purge 7677 failures encountered during coherency purges. Normally these are 7678 ignored for application compatibilty purposes. Since the normal 7679 behavior can lead to cache incoherency there needs to be a way to 7680 force error propagation, particulary when a filter has mapped a 7681 section for the purposes of scanning the file in the background. 7682 7683 The purge failure mode is a reference count because it is set 7684 per mapped section and there may be multiple sections backed by 7685 the file. 7686 7687 Arguments: 7688 7689 IrpContext - Supplies the Irp Context. 7690 Irp - Supplies the Irp being processed. 7691 7692 Return Value: 7693 7694 NTSTATUS - The return status for the operation. 7695 7696 --*/ 7697 { 7698 NTSTATUS Status = STATUS_SUCCESS; 7699 PIO_STACK_LOCATION IrpSp; 7700 TYPE_OF_OPEN TypeOfOpen; 7701 PVCB Vcb; 7702 PFCB Fcb; 7703 PCCB Ccb; 7704 PSET_PURGE_FAILURE_MODE_INPUT SetPurgeInput; 7705 BOOLEAN FcbAcquired = FALSE; 7706 7707 PAGED_CODE(); 7708 7709 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 7710 7711 // 7712 // Force WAIT to true. 7713 // 7714 7715 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 7716 7717 // 7718 // This has to be a kernel only call. Can't let a user request 7719 // change the purge failure mode count 7720 // 7721 7722 if (Irp->RequestorMode != KernelMode) { 7723 7724 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7725 return STATUS_INVALID_PARAMETER; 7726 } 7727 7728 // 7729 // Extract and decode the file object and check for type of open. 7730 // 7731 7732 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); 7733 7734 if (TypeOfOpen == UserDirectoryOpen) { 7735 7736 FatCompleteRequest( IrpContext, Irp, STATUS_FILE_IS_A_DIRECTORY ); 7737 return STATUS_FILE_IS_A_DIRECTORY; 7738 } 7739 7740 if (TypeOfOpen != UserFileOpen) { 7741 7742 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7743 return STATUS_INVALID_PARAMETER; 7744 } 7745 7746 // 7747 // Get the input buffer pointer and check its length. 7748 // 7749 7750 if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( SET_PURGE_FAILURE_MODE_INPUT )) { 7751 7752 FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL ); 7753 return STATUS_BUFFER_TOO_SMALL; 7754 } 7755 7756 SetPurgeInput = (PSET_PURGE_FAILURE_MODE_INPUT) Irp->AssociatedIrp.SystemBuffer; 7757 7758 if (!FlagOn( SetPurgeInput->Flags, SET_PURGE_FAILURE_MODE_ENABLED | SET_PURGE_FAILURE_MODE_DISABLED )) { 7759 7760 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 7761 return STATUS_INVALID_PARAMETER; 7762 } 7763 7764 try { 7765 7766 // 7767 // Acquire the FCB exclusively to synchronize with coherency flush 7768 // and purge. 7769 // 7770 7771 FatAcquireExclusiveFcb( IrpContext, Fcb ); 7772 FcbAcquired = TRUE; 7773 7774 FatVerifyFcb( IrpContext, Fcb ); 7775 7776 if (FlagOn( SetPurgeInput->Flags, SET_PURGE_FAILURE_MODE_ENABLED )) { 7777 7778 if (Fcb->PurgeFailureModeEnableCount == MAXULONG) { 7779 7780 try_return( Status = STATUS_INVALID_PARAMETER ); 7781 } 7782 7783 Fcb->PurgeFailureModeEnableCount += 1; 7784 7785 } else { 7786 7787 ASSERT( FlagOn( SetPurgeInput->Flags, SET_PURGE_FAILURE_MODE_DISABLED )); 7788 7789 if (Fcb->PurgeFailureModeEnableCount == 0) { 7790 7791 try_return( Status = STATUS_INVALID_PARAMETER ); 7792 } 7793 7794 Fcb->PurgeFailureModeEnableCount -= 1; 7795 } 7796 7797 try_exit: NOTHING; 7798 7799 } finally { 7800 7801 if (FcbAcquired) { 7802 FatReleaseFcb( IrpContext, Fcb ); 7803 } 7804 } 7805 7806 // 7807 // Complete the irp if we terminated normally. 7808 // 7809 7810 FatCompleteRequest( IrpContext, Irp, Status ); 7811 7812 return Status; 7813 } 7814 7815 #endif 7816 7817 7818 NTSTATUS 7819 FatSearchBufferForLabel( 7820 IN PIRP_CONTEXT IrpContext, 7821 IN PVPB Vpb, 7822 IN PVOID Buffer, 7823 IN ULONG Size, 7824 OUT PBOOLEAN LabelFound 7825 ) 7826 /*++ 7827 7828 Routine Description: 7829 7830 Search a buffer (taken from the root directory) for a volume label 7831 matching the label in the 7832 7833 Arguments: 7834 7835 IrpContext - Supplies our irp context 7836 Vpb - Vpb supplying the volume label 7837 Buffer - Supplies the buffer we'll search 7838 Size - The size of the buffer in bytes. 7839 LabelFound - Returns whether a label was found. 7840 7841 Return Value: 7842 7843 There are four interesting cases: 7844 7845 1) Some random error occurred - that error returned as status, LabelFound 7846 is indeterminate. 7847 7848 2) No label was found - STATUS_SUCCESS returned, LabelFound is FALSE. 7849 7850 3) A matching label was found - STATUS_SUCCESS returned, LabelFound is TRUE. 7851 7852 4) A non-matching label found - STATUS_WRONG_VOLUME returned, LabelFound 7853 is indeterminate. 7854 7855 --*/ 7856 7857 { 7858 NTSTATUS Status; 7859 WCHAR UnicodeBuffer[11]; 7860 7861 PDIRENT Dirent; 7862 PDIRENT TerminationDirent; 7863 ULONG VolumeLabelLength; 7864 UCHAR OemBuffer[11]; 7865 OEM_STRING OemString; 7866 UNICODE_STRING UnicodeString; 7867 7868 PAGED_CODE(); 7869 7870 UNREFERENCED_PARAMETER( IrpContext ); 7871 7872 Dirent = Buffer; 7873 7874 TerminationDirent = Dirent + Size / sizeof(DIRENT); 7875 7876 while ( Dirent < TerminationDirent ) { 7877 7878 if ( Dirent->FileName[0] == FAT_DIRENT_NEVER_USED ) { 7879 7880 Dirent = TerminationDirent; 7881 break; 7882 } 7883 7884 // 7885 // If the entry is the non-deleted volume label break from the loop. 7886 // 7887 // Note that all out parameters are already correctly set. 7888 // 7889 7890 if (((Dirent->Attributes & ~FAT_DIRENT_ATTR_ARCHIVE) == 7891 FAT_DIRENT_ATTR_VOLUME_ID) && 7892 (Dirent->FileName[0] != FAT_DIRENT_DELETED)) { 7893 7894 break; 7895 } 7896 7897 Dirent += 1; 7898 } 7899 7900 if (Dirent >= TerminationDirent) { 7901 7902 // 7903 // We've run out of buffer. 7904 // 7905 7906 *LabelFound = FALSE; 7907 return STATUS_SUCCESS; 7908 } 7909 7910 7911 OemString.Buffer = (PCHAR)&OemBuffer[0]; 7912 OemString.MaximumLength = 11; 7913 7914 RtlCopyMemory( OemString.Buffer, Dirent->FileName, 11 ); 7915 7916 // 7917 // Translate the first character from 0x5 to 0xe5. 7918 // 7919 7920 if (OemString.Buffer[0] == FAT_DIRENT_REALLY_0E5) { 7921 7922 OemString.Buffer[0] = 0xe5; 7923 } 7924 7925 // 7926 // Compute the length of the volume name 7927 // 7928 7929 for ( OemString.Length = 11; 7930 OemString.Length > 0; 7931 OemString.Length -= 1) { 7932 7933 if ( (OemString.Buffer[OemString.Length-1] != 0x00) && 7934 (OemString.Buffer[OemString.Length-1] != 0x20) ) { break; } 7935 } 7936 7937 UnicodeString.MaximumLength = sizeof( UnicodeBuffer ); 7938 UnicodeString.Buffer = &UnicodeBuffer[0]; 7939 7940 Status = RtlOemStringToCountedUnicodeString( &UnicodeString, 7941 &OemString, 7942 FALSE ); 7943 7944 if ( !NT_SUCCESS( Status ) ) { 7945 7946 return Status; 7947 } 7948 7949 VolumeLabelLength = UnicodeString.Length; 7950 7951 if ( (VolumeLabelLength != (ULONG)Vpb->VolumeLabelLength) || 7952 (!RtlEqualMemory(&UnicodeBuffer[0], 7953 &Vpb->VolumeLabel[0], 7954 VolumeLabelLength)) ) { 7955 7956 return STATUS_WRONG_VOLUME; 7957 } 7958 7959 // 7960 // We found a matching label. 7961 // 7962 7963 *LabelFound = TRUE; 7964 return STATUS_SUCCESS; 7965 } 7966 7967 7968 VOID 7969 FatVerifyLookupFatEntry ( 7970 IN PIRP_CONTEXT IrpContext, 7971 IN PVCB Vcb, 7972 IN ULONG FatIndex, 7973 IN OUT PULONG FatEntry 7974 ) 7975 { 7976 ULONG PageEntryOffset; 7977 ULONG OffsetIntoVolumeFile; 7978 PVOID Buffer; 7979 7980 PAGED_CODE(); 7981 7982 NT_ASSERT(Vcb->AllocationSupport.FatIndexBitSize == 32); 7983 7984 FatVerifyIndexIsValid( IrpContext, Vcb, FatIndex); 7985 7986 Buffer = FsRtlAllocatePoolWithTag( NonPagedPoolNxCacheAligned, 7987 PAGE_SIZE, 7988 TAG_ENTRY_LOOKUP_BUFFER ); 7989 7990 OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(ULONG); 7991 PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(ULONG); 7992 7993 _SEH2_TRY { 7994 7995 FatPerformVerifyDiskRead( IrpContext, 7996 Vcb, 7997 Buffer, 7998 OffsetIntoVolumeFile & ~(PAGE_SIZE - 1), 7999 PAGE_SIZE, 8000 TRUE ); 8001 8002 *FatEntry = ((PULONG)(Buffer))[PageEntryOffset]; 8003 8004 } _SEH2_FINALLY { 8005 8006 ExFreePool( Buffer ); 8007 } _SEH2_END; 8008 } 8009 8010 // 8011 // Local support routine 8012 // 8013 8014 _Requires_lock_held_(_Global_critical_region_) 8015 VOID 8016 FatScanForDismountedVcb ( 8017 IN PIRP_CONTEXT IrpContext 8018 ) 8019 8020 /*++ 8021 8022 Routine Description: 8023 8024 This routine walks through the list of Vcb's looking for any which may 8025 now be deleted. They may have been left on the list because there were 8026 outstanding references. 8027 8028 Arguments: 8029 8030 Return Value: 8031 8032 None 8033 8034 --*/ 8035 8036 { 8037 PVCB Vcb; 8038 PLIST_ENTRY Links; 8039 BOOLEAN VcbDeleted; 8040 8041 8042 PAGED_CODE(); 8043 8044 // 8045 // Walk through all of the Vcb's attached to the global data. 8046 // 8047 8048 NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); 8049 8050 #ifdef _MSC_VER 8051 #pragma prefast( push ) 8052 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 8053 #pragma prefast( disable: 28193, "this will always wait" ) 8054 #endif 8055 8056 FatAcquireExclusiveGlobal( IrpContext ); 8057 8058 #ifdef _MSC_VER 8059 #pragma prefast( pop ) 8060 #endif 8061 8062 Links = FatData.VcbQueue.Flink; 8063 8064 while (Links != &FatData.VcbQueue) { 8065 8066 Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks ); 8067 8068 // 8069 // Move to the next link now since the current Vcb may be deleted. 8070 // 8071 8072 Links = Links->Flink; 8073 8074 // 8075 // Try to acquire the VCB for exclusive access. If we cannot, just skip 8076 // it for now. 8077 // 8078 8079 #ifdef _MSC_VER 8080 #pragma prefast( push ) 8081 #pragma prefast( disable:28103,"prefast cannot work out that Vcb->Resource will be released below." ) 8082 #pragma prefast( disable:28109,"prefast cannot work out the Vcb is not already held" ); 8083 #endif 8084 8085 if (!ExAcquireResourceExclusiveLite( &(Vcb->Resource), FALSE )) { 8086 8087 continue; 8088 } 8089 8090 #ifdef _MSC_VER 8091 #pragma prefast( pop ) 8092 #endif 8093 // 8094 // Check if this Vcb can go away. 8095 // 8096 8097 VcbDeleted = FatCheckForDismount( IrpContext, 8098 Vcb, 8099 FALSE ); 8100 8101 // 8102 // If the VCB was not deleted, release it. 8103 // 8104 8105 if (!VcbDeleted) { 8106 8107 ExReleaseResourceLite( &(Vcb->Resource) ); 8108 } 8109 } 8110 8111 FatReleaseGlobal( IrpContext); 8112 8113 return; 8114 } 8115 8116 #if (NTDDI_VERSION >= NTDDI_WIN7) 8117 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 8118 // 8119 // FatSetZeroOnDeallocate is used when we need to stomp over the contents with zeros when a file is deleted. 8120 // 8121 8122 NTSTATUS 8123 FatSetZeroOnDeallocate ( 8124 __in PIRP_CONTEXT IrpContext, 8125 __in PIRP Irp 8126 ) 8127 { 8128 NTSTATUS Status = STATUS_SUCCESS; 8129 8130 PVCB Vcb; 8131 PFCB FcbOrDcb; 8132 PCCB Ccb; 8133 8134 TYPE_OF_OPEN TypeOfOpen; 8135 8136 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 8137 8138 BOOLEAN ReleaseFcb = FALSE; 8139 8140 PAGED_CODE(); 8141 8142 // 8143 // This call should always be synchronous. 8144 // 8145 8146 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 8147 8148 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ); 8149 8150 if ((TypeOfOpen != UserFileOpen) || 8151 (!IrpSp->FileObject->WriteAccess) ) { 8152 8153 FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); 8154 return STATUS_ACCESS_DENIED; 8155 } 8156 8157 // 8158 // Readonly mount should be just that: read only. 8159 // 8160 8161 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 8162 8163 FatCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED ); 8164 return STATUS_MEDIA_WRITE_PROTECTED; 8165 } 8166 8167 // 8168 // Acquire main then paging to exclude everyone from this FCB. 8169 // 8170 8171 FatAcquireExclusiveFcb(IrpContext, FcbOrDcb); 8172 ReleaseFcb = TRUE; 8173 8174 _SEH2_TRY { 8175 8176 SetFlag( FcbOrDcb->FcbState, FCB_STATE_ZERO_ON_DEALLOCATION ); 8177 8178 } _SEH2_FINALLY { 8179 8180 if (ReleaseFcb) { 8181 FatReleaseFcb(IrpContext, FcbOrDcb); 8182 } 8183 8184 } _SEH2_END; 8185 8186 FatCompleteRequest( IrpContext, Irp, Status ); 8187 return Status; 8188 } 8189 #endif 8190 8191