Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1835 lines
45 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. VerfySup.c
  5. Abstract:
  6. This module implements the Fat Verify volume and fcb/dcb support
  7. routines
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 01-Jun-1990
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_VERFYSUP)
  19. //
  20. // The Debug trace level for this module
  21. //
  22. #define Dbg (DEBUG_TRACE_VERFYSUP)
  23. //
  24. // Local procedure prototypes
  25. //
  26. VOID
  27. FatResetFcb (
  28. IN PIRP_CONTEXT IrpContext,
  29. IN PFCB Fcb
  30. );
  31. VOID
  32. FatDetermineAndMarkFcbCondition (
  33. IN PIRP_CONTEXT IrpContext,
  34. IN PFCB Fcb
  35. );
  36. VOID
  37. FatDeferredCleanVolume (
  38. PVOID Parameter
  39. );
  40. NTSTATUS
  41. FatMarkVolumeCompletionRoutine(
  42. IN PDEVICE_OBJECT DeviceObject,
  43. IN PIRP Irp,
  44. IN PVOID Contxt
  45. );
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGE, FatCheckDirtyBit)
  48. #pragma alloc_text(PAGE, FatVerifyOperationIsLegal)
  49. #pragma alloc_text(PAGE, FatDeferredCleanVolume)
  50. #pragma alloc_text(PAGE, FatDetermineAndMarkFcbCondition)
  51. #pragma alloc_text(PAGE, FatQuickVerifyVcb)
  52. #pragma alloc_text(PAGE, FatPerformVerify)
  53. #pragma alloc_text(PAGE, FatMarkFcbCondition)
  54. #pragma alloc_text(PAGE, FatResetFcb)
  55. #pragma alloc_text(PAGE, FatVerifyVcb)
  56. #pragma alloc_text(PAGE, FatVerifyFcb)
  57. #endif
  58. VOID
  59. FatMarkFcbCondition (
  60. IN PIRP_CONTEXT IrpContext,
  61. IN PFCB Fcb,
  62. IN FCB_CONDITION FcbCondition,
  63. IN BOOLEAN Recursive
  64. )
  65. /*++
  66. Routine Description:
  67. This routines marks the entire Fcb/Dcb structure from Fcb down with
  68. FcbCondition.
  69. Arguments:
  70. Fcb - Supplies the Fcb/Dcb being marked
  71. FcbCondition - Supplies the setting to use for the Fcb Condition
  72. Recursive - Specifies whether this condition should be applied to
  73. all children (see the case where we are invalidating a live volume
  74. for a case where this is now desireable).
  75. Return Value:
  76. None.
  77. --*/
  78. {
  79. DebugTrace(+1, Dbg, "FatMarkFcbCondition, Fcb = %08lx\n", Fcb );
  80. //
  81. // If we are marking this Fcb something other than Good, we will need
  82. // to have the Vcb exclusive.
  83. //
  84. ASSERT( FcbCondition != FcbNeedsToBeVerified ? TRUE :
  85. FatVcbAcquiredExclusive(IrpContext, Fcb->Vcb) );
  86. //
  87. // If this is a PagingFile it has to be good.
  88. //
  89. if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  90. Fcb->FcbCondition = FcbGood;
  91. return;
  92. }
  93. //
  94. // Update the condition of the Fcb.
  95. //
  96. Fcb->FcbCondition = FcbCondition;
  97. DebugTrace(0, Dbg, "MarkFcb: %Z\n", &Fcb->FullFileName);
  98. //
  99. // This FastIo flag is based on FcbCondition, so update it now. This only
  100. // applies to regular FCBs, of course.
  101. //
  102. if (Fcb->Header.NodeTypeCode == FAT_NTC_FCB) {
  103. Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
  104. }
  105. //
  106. // Now if we marked NeedsVerify or Bad a directory then we also need to
  107. // go and mark all of our children with the same condition.
  108. //
  109. if ( ((FcbCondition == FcbNeedsToBeVerified) ||
  110. (FcbCondition == FcbBad)) &&
  111. Recursive &&
  112. ((Fcb->Header.NodeTypeCode == FAT_NTC_DCB) ||
  113. (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB)) ) {
  114. PFCB OriginalFcb = Fcb;
  115. while ( (Fcb = FatGetNextFcbTopDown(IrpContext, Fcb, OriginalFcb)) != NULL ) {
  116. DebugTrace(0, Dbg, "MarkFcb: %Z\n", &Fcb->FullFileName);
  117. Fcb->FcbCondition = FcbCondition;
  118. //
  119. // We already know that FastIo is not possible since we are propagating
  120. // a parent's bad/verify flag down the tree - IO to the children must
  121. // take the long route for now.
  122. //
  123. Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
  124. }
  125. }
  126. DebugTrace(-1, Dbg, "FatMarkFcbCondition -> VOID\n", 0);
  127. return;
  128. }
  129. VOID
  130. FatVerifyVcb (
  131. IN PIRP_CONTEXT IrpContext,
  132. IN PVCB Vcb
  133. )
  134. /*++
  135. Routine Description:
  136. This routines verifies that the Vcb still denotes a valid Volume
  137. If the Vcb is bad it raises an error condition.
  138. Arguments:
  139. Vcb - Supplies the Vcb being verified
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. ULONG ChangeCount = 0;
  145. DebugTrace(+1, Dbg, "FatVerifyVcb, Vcb = %08lx\n", Vcb );
  146. //
  147. // If the media is removable and the verify volume flag in the
  148. // device object is not set then we want to ping the device
  149. // to see if it needs to be verified.
  150. //
  151. // Note that we only force this ping for create operations.
  152. // For others we take a sporting chance. If in the end we
  153. // have to physically access the disk, the right thing will happen.
  154. //
  155. if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  156. !FlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME) ) {
  157. IO_STATUS_BLOCK Iosb;
  158. NTSTATUS Status;
  159. Status = FatPerformDevIoCtrl( IrpContext,
  160. IOCTL_DISK_CHECK_VERIFY,
  161. Vcb->TargetDeviceObject,
  162. &ChangeCount,
  163. sizeof(ULONG),
  164. FALSE,
  165. TRUE,
  166. &Iosb );
  167. //
  168. // Verify potentially empty devices, explicit verify requests and
  169. // when we get the secondary indication of media change via the
  170. // device change count.
  171. //
  172. if ((Vcb->VcbCondition == VcbGood &&
  173. FatIsRawDevice( IrpContext, Status )) ||
  174. (Status == STATUS_VERIFY_REQUIRED) ||
  175. (NT_SUCCESS(Status) &&
  176. (Vcb->ChangeCount != ChangeCount))) {
  177. SetFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  178. }
  179. //
  180. // Raise the error condition otherwise.
  181. //
  182. else if (!NT_SUCCESS( Status )) {
  183. FatNormalizeAndRaiseStatus( IrpContext, Status );
  184. }
  185. }
  186. //
  187. // Now that the verify bit has been appropriately set, check the Vcb.
  188. //
  189. FatQuickVerifyVcb( IrpContext, Vcb );
  190. DebugTrace(-1, Dbg, "FatVerifyVcb -> VOID\n", 0);
  191. return;
  192. }
  193. VOID
  194. FatVerifyFcb (
  195. IN PIRP_CONTEXT IrpContext,
  196. IN PFCB Fcb
  197. )
  198. /*++
  199. Routine Description:
  200. This routines verifies that the Fcb still denotes the same file.
  201. If the Fcb is bad it raises a error condition.
  202. Arguments:
  203. Fcb - Supplies the Fcb being verified
  204. Return Value:
  205. None.
  206. --*/
  207. {
  208. PFCB CurrentFcb;
  209. DebugTrace(+1, Dbg, "FatVerifyFcb, Vcb = %08lx\n", Fcb );
  210. //
  211. // Always refuse operations on dismounted volumes.
  212. //
  213. if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
  214. FatRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED );
  215. }
  216. //
  217. // If this is the Fcb of a deleted dirent or our parent is deleted,
  218. // no-op this call with the hope that the caller will do the right thing.
  219. // The only caller we really have to worry about is the AdvanceOnly
  220. // callback for setting valid data length from Cc, this will happen after
  221. // cleanup (and file deletion), just before the SCM is ripped down.
  222. //
  223. if (IsFileDeleted( IrpContext, Fcb ) ||
  224. ((NodeType(Fcb) != FAT_NTC_ROOT_DCB) &&
  225. IsFileDeleted( IrpContext, Fcb->ParentDcb ))) {
  226. return;
  227. }
  228. //
  229. // If we are not in the process of doing a verify,
  230. // first do a quick spot check on the Vcb.
  231. //
  232. if ( Fcb->Vcb->VerifyThread != KeGetCurrentThread() ) {
  233. FatQuickVerifyVcb( IrpContext, Fcb->Vcb );
  234. }
  235. //
  236. // Now based on the condition of the Fcb we'll either return
  237. // immediately to the caller, raise a condition, or do some work
  238. // to verify the Fcb.
  239. //
  240. switch (Fcb->FcbCondition) {
  241. case FcbGood:
  242. DebugTrace(0, Dbg, "The Fcb is good\n", 0);
  243. break;
  244. case FcbBad:
  245. FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
  246. break;
  247. case FcbNeedsToBeVerified:
  248. //
  249. // We loop here checking our ancestors until we hit an Fcb which
  250. // is either good or bad.
  251. //
  252. CurrentFcb = Fcb;
  253. while (CurrentFcb->FcbCondition == FcbNeedsToBeVerified) {
  254. FatDetermineAndMarkFcbCondition(IrpContext, CurrentFcb);
  255. //
  256. // If this Fcb didn't make it, or it was the Root Dcb, exit
  257. // the loop now, else continue with out parent.
  258. //
  259. if ( (CurrentFcb->FcbCondition != FcbGood) ||
  260. (NodeType(CurrentFcb) == FAT_NTC_ROOT_DCB) ) {
  261. break;
  262. }
  263. CurrentFcb = CurrentFcb->ParentDcb;
  264. }
  265. //
  266. // Now we can just look at ourselves to see how we did.
  267. //
  268. if (Fcb->FcbCondition != FcbGood) {
  269. FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
  270. }
  271. break;
  272. default:
  273. DebugDump("Invalid FcbCondition\n", 0, Fcb);
  274. FatBugCheck( Fcb->FcbCondition, 0, 0 );
  275. }
  276. DebugTrace(-1, Dbg, "FatVerifyFcb -> VOID\n", 0);
  277. return;
  278. }
  279. VOID
  280. FatDeferredCleanVolume (
  281. PVOID Parameter
  282. )
  283. /*++
  284. Routine Description:
  285. This is the routine that performs the actual FatMarkVolumeClean call.
  286. It assures that the target volume still exists as there ia a race
  287. condition between queueing the ExWorker item and volumes going away.
  288. Arguments:
  289. Parameter - Points to a clean volume packet that was allocated from pool
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  295. PLIST_ENTRY Links;
  296. PVCB Vcb;
  297. IRP_CONTEXT IrpContext;
  298. BOOLEAN VcbExists = FALSE;
  299. DebugTrace(+1, Dbg, "FatDeferredCleanVolume\n", 0);
  300. Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter;
  301. Vcb = Packet->Vcb;
  302. //
  303. // Make us appear as a top level FSP request so that we will
  304. // receive any errors from the operation.
  305. //
  306. IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );
  307. //
  308. // Dummy up and Irp Context so we can call our worker routines
  309. //
  310. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT));
  311. SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  312. //
  313. // Acquire shared access to the global lock and make sure this volume
  314. // still exists.
  315. //
  316. FatAcquireSharedGlobal( &IrpContext );
  317. for (Links = FatData.VcbQueue.Flink;
  318. Links != &FatData.VcbQueue;
  319. Links = Links->Flink) {
  320. PVCB ExistingVcb;
  321. ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
  322. if ( Vcb == ExistingVcb ) {
  323. VcbExists = TRUE;
  324. break;
  325. }
  326. }
  327. //
  328. // If the vcb is good then mark it clean. Ignore any problems.
  329. //
  330. if ( VcbExists &&
  331. (Vcb->VcbCondition == VcbGood) &&
  332. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ) {
  333. try {
  334. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  335. FatMarkVolume( &IrpContext, Vcb, VolumeClean );
  336. }
  337. //
  338. // Check for a pathological race condition, and fix it.
  339. //
  340. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
  341. FatMarkVolume( &IrpContext, Vcb, VolumeDirty );
  342. } else {
  343. //
  344. // Unlock the volume if it is removable.
  345. //
  346. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  347. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
  348. FatToggleMediaEjectDisable( &IrpContext, Vcb, FALSE );
  349. }
  350. }
  351. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  352. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  353. NOTHING;
  354. }
  355. }
  356. //
  357. // Release the global resource, unpin and repinned Bcbs and return.
  358. //
  359. FatReleaseGlobal( &IrpContext );
  360. try {
  361. FatUnpinRepinnedBcbs( &IrpContext );
  362. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  363. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  364. NOTHING;
  365. }
  366. IoSetTopLevelIrp( NULL );
  367. //
  368. // and finally free the packet.
  369. //
  370. ExFreePool( Packet );
  371. return;
  372. }
  373. VOID
  374. FatCleanVolumeDpc (
  375. IN PKDPC Dpc,
  376. IN PVOID DeferredContext,
  377. IN PVOID SystemArgument1,
  378. IN PVOID SystemArgument2
  379. )
  380. /*++
  381. Routine Description:
  382. This routine is dispatched 5 seconds after the last disk structure was
  383. modified in a specific volume, and exqueues an execuative worker thread
  384. to perform the actual task of marking the volume dirty.
  385. Arguments:
  386. DefferedContext - Contains the Vcb to process.
  387. Return Value:
  388. None.
  389. --*/
  390. {
  391. PVCB Vcb;
  392. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  393. Vcb = (PVCB)DeferredContext;
  394. //
  395. // If there is still dirty data (highly unlikely), set the timer for a
  396. // second in the future.
  397. //
  398. if (CcIsThereDirtyData(Vcb->Vpb)) {
  399. LARGE_INTEGER TwoSecondsFromNow;
  400. TwoSecondsFromNow.QuadPart = (LONG)-2*1000*1000*10;
  401. KeSetTimer( &Vcb->CleanVolumeTimer,
  402. TwoSecondsFromNow,
  403. &Vcb->CleanVolumeDpc );
  404. return;
  405. }
  406. //
  407. // If we couldn't get pool, oh well....
  408. //
  409. Packet = ExAllocatePool(NonPagedPool, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET));
  410. if ( Packet ) {
  411. Packet->Vcb = Vcb;
  412. Packet->Irp = NULL;
  413. //
  414. // Clear the dirty flag now since we cannot synchronize after this point.
  415. //
  416. ClearFlag( Packet->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  417. ExInitializeWorkItem( &Packet->Item, &FatDeferredCleanVolume, Packet );
  418. ExQueueWorkItem( &Packet->Item, CriticalWorkQueue );
  419. }
  420. return;
  421. }
  422. VOID
  423. FatMarkVolume (
  424. IN PIRP_CONTEXT IrpContext,
  425. IN PVCB Vcb,
  426. IN FAT_VOLUME_STATE VolumeState
  427. )
  428. /*++
  429. Routine Description:
  430. This routine moves the physically marked volume state between the clean
  431. and dirty states. For compatibility with Win9x, we manipulate both the
  432. historical DOS (on==clean in index 1 of the FAT) and NT (on==dirty in
  433. the CurrentHead field of the BPB) dirty bits.
  434. Arguments:
  435. Vcb - Supplies the Vcb being modified
  436. VolumeState - Supplies the state the volume is transitioning to
  437. Return Value:
  438. None.
  439. --*/
  440. {
  441. PCHAR Sector;
  442. PBCB Bcb = NULL;
  443. KEVENT Event;
  444. PIRP Irp = NULL;
  445. NTSTATUS Status;
  446. BOOLEAN FsInfoUpdate = FALSE;
  447. ULONG FsInfoOffset;
  448. ULONG ThisPass;
  449. LARGE_INTEGER Offset;
  450. DebugTrace(+1, Dbg, "FatMarkVolume, Vcb = %08lx\n", Vcb);
  451. //
  452. // We had best not be trying to scribble dirty/clean bits if the
  453. // volume is write protected. The responsibility lies with the
  454. // callers to make sure that operations that could cause a state
  455. // change cannot happen. There are a few, though, that show it
  456. // just doesn't make sense to force everyone to do the dinky
  457. // check.
  458. //
  459. //
  460. // If we were called for FAT12 or readonly media, return immediately.
  461. //
  462. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) ||
  463. FatIsFat12( Vcb )) {
  464. return;
  465. }
  466. //
  467. // We have two possible additional tasks to do to mark a volume
  468. //
  469. // Pass 0) Flip the dirty bit in the Bpb
  470. // Pass 1) Rewrite the FsInfo sector for FAT32 if needed
  471. //
  472. // In most cases we can collapse these two either because the volume
  473. // is either not FAT32 or the FsInfo sector is adjacent to the boot sector.
  474. //
  475. for (ThisPass = 0; ThisPass < 2; ThisPass++) {
  476. //
  477. // If this volume is being dirtied, or isn't FAT32, or if it is and
  478. // we were able to perform the fast update, or the bpb lied to us
  479. // about where the FsInfo went, we're done - no FsInfo to update in
  480. // a seperate write.
  481. //
  482. if (ThisPass == 1 && (!FatIsFat32( Vcb ) ||
  483. VolumeState != VolumeClean ||
  484. FsInfoUpdate ||
  485. Vcb->Bpb.FsInfoSector == 0)) {
  486. break;
  487. }
  488. //
  489. // Bail if we get an IO error.
  490. //
  491. try {
  492. ULONG PinLength;
  493. ULONG WriteLength;
  494. //
  495. // If the FAT table is 12-bit then our strategy is to pin the entire
  496. // thing when any of it is modified. Here we're going to pin the
  497. // first page, so in the 12-bit case we also want to pin the rest
  498. // of the FAT table.
  499. //
  500. Offset.QuadPart = 0;
  501. if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
  502. //
  503. // But we only write back the first sector.
  504. //
  505. PinLength = FatReservedBytes(&Vcb->Bpb) + FatBytesPerFat(&Vcb->Bpb);
  506. WriteLength = Vcb->Bpb.BytesPerSector;
  507. } else {
  508. WriteLength = PinLength = Vcb->Bpb.BytesPerSector;
  509. //
  510. // If this is a FAT32 volume going into the clean state,
  511. // see about doing the FsInfo sector.
  512. //
  513. if (FatIsFat32( Vcb ) && VolumeState == VolumeClean) {
  514. //
  515. // If the FsInfo sector immediately follows the boot sector,
  516. // we can do this in a single operation by rewriting both
  517. // sectors at once.
  518. //
  519. if (Vcb->Bpb.FsInfoSector == 1) {
  520. ASSERT( ThisPass == 0 );
  521. FsInfoUpdate = TRUE;
  522. FsInfoOffset = Vcb->Bpb.BytesPerSector;
  523. WriteLength = PinLength = Vcb->Bpb.BytesPerSector * 2;
  524. } else if (ThisPass == 1) {
  525. //
  526. // We are doing an explicit write to the FsInfo sector.
  527. //
  528. FsInfoUpdate = TRUE;
  529. FsInfoOffset = 0;
  530. Offset.QuadPart = Vcb->Bpb.BytesPerSector * Vcb->Bpb.FsInfoSector;
  531. }
  532. }
  533. }
  534. //
  535. // Call Cc directly here so that we can avoid overhead and push this
  536. // right down to the disk.
  537. //
  538. CcPinRead( Vcb->VirtualVolumeFile,
  539. &Offset,
  540. PinLength,
  541. TRUE,
  542. &Bcb,
  543. (PVOID *)&Sector );
  544. DbgDoit( IrpContext->PinCount += 1 )
  545. //
  546. // Set the Bpb on Pass 0 always
  547. //
  548. if (ThisPass == 0) {
  549. PCHAR CurrentHead;
  550. //
  551. // Before we do anything, doublecheck that this still looks like a
  552. // FAT bootsector. If it doesn't, something remarkable happened
  553. // and we should avoid touching the volume.
  554. //
  555. // THIS IS TEMPORARY (but may last a while)
  556. //
  557. if (!FatIsBootSectorFat( (PPACKED_BOOT_SECTOR) Sector )) {
  558. return;
  559. }
  560. if (FatIsFat32( Vcb )) {
  561. CurrentHead = &((PPACKED_BOOT_SECTOR_EX) Sector)->CurrentHead;
  562. } else {
  563. CurrentHead = &((PPACKED_BOOT_SECTOR) Sector)->CurrentHead;
  564. }
  565. if (VolumeState == VolumeClean) {
  566. ClearFlag( *CurrentHead, FAT_BOOT_SECTOR_DIRTY );
  567. } else {
  568. SetFlag( *CurrentHead, FAT_BOOT_SECTOR_DIRTY );
  569. //
  570. // In addition, if this request received an error that may indicate
  571. // media corruption, have autochk perform a surface test.
  572. //
  573. if ( VolumeState == VolumeDirtyWithSurfaceTest ) {
  574. SetFlag( *CurrentHead, FAT_BOOT_SECTOR_TEST_SURFACE );
  575. }
  576. }
  577. }
  578. //
  579. // Update the FsInfo as appropriate.
  580. //
  581. if (FsInfoUpdate) {
  582. PFSINFO_SECTOR FsInfoSector = (PFSINFO_SECTOR) ((PCHAR)Sector + FsInfoOffset);
  583. //
  584. // We just rewrite all of the spec'd fields. Note that we don't
  585. // care to synchronize with the allocation package - this will be
  586. // quickly taken care of by a re-dirtying of the volume if a change
  587. // is racing with us. Remember that this is all a compatibility
  588. // deference for Win9x FAT32 - NT will never look at this information.
  589. //
  590. FsInfoSector->SectorBeginSignature = FSINFO_SECTOR_BEGIN_SIGNATURE;
  591. FsInfoSector->FsInfoSignature = FSINFO_SIGNATURE;
  592. FsInfoSector->FreeClusterCount = Vcb->AllocationSupport.NumberOfFreeClusters;
  593. FsInfoSector->NextFreeCluster = Vcb->ClusterHint;
  594. FsInfoSector->SectorEndSignature = FSINFO_SECTOR_END_SIGNATURE;
  595. }
  596. //
  597. // Initialize the event we're going to use
  598. //
  599. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  600. //
  601. // Build the irp for the operation and also set the override flag.
  602. // Note that we may be at APC level, so do this asyncrhonously and
  603. // use an event for synchronization as normal request completion
  604. // cannot occur at APC level.
  605. //
  606. Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
  607. Vcb->TargetDeviceObject,
  608. (PVOID)Sector,
  609. WriteLength,
  610. &Offset,
  611. NULL );
  612. if ( Irp == NULL ) {
  613. try_return(NOTHING);
  614. }
  615. //
  616. // Make this operation write-through. It never hurts to try to be
  617. // safer about this, even though we aren't logged.
  618. //
  619. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_WRITE_THROUGH );
  620. //
  621. // Set up the completion routine
  622. //
  623. IoSetCompletionRoutine( Irp,
  624. FatMarkVolumeCompletionRoutine,
  625. &Event,
  626. TRUE,
  627. TRUE,
  628. TRUE );
  629. //
  630. // Call the device to do the write and wait for it to finish.
  631. // Igmore any return status.
  632. //
  633. Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
  634. if (Status == STATUS_PENDING) {
  635. (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  636. }
  637. try_exit: NOTHING;
  638. } finally {
  639. //
  640. // Clean up the Irp and Mdl
  641. //
  642. if (Irp) {
  643. //
  644. // If there is an MDL (or MDLs) associated with this I/O
  645. // request, Free it (them) here. This is accomplished by
  646. // walking the MDL list hanging off of the IRP and deallocating
  647. // each MDL encountered.
  648. //
  649. while (Irp->MdlAddress != NULL) {
  650. PMDL NextMdl;
  651. NextMdl = Irp->MdlAddress->Next;
  652. MmUnlockPages( Irp->MdlAddress );
  653. IoFreeMdl( Irp->MdlAddress );
  654. Irp->MdlAddress = NextMdl;
  655. }
  656. IoFreeIrp( Irp );
  657. }
  658. if (Bcb != NULL) {
  659. FatUnpinBcb( IrpContext, Bcb );
  660. }
  661. }
  662. }
  663. //
  664. // Flip the dirty bit in the FAT
  665. //
  666. if (VolumeState == VolumeDirty) {
  667. FatSetFatEntry( IrpContext, Vcb, FAT_DIRTY_BIT_INDEX, FAT_DIRTY_VOLUME);
  668. } else {
  669. FatSetFatEntry( IrpContext, Vcb, FAT_DIRTY_BIT_INDEX, FAT_CLEAN_VOLUME);
  670. }
  671. DebugTrace(-1, Dbg, "FatMarkVolume -> VOID\n", 0);
  672. return;
  673. }
  674. VOID
  675. FatFspMarkVolumeDirtyWithRecover(
  676. PVOID Parameter
  677. )
  678. /*++
  679. Routine Description:
  680. This is the routine that performs the actual FatMarkVolume Dirty call
  681. on a paging file Io that encounters a media error. It is responsible
  682. for completing the PagingIo Irp as soon as this is done.
  683. Note: this routine (and thus FatMarkVolume()) must be resident as
  684. the paging file might be damaged at this point.
  685. Arguments:
  686. Parameter - Points to a dirty volume packet that was allocated from pool
  687. Return Value:
  688. None.
  689. --*/
  690. {
  691. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  692. PVCB Vcb;
  693. IRP_CONTEXT IrpContext;
  694. PIRP Irp;
  695. BOOLEAN VcbExists = FALSE;
  696. DebugTrace(+1, Dbg, "FatDeferredCleanVolume\n", 0);
  697. Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter;
  698. Vcb = Packet->Vcb;
  699. Irp = Packet->Irp;
  700. //
  701. // Dummy up the IrpContext so we can call our worker routines
  702. //
  703. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT));
  704. SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  705. IrpContext.OriginatingIrp = Irp;
  706. //
  707. // Make us appear as a top level FSP request so that we will
  708. // receive any errors from the operation.
  709. //
  710. IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );
  711. //
  712. // Try to write out the dirty bit. If something goes wrong, we
  713. // tried.
  714. //
  715. try {
  716. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  717. FatMarkVolume( &IrpContext, Vcb, VolumeDirtyWithSurfaceTest );
  718. } except(FatExceptionFilter( &IrpContext, GetExceptionInformation() )) {
  719. NOTHING;
  720. }
  721. IoSetTopLevelIrp( NULL );
  722. //
  723. // Now complete the originating Irp or set the synchronous event.
  724. //
  725. if (Packet->Event) {
  726. KeSetEvent( Packet->Event, 0, FALSE );
  727. } else {
  728. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  729. }
  730. }
  731. VOID
  732. FatCheckDirtyBit (
  733. IN PIRP_CONTEXT IrpContext,
  734. IN PVCB Vcb
  735. )
  736. /*++
  737. Routine Description:
  738. This routine looks at the volume dirty bit, and depending on the state of
  739. VCB_STATE_FLAG_MOUNTED_DIRTY, the appropriate action is taken.
  740. Arguments:
  741. Vcb - Supplies the Vcb being queried.
  742. Return Value:
  743. None.
  744. --*/
  745. {
  746. BOOLEAN Dirty;
  747. PPACKED_BOOT_SECTOR BootSector;
  748. PBCB BootSectorBcb;
  749. UNICODE_STRING VolumeLabel;
  750. //
  751. // Look in the boot sector
  752. //
  753. FatReadVolumeFile( IrpContext,
  754. Vcb,
  755. 0,
  756. sizeof(PACKED_BOOT_SECTOR),
  757. &BootSectorBcb,
  758. (PVOID *)&BootSector );
  759. try {
  760. //
  761. // Check if the magic bit is set
  762. //
  763. if (IsBpbFat32(&BootSector->PackedBpb)) {
  764. Dirty = BooleanFlagOn( ((PPACKED_BOOT_SECTOR_EX)BootSector)->CurrentHead,
  765. FAT_BOOT_SECTOR_DIRTY );
  766. } else {
  767. Dirty = BooleanFlagOn( BootSector->CurrentHead, FAT_BOOT_SECTOR_DIRTY );
  768. }
  769. //
  770. // Setup the VolumeLabel string
  771. //
  772. VolumeLabel.Length = Vcb->Vpb->VolumeLabelLength;
  773. VolumeLabel.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  774. VolumeLabel.Buffer = &Vcb->Vpb->VolumeLabel[0];
  775. if ( Dirty ) {
  776. //
  777. // Do not trigger the mounted dirty bit if this is a verify
  778. // and the volume is a boot or paging device. We know that
  779. // a boot or paging device cannot leave the system, and thus
  780. // that on its mount we will have figured this out correctly.
  781. //
  782. // This logic is a reasonable hack-o-rama to make BillG happy
  783. // since his machine ran chkdsk after he installed Beta 3. Why?
  784. // 'cause setup cracked a non-exclusive DASD handle near the
  785. // end of setup, wrote some data, closed the handle and we
  786. // set the verify bit ... came back around and saw that other
  787. // arbitrary activity had left the volume in a temporarily dirty
  788. // state.
  789. //
  790. // Of course, the real problem is that we don't have a journal.
  791. //
  792. if (!(IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  793. IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME &&
  794. FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE))) {
  795. KdPrintEx((DPFLTR_FASTFAT_ID,
  796. DPFLTR_INFO_LEVEL,
  797. "FASTFAT: WARNING! Mounting Dirty Volume %Z\n",
  798. &VolumeLabel));
  799. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  800. }
  801. } else {
  802. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  803. KdPrintEx((DPFLTR_FASTFAT_ID,
  804. DPFLTR_INFO_LEVEL,
  805. "FASTFAT: Volume %Z has been cleaned.\n",
  806. &VolumeLabel));
  807. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  808. } else {
  809. (VOID)FsRtlBalanceReads( Vcb->TargetDeviceObject );
  810. }
  811. }
  812. } finally {
  813. FatUnpinBcb( IrpContext, BootSectorBcb );
  814. }
  815. }
  816. VOID
  817. FatVerifyOperationIsLegal (
  818. IN PIRP_CONTEXT IrpContext
  819. )
  820. /*++
  821. Routine Description:
  822. This routine determines is the requested operation should be allowed to
  823. continue. It either returns to the user if the request is Okay, or
  824. raises an appropriate status.
  825. Arguments:
  826. Irp - Supplies the Irp to check
  827. Return Value:
  828. None.
  829. --*/
  830. {
  831. PIRP Irp;
  832. PFILE_OBJECT FileObject;
  833. Irp = IrpContext->OriginatingIrp;
  834. //
  835. // If the Irp is not present, then we got here via close.
  836. //
  837. //
  838. if ( Irp == NULL ) {
  839. return;
  840. }
  841. FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
  842. //
  843. // If there is not a file object, we cannot continue.
  844. //
  845. if ( FileObject == NULL ) {
  846. return;
  847. }
  848. //
  849. // If the file object has already been cleaned up, and
  850. //
  851. // A) This request is a paging io read or write, or
  852. // B) This request is a close operation, or
  853. // C) This request is a set or query info call (for Lou)
  854. // D) This is an MDL complete
  855. //
  856. // let it pass, otherwise return STATUS_FILE_CLOSED.
  857. //
  858. if ( FlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE) ) {
  859. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  860. if ( (FlagOn(Irp->Flags, IRP_PAGING_IO)) ||
  861. (IrpSp->MajorFunction == IRP_MJ_CLOSE ) ||
  862. (IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION) ||
  863. (IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) ||
  864. ( ( (IrpSp->MajorFunction == IRP_MJ_READ) ||
  865. (IrpSp->MajorFunction == IRP_MJ_WRITE) ) &&
  866. FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE) ) ) {
  867. NOTHING;
  868. } else {
  869. FatRaiseStatus( IrpContext, STATUS_FILE_CLOSED );
  870. }
  871. }
  872. return;
  873. }
  874. //
  875. // Internal support routine
  876. //
  877. VOID
  878. FatResetFcb (
  879. IN PIRP_CONTEXT IrpContext,
  880. IN PFCB Fcb
  881. )
  882. /*++
  883. Routine Description:
  884. This routine is called when an Fcb has been marked as needs to be verified.
  885. It does the following tasks:
  886. - Reset Mcb mapping information
  887. - For directories, reset dirent hints
  888. - Set allocation size to unknown
  889. Arguments:
  890. Fcb - Supplies the Fcb to reset
  891. Return Value:
  892. None.
  893. --*/
  894. {
  895. //
  896. // Don't do the two following operations for the Root Dcb
  897. // or paging files. Paging files!? Yes, if someone diddles
  898. // a volume we try to reverify all of the Fcbs just in case;
  899. // however, there is no safe way to chuck and retrieve the
  900. // mapping pair information for the paging file. Lose it and
  901. // die.
  902. //
  903. if ( NodeType(Fcb) != FAT_NTC_ROOT_DCB &&
  904. !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  905. //
  906. // Reset the mcb mapping.
  907. //
  908. FsRtlRemoveLargeMcbEntry( &Fcb->Mcb, 0, 0xFFFFFFFF );
  909. //
  910. // Reset the allocation size to 0 or unknown
  911. //
  912. if ( Fcb->FirstClusterOfFile == 0 ) {
  913. Fcb->Header.AllocationSize.QuadPart = 0;
  914. } else {
  915. Fcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
  916. }
  917. }
  918. //
  919. // If this is a directory, reset the hints.
  920. //
  921. if ( (NodeType(Fcb) == FAT_NTC_DCB) ||
  922. (NodeType(Fcb) == FAT_NTC_ROOT_DCB) ) {
  923. //
  924. // Force a rescan of the directory
  925. //
  926. Fcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
  927. Fcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
  928. }
  929. }
  930. //
  931. // Internal support routine
  932. //
  933. VOID
  934. FatDetermineAndMarkFcbCondition (
  935. IN PIRP_CONTEXT IrpContext,
  936. IN PFCB Fcb
  937. )
  938. /*++
  939. Routine Description:
  940. This routine checks a specific Fcb to see if it is different from what's
  941. on the disk. The following things are checked:
  942. - File Name
  943. - File Size (if not directory)
  944. - First Cluster Of File
  945. - Dirent Attributes
  946. Arguments:
  947. Fcb - Supplies the Fcb to examine
  948. Return Value:
  949. None.
  950. --*/
  951. {
  952. PDIRENT Dirent;
  953. PBCB DirentBcb;
  954. ULONG FirstClusterOfFile;
  955. OEM_STRING Name;
  956. CHAR Buffer[16];
  957. //
  958. // If this is the Root Dcb, special case it. That is, we know
  959. // by definition that it is good since it is fixed in the volume
  960. // structure.
  961. //
  962. if ( NodeType(Fcb) == FAT_NTC_ROOT_DCB ) {
  963. FatResetFcb( IrpContext, Fcb );
  964. FatMarkFcbCondition( IrpContext, Fcb, FcbGood, FALSE );
  965. return;
  966. }
  967. // The first thing we need to do to verify ourselves is
  968. // locate the dirent on the disk.
  969. //
  970. FatGetDirentFromFcbOrDcb( IrpContext,
  971. Fcb,
  972. &Dirent,
  973. &DirentBcb );
  974. //
  975. // If we couldn't get the dirent, this fcb must be bad (case of
  976. // enclosing directory shrinking during the time it was ejected).
  977. //
  978. if (DirentBcb == NULL) {
  979. FatMarkFcbCondition( IrpContext, Fcb, FcbBad, TRUE );
  980. return;
  981. }
  982. //
  983. // We located the dirent for ourselves now make sure it
  984. // is really ours by comparing the Name and FatFlags.
  985. // Then for a file we also check the file size.
  986. //
  987. // Note that we have to unpin the Bcb before calling FatResetFcb
  988. // in order to avoid a deadlock in CcUninitializeCacheMap.
  989. //
  990. try {
  991. Name.MaximumLength = 16;
  992. Name.Buffer = &Buffer[0];
  993. Fat8dot3ToString( IrpContext, Dirent, FALSE, &Name );
  994. //
  995. // We need to calculate the first cluster 'cause FAT32 splits
  996. // this field across the dirent.
  997. //
  998. FirstClusterOfFile = Dirent->FirstClusterOfFile;
  999. if (FatIsFat32( Fcb->Vcb )) {
  1000. FirstClusterOfFile += Dirent->FirstClusterOfFileHi << 16;
  1001. }
  1002. if (!RtlEqualString( &Name, &Fcb->ShortName.Name.Oem, TRUE )
  1003. ||
  1004. ( (NodeType(Fcb) == FAT_NTC_FCB) &&
  1005. (Fcb->Header.FileSize.LowPart != Dirent->FileSize) )
  1006. ||
  1007. (FirstClusterOfFile != Fcb->FirstClusterOfFile)
  1008. ||
  1009. (Dirent->Attributes != Fcb->DirentFatFlags) ) {
  1010. FatMarkFcbCondition( IrpContext, Fcb, FcbBad, TRUE );
  1011. } else {
  1012. //
  1013. // We passed. Get the Fcb ready to use again.
  1014. //
  1015. FatResetFcb( IrpContext, Fcb );
  1016. FatMarkFcbCondition( IrpContext, Fcb, FcbGood, FALSE );
  1017. }
  1018. } finally {
  1019. FatUnpinBcb( IrpContext, DirentBcb );
  1020. }
  1021. return;
  1022. }
  1023. //
  1024. // Internal support routine
  1025. //
  1026. VOID
  1027. FatQuickVerifyVcb (
  1028. IN PIRP_CONTEXT IrpContext,
  1029. IN PVCB Vcb
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. This routines just checks the verify bit in the real device and the
  1034. Vcb condition and raises an appropriate exception if so warented.
  1035. It is called when verifying both Fcbs and Vcbs.
  1036. Arguments:
  1037. Vcb - Supplies the Vcb to check the condition of.
  1038. Return Value:
  1039. None.
  1040. --*/
  1041. {
  1042. //
  1043. // If the real device needs to be verified we'll set the
  1044. // DeviceToVerify to be our real device and raise VerifyRequired.
  1045. //
  1046. if (FlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
  1047. DebugTrace(0, Dbg, "The Vcb needs to be verified\n", 0);
  1048. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  1049. Vcb->Vpb->RealDevice );
  1050. FatRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED );
  1051. }
  1052. //
  1053. // Based on the condition of the Vcb we'll either return to our
  1054. // caller or raise an error condition
  1055. //
  1056. switch (Vcb->VcbCondition) {
  1057. case VcbGood:
  1058. DebugTrace(0, Dbg, "The Vcb is good\n", 0);
  1059. //
  1060. // Do a check here of an operation that would try to modify a
  1061. // write protected media.
  1062. //
  1063. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) &&
  1064. ((IrpContext->MajorFunction == IRP_MJ_WRITE) ||
  1065. (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
  1066. (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
  1067. (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
  1068. (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
  1069. (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1070. IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
  1071. IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->Parameters.FileSystemControl.FsControlCode ==
  1072. FSCTL_MARK_VOLUME_DIRTY))) {
  1073. //
  1074. // Set the real device for the pop-up info, and set the verify
  1075. // bit in the device object, so that we will force a verify
  1076. // in case the user put the correct media back in.
  1077. //
  1078. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  1079. Vcb->Vpb->RealDevice );
  1080. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  1081. FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED );
  1082. }
  1083. break;
  1084. case VcbNotMounted:
  1085. DebugTrace(0, Dbg, "The Vcb is not mounted\n", 0);
  1086. //
  1087. // Set the real device for the pop-up info, and set the verify
  1088. // bit in the device object, so that we will force a verify
  1089. // in case the user put the correct media back in.
  1090. //
  1091. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  1092. Vcb->Vpb->RealDevice );
  1093. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  1094. FatRaiseStatus( IrpContext, STATUS_WRONG_VOLUME );
  1095. break;
  1096. case VcbBad:
  1097. DebugTrace(0, Dbg, "The Vcb is bad\n", 0);
  1098. if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
  1099. FatRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED );
  1100. } else {
  1101. FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
  1102. }
  1103. break;
  1104. default:
  1105. DebugDump("Invalid VcbCondition\n", 0, Vcb);
  1106. FatBugCheck( Vcb->VcbCondition, 0, 0 );
  1107. }
  1108. }
  1109. NTSTATUS
  1110. FatPerformVerify (
  1111. IN PIRP_CONTEXT IrpContext,
  1112. IN PIRP Irp,
  1113. IN PDEVICE_OBJECT Device
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This routines performs an IoVerifyVolume operation and takes the
  1118. appropriate action. After the Verify is complete the originating
  1119. Irp is sent off to an Ex Worker Thread. This routine is called
  1120. from the exception handler.
  1121. Arguments:
  1122. Irp - The irp to send off after all is well and done.
  1123. Device - The real device needing verification.
  1124. Return Value:
  1125. None.
  1126. --*/
  1127. {
  1128. PVCB Vcb;
  1129. NTSTATUS Status = STATUS_SUCCESS;
  1130. PIO_STACK_LOCATION IrpSp;
  1131. //
  1132. // Check if this Irp has a status of Verify required and if it does
  1133. // then call the I/O system to do a verify.
  1134. //
  1135. // Skip the IoVerifyVolume if this is a mount or verify request
  1136. // itself. Trying a recursive mount will cause a deadlock with
  1137. // the DeviceObject->DeviceLock.
  1138. //
  1139. if ( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)
  1140. &&
  1141. ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) ||
  1142. (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME)) ) {
  1143. return FatFsdPostRequest( IrpContext, Irp );
  1144. }
  1145. DebugTrace(0, Dbg, "Verify Required, DeviceObject = %08lx\n", Device);
  1146. //
  1147. // Extract a pointer to the Vcb from the VolumeDeviceObject.
  1148. // Note that since we have specifically excluded mount,
  1149. // requests, we know that IrpSp->DeviceObject is indeed a
  1150. // volume device object.
  1151. //
  1152. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1153. Vcb = &CONTAINING_RECORD( IrpSp->DeviceObject,
  1154. VOLUME_DEVICE_OBJECT,
  1155. DeviceObject )->Vcb;
  1156. //
  1157. // Check if the volume still thinks it needs to be verified,
  1158. // if it doesn't then we can skip doing a verify because someone
  1159. // else beat us to it.
  1160. //
  1161. try {
  1162. if (FlagOn(Device->Flags, DO_VERIFY_VOLUME)) {
  1163. PFILE_OBJECT FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
  1164. BOOLEAN AllowRawMount;
  1165. //
  1166. // We will allow Raw to mount this volume if we were doing a
  1167. // a DASD open.
  1168. //
  1169. if ( (IrpContext->MajorFunction == IRP_MJ_CREATE) &&
  1170. (IrpSp->FileObject->FileName.Length == 0) &&
  1171. (IrpSp->FileObject->RelatedFileObject == NULL) ) {
  1172. AllowRawMount = TRUE;
  1173. } else {
  1174. AllowRawMount = FALSE;
  1175. }
  1176. //
  1177. // If the IopMount in IoVerifyVolume did something, and
  1178. // this is an absolute open, force a reparse.
  1179. //
  1180. Status = IoVerifyVolume( Device, AllowRawMount );
  1181. //
  1182. // If the verify operation completed it will return
  1183. // either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly.
  1184. //
  1185. // If FatVerifyVolume encountered an error during
  1186. // processing, it will return that error. If we got
  1187. // STATUS_WRONG_VOLUME from the verfy, and our volume
  1188. // is now mounted, commute the status to STATUS_SUCCESS.
  1189. //
  1190. if ( (Status == STATUS_WRONG_VOLUME) &&
  1191. (Vcb->VcbCondition == VcbGood) ) {
  1192. Status = STATUS_SUCCESS;
  1193. }
  1194. //
  1195. // Do a quick unprotected check here. The routine will do
  1196. // a safe check. After here we can release the resource.
  1197. // Note that if the volume really went away, we will be taking
  1198. // the Reparse path.
  1199. //
  1200. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  1201. if ( ((Vcb->VcbCondition == VcbNotMounted) ||
  1202. (Vcb->VcbCondition == VcbBad)) &&
  1203. (Vcb->OpenFileCount == 0) ) {
  1204. (VOID)FatCheckForDismount( IrpContext, Vcb, FALSE );
  1205. }
  1206. FatReleaseGlobal( IrpContext );
  1207. if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
  1208. (FileObject->RelatedFileObject == NULL) &&
  1209. ((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) {
  1210. Irp->IoStatus.Information = IO_REMOUNT;
  1211. FatCompleteRequest( IrpContext, Irp, STATUS_REPARSE );
  1212. Status = STATUS_REPARSE;
  1213. Irp = NULL;
  1214. }
  1215. if ( (Irp != NULL) && !NT_SUCCESS(Status) ) {
  1216. //
  1217. // Fill in the device object if required.
  1218. //
  1219. if ( IoIsErrorUserInduced( Status ) ) {
  1220. IoSetHardErrorOrVerifyDevice( Irp, Device );
  1221. }
  1222. FatNormalizeAndRaiseStatus( IrpContext, Status );
  1223. }
  1224. } else {
  1225. DebugTrace(0, Dbg, "Volume no longer needs verification\n", 0);
  1226. }
  1227. //
  1228. // If there is still an Irp, send it off to an Ex Worker thread.
  1229. //
  1230. if ( Irp != NULL ) {
  1231. Status = FatFsdPostRequest( IrpContext, Irp );
  1232. }
  1233. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1234. //
  1235. // We had some trouble trying to perform the verify or raised
  1236. // an error ourselves. So we'll abort the I/O request with
  1237. // the error status that we get back from the execption code.
  1238. //
  1239. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  1240. }
  1241. return Status;
  1242. }
  1243. //
  1244. // Local support routine
  1245. //
  1246. NTSTATUS
  1247. FatMarkVolumeCompletionRoutine(
  1248. IN PDEVICE_OBJECT DeviceObject,
  1249. IN PIRP Irp,
  1250. IN PVOID Contxt
  1251. )
  1252. {
  1253. //
  1254. // Set the event so that our call will wake up.
  1255. //
  1256. KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
  1257. UNREFERENCED_PARAMETER( DeviceObject );
  1258. UNREFERENCED_PARAMETER( Irp );
  1259. return STATUS_MORE_PROCESSING_REQUIRED;
  1260. }