1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 VerfySup.c 8 9 Abstract: 10 11 This module implements the Fat Verify volume and fcb/dcb support 12 routines 13 14 15 --*/ 16 17 #include "fatprocs.h" 18 19 // 20 // The Bug check file id for this module 21 // 22 23 #define BugCheckFileId (FAT_BUG_CHECK_VERFYSUP) 24 25 // 26 // The Debug trace level for this module 27 // 28 29 #define Dbg (DEBUG_TRACE_VERFYSUP) 30 31 // 32 // Local procedure prototypes 33 // 34 35 VOID 36 FatResetFcb ( 37 IN PIRP_CONTEXT IrpContext, 38 IN PFCB Fcb 39 ); 40 41 BOOLEAN 42 FatMatchFileSize ( 43 __in PIRP_CONTEXT IrpContext, 44 __in PDIRENT Dirent, 45 __in PFCB Fcb 46 ); 47 48 _Requires_lock_held_(_Global_critical_region_) 49 VOID 50 FatDetermineAndMarkFcbCondition ( 51 IN PIRP_CONTEXT IrpContext, 52 IN PFCB Fcb 53 ); 54 55 WORKER_THREAD_ROUTINE FatDeferredCleanVolume; 56 57 VOID 58 NTAPI 59 FatDeferredCleanVolume ( 60 _In_ PVOID Parameter 61 ); 62 63 IO_COMPLETION_ROUTINE FatMarkVolumeCompletionRoutine; 64 65 NTSTATUS 66 NTAPI 67 FatMarkVolumeCompletionRoutine( 68 _In_ PDEVICE_OBJECT DeviceObject, 69 _In_ PIRP Irp, 70 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt 71 ); 72 73 #ifdef ALLOC_PRAGMA 74 #pragma alloc_text(PAGE, FatCheckDirtyBit) 75 #pragma alloc_text(PAGE, FatVerifyOperationIsLegal) 76 #pragma alloc_text(PAGE, FatDeferredCleanVolume) 77 #pragma alloc_text(PAGE, FatMatchFileSize) 78 #pragma alloc_text(PAGE, FatDetermineAndMarkFcbCondition) 79 #pragma alloc_text(PAGE, FatQuickVerifyVcb) 80 #pragma alloc_text(PAGE, FatPerformVerify) 81 #pragma alloc_text(PAGE, FatMarkFcbCondition) 82 #pragma alloc_text(PAGE, FatResetFcb) 83 #pragma alloc_text(PAGE, FatVerifyVcb) 84 #pragma alloc_text(PAGE, FatVerifyFcb) 85 #endif 86 87 88 VOID 89 FatMarkFcbCondition ( 90 IN PIRP_CONTEXT IrpContext, 91 IN PFCB Fcb, 92 IN FCB_CONDITION FcbCondition, 93 IN BOOLEAN Recursive 94 ) 95 96 /*++ 97 98 Routine Description: 99 100 This routines marks the entire Fcb/Dcb structure from Fcb down with 101 FcbCondition. 102 103 Arguments: 104 105 Fcb - Supplies the Fcb/Dcb being marked 106 107 FcbCondition - Supplies the setting to use for the Fcb Condition 108 109 Recursive - Specifies whether this condition should be applied to 110 all children (see the case where we are invalidating a live volume 111 for a case where this is now desireable). 112 113 Return Value: 114 115 None. 116 117 --*/ 118 119 { 120 PAGED_CODE(); 121 122 DebugTrace(+1, Dbg, "FatMarkFcbCondition, Fcb = %p\n", Fcb ); 123 124 // 125 // If we are marking this Fcb something other than Good, we will need 126 // to have the Vcb exclusive. 127 // 128 129 NT_ASSERT( FcbCondition != FcbNeedsToBeVerified ? TRUE : 130 FatVcbAcquiredExclusive(IrpContext, Fcb->Vcb) ); 131 132 // 133 // If this is a PagingFile it has to be good unless media underneath is 134 // removable. The "removable" check was added specifically for ReadyBoost, 135 // which opens its cache file on a removable device as a paging file and 136 // relies on the file system to validate its mapping information after a 137 // power transition. 138 // 139 140 if (!FlagOn(Fcb->Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && 141 FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) { 142 143 Fcb->FcbCondition = FcbGood; 144 return; 145 } 146 147 // 148 // Update the condition of the Fcb. 149 // 150 151 Fcb->FcbCondition = FcbCondition; 152 153 DebugTrace(0, Dbg, "MarkFcb: %wZ\n", &Fcb->FullFileName); 154 155 // 156 // This FastIo flag is based on FcbCondition, so update it now. This only 157 // applies to regular FCBs, of course. 158 // 159 160 if (Fcb->Header.NodeTypeCode == FAT_NTC_FCB) { 161 162 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 163 } 164 165 if (FcbCondition == FcbNeedsToBeVerified) { 166 FatResetFcb( IrpContext, Fcb ); 167 } 168 169 // 170 // Now if we marked NeedsVerify or Bad a directory then we also need to 171 // go and mark all of our children with the same condition. 172 // 173 174 if ( ((FcbCondition == FcbNeedsToBeVerified) || 175 (FcbCondition == FcbBad)) && 176 Recursive && 177 ((Fcb->Header.NodeTypeCode == FAT_NTC_DCB) || 178 (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB)) ) { 179 180 PFCB OriginalFcb = Fcb; 181 182 while ( (Fcb = FatGetNextFcbTopDown(IrpContext, Fcb, OriginalFcb)) != NULL ) { 183 184 DebugTrace(0, Dbg, "MarkFcb: %wZ\n", &Fcb->FullFileName); 185 186 Fcb->FcbCondition = FcbCondition; 187 188 // 189 // We already know that FastIo is not possible since we are propagating 190 // a parent's bad/verify flag down the tree - IO to the children must 191 // take the long route for now. 192 // 193 194 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible; 195 196 // 197 // Leave all the Fcbs in a condition to be verified. 198 // 199 200 if (FcbCondition == FcbNeedsToBeVerified) { 201 FatResetFcb( IrpContext, Fcb ); 202 } 203 204 } 205 } 206 207 DebugTrace(-1, Dbg, "FatMarkFcbCondition -> VOID\n", 0); 208 209 return; 210 } 211 212 BOOLEAN 213 FatMarkDevForVerifyIfVcbMounted( 214 IN PVCB Vcb 215 ) 216 217 /*++ 218 219 Routine Description: 220 221 This routine checks to see if the specified Vcb is currently mounted on 222 the device or not. If it is, it sets the verify flag on the device, if 223 not then the state is noted in the Vcb. 224 225 Arguments: 226 227 Vcb - This is the volume to check. 228 229 Return Value: 230 231 TRUE if the device has been marked for verify here, FALSE otherwise. 232 233 --*/ 234 { 235 BOOLEAN Marked = FALSE; 236 KIRQL SavedIrql; 237 238 IoAcquireVpbSpinLock( &SavedIrql ); 239 240 #ifdef _MSC_VER 241 #pragma prefast( push ) 242 #pragma prefast( disable: 28175, "touching Vpb is ok for a filesystem" ) 243 #endif 244 245 if (Vcb->Vpb->RealDevice->Vpb == Vcb->Vpb) { 246 247 SetFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 248 Marked = TRUE; 249 } 250 else { 251 252 // 253 // Flag this to avoid the VPB spinlock in future passes. 254 // 255 256 SetFlag( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE); 257 } 258 259 #ifdef _MSC_VER 260 #pragma prefast( pop ) 261 #endif 262 263 IoReleaseVpbSpinLock( SavedIrql ); 264 265 return Marked; 266 } 267 268 269 VOID 270 FatVerifyVcb ( 271 IN PIRP_CONTEXT IrpContext, 272 IN PVCB Vcb 273 ) 274 275 /*++ 276 277 Routine Description: 278 279 This routines verifies that the Vcb still denotes a valid Volume 280 If the Vcb is bad it raises an error condition. 281 282 Arguments: 283 284 Vcb - Supplies the Vcb being verified 285 286 Return Value: 287 288 None. 289 290 --*/ 291 292 { 293 BOOLEAN DevMarkedForVerify; 294 295 PAGED_CODE(); 296 297 DebugTrace(+1, Dbg, "FatVerifyVcb, Vcb = %p\n", Vcb ); 298 299 // 300 // If the verify volume flag in the device object is set 301 // this means the media has potentially changed. 302 // 303 // Note that we only force this ping for create operations. 304 // For others we take a sporting chance. If in the end we 305 // have to physically access the disk, the right thing will happen. 306 // 307 308 DevMarkedForVerify = BooleanFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 309 310 // 311 // We ALWAYS force CREATE requests on unmounted volumes through the 312 // verify path. These requests could have been in limbo between 313 // IoCheckMountedVpb and us, when a verify/mount took place and caused 314 // a completely different fs/volume to be mounted. In this case the 315 // checks above may not have caught the condition, since we may already 316 // have verified (wrong volume) and decided that we have nothing to do. 317 // We want the requests to be re routed to the currently mounted volume, 318 // since they were directed at the 'drive', not our volume. So we take 319 // the verify path for synchronisation, and the request will eventually 320 // be bounced back to IO with STATUS_REPARSE by our verify handler. 321 // 322 323 if (!DevMarkedForVerify && 324 (IrpContext->MajorFunction == IRP_MJ_CREATE) && 325 (IrpContext->OriginatingIrp != NULL)) { 326 327 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp); 328 329 if ((IrpSp->FileObject->RelatedFileObject == NULL) && 330 (Vcb->VcbCondition == VcbNotMounted)) { 331 332 DevMarkedForVerify = TRUE; 333 } 334 } 335 336 // 337 // Raise any error condition otherwise. 338 // 339 340 if (DevMarkedForVerify) { 341 342 DebugTrace(0, Dbg, "The Vcb needs to be verified\n", 0); 343 344 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 345 Vcb->Vpb->RealDevice ); 346 347 FatNormalizeAndRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED ); 348 } 349 350 // 351 // Check the operation is legal for current Vcb state. 352 // 353 354 FatQuickVerifyVcb( IrpContext, Vcb ); 355 356 DebugTrace(-1, Dbg, "FatVerifyVcb -> VOID\n", 0); 357 } 358 359 360 _Requires_lock_held_(_Global_critical_region_) 361 VOID 362 FatVerifyFcb ( 363 IN PIRP_CONTEXT IrpContext, 364 IN PFCB Fcb 365 ) 366 367 /*++ 368 369 Routine Description: 370 371 This routines verifies that the Fcb still denotes the same file. 372 If the Fcb is bad it raises a error condition. 373 374 Arguments: 375 376 Fcb - Supplies the Fcb being verified 377 378 Return Value: 379 380 None. 381 382 --*/ 383 384 { 385 PFCB CurrentFcb; 386 387 PAGED_CODE(); 388 389 DebugTrace(+1, Dbg, "FatVerifyFcb, Vcb = %p\n", Fcb ); 390 391 // 392 // Always refuse operations on dismounted volumes. 393 // 394 395 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) { 396 397 FatRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED ); 398 } 399 400 // 401 // If this is the Fcb of a deleted dirent or our parent is deleted, 402 // no-op this call with the hope that the caller will do the right thing. 403 // The only caller we really have to worry about is the AdvanceOnly 404 // callback for setting valid data length from Cc, this will happen after 405 // cleanup (and file deletion), just before the SCM is ripped down. 406 // 407 408 if (IsFileDeleted( IrpContext, Fcb ) || 409 ((NodeType(Fcb) != FAT_NTC_ROOT_DCB) && 410 IsFileDeleted( IrpContext, Fcb->ParentDcb ))) { 411 412 return; 413 } 414 415 // 416 // If we are not in the process of doing a verify, 417 // first do a quick spot check on the Vcb. 418 // 419 420 if ( Fcb->Vcb->VerifyThread != KeGetCurrentThread() ) { 421 422 FatQuickVerifyVcb( IrpContext, Fcb->Vcb ); 423 } 424 425 // 426 // Now based on the condition of the Fcb we'll either return 427 // immediately to the caller, raise a condition, or do some work 428 // to verify the Fcb. 429 // 430 431 switch (Fcb->FcbCondition) { 432 433 case FcbGood: 434 435 DebugTrace(0, Dbg, "The Fcb is good\n", 0); 436 break; 437 438 case FcbBad: 439 440 FatRaiseStatus( IrpContext, STATUS_FILE_INVALID ); 441 break; 442 443 case FcbNeedsToBeVerified: 444 445 // 446 // We loop here checking our ancestors until we hit an Fcb which 447 // is either good or bad. 448 // 449 450 CurrentFcb = Fcb; 451 452 while (CurrentFcb->FcbCondition == FcbNeedsToBeVerified) { 453 454 FatDetermineAndMarkFcbCondition(IrpContext, CurrentFcb); 455 456 // 457 // If this Fcb didn't make it, or it was the Root Dcb, exit 458 // the loop now, else continue with out parent. 459 // 460 461 if ( (CurrentFcb->FcbCondition != FcbGood) || 462 (NodeType(CurrentFcb) == FAT_NTC_ROOT_DCB) ) { 463 464 break; 465 } 466 467 CurrentFcb = CurrentFcb->ParentDcb; 468 } 469 470 // 471 // Now we can just look at ourselves to see how we did. 472 // 473 474 if (Fcb->FcbCondition != FcbGood) { 475 476 FatRaiseStatus( IrpContext, STATUS_FILE_INVALID ); 477 } 478 479 break; 480 481 default: 482 483 DebugDump("Invalid FcbCondition\n", 0, Fcb); 484 485 #ifdef _MSC_VER 486 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 487 #endif 488 FatBugCheck( Fcb->FcbCondition, 0, 0 ); 489 } 490 491 DebugTrace(-1, Dbg, "FatVerifyFcb -> VOID\n", 0); 492 493 return; 494 } 495 496 497 VOID 498 NTAPI 499 FatDeferredCleanVolume ( 500 _In_ PVOID Parameter 501 ) 502 503 /*++ 504 505 Routine Description: 506 507 This is the routine that performs the actual FatMarkVolumeClean call. 508 It assures that the target volume still exists as there ia a race 509 condition between queueing the ExWorker item and volumes going away. 510 511 Arguments: 512 513 Parameter - Points to a clean volume packet that was allocated from pool 514 515 Return Value: 516 517 None. 518 519 --*/ 520 521 { 522 PCLEAN_AND_DIRTY_VOLUME_PACKET Packet; 523 PLIST_ENTRY Links; 524 PVCB Vcb; 525 IRP_CONTEXT IrpContext; 526 BOOLEAN VcbExists = FALSE; 527 528 PAGED_CODE(); 529 530 DebugTrace(+1, Dbg, "FatDeferredCleanVolume\n", 0); 531 532 Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter; 533 534 Vcb = Packet->Vcb; 535 536 // 537 // Make us appear as a top level FSP request so that we will 538 // receive any errors from the operation. 539 // 540 541 IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP ); 542 543 // 544 // Dummy up and Irp Context so we can call our worker routines 545 // 546 547 RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT)); 548 549 SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT); 550 551 // 552 // Acquire shared access to the global lock and make sure this volume 553 // still exists. 554 // 555 556 #ifdef _MSC_VER 557 #pragma prefast( push ) 558 #pragma prefast( disable: 28193, "this will always wait" ) 559 #endif 560 FatAcquireSharedGlobal( &IrpContext ); 561 #ifdef _MSC_VER 562 #pragma prefast( pop ) 563 #endif 564 565 for (Links = FatData.VcbQueue.Flink; 566 Links != &FatData.VcbQueue; 567 Links = Links->Flink) { 568 569 PVCB ExistingVcb; 570 571 ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks); 572 573 if ( Vcb == ExistingVcb ) { 574 575 VcbExists = TRUE; 576 break; 577 } 578 } 579 580 // 581 // If the vcb is good then mark it clean. Ignore any problems. 582 // 583 584 if ( VcbExists && 585 (Vcb->VcbCondition == VcbGood) && 586 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ) { 587 588 _SEH2_TRY { 589 590 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { 591 592 FatMarkVolume( &IrpContext, Vcb, VolumeClean ); 593 } 594 595 // 596 // Check for a pathological race condition, and fix it. 597 // 598 599 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) { 600 601 FatMarkVolume( &IrpContext, Vcb, VolumeDirty ); 602 603 } else { 604 605 // 606 // Unlock the volume if it is removable. 607 // 608 609 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && 610 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { 611 612 FatToggleMediaEjectDisable( &IrpContext, Vcb, FALSE ); 613 } 614 } 615 616 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 617 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { 618 619 NOTHING; 620 } _SEH2_END; 621 } 622 623 // 624 // Release the global resource, unpin and repinned Bcbs and return. 625 // 626 627 FatReleaseGlobal( &IrpContext ); 628 629 _SEH2_TRY { 630 631 FatUnpinRepinnedBcbs( &IrpContext ); 632 633 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? 634 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { 635 636 NOTHING; 637 } _SEH2_END; 638 639 IoSetTopLevelIrp( NULL ); 640 641 // 642 // and finally free the packet. 643 // 644 645 ExFreePool( Packet ); 646 647 return; 648 } 649 650 651 652 VOID 653 NTAPI 654 FatCleanVolumeDpc ( 655 _In_ PKDPC Dpc, 656 _In_opt_ PVOID DeferredContext, 657 _In_opt_ PVOID SystemArgument1, 658 _In_opt_ PVOID SystemArgument2 659 ) 660 661 /*++ 662 663 Routine Description: 664 665 This routine is dispatched 5 seconds after the last disk structure was 666 modified in a specific volume, and exqueues an execuative worker thread 667 to perform the actual task of marking the volume dirty. 668 669 Arguments: 670 671 DefferedContext - Contains the Vcb to process. 672 673 Return Value: 674 675 None. 676 677 --*/ 678 679 { 680 PVCB Vcb; 681 PCLEAN_AND_DIRTY_VOLUME_PACKET Packet; 682 683 UNREFERENCED_PARAMETER( SystemArgument1 ); 684 UNREFERENCED_PARAMETER( SystemArgument2 ); 685 UNREFERENCED_PARAMETER( Dpc ); 686 687 Vcb = (PVCB)DeferredContext; 688 689 690 // 691 // If there is still dirty data (highly unlikely), set the timer for a 692 // second in the future. 693 // 694 695 if (CcIsThereDirtyData(Vcb->Vpb)) { 696 697 LARGE_INTEGER TwoSecondsFromNow; 698 699 TwoSecondsFromNow.QuadPart = (LONG)-2*1000*1000*10; 700 701 KeSetTimer( &Vcb->CleanVolumeTimer, 702 TwoSecondsFromNow, 703 &Vcb->CleanVolumeDpc ); 704 705 return; 706 } 707 708 // 709 // If we couldn't get pool, oh well.... 710 // 711 712 Packet = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET), ' taF'); 713 714 if ( Packet ) { 715 716 Packet->Vcb = Vcb; 717 Packet->Irp = NULL; 718 719 // 720 // Clear the dirty flag now since we cannot synchronize after this point. 721 // 722 723 ClearFlag( Packet->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); 724 725 ExInitializeWorkItem( &Packet->Item, &FatDeferredCleanVolume, Packet ); 726 727 #ifdef _MSC_VER 728 #pragma prefast( suppress:28159, "prefast indicates this is an obsolete API, but it is ok for fastfat to keep using it" ) 729 #endif 730 ExQueueWorkItem( &Packet->Item, CriticalWorkQueue ); 731 } 732 733 return; 734 } 735 736 737 _Requires_lock_held_(_Global_critical_region_) 738 VOID 739 FatMarkVolume ( 740 IN PIRP_CONTEXT IrpContext, 741 IN PVCB Vcb, 742 IN FAT_VOLUME_STATE VolumeState 743 ) 744 745 /*++ 746 747 Routine Description: 748 749 This routine moves the physically marked volume state between the clean 750 and dirty states. For compatibility with Win9x, we manipulate both the 751 historical DOS (on==clean in index 1 of the FAT) and NT (on==dirty in 752 the CurrentHead field of the BPB) dirty bits. 753 754 Arguments: 755 756 Vcb - Supplies the Vcb being modified 757 758 VolumeState - Supplies the state the volume is transitioning to 759 760 Return Value: 761 762 None. 763 764 --*/ 765 766 { 767 PCHAR Sector; 768 PBCB Bcb = NULL; 769 KEVENT Event; 770 PIRP Irp = NULL; 771 NTSTATUS Status; 772 BOOLEAN FsInfoUpdate = FALSE; 773 ULONG FsInfoOffset = 0; 774 ULONG ThisPass; 775 LARGE_INTEGER Offset; 776 BOOLEAN abort = FALSE; 777 778 DebugTrace(+1, Dbg, "FatMarkVolume, Vcb = %p\n", Vcb); 779 780 // 781 // We had best not be trying to scribble dirty/clean bits if the 782 // volume is write protected. The responsibility lies with the 783 // callers to make sure that operations that could cause a state 784 // change cannot happen. There are a few, though, that show it 785 // just doesn't make sense to force everyone to do the dinky 786 // check. 787 // 788 789 // 790 // If we were called for FAT12 or readonly media, return immediately. 791 // 792 793 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) || 794 FatIsFat12( Vcb )) { 795 796 return; 797 } 798 799 // 800 // We have two possible additional tasks to do to mark a volume 801 // 802 // Pass 0) Flip the dirty bit in the Bpb 803 // Pass 1) Rewrite the FsInfo sector for FAT32 if needed 804 // 805 // In most cases we can collapse these two either because the volume 806 // is either not FAT32 or the FsInfo sector is adjacent to the boot sector. 807 // 808 809 for (ThisPass = 0; ThisPass < 2; ThisPass++) { 810 811 // 812 // If this volume is being dirtied, or isn't FAT32, or if it is and 813 // we were able to perform the fast update, or the bpb lied to us 814 // about where the FsInfo went, we're done - no FsInfo to update in 815 // a seperate write. 816 // 817 818 if (ThisPass == 1 && (!FatIsFat32( Vcb ) || 819 VolumeState != VolumeClean || 820 FsInfoUpdate || 821 Vcb->Bpb.FsInfoSector == 0)) { 822 823 break; 824 } 825 826 // 827 // Bail if we get an IO error. 828 // 829 830 _SEH2_TRY { 831 832 ULONG PinLength; 833 ULONG WriteLength; 834 835 // 836 // If the FAT table is 12-bit then our strategy is to pin the entire 837 // thing when any of it is modified. Here we're going to pin the 838 // first page, so in the 12-bit case we also want to pin the rest 839 // of the FAT table. 840 // 841 842 Offset.QuadPart = 0; 843 844 if (Vcb->AllocationSupport.FatIndexBitSize == 12) { 845 846 // 847 // But we only write back the first sector. 848 // 849 850 PinLength = FatReservedBytes(&Vcb->Bpb) + FatBytesPerFat(&Vcb->Bpb); 851 WriteLength = Vcb->Bpb.BytesPerSector; 852 853 } else { 854 855 WriteLength = PinLength = Vcb->Bpb.BytesPerSector; 856 857 // 858 // If this is a FAT32 volume going into the clean state, 859 // see about doing the FsInfo sector. 860 // 861 862 if (FatIsFat32( Vcb ) && VolumeState == VolumeClean) { 863 864 // 865 // If the FsInfo sector immediately follows the boot sector, 866 // we can do this in a single operation by rewriting both 867 // sectors at once. 868 // 869 870 if (Vcb->Bpb.FsInfoSector == 1) { 871 872 NT_ASSERT( ThisPass == 0 ); 873 874 FsInfoUpdate = TRUE; 875 FsInfoOffset = Vcb->Bpb.BytesPerSector; 876 WriteLength = PinLength = Vcb->Bpb.BytesPerSector * 2; 877 878 } else if (ThisPass == 1) { 879 880 // 881 // We are doing an explicit write to the FsInfo sector. 882 // 883 884 FsInfoUpdate = TRUE; 885 FsInfoOffset = 0; 886 887 Offset.QuadPart = Vcb->Bpb.BytesPerSector * Vcb->Bpb.FsInfoSector; 888 } 889 } 890 } 891 892 // 893 // Call Cc directly here so that we can avoid overhead and push this 894 // right down to the disk. 895 // 896 897 CcPinRead( Vcb->VirtualVolumeFile, 898 &Offset, 899 PinLength, 900 TRUE, 901 &Bcb, 902 (PVOID *)&Sector ); 903 904 DbgDoit( IrpContext->PinCount += 1 ) 905 906 // 907 // Set the Bpb on Pass 0 always 908 // 909 910 if (ThisPass == 0) { 911 912 PCHAR CurrentHead; 913 914 // 915 // Before we do anything, doublecheck that this still looks like a 916 // FAT bootsector. If it doesn't, something remarkable happened 917 // and we should avoid touching the volume. 918 // 919 // THIS IS TEMPORARY (but may last a while) 920 // 921 922 if (!FatIsBootSectorFat( (PPACKED_BOOT_SECTOR) Sector )) { 923 abort = TRUE; 924 _SEH2_LEAVE; 925 } 926 927 if (FatIsFat32( Vcb )) { 928 929 CurrentHead = (PCHAR)&((PPACKED_BOOT_SECTOR_EX) Sector)->CurrentHead; 930 931 } else { 932 933 CurrentHead = (PCHAR)&((PPACKED_BOOT_SECTOR) Sector)->CurrentHead; 934 } 935 936 if (VolumeState == VolumeClean) { 937 938 ClearFlag( *CurrentHead, FAT_BOOT_SECTOR_DIRTY ); 939 940 } else { 941 942 SetFlag( *CurrentHead, FAT_BOOT_SECTOR_DIRTY ); 943 944 // 945 // In addition, if this request received an error that may indicate 946 // media corruption, have autochk perform a surface test. 947 // 948 949 if ( VolumeState == VolumeDirtyWithSurfaceTest ) { 950 951 SetFlag( *CurrentHead, FAT_BOOT_SECTOR_TEST_SURFACE ); 952 } 953 } 954 } 955 956 // 957 // Update the FsInfo as appropriate. 958 // 959 960 if (FsInfoUpdate) { 961 962 PFSINFO_SECTOR FsInfoSector = (PFSINFO_SECTOR) ((PCHAR)Sector + FsInfoOffset); 963 964 // 965 // We just rewrite all of the spec'd fields. Note that we don't 966 // care to synchronize with the allocation package - this will be 967 // quickly taken care of by a re-dirtying of the volume if a change 968 // is racing with us. Remember that this is all a compatibility 969 // deference for Win9x FAT32 - NT will never look at this information. 970 // 971 972 FsInfoSector->SectorBeginSignature = FSINFO_SECTOR_BEGIN_SIGNATURE; 973 FsInfoSector->FsInfoSignature = FSINFO_SIGNATURE; 974 FsInfoSector->FreeClusterCount = Vcb->AllocationSupport.NumberOfFreeClusters; 975 FsInfoSector->NextFreeCluster = Vcb->ClusterHint; 976 FsInfoSector->SectorEndSignature = FSINFO_SECTOR_END_SIGNATURE; 977 } 978 979 // 980 // Initialize the event we're going to use 981 // 982 983 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 984 985 // 986 // Build the irp for the operation and also set the override flag. 987 // Note that we may be at APC level, so do this asyncrhonously and 988 // use an event for synchronization as normal request completion 989 // cannot occur at APC level. 990 // 991 992 Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE, 993 Vcb->TargetDeviceObject, 994 (PVOID)Sector, 995 WriteLength, 996 &Offset, 997 NULL ); 998 999 if ( Irp == NULL ) { 1000 1001 try_return(NOTHING); 1002 } 1003 1004 // 1005 // Make this operation write-through. It never hurts to try to be 1006 // safer about this, even though we aren't logged. 1007 // 1008 1009 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_WRITE_THROUGH ); 1010 1011 // 1012 // Set up the completion routine 1013 // 1014 1015 IoSetCompletionRoutine( Irp, 1016 FatMarkVolumeCompletionRoutine, 1017 &Event, 1018 TRUE, 1019 TRUE, 1020 TRUE ); 1021 1022 // 1023 // Call the device to do the write and wait for it to finish. 1024 // Igmore any return status. 1025 // 1026 1027 Status = IoCallDriver( Vcb->TargetDeviceObject, Irp ); 1028 1029 if (Status == STATUS_PENDING) { 1030 1031 (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); 1032 } 1033 1034 try_exit: NOTHING; 1035 } _SEH2_FINALLY { 1036 1037 // 1038 // Clean up the Irp and Mdl 1039 // 1040 1041 1042 if (Irp) { 1043 1044 // 1045 // If there is an MDL (or MDLs) associated with this I/O 1046 // request, Free it (them) here. This is accomplished by 1047 // walking the MDL list hanging off of the IRP and deallocating 1048 // each MDL encountered. 1049 // 1050 1051 while (Irp->MdlAddress != NULL) { 1052 1053 PMDL NextMdl; 1054 1055 NextMdl = Irp->MdlAddress->Next; 1056 1057 MmUnlockPages( Irp->MdlAddress ); 1058 1059 IoFreeMdl( Irp->MdlAddress ); 1060 1061 Irp->MdlAddress = NextMdl; 1062 } 1063 1064 IoFreeIrp( Irp ); 1065 } 1066 1067 if (Bcb != NULL) { 1068 1069 FatUnpinBcb( IrpContext, Bcb ); 1070 } 1071 } _SEH2_END; 1072 } 1073 1074 if (!abort) { 1075 1076 // 1077 // Flip the dirty bit in the FAT 1078 // 1079 1080 if (VolumeState == VolumeDirty) { 1081 1082 FatSetFatEntry( IrpContext, Vcb, FAT_DIRTY_BIT_INDEX, FAT_DIRTY_VOLUME); 1083 1084 } else { 1085 1086 FatSetFatEntry( IrpContext, Vcb, FAT_DIRTY_BIT_INDEX, FAT_CLEAN_VOLUME); 1087 } 1088 } 1089 1090 DebugTrace(-1, Dbg, "FatMarkVolume -> VOID\n", 0); 1091 1092 return; 1093 } 1094 1095 1096 VOID 1097 NTAPI 1098 FatFspMarkVolumeDirtyWithRecover( 1099 PVOID Parameter 1100 ) 1101 1102 /*++ 1103 1104 Routine Description: 1105 1106 This is the routine that performs the actual FatMarkVolume Dirty call 1107 on a paging file Io that encounters a media error. It is responsible 1108 for completing the PagingIo Irp as soon as this is done. 1109 1110 Note: this routine (and thus FatMarkVolume()) must be resident as 1111 the paging file might be damaged at this point. 1112 1113 Arguments: 1114 1115 Parameter - Points to a dirty volume packet that was allocated from pool 1116 1117 Return Value: 1118 1119 None. 1120 1121 --*/ 1122 1123 { 1124 PCLEAN_AND_DIRTY_VOLUME_PACKET Packet; 1125 PVCB Vcb; 1126 IRP_CONTEXT IrpContext; 1127 PIRP Irp; 1128 1129 DebugTrace(+1, Dbg, "FatFspMarkVolumeDirtyWithRecover\n", 0); 1130 1131 Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter; 1132 1133 Vcb = Packet->Vcb; 1134 Irp = Packet->Irp; 1135 1136 // 1137 // Dummy up the IrpContext so we can call our worker routines 1138 // 1139 1140 RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT)); 1141 1142 SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT); 1143 IrpContext.OriginatingIrp = Irp; 1144 1145 // 1146 // Make us appear as a top level FSP request so that we will 1147 // receive any errors from the operation. 1148 // 1149 1150 IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP ); 1151 1152 // 1153 // Try to write out the dirty bit. If something goes wrong, we 1154 // tried. 1155 // 1156 1157 _SEH2_TRY { 1158 1159 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); 1160 1161 FatMarkVolume( &IrpContext, Vcb, VolumeDirtyWithSurfaceTest ); 1162 1163 } _SEH2_EXCEPT(FatExceptionFilter( &IrpContext, _SEH2_GetExceptionInformation() )) { 1164 1165 NOTHING; 1166 } _SEH2_END; 1167 1168 IoSetTopLevelIrp( NULL ); 1169 1170 // 1171 // Now complete the originating Irp or set the synchronous event. 1172 // 1173 1174 if (Packet->Event) { 1175 KeSetEvent( Packet->Event, 0, FALSE ); 1176 } else { 1177 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 1178 } 1179 1180 DebugTrace(-1, Dbg, "FatFspMarkVolumeDirtyWithRecover -> VOID\n", 0); 1181 } 1182 1183 1184 VOID 1185 FatCheckDirtyBit ( 1186 IN PIRP_CONTEXT IrpContext, 1187 IN PVCB Vcb 1188 ) 1189 1190 /*++ 1191 1192 Routine Description: 1193 1194 This routine looks at the volume dirty bit, and depending on the state of 1195 VCB_STATE_FLAG_MOUNTED_DIRTY, the appropriate action is taken. 1196 1197 Arguments: 1198 1199 Vcb - Supplies the Vcb being queried. 1200 1201 Return Value: 1202 1203 None. 1204 1205 --*/ 1206 1207 { 1208 BOOLEAN Dirty; 1209 1210 PPACKED_BOOT_SECTOR BootSector; 1211 PBCB BootSectorBcb; 1212 1213 UNICODE_STRING VolumeLabel; 1214 1215 PAGED_CODE(); 1216 1217 // 1218 // Look in the boot sector 1219 // 1220 1221 FatReadVolumeFile( IrpContext, 1222 Vcb, 1223 0, 1224 sizeof(PACKED_BOOT_SECTOR), 1225 &BootSectorBcb, 1226 (PVOID *)&BootSector ); 1227 1228 _SEH2_TRY { 1229 1230 // 1231 // Check if the magic bit is set 1232 // 1233 1234 if (IsBpbFat32(&BootSector->PackedBpb)) { 1235 Dirty = BooleanFlagOn( ((PPACKED_BOOT_SECTOR_EX)BootSector)->CurrentHead, 1236 FAT_BOOT_SECTOR_DIRTY ); 1237 } else { 1238 Dirty = BooleanFlagOn( BootSector->CurrentHead, FAT_BOOT_SECTOR_DIRTY ); 1239 } 1240 1241 // 1242 // Setup the VolumeLabel string 1243 // 1244 1245 VolumeLabel.Length = Vcb->Vpb->VolumeLabelLength; 1246 VolumeLabel.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH; 1247 VolumeLabel.Buffer = &Vcb->Vpb->VolumeLabel[0]; 1248 1249 if ( Dirty ) { 1250 1251 // 1252 // Do not trigger the mounted dirty bit if this is a verify 1253 // and the volume is a boot or paging device. We know that 1254 // a boot or paging device cannot leave the system, and thus 1255 // that on its mount we will have figured this out correctly. 1256 // 1257 // This logic is a reasonable change. Why? 1258 // 'cause setup cracked a non-exclusive DASD handle near the 1259 // end of setup, wrote some data, closed the handle and we 1260 // set the verify bit ... came back around and saw that other 1261 // arbitrary activity had left the volume in a temporarily dirty 1262 // state. 1263 // 1264 // Of course, the real problem is that we don't have a journal. 1265 // 1266 1267 if (!(IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 1268 IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME && 1269 FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE))) { 1270 1271 KdPrintEx((DPFLTR_FASTFAT_ID, 1272 DPFLTR_INFO_LEVEL, 1273 "FASTFAT: WARNING! Mounting Dirty Volume %Z\n", 1274 &VolumeLabel)); 1275 1276 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); 1277 } 1278 1279 } else { 1280 1281 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { 1282 1283 KdPrintEx((DPFLTR_FASTFAT_ID, 1284 DPFLTR_INFO_LEVEL, 1285 "FASTFAT: Volume %Z has been cleaned.\n", 1286 &VolumeLabel)); 1287 1288 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); 1289 1290 } else { 1291 1292 (VOID)FsRtlBalanceReads( Vcb->TargetDeviceObject ); 1293 } 1294 } 1295 1296 } _SEH2_FINALLY { 1297 1298 FatUnpinBcb( IrpContext, BootSectorBcb ); 1299 } _SEH2_END; 1300 } 1301 1302 1303 VOID 1304 FatVerifyOperationIsLegal ( 1305 IN PIRP_CONTEXT IrpContext 1306 ) 1307 1308 /*++ 1309 1310 Routine Description: 1311 1312 This routine determines is the requested operation should be allowed to 1313 continue. It either returns to the user if the request is Okay, or 1314 raises an appropriate status. 1315 1316 Arguments: 1317 1318 Irp - Supplies the Irp to check 1319 1320 Return Value: 1321 1322 None. 1323 1324 --*/ 1325 1326 { 1327 PIRP Irp; 1328 PFILE_OBJECT FileObject; 1329 1330 PAGED_CODE(); 1331 1332 Irp = IrpContext->OriginatingIrp; 1333 1334 // 1335 // If the Irp is not present, then we got here via close. 1336 // 1337 // 1338 1339 if ( Irp == NULL ) { 1340 1341 return; 1342 } 1343 1344 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject; 1345 1346 // 1347 // If there is not a file object, we cannot continue. 1348 // 1349 1350 if ( FileObject == NULL ) { 1351 1352 return; 1353 } 1354 1355 // 1356 // If the file object has already been cleaned up, and 1357 // 1358 // A) This request is a paging io read or write, or 1359 // B) This request is a close operation, or 1360 // C) This request is a set or query info call (for Lou) 1361 // D) This is an MDL complete 1362 // 1363 // let it pass, otherwise return STATUS_FILE_CLOSED. 1364 // 1365 1366 if ( FlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE) ) { 1367 1368 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 1369 1370 if ( (FlagOn(Irp->Flags, IRP_PAGING_IO)) || 1371 (IrpSp->MajorFunction == IRP_MJ_CLOSE ) || 1372 (IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION) || 1373 (IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) || 1374 ( ( (IrpSp->MajorFunction == IRP_MJ_READ) || 1375 (IrpSp->MajorFunction == IRP_MJ_WRITE) ) && 1376 FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE) ) ) { 1377 1378 NOTHING; 1379 1380 } else { 1381 1382 FatRaiseStatus( IrpContext, STATUS_FILE_CLOSED ); 1383 } 1384 } 1385 1386 return; 1387 } 1388 1389 1390 1391 // 1392 // Internal support routine 1393 // 1394 1395 VOID 1396 FatResetFcb ( 1397 IN PIRP_CONTEXT IrpContext, 1398 IN PFCB Fcb 1399 ) 1400 1401 /*++ 1402 1403 Routine Description: 1404 1405 This routine is called when an Fcb has been marked as needs to be verified. 1406 1407 It does the following tasks: 1408 1409 - Reset Mcb mapping information 1410 - For directories, reset dirent hints 1411 - Set allocation size to unknown 1412 1413 Arguments: 1414 1415 Fcb - Supplies the Fcb to reset 1416 1417 Return Value: 1418 1419 None. 1420 1421 --*/ 1422 1423 { 1424 LOGICAL IsRealPagingFile; 1425 1426 PAGED_CODE(); 1427 UNREFERENCED_PARAMETER( IrpContext ); 1428 1429 // 1430 // Don't do the two following operations for the Root Dcb 1431 // of a non FAT32 volume or paging files. Paging files!? 1432 // Yes, if someone diddles a volume we try to reverify all 1433 // of the Fcbs just in case; however, there is no safe way 1434 // to chuck and retrieve the mapping pair information for 1435 // a real paging file. Lose it and die. 1436 // 1437 // An exception is made for ReadyBoost cache files, which 1438 // are created as paging files on removable devices and 1439 // require validation after a power transition. 1440 // 1441 1442 if (!FlagOn(Fcb->Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && 1443 FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) { 1444 1445 IsRealPagingFile = TRUE; 1446 1447 } else { 1448 1449 IsRealPagingFile = FALSE; 1450 } 1451 1452 if ( (NodeType(Fcb) != FAT_NTC_ROOT_DCB || 1453 FatIsFat32( Fcb->Vcb )) && 1454 !IsRealPagingFile ) { 1455 1456 // 1457 // Reset the mcb mapping. 1458 // 1459 1460 FsRtlRemoveLargeMcbEntry( &Fcb->Mcb, 0, 0xFFFFFFFF ); 1461 1462 // 1463 // Reset the allocation size to 0 or unknown 1464 // 1465 1466 if ( Fcb->FirstClusterOfFile == 0 ) { 1467 1468 Fcb->Header.AllocationSize.QuadPart = 0; 1469 1470 } else { 1471 1472 Fcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT; 1473 } 1474 } 1475 1476 // 1477 // If this is a directory, reset the hints. 1478 // 1479 1480 if ( (NodeType(Fcb) == FAT_NTC_DCB) || 1481 (NodeType(Fcb) == FAT_NTC_ROOT_DCB) ) { 1482 1483 // 1484 // Force a rescan of the directory 1485 // 1486 1487 Fcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff; 1488 Fcb->Specific.Dcb.DeletedDirentHint = 0xffffffff; 1489 } 1490 } 1491 1492 1493 1494 BOOLEAN 1495 FatMatchFileSize ( 1496 __in PIRP_CONTEXT IrpContext, 1497 __in PDIRENT Dirent, 1498 __in PFCB Fcb 1499 ) 1500 { 1501 1502 UNREFERENCED_PARAMETER(IrpContext); 1503 1504 if (NodeType(Fcb) != FAT_NTC_FCB) { 1505 return TRUE; 1506 } 1507 1508 1509 if (Fcb->Header.FileSize.LowPart != Dirent->FileSize) { 1510 return FALSE; 1511 } 1512 1513 1514 return TRUE; 1515 } 1516 1517 // 1518 // Internal support routine 1519 // 1520 1521 _Requires_lock_held_(_Global_critical_region_) 1522 VOID 1523 FatDetermineAndMarkFcbCondition ( 1524 IN PIRP_CONTEXT IrpContext, 1525 IN PFCB Fcb 1526 ) 1527 1528 /*++ 1529 1530 Routine Description: 1531 1532 This routine checks a specific Fcb to see if it is different from what's 1533 on the disk. The following things are checked: 1534 1535 - File Name 1536 - File Size (if not directory) 1537 - First Cluster Of File 1538 - Dirent Attributes 1539 1540 Arguments: 1541 1542 Fcb - Supplies the Fcb to examine 1543 1544 Return Value: 1545 1546 None. 1547 1548 --*/ 1549 1550 { 1551 PDIRENT Dirent; 1552 PBCB DirentBcb; 1553 ULONG FirstClusterOfFile; 1554 1555 OEM_STRING Name; 1556 CHAR Buffer[16]; 1557 1558 PAGED_CODE(); 1559 1560 // 1561 // If this is the Root Dcb, special case it. That is, we know 1562 // by definition that it is good since it is fixed in the volume 1563 // structure. 1564 // 1565 1566 if ( NodeType(Fcb) == FAT_NTC_ROOT_DCB ) { 1567 1568 FatMarkFcbCondition( IrpContext, Fcb, FcbGood, FALSE ); 1569 1570 return; 1571 } 1572 1573 // The first thing we need to do to verify ourselves is 1574 // locate the dirent on the disk. 1575 // 1576 1577 FatGetDirentFromFcbOrDcb( IrpContext, 1578 Fcb, 1579 TRUE, 1580 &Dirent, 1581 &DirentBcb ); 1582 // 1583 // If we couldn't get the dirent, this fcb must be bad (case of 1584 // enclosing directory shrinking during the time it was ejected). 1585 // 1586 1587 if (DirentBcb == NULL) { 1588 1589 FatMarkFcbCondition( IrpContext, Fcb, FcbBad, FALSE ); 1590 1591 return; 1592 } 1593 1594 // 1595 // We located the dirent for ourselves now make sure it 1596 // is really ours by comparing the Name and FatFlags. 1597 // Then for a file we also check the file size. 1598 // 1599 // Note that we have to unpin the Bcb before calling FatResetFcb 1600 // in order to avoid a deadlock in CcUninitializeCacheMap. 1601 // 1602 1603 _SEH2_TRY { 1604 1605 Name.MaximumLength = 16; 1606 Name.Buffer = &Buffer[0]; 1607 1608 Fat8dot3ToString( IrpContext, Dirent, FALSE, &Name ); 1609 1610 // 1611 // We need to calculate the first cluster 'cause FAT32 splits 1612 // this field across the dirent. 1613 // 1614 1615 FirstClusterOfFile = Dirent->FirstClusterOfFile; 1616 1617 if (FatIsFat32( Fcb->Vcb )) { 1618 1619 FirstClusterOfFile += Dirent->FirstClusterOfFileHi << 16; 1620 } 1621 1622 if (!RtlEqualString( &Name, &Fcb->ShortName.Name.Oem, TRUE ) 1623 1624 || 1625 1626 !FatMatchFileSize(IrpContext, Dirent, Fcb ) 1627 1628 || 1629 1630 (FirstClusterOfFile != Fcb->FirstClusterOfFile) 1631 1632 || 1633 1634 (Dirent->Attributes != Fcb->DirentFatFlags) ) { 1635 1636 FatMarkFcbCondition( IrpContext, Fcb, FcbBad, FALSE ); 1637 1638 } else { 1639 1640 // 1641 // We passed. Get the Fcb ready to use again. 1642 // 1643 1644 FatMarkFcbCondition( IrpContext, Fcb, FcbGood, FALSE ); 1645 } 1646 1647 } _SEH2_FINALLY { 1648 1649 FatUnpinBcb( IrpContext, DirentBcb ); 1650 } _SEH2_END; 1651 1652 return; 1653 } 1654 1655 1656 1657 // 1658 // Internal support routine 1659 // 1660 1661 VOID 1662 FatQuickVerifyVcb ( 1663 IN PIRP_CONTEXT IrpContext, 1664 IN PVCB Vcb 1665 ) 1666 1667 /*++ 1668 1669 Routine Description: 1670 1671 This routines just checks the verify bit in the real device and the 1672 Vcb condition and raises an appropriate exception if so warented. 1673 It is called when verifying both Fcbs and Vcbs. 1674 1675 Arguments: 1676 1677 Vcb - Supplies the Vcb to check the condition of. 1678 1679 Return Value: 1680 1681 None. 1682 1683 --*/ 1684 1685 { 1686 PAGED_CODE(); 1687 1688 // 1689 // If the real device needs to be verified we'll set the 1690 // DeviceToVerify to be our real device and raise VerifyRequired. 1691 // 1692 1693 if (FlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) { 1694 1695 DebugTrace(0, Dbg, "The Vcb needs to be verified\n", 0); 1696 1697 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 1698 Vcb->Vpb->RealDevice ); 1699 1700 FatRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED ); 1701 } 1702 1703 // 1704 // Based on the condition of the Vcb we'll either return to our 1705 // caller or raise an error condition 1706 // 1707 1708 switch (Vcb->VcbCondition) { 1709 1710 case VcbGood: 1711 1712 DebugTrace(0, Dbg, "The Vcb is good\n", 0); 1713 1714 // 1715 // Do a check here of an operation that would try to modify a 1716 // write protected media. 1717 // 1718 1719 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) && 1720 ((IrpContext->MajorFunction == IRP_MJ_WRITE) || 1721 (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) || 1722 (IrpContext->MajorFunction == IRP_MJ_SET_EA) || 1723 (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) || 1724 (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) || 1725 (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 1726 IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST && 1727 IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->Parameters.FileSystemControl.FsControlCode == 1728 FSCTL_MARK_VOLUME_DIRTY))) { 1729 1730 // 1731 // Set the real device for the pop-up info, and set the verify 1732 // bit in the device object, so that we will force a verify 1733 // in case the user put the correct media back in. 1734 // 1735 1736 1737 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 1738 Vcb->Vpb->RealDevice ); 1739 1740 FatMarkDevForVerifyIfVcbMounted(Vcb); 1741 1742 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 1743 } 1744 1745 break; 1746 1747 case VcbNotMounted: 1748 1749 DebugTrace(0, Dbg, "The Vcb is not mounted\n", 0); 1750 1751 // 1752 // Set the real device for the pop-up info, and set the verify 1753 // bit in the device object, so that we will force a verify 1754 // in case the user put the correct media back in. 1755 // 1756 1757 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 1758 Vcb->Vpb->RealDevice ); 1759 1760 FatRaiseStatus( IrpContext, STATUS_WRONG_VOLUME ); 1761 1762 break; 1763 1764 case VcbBad: 1765 1766 DebugTrace(0, Dbg, "The Vcb is bad\n", 0); 1767 1768 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) { 1769 1770 FatRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED ); 1771 1772 } else { 1773 1774 FatRaiseStatus( IrpContext, STATUS_FILE_INVALID ); 1775 } 1776 break; 1777 1778 default: 1779 1780 DebugDump("Invalid VcbCondition\n", 0, Vcb); 1781 #ifdef _MSC_VER 1782 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 1783 #endif 1784 FatBugCheck( Vcb->VcbCondition, 0, 0 ); 1785 } 1786 } 1787 1788 _Requires_lock_held_(_Global_critical_region_) 1789 NTSTATUS 1790 FatPerformVerify ( 1791 _In_ PIRP_CONTEXT IrpContext, 1792 _In_ PIRP Irp, 1793 _In_ PDEVICE_OBJECT Device 1794 ) 1795 1796 /*++ 1797 1798 Routine Description: 1799 1800 This routines performs an IoVerifyVolume operation and takes the 1801 appropriate action. After the Verify is complete the originating 1802 Irp is sent off to an Ex Worker Thread. This routine is called 1803 from the exception handler. 1804 1805 Arguments: 1806 1807 Irp - The irp to send off after all is well and done. 1808 1809 Device - The real device needing verification. 1810 1811 Return Value: 1812 1813 None. 1814 1815 --*/ 1816 1817 { 1818 PVCB Vcb; 1819 NTSTATUS Status = STATUS_SUCCESS; 1820 PIO_STACK_LOCATION IrpSp; 1821 PFILE_OBJECT FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject; 1822 BOOLEAN AllowRawMount = FALSE; 1823 BOOLEAN VcbDeleted = FALSE; 1824 1825 PAGED_CODE(); 1826 1827 // 1828 // Check if this Irp has a status of Verify required and if it does 1829 // then call the I/O system to do a verify. 1830 // 1831 // Skip the IoVerifyVolume if this is a mount or verify request 1832 // itself. Trying a recursive mount will cause a deadlock with 1833 // the DeviceObject->DeviceLock. 1834 // 1835 1836 if ( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && 1837 ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) || 1838 (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME)) ) { 1839 1840 return FatFsdPostRequest( IrpContext, Irp ); 1841 } 1842 1843 DebugTrace(0, Dbg, "Verify Required, DeviceObject = %p\n", Device); 1844 1845 // 1846 // Extract a pointer to the Vcb from the VolumeDeviceObject. 1847 // Note that since we have specifically excluded mount, 1848 // requests, we know that IrpSp->DeviceObject is indeed a 1849 // volume device object. 1850 // 1851 1852 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1853 1854 Vcb = &CONTAINING_RECORD( IrpSp->DeviceObject, 1855 VOLUME_DEVICE_OBJECT, 1856 DeviceObject )->Vcb; 1857 1858 // 1859 // Check if the volume still thinks it needs to be verified, 1860 // if it doesn't then we can skip doing a verify because someone 1861 // else beat us to it. 1862 // 1863 1864 _SEH2_TRY { 1865 1866 // 1867 // We will allow Raw to mount this volume if we were doing a 1868 // a DASD open. 1869 // 1870 1871 if ( (IrpContext->MajorFunction == IRP_MJ_CREATE) && 1872 (IrpSp->FileObject->FileName.Length == 0) && 1873 (IrpSp->FileObject->RelatedFileObject == NULL) ) { 1874 1875 AllowRawMount = TRUE; 1876 } 1877 1878 // 1879 // Send down the verify. This could be going to a different 1880 // filesystem. 1881 // 1882 1883 Status = IoVerifyVolume( Device, AllowRawMount ); 1884 1885 // 1886 // If the verify operation completed it will return 1887 // either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. 1888 // 1889 // If FatVerifyVolume encountered an error during 1890 // processing, it will return that error. If we got 1891 // STATUS_WRONG_VOLUME from the verfy, and our volume 1892 // is now mounted, commute the status to STATUS_SUCCESS. 1893 // 1894 // Acquire the Vcb so we're working with a stable Vcb condition. 1895 // 1896 1897 FatAcquireSharedVcb(IrpContext, Vcb); 1898 1899 if ( (Status == STATUS_WRONG_VOLUME) && 1900 (Vcb->VcbCondition == VcbGood) ) { 1901 1902 Status = STATUS_SUCCESS; 1903 } 1904 else if ((STATUS_SUCCESS == Status) && (Vcb->VcbCondition != VcbGood)) { 1905 1906 Status = STATUS_WRONG_VOLUME; 1907 } 1908 1909 // 1910 // Do a quick unprotected check here. The routine will do 1911 // a safe check. After here we can release the resource. 1912 // Note that if the volume really went away, we will be taking 1913 // the Reparse path. 1914 // 1915 1916 if ((VcbGood != Vcb->VcbCondition) && 1917 (0 == Vcb->OpenFileCount) ) { 1918 1919 FatReleaseVcb( IrpContext, Vcb); 1920 1921 #ifdef _MSC_VER 1922 #pragma prefast( push ) 1923 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 1924 #pragma prefast( disable: 28193 ) 1925 #endif 1926 FatAcquireExclusiveGlobal( IrpContext ); 1927 #ifdef _MSC_VER 1928 #pragma prefast( pop ) 1929 #endif 1930 1931 FatAcquireExclusiveVcb( IrpContext, 1932 Vcb ); 1933 1934 VcbDeleted = FatCheckForDismount( IrpContext, 1935 Vcb, 1936 FALSE ); 1937 1938 if (!VcbDeleted) { 1939 1940 FatReleaseVcb( IrpContext, 1941 Vcb ); 1942 } 1943 1944 FatReleaseGlobal( IrpContext ); 1945 } 1946 else { 1947 1948 FatReleaseVcb( IrpContext, Vcb); 1949 } 1950 1951 // 1952 // If the IopMount in IoVerifyVolume did something, and 1953 // this is an absolute open, force a reparse. 1954 // 1955 1956 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) && 1957 (FileObject->RelatedFileObject == NULL) && 1958 ((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) { 1959 1960 Irp->IoStatus.Information = IO_REMOUNT; 1961 1962 FatCompleteRequest( IrpContext, Irp, STATUS_REPARSE ); 1963 Status = STATUS_REPARSE; 1964 Irp = NULL; 1965 } 1966 1967 if ( (Irp != NULL) && !NT_SUCCESS(Status) ) { 1968 1969 // 1970 // Fill in the device object if required. 1971 // 1972 1973 if ( IoIsErrorUserInduced( Status ) ) { 1974 1975 IoSetHardErrorOrVerifyDevice( Irp, Device ); 1976 } 1977 1978 NT_ASSERT( STATUS_VERIFY_REQUIRED != Status); 1979 1980 FatNormalizeAndRaiseStatus( IrpContext, Status ); 1981 } 1982 1983 // 1984 // If there is still an Irp, send it off to an Ex Worker thread. 1985 // 1986 1987 if ( Irp != NULL ) { 1988 1989 Status = FatFsdPostRequest( IrpContext, Irp ); 1990 } 1991 1992 } 1993 _SEH2_EXCEPT (FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 1994 1995 // 1996 // We had some trouble trying to perform the verify or raised 1997 // an error ourselves. So we'll abort the I/O request with 1998 // the error status that we get back from the execption code. 1999 // 2000 2001 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 2002 } _SEH2_END; 2003 2004 return Status; 2005 } 2006 2007 // 2008 // Local support routine 2009 // 2010 2011 NTSTATUS 2012 NTAPI 2013 FatMarkVolumeCompletionRoutine( 2014 _In_ PDEVICE_OBJECT DeviceObject, 2015 _In_ PIRP Irp, 2016 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt 2017 ) 2018 2019 { 2020 // 2021 // Set the event so that our call will wake up. 2022 // 2023 2024 KeSetEvent( (PKEVENT)Contxt, 0, FALSE ); 2025 2026 UNREFERENCED_PARAMETER( DeviceObject ); 2027 UNREFERENCED_PARAMETER( Irp ); 2028 2029 return STATUS_MORE_PROCESSING_REQUIRED; 2030 } 2031 2032 2033