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.

6550 lines
173 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for Fat called
  7. by the dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 28-Dec-1989
  11. Revision History:
  12. Scott Quinn [ScottQ] 05-Apr-1996 Added fat32 support.
  13. Mike Sliger [MSliger] 05-Apr-1996
  14. // @@END_DDKSPLIT
  15. --*/
  16. #include "FatProcs.h"
  17. //
  18. // The Bug check file id for this module
  19. //
  20. #define BugCheckFileId (FAT_BUG_CHECK_FSCTRL)
  21. //
  22. // The local debug trace level
  23. //
  24. #define Dbg (DEBUG_TRACE_FSCTRL)
  25. //
  26. // Local procedure prototypes
  27. //
  28. NTSTATUS
  29. FatMountVolume (
  30. IN PIRP_CONTEXT IrpContext,
  31. IN PDEVICE_OBJECT TargetDeviceObject,
  32. IN PVPB Vpb,
  33. IN PDEVICE_OBJECT FsDeviceObject
  34. );
  35. NTSTATUS
  36. FatVerifyVolume (
  37. IN PIRP_CONTEXT IrpContext,
  38. IN PIRP Irp
  39. );
  40. BOOLEAN
  41. FatIsMediaWriteProtected (
  42. IN PIRP_CONTEXT IrpContext,
  43. IN PDEVICE_OBJECT TargetDeviceObject
  44. );
  45. NTSTATUS
  46. FatUserFsCtrl (
  47. IN PIRP_CONTEXT IrpContext,
  48. IN PIRP Irp
  49. );
  50. NTSTATUS
  51. FatOplockRequest (
  52. IN PIRP_CONTEXT IrpContext,
  53. IN PIRP Irp
  54. );
  55. NTSTATUS
  56. FatLockVolume (
  57. IN PIRP_CONTEXT IrpContext,
  58. IN PIRP Irp
  59. );
  60. NTSTATUS
  61. FatUnlockVolume (
  62. IN PIRP_CONTEXT IrpContext,
  63. IN PIRP Irp
  64. );
  65. NTSTATUS
  66. FatDismountVolume (
  67. IN PIRP_CONTEXT IrpContext,
  68. IN PIRP Irp
  69. );
  70. NTSTATUS
  71. FatDirtyVolume (
  72. IN PIRP_CONTEXT IrpContext,
  73. IN PIRP Irp
  74. );
  75. NTSTATUS
  76. FatIsVolumeDirty (
  77. IN PIRP_CONTEXT IrpContext,
  78. IN PIRP Irp
  79. );
  80. NTSTATUS
  81. FatIsVolumeMounted (
  82. IN PIRP_CONTEXT IrpContext,
  83. IN PIRP Irp
  84. );
  85. NTSTATUS
  86. FatIsPathnameValid (
  87. IN PIRP_CONTEXT IrpContext,
  88. IN PIRP Irp
  89. );
  90. NTSTATUS
  91. FatInvalidateVolumes (
  92. IN PIRP Irp
  93. );
  94. BOOLEAN
  95. FatPerformVerifyDiskRead (
  96. IN PIRP_CONTEXT IrpContext,
  97. IN PVCB Vcb,
  98. IN PVOID Buffer,
  99. IN LBO Lbo,
  100. IN ULONG NumberOfBytesToRead,
  101. IN BOOLEAN ReturnOnError
  102. );
  103. NTSTATUS
  104. FatQueryRetrievalPointers (
  105. IN PIRP_CONTEXT IrpContext,
  106. IN PIRP Irp
  107. );
  108. NTSTATUS
  109. FatQueryBpb (
  110. IN PIRP_CONTEXT IrpContext,
  111. IN PIRP Irp
  112. );
  113. NTSTATUS
  114. FatGetStatistics (
  115. IN PIRP_CONTEXT IrpContext,
  116. IN PIRP Irp
  117. );
  118. NTSTATUS
  119. FatAllowExtendedDasdIo (
  120. IN PIRP_CONTEXT IrpContext,
  121. IN PIRP Irp
  122. );
  123. //
  124. // Local support routine prototypes
  125. //
  126. NTSTATUS
  127. FatGetVolumeBitmap (
  128. IN PIRP_CONTEXT IrpContext,
  129. IN PIRP Irp
  130. );
  131. NTSTATUS
  132. FatGetRetrievalPointers (
  133. IN PIRP_CONTEXT IrpContext,
  134. IN PIRP Irp
  135. );
  136. NTSTATUS
  137. FatMoveFile (
  138. IN PIRP_CONTEXT IrpContext,
  139. IN PIRP Irp
  140. );
  141. VOID
  142. FatComputeMoveFileSplicePoints (
  143. PIRP_CONTEXT IrpContext,
  144. PFCB FcbOrDcb,
  145. ULONG FileOffset,
  146. ULONG TargetCluster,
  147. ULONG BytesToReallocate,
  148. PULONG FirstSpliceSourceCluster,
  149. PULONG FirstSpliceTargetCluster,
  150. PULONG SecondSpliceSourceCluster,
  151. PULONG SecondSpliceTargetCluster,
  152. PLARGE_MCB SourceMcb
  153. );
  154. VOID
  155. FatComputeMoveFileParameter (
  156. IN PIRP_CONTEXT IrpContext,
  157. IN PFCB FcbOrDcb,
  158. IN ULONG FileOffset,
  159. IN OUT PULONG ByteCount,
  160. OUT PULONG BytesToReallocate,
  161. OUT PULONG BytesToWrite
  162. );
  163. NTSTATUS
  164. FatSearchBufferForLabel(
  165. IN PIRP_CONTEXT IrpContext,
  166. IN PVPB Vpb,
  167. IN PVOID Buffer,
  168. IN ULONG Size,
  169. OUT PBOOLEAN LabelFound
  170. );
  171. VOID
  172. FatVerifyLookupFatEntry (
  173. IN PIRP_CONTEXT IrpContext,
  174. IN PVCB Vcb,
  175. IN ULONG FatIndex,
  176. IN OUT PULONG FatEntry
  177. );
  178. #ifdef ALLOC_PRAGMA
  179. #pragma alloc_text(PAGE, FatAddMcbEntry)
  180. #pragma alloc_text(PAGE, FatAllowExtendedDasdIo)
  181. #pragma alloc_text(PAGE, FatCommonFileSystemControl)
  182. #pragma alloc_text(PAGE, FatComputeMoveFileParameter)
  183. #pragma alloc_text(PAGE, FatComputeMoveFileSplicePoints)
  184. #pragma alloc_text(PAGE, FatDirtyVolume)
  185. #pragma alloc_text(PAGE, FatDismountVolume)
  186. #pragma alloc_text(PAGE, FatFsdFileSystemControl)
  187. #pragma alloc_text(PAGE, FatGetRetrievalPointers)
  188. #pragma alloc_text(PAGE, FatGetStatistics)
  189. #pragma alloc_text(PAGE, FatGetVolumeBitmap)
  190. #pragma alloc_text(PAGE, FatIsMediaWriteProtected)
  191. #pragma alloc_text(PAGE, FatIsPathnameValid)
  192. #pragma alloc_text(PAGE, FatIsVolumeDirty)
  193. #pragma alloc_text(PAGE, FatIsVolumeMounted)
  194. #pragma alloc_text(PAGE, FatLockVolume)
  195. #pragma alloc_text(PAGE, FatLookupLastMcbEntry)
  196. #pragma alloc_text(PAGE, FatMountVolume)
  197. #pragma alloc_text(PAGE, FatMoveFile)
  198. #pragma alloc_text(PAGE, FatOplockRequest)
  199. #pragma alloc_text(PAGE, FatPerformVerifyDiskRead)
  200. #pragma alloc_text(PAGE, FatQueryBpb)
  201. #pragma alloc_text(PAGE, FatQueryRetrievalPointers)
  202. #pragma alloc_text(PAGE, FatRemoveMcbEntry)
  203. #pragma alloc_text(PAGE, FatSearchBufferForLabel)
  204. #pragma alloc_text(PAGE, FatUnlockVolume)
  205. #pragma alloc_text(PAGE, FatUserFsCtrl)
  206. #pragma alloc_text(PAGE, FatVerifyLookupFatEntry)
  207. #pragma alloc_text(PAGE, FatVerifyVolume)
  208. #endif
  209. #if DBG
  210. BOOLEAN FatMoveFileDebug = 0;
  211. #endif
  212. //
  213. // These wrappers go around the MCB package; we scale the LBO's passed
  214. // in (which can be bigger than 32 bits on fat32) by the volume's sector
  215. // size.
  216. //
  217. // Note we now use the real large mcb package. This means these shims
  218. // now also convert the -1 unused LBN number to the 0 of the original
  219. // mcb package.
  220. //
  221. #define MCB_SCALE_LOG2 (Vcb->AllocationSupport.LogOfBytesPerSector)
  222. #define MCB_SCALE (1 << MCB_SCALE_LOG2)
  223. #define MCB_SCALE_MODULO (MCB_SCALE - 1)
  224. BOOLEAN
  225. FatAddMcbEntry (
  226. IN PVCB Vcb,
  227. IN PLARGE_MCB Mcb,
  228. IN VBO Vbo,
  229. IN LBO Lbo,
  230. IN ULONG SectorCount
  231. )
  232. {
  233. PAGED_CODE();
  234. if (SectorCount) {
  235. //
  236. // Round up sectors, but be careful as SectorCount approaches 4Gb.
  237. // Note that for x>0, (x+m-1)/m = ((x-1)/m)+(m/m) = ((x-1)/m)+1
  238. //
  239. SectorCount--;
  240. SectorCount >>= MCB_SCALE_LOG2;
  241. SectorCount++;
  242. }
  243. Vbo >>= MCB_SCALE_LOG2;
  244. Lbo >>= MCB_SCALE_LOG2;
  245. return FsRtlAddLargeMcbEntry( Mcb,
  246. ((LONGLONG) Vbo),
  247. ((LONGLONG) Lbo),
  248. ((LONGLONG) SectorCount) );
  249. }
  250. BOOLEAN
  251. FatLookupMcbEntry (
  252. IN PVCB Vcb,
  253. IN PLARGE_MCB Mcb,
  254. IN VBO Vbo,
  255. OUT PLBO Lbo,
  256. OUT PULONG SectorCount OPTIONAL,
  257. OUT PULONG Index OPTIONAL
  258. )
  259. {
  260. BOOLEAN Results;
  261. LONGLONG LiLbo;
  262. LONGLONG LiSectorCount;
  263. ULONG Remainder;
  264. LiLbo = 0;
  265. LiSectorCount = 0;
  266. Remainder = Vbo & MCB_SCALE_MODULO;
  267. Results = FsRtlLookupLargeMcbEntry( Mcb,
  268. (Vbo >> MCB_SCALE_LOG2),
  269. &LiLbo,
  270. ARGUMENT_PRESENT(SectorCount) ? &LiSectorCount : NULL,
  271. NULL,
  272. NULL,
  273. Index );
  274. if ((ULONG) LiLbo != -1) {
  275. *Lbo = (((LBO) LiLbo) << MCB_SCALE_LOG2);
  276. if (Results) {
  277. *Lbo += Remainder;
  278. }
  279. } else {
  280. *Lbo = 0;
  281. }
  282. if (ARGUMENT_PRESENT(SectorCount)) {
  283. *SectorCount = (ULONG) LiSectorCount;
  284. if (*SectorCount) {
  285. *SectorCount <<= MCB_SCALE_LOG2;
  286. if (*SectorCount == 0) {
  287. *SectorCount = (ULONG) -1;
  288. }
  289. if (Results) {
  290. *SectorCount -= Remainder;
  291. }
  292. }
  293. }
  294. return Results;
  295. }
  296. //
  297. // NOTE: Vbo/Lbn undefined if MCB is empty & return code false.
  298. //
  299. BOOLEAN
  300. FatLookupLastMcbEntry (
  301. IN PVCB Vcb,
  302. IN PLARGE_MCB Mcb,
  303. OUT PVBO Vbo,
  304. OUT PLBO Lbo,
  305. OUT PULONG Index
  306. )
  307. {
  308. BOOLEAN Results;
  309. LONGLONG LiVbo;
  310. LONGLONG LiLbo;
  311. ULONG LocalIndex;
  312. PAGED_CODE();
  313. LiVbo = LiLbo = 0;
  314. LocalIndex = 0;
  315. Results = FsRtlLookupLastLargeMcbEntryAndIndex( Mcb,
  316. &LiVbo,
  317. &LiLbo,
  318. &LocalIndex );
  319. *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2;
  320. if (((ULONG) LiLbo) != -1) {
  321. *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2;
  322. *Lbo += (MCB_SCALE - 1);
  323. *Vbo += (MCB_SCALE - 1);
  324. } else {
  325. *Lbo = 0;
  326. }
  327. if (Index) {
  328. *Index = LocalIndex;
  329. }
  330. return Results;
  331. }
  332. BOOLEAN
  333. FatGetNextMcbEntry (
  334. IN PVCB Vcb,
  335. IN PLARGE_MCB Mcb,
  336. IN ULONG RunIndex,
  337. OUT PVBO Vbo,
  338. OUT PLBO Lbo,
  339. OUT PULONG SectorCount
  340. )
  341. {
  342. BOOLEAN Results;
  343. LONGLONG LiVbo;
  344. LONGLONG LiLbo;
  345. LONGLONG LiSectorCount;
  346. PAGED_CODE();
  347. LiVbo = LiLbo = 0;
  348. Results = FsRtlGetNextLargeMcbEntry( Mcb,
  349. RunIndex,
  350. &LiVbo,
  351. &LiLbo,
  352. &LiSectorCount );
  353. if (Results) {
  354. *Vbo = ((VBO) LiVbo) << MCB_SCALE_LOG2;
  355. if (((ULONG) LiLbo) != -1) {
  356. *Lbo = ((LBO) LiLbo) << MCB_SCALE_LOG2;
  357. } else {
  358. *Lbo = 0;
  359. }
  360. *SectorCount = ((ULONG) LiSectorCount) << MCB_SCALE_LOG2;
  361. if ((*SectorCount == 0) && (LiSectorCount != 0)) {
  362. *SectorCount = (ULONG) -1; /* it overflowed */
  363. }
  364. }
  365. return Results;
  366. }
  367. VOID
  368. FatRemoveMcbEntry (
  369. IN PVCB Vcb,
  370. IN PLARGE_MCB Mcb,
  371. IN VBO Vbo,
  372. IN ULONG SectorCount
  373. )
  374. {
  375. if ((SectorCount) && (SectorCount != 0xFFFFFFFF)) {
  376. SectorCount--;
  377. SectorCount >>= MCB_SCALE_LOG2;
  378. SectorCount++;
  379. }
  380. Vbo >>= MCB_SCALE_LOG2;
  381. #if DBG
  382. try {
  383. #endif
  384. FsRtlRemoveLargeMcbEntry( Mcb,
  385. (LONGLONG) Vbo,
  386. (LONGLONG) SectorCount);
  387. #if DBG
  388. } except(FatBugCheckExceptionFilter( GetExceptionInformation() )) {
  389. NOTHING;
  390. }
  391. #endif
  392. }
  393. NTSTATUS
  394. FatFsdFileSystemControl (
  395. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  396. IN PIRP Irp
  397. )
  398. /*++
  399. Routine Description:
  400. This routine implements the FSD part of FileSystem control operations
  401. Arguments:
  402. VolumeDeviceObject - Supplies the volume device object where the
  403. file exists
  404. Irp - Supplies the Irp being processed
  405. Return Value:
  406. NTSTATUS - The FSD status for the IRP
  407. --*/
  408. {
  409. BOOLEAN Wait;
  410. NTSTATUS Status;
  411. PIRP_CONTEXT IrpContext = NULL;
  412. BOOLEAN TopLevel;
  413. DebugTrace(+1, Dbg,"FatFsdFileSystemControl\n", 0);
  414. //
  415. // Call the common FileSystem Control routine, with blocking allowed if
  416. // synchronous. This opeation needs to special case the mount
  417. // and verify suboperations because we know they are allowed to block.
  418. // We identify these suboperations by looking at the file object field
  419. // and seeing if its null.
  420. //
  421. if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) {
  422. Wait = TRUE;
  423. } else {
  424. Wait = CanFsdWait( Irp );
  425. }
  426. FsRtlEnterFileSystem();
  427. TopLevel = FatIsIrpTopLevel( Irp );
  428. try {
  429. PIO_STACK_LOCATION IrpSp;
  430. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  431. //
  432. // We need to made a special check here for the InvalidateVolumes
  433. // FSCTL as that comes in with a FileSystem device object instead
  434. // of a volume device object.
  435. //
  436. if (FatDeviceIsFatFsdo( IrpSp->DeviceObject) &&
  437. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  438. (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
  439. (IrpSp->Parameters.FileSystemControl.FsControlCode ==
  440. FSCTL_INVALIDATE_VOLUMES)) {
  441. Status = FatInvalidateVolumes( Irp );
  442. } else {
  443. IrpContext = FatCreateIrpContext( Irp, Wait );
  444. Status = FatCommonFileSystemControl( IrpContext, Irp );
  445. }
  446. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  447. //
  448. // We had some trouble trying to perform the requested
  449. // operation, so we'll abort the I/O request with
  450. // the error status that we get back from the
  451. // execption code
  452. //
  453. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  454. }
  455. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  456. FsRtlExitFileSystem();
  457. //
  458. // And return to our caller
  459. //
  460. DebugTrace(-1, Dbg, "FatFsdFileSystemControl -> %08lx\n", Status);
  461. return Status;
  462. }
  463. NTSTATUS
  464. FatCommonFileSystemControl (
  465. IN PIRP_CONTEXT IrpContext,
  466. IN PIRP Irp
  467. )
  468. /*++
  469. Routine Description:
  470. This is the common routine for doing FileSystem control operations called
  471. by both the fsd and fsp threads
  472. Arguments:
  473. Irp - Supplies the Irp to process
  474. Return Value:
  475. NTSTATUS - The return status for the operation
  476. --*/
  477. {
  478. NTSTATUS Status;
  479. PIO_STACK_LOCATION IrpSp;
  480. //
  481. // Get a pointer to the current Irp stack location
  482. //
  483. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  484. DebugTrace(+1, Dbg,"FatCommonFileSystemControl\n", 0);
  485. DebugTrace( 0, Dbg,"Irp = %08lx\n", Irp);
  486. DebugTrace( 0, Dbg,"MinorFunction = %08lx\n", IrpSp->MinorFunction);
  487. //
  488. // We know this is a file system control so we'll case on the
  489. // minor function, and call a internal worker routine to complete
  490. // the irp.
  491. //
  492. switch (IrpSp->MinorFunction) {
  493. case IRP_MN_USER_FS_REQUEST:
  494. Status = FatUserFsCtrl( IrpContext, Irp );
  495. break;
  496. case IRP_MN_MOUNT_VOLUME:
  497. Status = FatMountVolume( IrpContext,
  498. IrpSp->Parameters.MountVolume.DeviceObject,
  499. IrpSp->Parameters.MountVolume.Vpb,
  500. IrpSp->DeviceObject );
  501. //
  502. // Complete the request.
  503. //
  504. // We do this here because FatMountVolume can be called recursively,
  505. // but the Irp is only to be completed once.
  506. //
  507. // NOTE: I don't think this is true anymore (danlo 3/15/1999). Probably
  508. // an artifact of the old doublespace attempt.
  509. //
  510. FatCompleteRequest( IrpContext, Irp, Status );
  511. break;
  512. case IRP_MN_VERIFY_VOLUME:
  513. Status = FatVerifyVolume( IrpContext, Irp );
  514. break;
  515. default:
  516. DebugTrace( 0, Dbg, "Invalid FS Control Minor Function %08lx\n", IrpSp->MinorFunction);
  517. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  518. Status = STATUS_INVALID_DEVICE_REQUEST;
  519. break;
  520. }
  521. DebugTrace(-1, Dbg, "FatCommonFileSystemControl -> %08lx\n", Status);
  522. return Status;
  523. }
  524. //
  525. // Local Support Routine
  526. //
  527. NTSTATUS
  528. FatMountVolume (
  529. IN PIRP_CONTEXT IrpContext,
  530. IN PDEVICE_OBJECT TargetDeviceObject,
  531. IN PVPB Vpb,
  532. IN PDEVICE_OBJECT FsDeviceObject
  533. )
  534. /*++
  535. Routine Description:
  536. This routine performs the mount volume operation. It is responsible for
  537. either completing of enqueuing the input Irp.
  538. Its job is to verify that the volume denoted in the IRP is a Fat volume,
  539. and create the VCB and root DCB structures. The algorithm it uses is
  540. essentially as follows:
  541. 1. Create a new Vcb Structure, and initialize it enough to do cached
  542. volume file I/O.
  543. 2. Read the disk and check if it is a Fat volume.
  544. 3. If it is not a Fat volume then free the cached volume file, delete
  545. the VCB, and complete the IRP with STATUS_UNRECOGNIZED_VOLUME
  546. 4. Check if the volume was previously mounted and if it was then do a
  547. remount operation. This involves reinitializing the cached volume
  548. file, checking the dirty bit, resetting up the allocation support,
  549. deleting the VCB, hooking in the old VCB, and completing the IRP.
  550. 5. Otherwise create a root DCB, create Fsp threads as necessary, and
  551. complete the IRP.
  552. Arguments:
  553. TargetDeviceObject - This is where we send all of our requests.
  554. Vpb - This gives us additional information needed to complete the mount.
  555. Return Value:
  556. NTSTATUS - The return status for the operation
  557. --*/
  558. {
  559. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
  560. NTSTATUS Status;
  561. PBCB BootBcb;
  562. PPACKED_BOOT_SECTOR BootSector;
  563. PBCB DirentBcb;
  564. PDIRENT Dirent;
  565. ULONG ByteOffset;
  566. BOOLEAN MountNewVolume = FALSE;
  567. BOOLEAN WeClearedVerifyRequiredBit = FALSE;
  568. PDEVICE_OBJECT RealDevice;
  569. PVOLUME_DEVICE_OBJECT VolDo = NULL;
  570. PVCB Vcb = NULL;
  571. PLIST_ENTRY Links;
  572. IO_STATUS_BLOCK Iosb;
  573. ULONG ChangeCount = 0;
  574. DISK_GEOMETRY Geometry;
  575. PARTITION_INFORMATION_EX PartitionInformation;
  576. NTSTATUS StatusPartInfo;
  577. DebugTrace(+1, Dbg, "FatMountVolume\n", 0);
  578. DebugTrace( 0, Dbg, "TargetDeviceObject = %08lx\n", TargetDeviceObject);
  579. DebugTrace( 0, Dbg, "Vpb = %08lx\n", Vpb);
  580. ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  581. ASSERT( FatDeviceIsFatFsdo( FsDeviceObject));
  582. //
  583. // Verify that there is a disk here and pick up the change count.
  584. //
  585. Status = FatPerformDevIoCtrl( IrpContext,
  586. IOCTL_DISK_CHECK_VERIFY,
  587. TargetDeviceObject,
  588. &ChangeCount,
  589. sizeof(ULONG),
  590. FALSE,
  591. TRUE,
  592. &Iosb );
  593. if (!NT_SUCCESS( Status )) {
  594. //
  595. // If we will allow a raw mount then avoid sending the popup.
  596. //
  597. // Only send this on "true" disk devices to handle the accidental
  598. // legacy of FAT. No other FS will throw a harderror on empty
  599. // drives.
  600. //
  601. // Cmd should really handle this per 9x.
  602. //
  603. if (!FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT ) &&
  604. Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK) {
  605. FatNormalizeAndRaiseStatus( IrpContext, Status );
  606. }
  607. return Status;
  608. }
  609. if (Iosb.Information != sizeof(ULONG)) {
  610. //
  611. // Be safe about the count in case the driver didn't fill it in
  612. //
  613. ChangeCount = 0;
  614. }
  615. //
  616. // If this is a CD class device, then check to see if there is a
  617. // 'data track' or not. This is to avoid issuing paging reads which will
  618. // fail later in the mount process (e.g. CD-DA or blank CD media)
  619. //
  620. if ((TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) &&
  621. !FatScanForDataTrack( IrpContext, TargetDeviceObject)) {
  622. return STATUS_UNRECOGNIZED_VOLUME;
  623. }
  624. //
  625. // Ping the volume with a partition query and pick up the partition
  626. // type. We'll check this later to avoid some scurrilous volumes.
  627. //
  628. StatusPartInfo = FatPerformDevIoCtrl( IrpContext,
  629. IOCTL_DISK_GET_PARTITION_INFO_EX,
  630. TargetDeviceObject,
  631. &PartitionInformation,
  632. sizeof(PARTITION_INFORMATION_EX),
  633. FALSE,
  634. TRUE,
  635. &Iosb );
  636. //
  637. // Make sure we can wait.
  638. //
  639. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  640. //
  641. // Initialize the Bcbs and our final state so that the termination
  642. // handlers will know what to free or unpin
  643. //
  644. BootBcb = NULL;
  645. DirentBcb = NULL;
  646. Vcb = NULL;
  647. VolDo = NULL;
  648. MountNewVolume = FALSE;
  649. try {
  650. BOOLEAN DoARemount = FALSE;
  651. PVCB OldVcb;
  652. PVPB OldVpb;
  653. //
  654. // Synchronize with FatCheckForDismount(), which modifies the vpb.
  655. //
  656. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  657. //
  658. // Create a new volume device object. This will have the Vcb
  659. // hanging off of its end, and set its alignment requirement
  660. // from the device we talk to.
  661. //
  662. if (!NT_SUCCESS(Status = IoCreateDevice( FatData.DriverObject,
  663. sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
  664. NULL,
  665. FILE_DEVICE_DISK_FILE_SYSTEM,
  666. 0,
  667. FALSE,
  668. (PDEVICE_OBJECT *)&VolDo))) {
  669. try_return( Status );
  670. }
  671. #ifdef _PNP_POWER_
  672. //
  673. // This driver doesn't talk directly to a device, and (at the moment)
  674. // isn't otherwise concerned about power management.
  675. //
  676. VolDo->DeviceObject.DeviceObjectExtension->PowerControlNeeded = FALSE;
  677. #endif
  678. //
  679. // Our alignment requirement is the larger of the processor alignment requirement
  680. // already in the volume device object and that in the TargetDeviceObject
  681. //
  682. if (TargetDeviceObject->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
  683. VolDo->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
  684. }
  685. //
  686. // Initialize the overflow queue for the volume
  687. //
  688. VolDo->OverflowQueueCount = 0;
  689. InitializeListHead( &VolDo->OverflowQueue );
  690. VolDo->PostedRequestCount = 0;
  691. KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
  692. //
  693. // We must initialize the stack size in our device object before
  694. // the following reads, because the I/O system has not done it yet.
  695. // This must be done before we clear the device initializing flag
  696. // otherwise a filter could attach and copy the wrong stack size into
  697. // it's device object.
  698. //
  699. VolDo->DeviceObject.StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
  700. //
  701. // We must also set the sector size correctly in our device object
  702. // before clearing the device initializing flag.
  703. //
  704. Status = FatPerformDevIoCtrl( IrpContext,
  705. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  706. TargetDeviceObject,
  707. &Geometry,
  708. sizeof( DISK_GEOMETRY ),
  709. FALSE,
  710. TRUE,
  711. NULL );
  712. VolDo->DeviceObject.SectorSize = (USHORT)Geometry.BytesPerSector;
  713. //
  714. // Indicate that this device object is now completely initialized
  715. //
  716. ClearFlag(VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING);
  717. //
  718. // Now Before we can initialize the Vcb we need to set up the device
  719. // object field in the Vpb to point to our new volume device object.
  720. // This is needed when we create the virtual volume file's file object
  721. // in initialize vcb.
  722. //
  723. Vpb->DeviceObject = (PDEVICE_OBJECT)VolDo;
  724. //
  725. // If the real device needs verification, temporarily clear the
  726. // field.
  727. //
  728. RealDevice = Vpb->RealDevice;
  729. if ( FlagOn(RealDevice->Flags, DO_VERIFY_VOLUME) ) {
  730. ClearFlag(RealDevice->Flags, DO_VERIFY_VOLUME);
  731. WeClearedVerifyRequiredBit = TRUE;
  732. }
  733. //
  734. // Initialize the new vcb
  735. //
  736. FatInitializeVcb( IrpContext,
  737. &VolDo->Vcb,
  738. TargetDeviceObject,
  739. Vpb,
  740. FsDeviceObject);
  741. //
  742. // Get a reference to the Vcb hanging off the end of the device object
  743. //
  744. Vcb = &VolDo->Vcb;
  745. //
  746. // Read in the boot sector, and have the read be the minumum size
  747. // needed. We know we can wait.
  748. //
  749. //
  750. // We need to commute errors on CD so that CDFS will get its crack. Audio
  751. // and even data media may not be universally readable on sector zero.
  752. //
  753. try {
  754. FatReadVolumeFile( IrpContext,
  755. Vcb,
  756. 0, // Starting Byte
  757. sizeof(PACKED_BOOT_SECTOR),
  758. &BootBcb,
  759. (PVOID *)&BootSector );
  760. } except( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
  761. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  762. NOTHING;
  763. }
  764. //
  765. // Call a routine to check the boot sector to see if it is fat
  766. //
  767. if (BootBcb == NULL || !FatIsBootSectorFat( BootSector)) {
  768. DebugTrace(0, Dbg, "Not a Fat Volume\n", 0);
  769. //
  770. // Complete the request and return to our caller
  771. //
  772. try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
  773. }
  774. //
  775. // Unpack the BPB. We used to do some sanity checking of the FATs at
  776. // this point, but authoring errors on third-party devices prevent
  777. // us from continuing to safeguard ourselves. We can only hope the
  778. // boot sector check is good enough.
  779. //
  780. // (read: digital cameras)
  781. //
  782. // Win9x does the same.
  783. //
  784. FatUnpackBios( &Vcb->Bpb, &BootSector->PackedBpb );
  785. //
  786. // Check if we have an OS/2 Boot Manager partition and treat it as an
  787. // unknown file system. We'll check the partition type in from the
  788. // partition table and we ensure that it has less than 0x80 sectors,
  789. // which is just a heuristic that will capture all real OS/2 BM partitions
  790. // and avoid the chance we'll discover partitions which erroneously
  791. // (but to this point, harmlessly) put down the OS/2 BM type.
  792. //
  793. // Note that this is only conceivable on good old MBR media.
  794. //
  795. // The OS/2 Boot Manager boot format mimics a FAT16 partition in sector
  796. // zero but does is not a real FAT16 file system. For example, the boot
  797. // sector indicates it has 2 FATs but only really has one, with the boot
  798. // manager code overlaying the second FAT. If we then set clean bits in
  799. // FAT[0] we'll corrupt that code.
  800. //
  801. if (NT_SUCCESS( StatusPartInfo ) &&
  802. (PartitionInformation.PartitionStyle == PARTITION_STYLE_MBR &&
  803. PartitionInformation.Mbr.PartitionType == PARTITION_OS2BOOTMGR) &&
  804. (Vcb->Bpb.Sectors != 0 &&
  805. Vcb->Bpb.Sectors < 0x80)) {
  806. DebugTrace( 0, Dbg, "OS/2 Boot Manager volume detected, volume not mounted. \n", 0 );
  807. //
  808. // Complete the request and return to our caller
  809. //
  810. try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
  811. }
  812. //
  813. // Verify that the sector size recorded in the Bpb matches what the
  814. // device currently reports it's sector size to be.
  815. //
  816. if ( !NT_SUCCESS( Status) ||
  817. (Geometry.BytesPerSector != Vcb->Bpb.BytesPerSector)) {
  818. try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
  819. }
  820. //
  821. // This is a fat volume, so extract the bpb, serial number. The
  822. // label we'll get later after we've created the root dcb.
  823. //
  824. // Note that the way data caching is done, we set neither the
  825. // direct I/O or Buffered I/O bit in the device object flags.
  826. //
  827. if (Vcb->Bpb.Sectors != 0) { Vcb->Bpb.LargeSectors = 0; }
  828. if (IsBpbFat32(&BootSector->PackedBpb)) {
  829. CopyUchar4( &Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id );
  830. } else {
  831. CopyUchar4( &Vpb->SerialNumber, BootSector->Id );
  832. //
  833. // Allocate space for the stashed boot sector chunk. This only has meaning on
  834. // FAT12/16 volumes since this only is kept for the FSCTL_QUERY_FAT_BPB and it and
  835. // its users are a bit wierd, thinking that a BPB exists wholly in the first 0x24
  836. // bytes.
  837. //
  838. Vcb->First0x24BytesOfBootSector =
  839. FsRtlAllocatePoolWithTag( PagedPool,
  840. 0x24,
  841. TAG_STASHED_BPB );
  842. //
  843. // Stash a copy of the first 0x24 bytes
  844. //
  845. RtlCopyMemory( Vcb->First0x24BytesOfBootSector,
  846. BootSector,
  847. 0x24 );
  848. }
  849. //
  850. // Now unpin the boot sector, so when we set up allocation eveything
  851. // works.
  852. //
  853. FatUnpinBcb( IrpContext, BootBcb );
  854. //
  855. // Compute a number of fields for Vcb.AllocationSupport
  856. //
  857. FatSetupAllocationSupport( IrpContext, Vcb );
  858. //
  859. // Sanity check the FsInfo information for FAT32 volumes. Silently deal
  860. // with messed up information by effectively disabling FsInfo updates.
  861. //
  862. if (FatIsFat32( Vcb )) {
  863. if (Vcb->Bpb.FsInfoSector >= Vcb->Bpb.ReservedSectors) {
  864. Vcb->Bpb.FsInfoSector = 0;
  865. }
  866. }
  867. //
  868. // Create a root Dcb so we can read in the volume label. If this is FAT32, we can
  869. // discover corruption in the FAT chain.
  870. //
  871. // NOTE: this exception handler presumes that this is the only spot where we can
  872. // discover corruption in the mount process. If this ever changes, this handler
  873. // MUST be expanded. The reason we have this guy here is because we have to rip
  874. // the structures down now (in the finally below) and can't wait for the outer
  875. // exception handling to do it for us, at which point everything will have vanished.
  876. //
  877. try {
  878. FatCreateRootDcb( IrpContext, Vcb );
  879. } except (GetExceptionCode() == STATUS_FILE_CORRUPT_ERROR ? EXCEPTION_EXECUTE_HANDLER :
  880. EXCEPTION_CONTINUE_SEARCH) {
  881. //
  882. // The volume needs to be dirtied, do it now. Note that at this point we have built
  883. // enough of the Vcb to pull this off.
  884. //
  885. FatMarkVolume( IrpContext, Vcb, VolumeDirty );
  886. //
  887. // Now keep bailing out ...
  888. //
  889. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  890. }
  891. FatLocateVolumeLabel( IrpContext,
  892. Vcb,
  893. &Dirent,
  894. &DirentBcb,
  895. &ByteOffset );
  896. if (Dirent != NULL) {
  897. OEM_STRING OemString;
  898. UNICODE_STRING UnicodeString;
  899. //
  900. // Compute the length of the volume name
  901. //
  902. OemString.Buffer = &Dirent->FileName[0];
  903. OemString.MaximumLength = 11;
  904. for ( OemString.Length = 11;
  905. OemString.Length > 0;
  906. OemString.Length -= 1) {
  907. if ( (Dirent->FileName[OemString.Length-1] != 0x00) &&
  908. (Dirent->FileName[OemString.Length-1] != 0x20) ) { break; }
  909. }
  910. UnicodeString.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  911. UnicodeString.Buffer = &Vcb->Vpb->VolumeLabel[0];
  912. Status = RtlOemStringToCountedUnicodeString( &UnicodeString,
  913. &OemString,
  914. FALSE );
  915. if ( !NT_SUCCESS( Status ) ) {
  916. try_return( Status );
  917. }
  918. Vpb->VolumeLabelLength = UnicodeString.Length;
  919. } else {
  920. Vpb->VolumeLabelLength = 0;
  921. }
  922. //
  923. // Use the change count we noted initially *before* doing any work.
  924. // If something came along in the midst of this operation, we'll
  925. // verify and discover the problem.
  926. //
  927. Vcb->ChangeCount = ChangeCount;
  928. //
  929. // Now scan the list of previously mounted volumes and compare
  930. // serial numbers and volume labels off not currently mounted
  931. // volumes to see if we have a match.
  932. //
  933. for (Links = FatData.VcbQueue.Flink;
  934. Links != &FatData.VcbQueue;
  935. Links = Links->Flink) {
  936. OldVcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
  937. OldVpb = OldVcb->Vpb;
  938. //
  939. // Skip over ourselves since we're already in the VcbQueue
  940. //
  941. if (OldVpb == Vpb) { continue; }
  942. //
  943. // Check for a match:
  944. //
  945. // Serial Number, VolumeLabel and Bpb must all be the same.
  946. // Also the volume must have failed a verify before (ie.
  947. // VolumeNotMounted), and it must be in the same physical
  948. // drive than it was mounted in before.
  949. //
  950. if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
  951. (OldVcb->VcbCondition == VcbNotMounted) &&
  952. (OldVpb->RealDevice == RealDevice) &&
  953. (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
  954. (RtlEqualMemory(&OldVpb->VolumeLabel[0],
  955. &Vpb->VolumeLabel[0],
  956. Vpb->VolumeLabelLength)) &&
  957. (RtlEqualMemory(&OldVcb->Bpb,
  958. &Vcb->Bpb,
  959. IsBpbFat32(&Vcb->Bpb) ?
  960. sizeof(BIOS_PARAMETER_BLOCK) :
  961. FIELD_OFFSET(BIOS_PARAMETER_BLOCK,
  962. LargeSectorsPerFat) ))) {
  963. DoARemount = TRUE;
  964. break;
  965. }
  966. }
  967. if ( DoARemount ) {
  968. PVPB *IrpVpb;
  969. DebugTrace(0, Dbg, "Doing a remount\n", 0);
  970. DebugTrace(0, Dbg, "Vcb = %08lx\n", Vcb);
  971. DebugTrace(0, Dbg, "Vpb = %08lx\n", Vpb);
  972. DebugTrace(0, Dbg, "OldVcb = %08lx\n", OldVcb);
  973. DebugTrace(0, Dbg, "OldVpb = %08lx\n", OldVpb);
  974. //
  975. // The old target device object is about to be overwritten.
  976. // Drop the reference being held on that device object.
  977. //
  978. ObDereferenceObject( OldVcb->TargetDeviceObject );
  979. //
  980. // This is a remount, so link the old vpb in place
  981. // of the new vpb and release the new vpb and the extra
  982. // volume device object we created earlier.
  983. //
  984. OldVpb->RealDevice = Vpb->RealDevice;
  985. OldVpb->RealDevice->Vpb = OldVpb;
  986. OldVcb->TargetDeviceObject = TargetDeviceObject;
  987. OldVcb->VcbCondition = VcbGood;
  988. //
  989. // Use the new changecount.
  990. //
  991. OldVcb->ChangeCount = Vcb->ChangeCount;
  992. //
  993. // Delete the extra new vpb, and make sure we don't use it again.
  994. //
  995. // Also if this is the Vpb referenced in the original Irp, set
  996. // that reference back to the old VPB.
  997. //
  998. IrpVpb = &IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->Parameters.MountVolume.Vpb;
  999. if (*IrpVpb == Vpb) {
  1000. *IrpVpb = OldVpb;
  1001. }
  1002. ExFreePool( Vpb );
  1003. Vpb = NULL;
  1004. //
  1005. // Make sure the remaining stream files are orphaned.
  1006. //
  1007. Vcb->VirtualVolumeFile->Vpb = NULL;
  1008. Vcb->RootDcb->Specific.Dcb.DirectoryFile->Vpb = NULL;
  1009. //
  1010. // Reinitialize the volume file cache and allocation support.
  1011. //
  1012. {
  1013. CC_FILE_SIZES FileSizes;
  1014. FileSizes.AllocationSize.QuadPart =
  1015. FileSizes.FileSize.QuadPart = ( 0x40000 + 0x1000 );
  1016. FileSizes.ValidDataLength = FatMaxLarge;
  1017. DebugTrace(0, Dbg, "Truncate and reinitialize the volume file\n", 0);
  1018. CcInitializeCacheMap( OldVcb->VirtualVolumeFile,
  1019. &FileSizes,
  1020. TRUE,
  1021. &FatData.CacheManagerNoOpCallbacks,
  1022. Vcb );
  1023. //
  1024. // Redo the allocation support
  1025. //
  1026. FatSetupAllocationSupport( IrpContext, OldVcb );
  1027. //
  1028. // Get the state of the dirty bit.
  1029. //
  1030. FatCheckDirtyBit( IrpContext, OldVcb );
  1031. //
  1032. // Check for write protected media.
  1033. //
  1034. if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
  1035. SetFlag( OldVcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
  1036. } else {
  1037. ClearFlag( OldVcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
  1038. }
  1039. }
  1040. //
  1041. // Complete the request and return to our caller
  1042. //
  1043. try_return( Status = STATUS_SUCCESS );
  1044. }
  1045. DebugTrace(0, Dbg, "Mount a new volume\n", 0);
  1046. //
  1047. // This is a new mount
  1048. //
  1049. // Create a blank ea data file fcb, just not for Fat32.
  1050. //
  1051. if (!FatIsFat32(Vcb)) {
  1052. DIRENT TempDirent;
  1053. PFCB EaFcb;
  1054. RtlZeroMemory( &TempDirent, sizeof(DIRENT) );
  1055. RtlCopyMemory( &TempDirent.FileName[0], "EA DATA SF", 11 );
  1056. EaFcb = FatCreateFcb( IrpContext,
  1057. Vcb,
  1058. Vcb->RootDcb,
  1059. 0,
  1060. 0,
  1061. &TempDirent,
  1062. NULL,
  1063. FALSE,
  1064. TRUE );
  1065. //
  1066. // Deny anybody who trys to open the file.
  1067. //
  1068. SetFlag( EaFcb->FcbState, FCB_STATE_SYSTEM_FILE );
  1069. Vcb->EaFcb = EaFcb;
  1070. }
  1071. //
  1072. // Get the state of the dirty bit.
  1073. //
  1074. FatCheckDirtyBit( IrpContext, Vcb );
  1075. //
  1076. // Check for write protected media.
  1077. //
  1078. if (FatIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
  1079. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
  1080. } else {
  1081. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
  1082. }
  1083. //
  1084. // Lock volume in drive if we just mounted the boot drive.
  1085. //
  1086. if (FlagOn(RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION)) {
  1087. SetFlag(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE);
  1088. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
  1089. FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
  1090. }
  1091. }
  1092. //
  1093. // Indicate to our termination handler that we have mounted
  1094. // a new volume.
  1095. //
  1096. MountNewVolume = TRUE;
  1097. //
  1098. // Complete the request
  1099. //
  1100. Status = STATUS_SUCCESS;
  1101. //
  1102. // Ref the root dir stream object so we can send mount notification.
  1103. //
  1104. ObReferenceObject( Vcb->RootDcb->Specific.Dcb.DirectoryFile );
  1105. //
  1106. // Remove the extra reference to this target DO made on behalf of us
  1107. // by the IO system. In the remount case, we permit regular Vcb
  1108. // deletion to do this work.
  1109. //
  1110. ObDereferenceObject( TargetDeviceObject );
  1111. try_exit: NOTHING;
  1112. } finally {
  1113. DebugUnwind( FatMountVolume );
  1114. FatUnpinBcb( IrpContext, BootBcb );
  1115. FatUnpinBcb( IrpContext, DirentBcb );
  1116. //
  1117. // Check if a volume was mounted. If not then we need to
  1118. // mark the Vpb not mounted again and delete the volume.
  1119. //
  1120. if ( !MountNewVolume ) {
  1121. if ( Vpb != NULL ) {
  1122. Vpb->DeviceObject = NULL;
  1123. }
  1124. if ( Vcb != NULL ) {
  1125. //
  1126. // Make sure we clean up the IrpContext field if the Vcb is
  1127. // being taken down.
  1128. //
  1129. IrpContext->Vcb = NULL;
  1130. FatDeleteVcb( IrpContext, Vcb );
  1131. }
  1132. if ( VolDo != NULL ) {
  1133. IoDeleteDevice( &VolDo->DeviceObject );
  1134. }
  1135. }
  1136. if ( WeClearedVerifyRequiredBit == TRUE ) {
  1137. SetFlag(RealDevice->Flags, DO_VERIFY_VOLUME);
  1138. }
  1139. FatReleaseGlobal( IrpContext );
  1140. DebugTrace(-1, Dbg, "FatMountVolume -> %08lx\n", Status);
  1141. }
  1142. //
  1143. // Now send mount notification. Note that since this is outside of any
  1144. // synchronization since the synchronous delivery of this may go to
  1145. // folks that provoke re-entrance to the FS.
  1146. //
  1147. if (MountNewVolume) {
  1148. FsRtlNotifyVolumeEvent( Vcb->RootDcb->Specific.Dcb.DirectoryFile, FSRTL_VOLUME_MOUNT );
  1149. ObDereferenceObject( Vcb->RootDcb->Specific.Dcb.DirectoryFile );
  1150. }
  1151. return Status;
  1152. }
  1153. //
  1154. // Local Support Routine
  1155. //
  1156. NTSTATUS
  1157. FatVerifyVolume (
  1158. IN PIRP_CONTEXT IrpContext,
  1159. IN PIRP Irp
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. This routine performs the verify volume operation by checking the volume
  1164. label and serial number physically on the media with the the Vcb
  1165. currently claiming to have the volume mounted. It is responsible for
  1166. either completing or enqueuing the input Irp.
  1167. Regardless of whether the verify operation succeeds, the following
  1168. operations are performed:
  1169. - Set Vcb->VirtualEaFile back to its virgin state.
  1170. - Purge all cached data (flushing first if verify succeeds)
  1171. - Mark all Fcbs as needing verification
  1172. If the volumes verifies correctly we also must:
  1173. - Check the volume dirty bit.
  1174. - Reinitialize the allocation support
  1175. - Flush any dirty data
  1176. If the volume verify fails, it may never be mounted again. If it is
  1177. mounted again, it will happen as a remount operation. In preparation
  1178. for that, and to leave the volume in a state that can be "lazy deleted"
  1179. the following operations are performed:
  1180. - Set the Vcb condition to VcbNotMounted
  1181. - Uninitialize the volume file cachemap
  1182. - Tear down the allocation support
  1183. In the case of an abnormal termination we haven't determined the state
  1184. of the volume, so we set the Device Object as needing verification again.
  1185. Arguments:
  1186. Irp - Supplies the Irp to process
  1187. Return Value:
  1188. NTSTATUS - If the verify operation completes, it will return either
  1189. STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. If an IO or
  1190. other error is encountered, that status will be returned.
  1191. --*/
  1192. {
  1193. NTSTATUS Status = STATUS_SUCCESS;
  1194. PIO_STACK_LOCATION IrpSp;
  1195. PDIRENT RootDirectory = NULL;
  1196. PPACKED_BOOT_SECTOR BootSector = NULL;
  1197. BIOS_PARAMETER_BLOCK Bpb;
  1198. PVOLUME_DEVICE_OBJECT VolDo;
  1199. PVCB Vcb;
  1200. PVPB Vpb;
  1201. ULONG SectorSize;
  1202. BOOLEAN ClearVerify = FALSE;
  1203. BOOLEAN ReleaseEntireVolume = FALSE;
  1204. BOOLEAN VerifyAlreadyDone = FALSE;
  1205. DISK_GEOMETRY DiskGeometry;
  1206. LBO RootDirectoryLbo;
  1207. ULONG RootDirectorySize;
  1208. BOOLEAN LabelFound;
  1209. ULONG ChangeCount = 0;
  1210. IO_STATUS_BLOCK Iosb;
  1211. //
  1212. // Get the current Irp stack location
  1213. //
  1214. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1215. DebugTrace(+1, Dbg, "FatVerifyVolume\n", 0);
  1216. DebugTrace( 0, Dbg, "DeviceObject = %08lx\n", IrpSp->Parameters.VerifyVolume.DeviceObject);
  1217. DebugTrace( 0, Dbg, "Vpb = %08lx\n", IrpSp->Parameters.VerifyVolume.Vpb);
  1218. //
  1219. // Save some references to make our life a little easier. Note the Vcb for the purposes
  1220. // of exception handling.
  1221. //
  1222. VolDo = (PVOLUME_DEVICE_OBJECT)IrpSp->Parameters.VerifyVolume.DeviceObject;
  1223. Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
  1224. IrpContext->Vcb = Vcb = &VolDo->Vcb;
  1225. //
  1226. // If we cannot wait then enqueue the irp to the fsp and
  1227. // return the status to our caller.
  1228. //
  1229. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
  1230. DebugTrace(0, Dbg, "Cannot wait for verify.\n", 0);
  1231. Status = FatFsdPostRequest( IrpContext, Irp );
  1232. DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status );
  1233. return Status;
  1234. }
  1235. //
  1236. // We are serialized at this point allowing only one thread to
  1237. // actually perform the verify operation. Any others will just
  1238. // wait and then no-op when checking if the volume still needs
  1239. // verification.
  1240. //
  1241. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  1242. (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
  1243. try {
  1244. BOOLEAN AllowRawMount = BooleanFlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT );
  1245. //
  1246. // Mark ourselves as verifying this volume so that recursive I/Os
  1247. // will be able to complete.
  1248. //
  1249. ASSERT( Vcb->VerifyThread == NULL );
  1250. Vcb->VerifyThread = KeGetCurrentThread();
  1251. //
  1252. // Check if the real device still needs to be verified. If it doesn't
  1253. // then obviously someone beat us here and already did the work
  1254. // so complete the verify irp with success. Otherwise reenable
  1255. // the real device and get to work.
  1256. //
  1257. if (!FlagOn(Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
  1258. DebugTrace(0, Dbg, "RealDevice has already been verified\n", 0);
  1259. VerifyAlreadyDone = TRUE;
  1260. try_return( Status = STATUS_SUCCESS );
  1261. }
  1262. //
  1263. // Ping the volume with a partition query to make Jeff happy.
  1264. //
  1265. {
  1266. PARTITION_INFORMATION_EX PartitionInformation;
  1267. (VOID) FatPerformDevIoCtrl( IrpContext,
  1268. IOCTL_DISK_GET_PARTITION_INFO_EX,
  1269. Vcb->TargetDeviceObject,
  1270. &PartitionInformation,
  1271. sizeof(PARTITION_INFORMATION_EX),
  1272. FALSE,
  1273. TRUE,
  1274. &Iosb );
  1275. }
  1276. //
  1277. // Verify that there is a disk here and pick up the change count.
  1278. //
  1279. Status = FatPerformDevIoCtrl( IrpContext,
  1280. IOCTL_DISK_CHECK_VERIFY,
  1281. Vcb->TargetDeviceObject,
  1282. &ChangeCount,
  1283. sizeof(ULONG),
  1284. FALSE,
  1285. TRUE,
  1286. &Iosb );
  1287. if (!NT_SUCCESS( Status )) {
  1288. //
  1289. // If we will allow a raw mount then return WRONG_VOLUME to
  1290. // allow the volume to be mounted by raw.
  1291. //
  1292. if (AllowRawMount) {
  1293. try_return( Status = STATUS_WRONG_VOLUME );
  1294. }
  1295. FatNormalizeAndRaiseStatus( IrpContext, Status );
  1296. }
  1297. if (Iosb.Information != sizeof(ULONG)) {
  1298. //
  1299. // Be safe about the count in case the driver didn't fill it in
  1300. //
  1301. ChangeCount = 0;
  1302. }
  1303. //
  1304. // Whatever happens we will have verified this volume at this change
  1305. // count, so record that fact.
  1306. //
  1307. Vcb->ChangeCount = ChangeCount;
  1308. //
  1309. // If this is a CD class device, then check to see if there is a
  1310. // 'data track' or not. This is to avoid issuing paging reads which will
  1311. // fail later in the mount process (e.g. CD-DA or blank CD media)
  1312. //
  1313. if ((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) &&
  1314. !FatScanForDataTrack( IrpContext, Vcb->TargetDeviceObject)) {
  1315. try_return( Status = STATUS_WRONG_VOLUME);
  1316. }
  1317. //
  1318. // Some devices can change sector sizes on the fly. Obviously, it
  1319. // isn't the same volume if that happens.
  1320. //
  1321. Status = FatPerformDevIoCtrl( IrpContext,
  1322. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1323. Vcb->TargetDeviceObject,
  1324. &DiskGeometry,
  1325. sizeof( DISK_GEOMETRY ),
  1326. FALSE,
  1327. TRUE,
  1328. NULL );
  1329. if (!NT_SUCCESS( Status )) {
  1330. //
  1331. // If we will allow a raw mount then return WRONG_VOLUME to
  1332. // allow the volume to be mounted by raw.
  1333. //
  1334. if (AllowRawMount) {
  1335. try_return( Status = STATUS_WRONG_VOLUME );
  1336. }
  1337. FatNormalizeAndRaiseStatus( IrpContext, Status );
  1338. }
  1339. //
  1340. // Read in the boot sector
  1341. //
  1342. SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
  1343. if (SectorSize != DiskGeometry.BytesPerSector) {
  1344. try_return( Status = STATUS_WRONG_VOLUME );
  1345. }
  1346. BootSector = FsRtlAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1347. (ULONG) ROUND_TO_PAGES( SectorSize ),
  1348. TAG_VERIFY_BOOTSECTOR);
  1349. //
  1350. // If this verify is on behalf of a DASD open, allow a RAW mount.
  1351. //
  1352. if (!FatPerformVerifyDiskRead( IrpContext,
  1353. Vcb,
  1354. BootSector,
  1355. 0,
  1356. SectorSize,
  1357. AllowRawMount )) {
  1358. try_return( Status = STATUS_WRONG_VOLUME );
  1359. }
  1360. //
  1361. // Call a routine to check the boot sector to see if it is fat.
  1362. // If it is not fat then mark the vcb as not mounted tell our
  1363. // caller its the wrong volume
  1364. //
  1365. if (!FatIsBootSectorFat( BootSector )) {
  1366. DebugTrace(0, Dbg, "Not a Fat Volume\n", 0);
  1367. try_return( Status = STATUS_WRONG_VOLUME );
  1368. }
  1369. //
  1370. // This is a fat volume, so extract serial number and see if it is
  1371. // ours.
  1372. //
  1373. {
  1374. ULONG SerialNumber;
  1375. if (IsBpbFat32(&BootSector->PackedBpb)) {
  1376. CopyUchar4( &SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id );
  1377. } else {
  1378. CopyUchar4( &SerialNumber, BootSector->Id );
  1379. }
  1380. if (SerialNumber != Vpb->SerialNumber) {
  1381. DebugTrace(0, Dbg, "Not our serial number\n", 0);
  1382. try_return( Status = STATUS_WRONG_VOLUME );
  1383. }
  1384. }
  1385. //
  1386. // Make sure the Bpbs are not different. We have to zero out our
  1387. // stack version of the Bpb since unpacking leaves holes.
  1388. //
  1389. RtlZeroMemory( &Bpb, sizeof(BIOS_PARAMETER_BLOCK) );
  1390. FatUnpackBios( &Bpb, &BootSector->PackedBpb );
  1391. if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; }
  1392. if ( !RtlEqualMemory( &Bpb,
  1393. &Vcb->Bpb,
  1394. IsBpbFat32(&Bpb) ?
  1395. sizeof(BIOS_PARAMETER_BLOCK) :
  1396. FIELD_OFFSET(BIOS_PARAMETER_BLOCK,
  1397. LargeSectorsPerFat) )) {
  1398. DebugTrace(0, Dbg, "Bpb is different\n", 0);
  1399. try_return( Status = STATUS_WRONG_VOLUME );
  1400. }
  1401. //
  1402. // Check the volume label. We do this by trying to locate the
  1403. // volume label, making two strings one for the saved volume label
  1404. // and the other for the new volume label and then we compare the
  1405. // two labels.
  1406. //
  1407. if (FatRootDirectorySize(&Bpb) > 0) {
  1408. RootDirectorySize = FatRootDirectorySize(&Bpb);
  1409. } else {
  1410. RootDirectorySize = FatBytesPerCluster(&Bpb);
  1411. }
  1412. RootDirectory = FsRtlAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1413. (ULONG) ROUND_TO_PAGES( RootDirectorySize ),
  1414. TAG_VERIFY_ROOTDIR);
  1415. if (!IsBpbFat32(&BootSector->PackedBpb)) {
  1416. //
  1417. // The Fat12/16 case is simple -- read the root directory in and
  1418. // search it.
  1419. //
  1420. RootDirectoryLbo = FatRootDirectoryLbo(&Bpb);
  1421. if (!FatPerformVerifyDiskRead( IrpContext,
  1422. Vcb,
  1423. RootDirectory,
  1424. RootDirectoryLbo,
  1425. RootDirectorySize,
  1426. AllowRawMount )) {
  1427. try_return( Status = STATUS_WRONG_VOLUME );
  1428. }
  1429. Status = FatSearchBufferForLabel(IrpContext, Vpb,
  1430. RootDirectory, RootDirectorySize,
  1431. &LabelFound);
  1432. if (!NT_SUCCESS(Status)) {
  1433. try_return( Status );
  1434. }
  1435. if (!LabelFound && Vpb->VolumeLabelLength > 0) {
  1436. try_return( Status = STATUS_WRONG_VOLUME );
  1437. }
  1438. } else {
  1439. ULONG RootDirectoryCluster;
  1440. RootDirectoryCluster = Bpb.RootDirFirstCluster;
  1441. while (RootDirectoryCluster != FAT_CLUSTER_LAST) {
  1442. RootDirectoryLbo = FatGetLboFromIndex(Vcb, RootDirectoryCluster);
  1443. if (!FatPerformVerifyDiskRead( IrpContext,
  1444. Vcb,
  1445. RootDirectory,
  1446. RootDirectoryLbo,
  1447. RootDirectorySize,
  1448. AllowRawMount )) {
  1449. try_return( Status = STATUS_WRONG_VOLUME );
  1450. }
  1451. Status = FatSearchBufferForLabel(IrpContext, Vpb,
  1452. RootDirectory, RootDirectorySize,
  1453. &LabelFound);
  1454. if (!NT_SUCCESS(Status)) {
  1455. try_return( Status );
  1456. }
  1457. if (LabelFound) {
  1458. //
  1459. // Found a matching label.
  1460. //
  1461. break;
  1462. }
  1463. //
  1464. // Set ourselves up for the next loop iteration.
  1465. //
  1466. FatVerifyLookupFatEntry( IrpContext, Vcb,
  1467. RootDirectoryCluster,
  1468. &RootDirectoryCluster );
  1469. switch (FatInterpretClusterType(Vcb, RootDirectoryCluster)) {
  1470. case FatClusterAvailable:
  1471. case FatClusterReserved:
  1472. case FatClusterBad:
  1473. //
  1474. // Bail all the way out if we have a bad root.
  1475. //
  1476. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  1477. break;
  1478. default:
  1479. break;
  1480. }
  1481. }
  1482. if (RootDirectoryCluster == FAT_CLUSTER_LAST &&
  1483. Vpb->VolumeLabelLength > 0) {
  1484. //
  1485. // Should have found a label, didn't find any.
  1486. //
  1487. try_return( Status = STATUS_WRONG_VOLUME );
  1488. }
  1489. }
  1490. try_exit: NOTHING;
  1491. //
  1492. // Note that we have previously acquired the Vcb to serialize
  1493. // the EA file stuff the marking all the Fcbs as NeedToBeVerified.
  1494. //
  1495. // Put the Ea file back in a virgin state.
  1496. //
  1497. FatCloseEaFile( IrpContext, Vcb, (BOOLEAN)(Status == STATUS_SUCCESS) );
  1498. //
  1499. // Mark all Fcbs as needing verification, but only if we really have
  1500. // to do it.
  1501. //
  1502. if (!VerifyAlreadyDone) {
  1503. FatMarkFcbCondition( IrpContext, Vcb->RootDcb, FcbNeedsToBeVerified, TRUE );
  1504. }
  1505. //
  1506. // If the verify didn't succeed, get the volume ready for a
  1507. // remount or eventual deletion.
  1508. //
  1509. if (Vcb->VcbCondition == VcbNotMounted) {
  1510. //
  1511. // If the volume was already in an unmounted state, just bail
  1512. // and make sure we return STATUS_WRONG_VOLUME.
  1513. //
  1514. Status = STATUS_WRONG_VOLUME;
  1515. } else if ( Status == STATUS_WRONG_VOLUME ) {
  1516. //
  1517. // Grab everything so we can safely transition the volume state without
  1518. // having a thread stumble into the torn-down allocation engine.
  1519. //
  1520. FatAcquireExclusiveVolume( IrpContext, Vcb );
  1521. ReleaseEntireVolume = TRUE;
  1522. //
  1523. // Get rid of any cached data, without flushing
  1524. //
  1525. FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush );
  1526. //
  1527. // Uninitialize the volume file cache map. Note that we cannot
  1528. // do a "FatSyncUninit" because of deadlock problems. However,
  1529. // since this FileObject is referenced by us, and thus included
  1530. // in the Vpb residual count, it is OK to do a normal CcUninit.
  1531. //
  1532. CcUninitializeCacheMap( Vcb->VirtualVolumeFile,
  1533. &FatLargeZero,
  1534. NULL );
  1535. FatTearDownAllocationSupport( IrpContext, Vcb );
  1536. Vcb->VcbCondition = VcbNotMounted;
  1537. ClearVerify = TRUE;
  1538. } else if (!VerifyAlreadyDone) {
  1539. //
  1540. // Grab everything so we can safely transition the volume state without
  1541. // having a thread stumble into the torn-down allocation engine.
  1542. //
  1543. FatAcquireExclusiveVolume( IrpContext, Vcb );
  1544. ReleaseEntireVolume = TRUE;
  1545. //
  1546. // Get rid of any cached data, flushing first.
  1547. //
  1548. // Future work (and for bonus points, around the other flush points)
  1549. // could address the possibility that the dirent filesize hasn't been
  1550. // updated yet, causing us to fail the re-verification of a file in
  1551. // DetermineAndMark. This is pretty subtle and very very uncommon.
  1552. //
  1553. FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
  1554. //
  1555. // Flush and Purge the volume file.
  1556. //
  1557. (VOID)FatFlushFat( IrpContext, Vcb );
  1558. CcPurgeCacheSection( &Vcb->SectionObjectPointers, NULL, 0, FALSE );
  1559. //
  1560. // Redo the allocation support with newly paged stuff.
  1561. //
  1562. FatTearDownAllocationSupport( IrpContext, Vcb );
  1563. FatSetupAllocationSupport( IrpContext, Vcb );
  1564. FatCheckDirtyBit( IrpContext, Vcb );
  1565. //
  1566. // Check for write protected media.
  1567. //
  1568. if (FatIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
  1569. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
  1570. } else {
  1571. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED );
  1572. }
  1573. ClearVerify = TRUE;
  1574. }
  1575. if (ClearVerify) {
  1576. //
  1577. // Mark the device as no longer needing verification.
  1578. //
  1579. ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  1580. }
  1581. } finally {
  1582. DebugUnwind( FatVerifyVolume );
  1583. //
  1584. // Free any buffer we may have allocated
  1585. //
  1586. if ( BootSector != NULL ) { ExFreePool( BootSector ); }
  1587. if ( RootDirectory != NULL ) { ExFreePool( RootDirectory ); }
  1588. //
  1589. // Show that we are done with this volume.
  1590. //
  1591. ASSERT( Vcb->VerifyThread == KeGetCurrentThread() );
  1592. Vcb->VerifyThread = NULL;
  1593. if (ReleaseEntireVolume) {
  1594. FatReleaseVolume( IrpContext, Vcb );
  1595. }
  1596. FatReleaseVcb( IrpContext, Vcb );
  1597. FatReleaseGlobal( IrpContext );
  1598. //
  1599. // If this was not an abnormal termination, complete the irp.
  1600. //
  1601. if (!AbnormalTermination()) {
  1602. FatCompleteRequest( IrpContext, Irp, Status );
  1603. }
  1604. DebugTrace(-1, Dbg, "FatVerifyVolume -> %08lx\n", Status);
  1605. }
  1606. return Status;
  1607. }
  1608. //
  1609. // Local Support Routine
  1610. //
  1611. BOOLEAN
  1612. FatIsBootSectorFat (
  1613. IN PPACKED_BOOT_SECTOR BootSector
  1614. )
  1615. /*++
  1616. Routine Description:
  1617. This routine checks if the boot sector is for a fat file volume.
  1618. Arguments:
  1619. BootSector - Supplies the packed boot sector to check
  1620. Return Value:
  1621. BOOLEAN - TRUE if the volume is Fat and FALSE otherwise.
  1622. --*/
  1623. {
  1624. BOOLEAN Result;
  1625. BIOS_PARAMETER_BLOCK Bpb;
  1626. DebugTrace(+1, Dbg, "FatIsBootSectorFat, BootSector = %08lx\n", BootSector);
  1627. //
  1628. // The result is true unless we decide that it should be false
  1629. //
  1630. Result = TRUE;
  1631. //
  1632. // Unpack the bios and then test everything
  1633. //
  1634. FatUnpackBios( &Bpb, &BootSector->PackedBpb );
  1635. if (Bpb.Sectors != 0) { Bpb.LargeSectors = 0; }
  1636. if ((BootSector->Jump[0] != 0xe9) &&
  1637. (BootSector->Jump[0] != 0xeb) &&
  1638. (BootSector->Jump[0] != 0x49)) {
  1639. Result = FALSE;
  1640. //
  1641. // Enforce some sanity on the sector size (easy check)
  1642. //
  1643. } else if ((Bpb.BytesPerSector != 128) &&
  1644. (Bpb.BytesPerSector != 256) &&
  1645. (Bpb.BytesPerSector != 512) &&
  1646. (Bpb.BytesPerSector != 1024) &&
  1647. (Bpb.BytesPerSector != 2048) &&
  1648. (Bpb.BytesPerSector != 4096)) {
  1649. Result = FALSE;
  1650. //
  1651. // Likewise on the clustering.
  1652. //
  1653. } else if ((Bpb.SectorsPerCluster != 1) &&
  1654. (Bpb.SectorsPerCluster != 2) &&
  1655. (Bpb.SectorsPerCluster != 4) &&
  1656. (Bpb.SectorsPerCluster != 8) &&
  1657. (Bpb.SectorsPerCluster != 16) &&
  1658. (Bpb.SectorsPerCluster != 32) &&
  1659. (Bpb.SectorsPerCluster != 64) &&
  1660. (Bpb.SectorsPerCluster != 128)) {
  1661. Result = FALSE;
  1662. //
  1663. // Likewise on the reserved sectors (must reflect at least the boot sector!)
  1664. //
  1665. } else if (Bpb.ReservedSectors == 0) {
  1666. Result = FALSE;
  1667. //
  1668. // No FATs? Wrong ...
  1669. //
  1670. } else if (Bpb.Fats == 0) {
  1671. Result = FALSE;
  1672. //
  1673. // Prior to DOS 3.2 might contains value in both of Sectors and
  1674. // Sectors Large.
  1675. //
  1676. } else if ((Bpb.Sectors == 0) && (Bpb.LargeSectors == 0)) {
  1677. Result = FALSE;
  1678. //
  1679. // Check that FAT32 (SectorsPerFat == 0) claims some FAT space and
  1680. // is of a version we recognize, currently Version 0.0.
  1681. //
  1682. } else if (Bpb.SectorsPerFat == 0 && ( Bpb.LargeSectorsPerFat == 0 ||
  1683. Bpb.FsVersion != 0 )) {
  1684. Result = FALSE;
  1685. } else if ((Bpb.Media != 0xf0) &&
  1686. (Bpb.Media != 0xf8) &&
  1687. (Bpb.Media != 0xf9) &&
  1688. (Bpb.Media != 0xfb) &&
  1689. (Bpb.Media != 0xfc) &&
  1690. (Bpb.Media != 0xfd) &&
  1691. (Bpb.Media != 0xfe) &&
  1692. (Bpb.Media != 0xff) &&
  1693. (!FatData.FujitsuFMR || ((Bpb.Media != 0x00) &&
  1694. (Bpb.Media != 0x01) &&
  1695. (Bpb.Media != 0xfa)))) {
  1696. Result = FALSE;
  1697. //
  1698. // If this isn't FAT32, then there better be a claimed root directory
  1699. // size here ...
  1700. //
  1701. } else if (Bpb.SectorsPerFat != 0 && Bpb.RootEntries == 0) {
  1702. Result = FALSE;
  1703. //
  1704. // If this is FAT32 (i.e., extended BPB), look for and refuse to mount
  1705. // mirror-disabled volumes. If we did, we would need to only write to
  1706. // the FAT# indicated in the ActiveFat field. The only user of this is
  1707. // the FAT->FAT32 converter after the first pass of protected mode work
  1708. // (booting into realmode) and NT should absolutely not be attempting
  1709. // to mount such an in-transition volume.
  1710. //
  1711. } else if (Bpb.SectorsPerFat == 0 && Bpb.MirrorDisabled) {
  1712. Result = FALSE;
  1713. }
  1714. DebugTrace(-1, Dbg, "FatIsBootSectorFat -> %08lx\n", Result);
  1715. return Result;
  1716. }
  1717. //
  1718. // Local Support Routine
  1719. //
  1720. BOOLEAN
  1721. FatIsMediaWriteProtected (
  1722. IN PIRP_CONTEXT IrpContext,
  1723. IN PDEVICE_OBJECT TargetDeviceObject
  1724. )
  1725. /*++
  1726. Routine Description:
  1727. This routine determines if the target media is write protected.
  1728. Arguments:
  1729. TargetDeviceObject - The target of the query
  1730. Return Value:
  1731. NTSTATUS - The return status for the operation
  1732. --*/
  1733. {
  1734. PIRP Irp;
  1735. KEVENT Event;
  1736. NTSTATUS Status;
  1737. IO_STATUS_BLOCK Iosb;
  1738. //
  1739. // Query the partition table
  1740. //
  1741. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1742. //
  1743. // See if the media is write protected. On success or any kind
  1744. // of error (possibly illegal device function), assume it is
  1745. // writeable, and only complain if he tells us he is write protected.
  1746. //
  1747. Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
  1748. TargetDeviceObject,
  1749. NULL,
  1750. 0,
  1751. NULL,
  1752. 0,
  1753. FALSE,
  1754. &Event,
  1755. &Iosb );
  1756. //
  1757. // Just return FALSE in the unlikely event we couldn't allocate an Irp.
  1758. //
  1759. if ( Irp == NULL ) {
  1760. return FALSE;
  1761. }
  1762. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1763. Status = IoCallDriver( TargetDeviceObject, Irp );
  1764. if ( Status == STATUS_PENDING ) {
  1765. (VOID) KeWaitForSingleObject( &Event,
  1766. Executive,
  1767. KernelMode,
  1768. FALSE,
  1769. (PLARGE_INTEGER)NULL );
  1770. Status = Iosb.Status;
  1771. }
  1772. return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
  1773. }
  1774. //
  1775. // Local Support Routine
  1776. //
  1777. NTSTATUS
  1778. FatUserFsCtrl (
  1779. IN PIRP_CONTEXT IrpContext,
  1780. IN PIRP Irp
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. This is the common routine for implementing the user's requests made
  1785. through NtFsControlFile.
  1786. Arguments:
  1787. Irp - Supplies the Irp being processed
  1788. Return Value:
  1789. NTSTATUS - The return status for the operation
  1790. --*/
  1791. {
  1792. NTSTATUS Status;
  1793. ULONG FsControlCode;
  1794. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1795. //
  1796. // Save some references to make our life a little easier
  1797. //
  1798. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  1799. DebugTrace(+1, Dbg,"FatUserFsCtrl...\n", 0);
  1800. DebugTrace( 0, Dbg,"FsControlCode = %08lx\n", FsControlCode);
  1801. //
  1802. // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode
  1803. // of the caller was userspace and this is a METHOD_NEITHER, we have the choice
  1804. // of realy buffering the request through so we can possibly post, or making the
  1805. // request synchronous. Since the former was not done by design, do the latter.
  1806. //
  1807. if (Irp->RequestorMode != KernelMode && (FsControlCode & 3) == METHOD_NEITHER) {
  1808. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  1809. }
  1810. //
  1811. // Case on the control code.
  1812. //
  1813. switch ( FsControlCode ) {
  1814. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  1815. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  1816. case FSCTL_REQUEST_BATCH_OPLOCK:
  1817. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  1818. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  1819. case FSCTL_OPLOCK_BREAK_NOTIFY:
  1820. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  1821. case FSCTL_REQUEST_FILTER_OPLOCK :
  1822. Status = FatOplockRequest( IrpContext, Irp );
  1823. break;
  1824. case FSCTL_LOCK_VOLUME:
  1825. Status = FatLockVolume( IrpContext, Irp );
  1826. break;
  1827. case FSCTL_UNLOCK_VOLUME:
  1828. Status = FatUnlockVolume( IrpContext, Irp );
  1829. break;
  1830. case FSCTL_DISMOUNT_VOLUME:
  1831. Status = FatDismountVolume( IrpContext, Irp );
  1832. break;
  1833. case FSCTL_MARK_VOLUME_DIRTY:
  1834. Status = FatDirtyVolume( IrpContext, Irp );
  1835. break;
  1836. case FSCTL_IS_VOLUME_DIRTY:
  1837. Status = FatIsVolumeDirty( IrpContext, Irp );
  1838. break;
  1839. case FSCTL_IS_VOLUME_MOUNTED:
  1840. Status = FatIsVolumeMounted( IrpContext, Irp );
  1841. break;
  1842. case FSCTL_IS_PATHNAME_VALID:
  1843. Status = FatIsPathnameValid( IrpContext, Irp );
  1844. break;
  1845. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  1846. Status = FatQueryRetrievalPointers( IrpContext, Irp );
  1847. break;
  1848. case FSCTL_QUERY_FAT_BPB:
  1849. Status = FatQueryBpb( IrpContext, Irp );
  1850. break;
  1851. case FSCTL_FILESYSTEM_GET_STATISTICS:
  1852. Status = FatGetStatistics( IrpContext, Irp );
  1853. break;
  1854. case FSCTL_GET_VOLUME_BITMAP:
  1855. Status = FatGetVolumeBitmap( IrpContext, Irp );
  1856. break;
  1857. case FSCTL_GET_RETRIEVAL_POINTERS:
  1858. Status = FatGetRetrievalPointers( IrpContext, Irp );
  1859. break;
  1860. case FSCTL_MOVE_FILE:
  1861. Status = FatMoveFile( IrpContext, Irp );
  1862. break;
  1863. case FSCTL_ALLOW_EXTENDED_DASD_IO:
  1864. Status = FatAllowExtendedDasdIo( IrpContext, Irp );
  1865. break;
  1866. default :
  1867. DebugTrace(0, Dbg, "Invalid control code -> %08lx\n", FsControlCode );
  1868. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  1869. Status = STATUS_INVALID_DEVICE_REQUEST;
  1870. break;
  1871. }
  1872. DebugTrace(-1, Dbg, "FatUserFsCtrl -> %08lx\n", Status );
  1873. return Status;
  1874. }
  1875. //
  1876. // Local support routine
  1877. //
  1878. NTSTATUS
  1879. FatOplockRequest (
  1880. IN PIRP_CONTEXT IrpContext,
  1881. IN PIRP Irp
  1882. )
  1883. /*++
  1884. Routine Description:
  1885. This is the common routine to handle oplock requests made via the
  1886. NtFsControlFile call.
  1887. Arguments:
  1888. Irp - Supplies the Irp being processed
  1889. Return Value:
  1890. NTSTATUS - The return status for the operation
  1891. --*/
  1892. {
  1893. NTSTATUS Status;
  1894. ULONG FsControlCode;
  1895. PFCB Fcb;
  1896. PVCB Vcb;
  1897. PCCB Ccb;
  1898. ULONG OplockCount = 0;
  1899. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1900. BOOLEAN AcquiredVcb = FALSE;
  1901. BOOLEAN AcquiredFcb = FALSE;
  1902. //
  1903. // Save some references to make our life a little easier
  1904. //
  1905. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  1906. DebugTrace(+1, Dbg, "FatOplockRequest...\n", 0);
  1907. DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode);
  1908. //
  1909. // We only permit oplock requests on files.
  1910. //
  1911. if ( FatDecodeFileObject( IrpSp->FileObject,
  1912. &Vcb,
  1913. &Fcb,
  1914. &Ccb ) != UserFileOpen ) {
  1915. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1916. DebugTrace(-1, Dbg, "FatOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
  1917. return STATUS_INVALID_PARAMETER;
  1918. }
  1919. //
  1920. // Make this a waitable Irpcontext so we don't fail to acquire
  1921. // the resources.
  1922. //
  1923. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1924. //
  1925. // Use a try finally to free the Fcb/Vcb
  1926. //
  1927. try {
  1928. //
  1929. // Switch on the function control code. We grab the Fcb exclusively
  1930. // for oplock requests, shared for oplock break acknowledgement.
  1931. //
  1932. switch ( FsControlCode ) {
  1933. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  1934. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  1935. case FSCTL_REQUEST_BATCH_OPLOCK:
  1936. case FSCTL_REQUEST_FILTER_OPLOCK :
  1937. FatAcquireSharedVcb( IrpContext, Fcb->Vcb );
  1938. AcquiredVcb = TRUE;
  1939. FatAcquireExclusiveFcb( IrpContext, Fcb );
  1940. AcquiredFcb = TRUE;
  1941. if (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
  1942. OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( &Fcb->Specific.Fcb.FileLock );
  1943. } else {
  1944. OplockCount = Fcb->UncleanCount;
  1945. }
  1946. break;
  1947. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  1948. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  1949. case FSCTL_OPLOCK_BREAK_NOTIFY:
  1950. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  1951. FatAcquireSharedFcb( IrpContext, Fcb );
  1952. AcquiredFcb = TRUE;
  1953. break;
  1954. default:
  1955. FatBugCheck( FsControlCode, 0, 0 );
  1956. }
  1957. //
  1958. // Call the FsRtl routine to grant/acknowledge oplock.
  1959. //
  1960. Status = FsRtlOplockFsctrl( &Fcb->Specific.Fcb.Oplock,
  1961. Irp,
  1962. OplockCount );
  1963. //
  1964. // Set the flag indicating if Fast I/O is possible
  1965. //
  1966. Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
  1967. } finally {
  1968. DebugUnwind( FatOplockRequest );
  1969. //
  1970. // Release all of our resources
  1971. //
  1972. if (AcquiredVcb) {
  1973. FatReleaseVcb( IrpContext, Fcb->Vcb );
  1974. }
  1975. if (AcquiredFcb) {
  1976. FatReleaseFcb( IrpContext, Fcb );
  1977. }
  1978. if (!AbnormalTermination()) {
  1979. FatCompleteRequest( IrpContext, FatNull, 0 );
  1980. }
  1981. DebugTrace(-1, Dbg, "FatOplockRequest -> %08lx\n", Status );
  1982. }
  1983. return Status;
  1984. }
  1985. //
  1986. // Local Support Routine
  1987. //
  1988. NTSTATUS
  1989. FatLockVolume (
  1990. IN PIRP_CONTEXT IrpContext,
  1991. IN PIRP Irp
  1992. )
  1993. /*++
  1994. Routine Description:
  1995. This routine performs the lock volume operation. It is responsible for
  1996. either completing of enqueuing the input Irp.
  1997. Arguments:
  1998. Irp - Supplies the Irp to process
  1999. Return Value:
  2000. NTSTATUS - The return status for the operation
  2001. --*/
  2002. {
  2003. NTSTATUS Status;
  2004. PIO_STACK_LOCATION IrpSp;
  2005. PVCB Vcb;
  2006. PFCB Fcb;
  2007. PCCB Ccb;
  2008. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2009. DebugTrace(+1, Dbg, "FatLockVolume...\n", 0);
  2010. //
  2011. // Decode the file object, the only type of opens we accept are
  2012. // user volume opens.
  2013. //
  2014. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
  2015. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2016. DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2017. return STATUS_INVALID_PARAMETER;
  2018. }
  2019. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  2020. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2021. DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2022. return STATUS_INVALID_PARAMETER;
  2023. }
  2024. //
  2025. // Send our notification so that folks that like to hold handles on
  2026. // volumes can get out of the way.
  2027. //
  2028. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK );
  2029. //
  2030. // Acquire exclusive access to the Vcb and enqueue the Irp if we
  2031. // didn't get access.
  2032. //
  2033. if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
  2034. DebugTrace( 0, Dbg, "Cannot acquire Vcb\n", 0);
  2035. Status = FatFsdPostRequest( IrpContext, Irp );
  2036. DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status);
  2037. return Status;
  2038. }
  2039. try {
  2040. Status = FatLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
  2041. } finally {
  2042. //
  2043. // Since we drop and release the vcb while trying to punch the volume
  2044. // down, it may be the case that we decide the operation should not
  2045. // continue if the user raced a CloeseHandle() with us (and it finished
  2046. // the cleanup) while we were waiting for our closes to finish.
  2047. //
  2048. // In this case, we will have been raised out of the acquire logic with
  2049. // STATUS_FILE_CLOSED, and the volume will not be held.
  2050. //
  2051. if (!AbnormalTermination() || ExIsResourceAcquiredExclusiveLite( &Vcb->Resource )) {
  2052. FatReleaseVcb( IrpContext, Vcb );
  2053. }
  2054. if (!NT_SUCCESS( Status ) || AbnormalTermination()) {
  2055. //
  2056. // The volume lock will be failing.
  2057. //
  2058. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED );
  2059. }
  2060. }
  2061. FatCompleteRequest( IrpContext, Irp, Status );
  2062. DebugTrace(-1, Dbg, "FatLockVolume -> %08lx\n", Status);
  2063. return Status;
  2064. }
  2065. //
  2066. // Local Support Routine
  2067. //
  2068. NTSTATUS
  2069. FatUnlockVolume (
  2070. IN PIRP_CONTEXT IrpContext,
  2071. IN PIRP Irp
  2072. )
  2073. /*++
  2074. Routine Description:
  2075. This routine performs the unlock volume operation. It is responsible for
  2076. either completing of enqueuing the input Irp.
  2077. Arguments:
  2078. Irp - Supplies the Irp to process
  2079. Return Value:
  2080. NTSTATUS - The return status for the operation
  2081. --*/
  2082. {
  2083. NTSTATUS Status;
  2084. PIO_STACK_LOCATION IrpSp;
  2085. PVCB Vcb;
  2086. PFCB Fcb;
  2087. PCCB Ccb;
  2088. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2089. DebugTrace(+1, Dbg, "FatUnlockVolume...\n", 0);
  2090. //
  2091. // Decode the file object, the only type of opens we accept are
  2092. // user volume opens.
  2093. //
  2094. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
  2095. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2096. DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2097. return STATUS_INVALID_PARAMETER;
  2098. }
  2099. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  2100. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2101. DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2102. return STATUS_INVALID_PARAMETER;
  2103. }
  2104. Status = FatUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
  2105. //
  2106. // Send notification that the volume is avaliable.
  2107. //
  2108. if (NT_SUCCESS( Status )) {
  2109. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK );
  2110. }
  2111. FatCompleteRequest( IrpContext, Irp, Status );
  2112. DebugTrace(-1, Dbg, "FatUnlockVolume -> %08lx\n", Status);
  2113. return Status;
  2114. }
  2115. NTSTATUS
  2116. FatLockVolumeInternal (
  2117. IN PIRP_CONTEXT IrpContext,
  2118. IN PVCB Vcb,
  2119. IN PFILE_OBJECT FileObject OPTIONAL
  2120. )
  2121. /*++
  2122. Routine Description:
  2123. This routine performs the actual lock volume operation. It will be called
  2124. by anyone wishing to try to protect the volume for a long duration. PNP
  2125. operations are such a user.
  2126. The volume must be held exclusive by the caller.
  2127. Arguments:
  2128. Vcb - The volume being locked.
  2129. FileObject - File corresponding to the handle locking the volume. If this
  2130. is not specified, a system lock is assumed.
  2131. Return Value:
  2132. NTSTATUS - The return status for the operation
  2133. --*/
  2134. {
  2135. NTSTATUS Status = STATUS_SUCCESS;
  2136. KIRQL SavedIrql;
  2137. ULONG RemainingUserReferences = (FileObject? 1: 0);
  2138. ASSERT( ExIsResourceAcquiredExclusiveLite( &Vcb->Resource ) &&
  2139. !ExIsResourceAcquiredExclusiveLite( &FatData.Resource ));
  2140. //
  2141. // Go synchronous for the rest of the lock operation. It may be
  2142. // reasonable to try to revisit this in the future, but for now
  2143. // the purge below expects to be able to wait.
  2144. //
  2145. // We know it is OK to leave the flag up given how we're used at
  2146. // the moment.
  2147. //
  2148. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  2149. //
  2150. // If there are any open handles, this will fail.
  2151. //
  2152. if (!FatIsHandleCountZero( IrpContext, Vcb )) {
  2153. return STATUS_ACCESS_DENIED;
  2154. }
  2155. //
  2156. // Force Mm to get rid of its referenced file objects.
  2157. //
  2158. FatFlushFat( IrpContext, Vcb );
  2159. FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
  2160. FatCloseEaFile( IrpContext, Vcb, TRUE );
  2161. //
  2162. // Now back out of our synchronization and wait for the lazy writer
  2163. // to finish off any lazy closes that could have been outstanding.
  2164. //
  2165. // Since we flushed, we know that the lazy writer will issue all
  2166. // possible lazy closes in the next tick - if we hadn't, an otherwise
  2167. // unopened file with a large amount of dirty data could have hung
  2168. // around for a while as the data trickled out to the disk.
  2169. //
  2170. // This is even more important now since we send notification to
  2171. // alert other folks that this style of check is about to happen so
  2172. // that they can close their handles. We don't want to enter a fast
  2173. // race with the lazy writer tearing down his references to the file.
  2174. //
  2175. FatReleaseVcb( IrpContext, Vcb );
  2176. Status = CcWaitForCurrentLazyWriterActivity();
  2177. FatAcquireExclusiveVcb( IrpContext, Vcb );
  2178. if (!NT_SUCCESS( Status )) {
  2179. return Status;
  2180. }
  2181. //
  2182. // Now rundown the delayed closes one last time. We appear to be able
  2183. // to have additional collisions.
  2184. //
  2185. FatFspClose( Vcb );
  2186. //
  2187. // Check if the Vcb is already locked, or if the open file count
  2188. // is greater than 1 (which implies that someone else also is
  2189. // currently using the volume, or a file on the volume), and that the
  2190. // VPB reference count only includes our residual and the handle (as
  2191. // appropriate).
  2192. //
  2193. // We used to only check for the vpb refcount. This is unreliable since
  2194. // the vpb refcount is dropped immediately before final close, meaning
  2195. // that even though we had a good refcount, the close was inflight and
  2196. // subsequent operations could get confused. Especially if the PNP path
  2197. // was the lock caller, we delete the VCB with an outstanding opencount!
  2198. //
  2199. IoAcquireVpbSpinLock( &SavedIrql );
  2200. if (!FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) &&
  2201. (Vcb->Vpb->ReferenceCount <= 2 + RemainingUserReferences) &&
  2202. (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 ))) {
  2203. SetFlag(Vcb->Vpb->Flags, VPB_LOCKED);
  2204. SetFlag(Vcb->VcbState, VCB_STATE_FLAG_LOCKED);
  2205. Vcb->FileObjectWithVcbLocked = FileObject;
  2206. } else {
  2207. Status = STATUS_ACCESS_DENIED;
  2208. }
  2209. IoReleaseVpbSpinLock( SavedIrql );
  2210. //
  2211. // If we successully locked the volume, see if it is clean now.
  2212. //
  2213. if (NT_SUCCESS( Status ) &&
  2214. FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) &&
  2215. !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) &&
  2216. !CcIsThereDirtyData(Vcb->Vpb)) {
  2217. FatMarkVolume( IrpContext, Vcb, VolumeClean );
  2218. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  2219. }
  2220. ASSERT( !NT_SUCCESS(Status) || (Vcb->OpenFileCount == (CLONG)( FileObject? 1: 0 )));
  2221. return Status;
  2222. }
  2223. NTSTATUS
  2224. FatUnlockVolumeInternal (
  2225. IN PIRP_CONTEXT IrpContext,
  2226. IN PVCB Vcb,
  2227. IN PFILE_OBJECT FileObject OPTIONAL
  2228. )
  2229. /*++
  2230. Routine Description:
  2231. This routine performs the actual unlock volume operation.
  2232. The volume must be held exclusive by the caller.
  2233. Arguments:
  2234. Vcb - The volume being locked.
  2235. FileObject - File corresponding to the handle locking the volume. If this
  2236. is not specified, a system lock is assumed.
  2237. Return Value:
  2238. NTSTATUS - The return status for the operation
  2239. Attempting to remove a system lock that did not exist is OK.
  2240. --*/
  2241. {
  2242. KIRQL SavedIrql;
  2243. NTSTATUS Status = STATUS_NOT_LOCKED;
  2244. IoAcquireVpbSpinLock( &SavedIrql );
  2245. if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && FileObject == Vcb->FileObjectWithVcbLocked) {
  2246. //
  2247. // This one locked it, unlock the volume
  2248. //
  2249. ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED );
  2250. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_LOCKED );
  2251. Vcb->FileObjectWithVcbLocked = NULL;
  2252. Status = STATUS_SUCCESS;
  2253. }
  2254. IoReleaseVpbSpinLock( SavedIrql );
  2255. return Status;
  2256. }
  2257. //
  2258. // Local Support Routine
  2259. //
  2260. NTSTATUS
  2261. FatDismountVolume (
  2262. IN PIRP_CONTEXT IrpContext,
  2263. IN PIRP Irp
  2264. )
  2265. /*++
  2266. Routine Description:
  2267. This routine performs the dismount volume operation. It is responsible for
  2268. either completing of enqueuing the input Irp.
  2269. Arguments:
  2270. Irp - Supplies the Irp to process
  2271. Return Value:
  2272. NTSTATUS - The return status for the operation
  2273. --*/
  2274. {
  2275. PIO_STACK_LOCATION IrpSp;
  2276. NTSTATUS Status;
  2277. BOOLEAN VcbHeld = FALSE;
  2278. PVCB Vcb;
  2279. PFCB Fcb;
  2280. PCCB Ccb;
  2281. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2282. DebugTrace(+1, Dbg, "FatDismountVolume...\n", 0);
  2283. //
  2284. // Decode the file object, the only type of opens we accept are
  2285. // user volume opens on media that is not boot/paging and is not
  2286. // already dismounted ... (but we need to check that stuff while
  2287. // synchronized)
  2288. //
  2289. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
  2290. Status = STATUS_INVALID_PARAMETER;
  2291. goto fn_return;
  2292. }
  2293. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  2294. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2295. DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2296. return STATUS_INVALID_PARAMETER;
  2297. }
  2298. //
  2299. // Make some unsynchronized checks to see if this operation is possible.
  2300. // We will repeat the appropriate ones inside synchronization, but it is
  2301. // good to avoid bogus notifications.
  2302. //
  2303. if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE )) {
  2304. Status = STATUS_ACCESS_DENIED;
  2305. goto fn_return;
  2306. }
  2307. if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
  2308. Status = STATUS_VOLUME_DISMOUNTED;
  2309. goto fn_return;
  2310. }
  2311. //
  2312. // A bit of historical comment is in order.
  2313. //
  2314. // In all versions prior to NT5, we only permitted dismount if the volume had
  2315. // previously been locked. Now we must permit a forced dismount, meaning that
  2316. // we grab ahold of the whole kit-n-kaboodle - regardless of activity, open
  2317. // handles, etc. - to flush and invalidate the volume.
  2318. //
  2319. // Previously, dismount assumed that lock had come along earlier and done some
  2320. // of the work that we are now going to do - i.e., flush, tear down the eas. All
  2321. // we had to do here is flush the device out and kill off as many of the orphan
  2322. // fcbs as possible. This now changes.
  2323. //
  2324. // In fact, everything is a forced dismount now. This changes one interesting
  2325. // aspect, which is that it used to be the case that the handle used to dismount
  2326. // could come back, read, and induce a verify/remount. This is just not possible
  2327. // now. The point of forced dismount is that very shortly someone will come along
  2328. // and be destructive to the possibility of using the media further - format, eject,
  2329. // etc. By using this path, callers are expected to tolerate the consequences.
  2330. //
  2331. // Note that the volume can still be successfully unlocked by this handle.
  2332. //
  2333. //
  2334. // Send notification.
  2335. //
  2336. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT );
  2337. //
  2338. // Force ourselves to wait and grab everything.
  2339. //
  2340. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  2341. (VOID)FatAcquireExclusiveGlobal( IrpContext );
  2342. try {
  2343. //
  2344. // Guess what? This can raise if a cleanup on the fileobject we
  2345. // got races in ahead of us.
  2346. //
  2347. FatAcquireExclusiveVolume( IrpContext, Vcb );
  2348. VcbHeld = TRUE;
  2349. if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
  2350. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  2351. }
  2352. FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushAndInvalidate );
  2353. //
  2354. // We defer the physical dismount until this handle is closed, per symmetric
  2355. // implemntation in the other FS. This permits a dismounter to issue IOCTL
  2356. // through this handle and perform device manipulation without racing with
  2357. // creates attempting to mount the volume again.
  2358. //
  2359. // Raise a flag to tell the cleanup path to complete the dismount.
  2360. //
  2361. SetFlag( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT );
  2362. //
  2363. // Indicate that the volume was dismounted so that we may return the
  2364. // correct error code when operations are attempted via open handles.
  2365. //
  2366. Vcb->VcbCondition = VcbBad;
  2367. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED );
  2368. Status = STATUS_SUCCESS;
  2369. try_exit: NOTHING;
  2370. } finally {
  2371. if (VcbHeld) {
  2372. FatReleaseVolume( IrpContext, Vcb );
  2373. }
  2374. FatReleaseGlobal( IrpContext );
  2375. //
  2376. // I do not believe it is possible to raise, but for completeness
  2377. // notice and send notification of failure. We absolutely
  2378. // cannot have raised in CheckForDismount.
  2379. //
  2380. // We decline to call an attempt to dismount a dismounted volume
  2381. // a failure to do so.
  2382. //
  2383. if ((!NT_SUCCESS( Status ) && Status != STATUS_VOLUME_DISMOUNTED)
  2384. || AbnormalTermination()) {
  2385. FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED );
  2386. }
  2387. }
  2388. fn_return:
  2389. FatCompleteRequest( IrpContext, Irp, Status );
  2390. DebugTrace(-1, Dbg, "FatDismountVolume -> %08lx\n", Status);
  2391. return Status;
  2392. }
  2393. //
  2394. // Local Support Routine
  2395. //
  2396. NTSTATUS
  2397. FatDirtyVolume (
  2398. IN PIRP_CONTEXT IrpContext,
  2399. IN PIRP Irp
  2400. )
  2401. /*++
  2402. Routine Description:
  2403. This routine marks the volume as dirty.
  2404. Arguments:
  2405. Irp - Supplies the Irp to process
  2406. Return Value:
  2407. NTSTATUS - The return status for the operation
  2408. --*/
  2409. {
  2410. PIO_STACK_LOCATION IrpSp;
  2411. PVCB Vcb;
  2412. PFCB Fcb;
  2413. PCCB Ccb;
  2414. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2415. DebugTrace(+1, Dbg, "FatDirtyVolume...\n", 0);
  2416. //
  2417. // Decode the file object, the only type of opens we accept are
  2418. // user volume opens.
  2419. //
  2420. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
  2421. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2422. DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2423. return STATUS_INVALID_PARAMETER;
  2424. }
  2425. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  2426. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2427. DebugTrace(-1, Dbg, "FatDirtyVolume -> %08lx\n", STATUS_INVALID_PARAMETER);
  2428. return STATUS_INVALID_PARAMETER;
  2429. }
  2430. //
  2431. // Disable popups, we will just return any error.
  2432. //
  2433. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
  2434. //
  2435. // Verify the Vcb. We want to make sure we don't dirty some
  2436. // random chunk of media that happens to be in the drive now.
  2437. //
  2438. FatVerifyVcb( IrpContext, Vcb );
  2439. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  2440. FatMarkVolume( IrpContext, Vcb, VolumeDirty );
  2441. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  2442. DebugTrace(-1, Dbg, "FatDirtyVolume -> STATUS_SUCCESS\n", 0);
  2443. return STATUS_SUCCESS;
  2444. }
  2445. //
  2446. // Local Support Routine
  2447. //
  2448. NTSTATUS
  2449. FatIsVolumeDirty (
  2450. IN PIRP_CONTEXT IrpContext,
  2451. IN PIRP Irp
  2452. )
  2453. /*++
  2454. Routine Description:
  2455. This routine determines if a volume is currently dirty.
  2456. Arguments:
  2457. Irp - Supplies the Irp to process
  2458. Return Value:
  2459. NTSTATUS - The return status for the operation
  2460. --*/
  2461. {
  2462. PIO_STACK_LOCATION IrpSp;
  2463. TYPE_OF_OPEN TypeOfOpen;
  2464. PVCB Vcb;
  2465. PFCB Fcb;
  2466. PCCB Ccb;
  2467. PULONG VolumeState;
  2468. //
  2469. // Get the current stack location and extract the output
  2470. // buffer information.
  2471. //
  2472. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2473. //
  2474. // Get a pointer to the output buffer. Look at the system buffer field in the
  2475. // irp first. Then the Irp Mdl.
  2476. //
  2477. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  2478. VolumeState = Irp->AssociatedIrp.SystemBuffer;
  2479. } else if (Irp->MdlAddress != NULL) {
  2480. VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, LowPagePriority );
  2481. if (VolumeState == NULL) {
  2482. FatCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  2483. return STATUS_INSUFFICIENT_RESOURCES;
  2484. }
  2485. } else {
  2486. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  2487. return STATUS_INVALID_USER_BUFFER;
  2488. }
  2489. //
  2490. // Make sure the output buffer is large enough and then initialize
  2491. // the answer to be that the volume isn't dirty.
  2492. //
  2493. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
  2494. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2495. return STATUS_INVALID_PARAMETER;
  2496. }
  2497. *VolumeState = 0;
  2498. //
  2499. // Decode the file object
  2500. //
  2501. TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
  2502. if (TypeOfOpen != UserVolumeOpen) {
  2503. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2504. return STATUS_INVALID_PARAMETER;
  2505. }
  2506. if (Vcb->VcbCondition != VcbGood) {
  2507. FatCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  2508. return STATUS_VOLUME_DISMOUNTED;
  2509. }
  2510. //
  2511. // Disable PopUps, we want to return any error.
  2512. //
  2513. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
  2514. //
  2515. // Verify the Vcb. We want to make double sure that this volume
  2516. // is around so that we know our information is good.
  2517. //
  2518. FatVerifyVcb( IrpContext, Vcb );
  2519. //
  2520. // Now set the returned information. We can avoid probing the disk since
  2521. // we know our internal state is in sync.
  2522. //
  2523. if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY | VCB_STATE_FLAG_MOUNTED_DIRTY) ) {
  2524. SetFlag( *VolumeState, VOLUME_IS_DIRTY );
  2525. }
  2526. Irp->IoStatus.Information = sizeof( ULONG );
  2527. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  2528. return STATUS_SUCCESS;
  2529. }
  2530. //
  2531. // Local Support Routine
  2532. //
  2533. NTSTATUS
  2534. FatIsVolumeMounted (
  2535. IN PIRP_CONTEXT IrpContext,
  2536. IN PIRP Irp
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. This routine determines if a volume is currently mounted.
  2541. Arguments:
  2542. Irp - Supplies the Irp to process
  2543. Return Value:
  2544. NTSTATUS - The return status for the operation
  2545. --*/
  2546. {
  2547. NTSTATUS Status;
  2548. PIO_STACK_LOCATION IrpSp;
  2549. PVCB Vcb = NULL;
  2550. PFCB Fcb;
  2551. PCCB Ccb;
  2552. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2553. Status = STATUS_SUCCESS;
  2554. DebugTrace(+1, Dbg, "FatIsVolumeMounted...\n", 0);
  2555. //
  2556. // Decode the file object.
  2557. //
  2558. (VOID)FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
  2559. ASSERT( Vcb != NULL );
  2560. //
  2561. // Disable PopUps, we want to return any error.
  2562. //
  2563. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS);
  2564. //
  2565. // Verify the Vcb.
  2566. //
  2567. FatVerifyVcb( IrpContext, Vcb );
  2568. FatCompleteRequest( IrpContext, Irp, Status );
  2569. DebugTrace(-1, Dbg, "FatIsVolumeMounted -> %08lx\n", Status);
  2570. return Status;
  2571. }
  2572. //
  2573. // Local Support Routine
  2574. //
  2575. NTSTATUS
  2576. FatIsPathnameValid (
  2577. IN PIRP_CONTEXT IrpContext,
  2578. IN PIRP Irp
  2579. )
  2580. /*++
  2581. Routine Description:
  2582. This routine determines if a pathname is a-priori illegal by inspecting
  2583. the the characters used. It is required to be correct on a FALSE return.
  2584. N.B.: current implementation is intentioanlly a no-op. This may change
  2585. in the future. A careful reader of the previous implementation of this
  2586. FSCTL in FAT would discover that it violated the requirement stated above
  2587. and could return FALSE for a valid (createable) pathname.
  2588. Arguments:
  2589. Irp - Supplies the Irp to process
  2590. Return Value:
  2591. NTSTATUS - The return status for the operation
  2592. --*/
  2593. {
  2594. DebugTrace(+1, Dbg, "FatIsPathnameValid...\n", 0);
  2595. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  2596. DebugTrace(-1, Dbg, "FatIsPathnameValid -> %08lx\n", STATUS_SUCCESS);
  2597. return STATUS_SUCCESS;
  2598. }
  2599. //
  2600. // Local Support Routine
  2601. //
  2602. NTSTATUS
  2603. FatQueryBpb (
  2604. IN PIRP_CONTEXT IrpContext,
  2605. IN PIRP Irp
  2606. )
  2607. /*++
  2608. Routine Description:
  2609. This routine simply returns the first 0x24 bytes of sector 0.
  2610. Arguments:
  2611. Irp - Supplies the Irp to process
  2612. Return Value:
  2613. NTSTATUS - The return status for the operation
  2614. --*/
  2615. {
  2616. PIO_STACK_LOCATION IrpSp;
  2617. PVCB Vcb;
  2618. PFSCTL_QUERY_FAT_BPB_BUFFER BpbBuffer;
  2619. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2620. DebugTrace(+1, Dbg, "FatQueryBpb...\n", 0);
  2621. //
  2622. // Get the Vcb. If we didn't keep the information needed for this call,
  2623. // we had a reason ...
  2624. //
  2625. Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
  2626. if (Vcb->First0x24BytesOfBootSector == NULL) {
  2627. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  2628. DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST );
  2629. return STATUS_INVALID_DEVICE_REQUEST;
  2630. }
  2631. //
  2632. // Extract the buffer
  2633. //
  2634. BpbBuffer = (PFSCTL_QUERY_FAT_BPB_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  2635. //
  2636. // Make sure the buffer is big enough.
  2637. //
  2638. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < 0x24) {
  2639. FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  2640. DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
  2641. return STATUS_BUFFER_TOO_SMALL;
  2642. }
  2643. //
  2644. // Fill in the output buffer
  2645. //
  2646. RtlCopyMemory( BpbBuffer->First0x24BytesOfBootSector,
  2647. Vcb->First0x24BytesOfBootSector,
  2648. 0x24 );
  2649. Irp->IoStatus.Information = 0x24;
  2650. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  2651. DebugTrace(-1, Dbg, "FatQueryBpb -> %08lx\n", STATUS_SUCCESS);
  2652. return STATUS_SUCCESS;
  2653. }
  2654. //
  2655. // Local Support Routine
  2656. //
  2657. NTSTATUS
  2658. FatInvalidateVolumes (
  2659. IN PIRP Irp
  2660. )
  2661. /*++
  2662. Routine Description:
  2663. This routine searches for all the volumes mounted on the same real device
  2664. of the current DASD handle, and marks them all bad. The only operation
  2665. that can be done on such handles is cleanup and close.
  2666. Arguments:
  2667. Irp - Supplies the Irp to process
  2668. Return Value:
  2669. NTSTATUS - The return status for the operation
  2670. --*/
  2671. {
  2672. NTSTATUS Status;
  2673. IRP_CONTEXT IrpContext;
  2674. PIO_STACK_LOCATION IrpSp;
  2675. LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
  2676. HANDLE Handle;
  2677. PLIST_ENTRY Links;
  2678. PFILE_OBJECT FileToMarkBad;
  2679. PDEVICE_OBJECT DeviceToMarkBad;
  2680. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2681. DebugTrace(+1, Dbg, "FatInvalidateVolumes...\n", 0);
  2682. //
  2683. // Check for the correct security access.
  2684. // The caller must have the SeTcbPrivilege.
  2685. //
  2686. if (!SeSinglePrivilegeCheck(TcbPrivilege, Irp->RequestorMode)) {
  2687. FatCompleteRequest( FatNull, Irp, STATUS_PRIVILEGE_NOT_HELD );
  2688. DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_PRIVILEGE_NOT_HELD);
  2689. return STATUS_PRIVILEGE_NOT_HELD;
  2690. }
  2691. //
  2692. // Try to get a pointer to the device object from the handle passed in.
  2693. //
  2694. #if defined(_WIN64)
  2695. if (IoIs32bitProcess( Irp )) {
  2696. if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(UINT32)) {
  2697. FatCompleteRequest( FatNull, Irp, STATUS_INVALID_PARAMETER );
  2698. DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER);
  2699. return STATUS_INVALID_PARAMETER;
  2700. }
  2701. Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
  2702. } else {
  2703. #endif
  2704. if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof(HANDLE)) {
  2705. FatCompleteRequest( FatNull, Irp, STATUS_INVALID_PARAMETER );
  2706. DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", STATUS_INVALID_PARAMETER);
  2707. return STATUS_INVALID_PARAMETER;
  2708. }
  2709. Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
  2710. #if defined(_WIN64)
  2711. }
  2712. #endif
  2713. Status = ObReferenceObjectByHandle( Handle,
  2714. 0,
  2715. *IoFileObjectType,
  2716. KernelMode,
  2717. &FileToMarkBad,
  2718. NULL );
  2719. if (!NT_SUCCESS(Status)) {
  2720. FatCompleteRequest( FatNull, Irp, Status );
  2721. DebugTrace(-1, Dbg, "FatInvalidateVolumes -> %08lx\n", Status);
  2722. return Status;
  2723. } else {
  2724. //
  2725. // We only needed the pointer, not a reference.
  2726. //
  2727. ObDereferenceObject( FileToMarkBad );
  2728. //
  2729. // Grab the DeviceObject from the FileObject.
  2730. //
  2731. DeviceToMarkBad = FileToMarkBad->DeviceObject;
  2732. }
  2733. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  2734. SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
  2735. IrpContext.MajorFunction = IrpSp->MajorFunction;
  2736. IrpContext.MinorFunction = IrpSp->MinorFunction;
  2737. FatAcquireExclusiveGlobal( &IrpContext );
  2738. //
  2739. // First acquire the FatData resource shared, then walk through all the
  2740. // mounted VCBs looking for candidates to mark BAD.
  2741. //
  2742. // On volumes we mark bad, check for dismount possibility (which is
  2743. // why we have to get the next link early).
  2744. //
  2745. Links = FatData.VcbQueue.Flink;
  2746. while (Links != &FatData.VcbQueue) {
  2747. PVCB ExistingVcb;
  2748. ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
  2749. Links = Links->Flink;
  2750. //
  2751. // If we get a match, mark the volume Bad, and also check to
  2752. // see if the volume should go away.
  2753. //
  2754. if (ExistingVcb->Vpb->RealDevice == DeviceToMarkBad) {
  2755. //
  2756. // Here we acquire the Vcb exclusive and try to purge
  2757. // all the open files. The idea is to have as little as
  2758. // possible stale data visible and to hasten the volume
  2759. // going away.
  2760. //
  2761. (VOID)FatAcquireExclusiveVcb( &IrpContext, ExistingVcb );
  2762. if (ExistingVcb->Vpb == DeviceToMarkBad->Vpb) {
  2763. KIRQL OldIrql;
  2764. IoAcquireVpbSpinLock( &OldIrql );
  2765. if (FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_MOUNTED )) {
  2766. PVPB NewVpb;
  2767. NewVpb = ExistingVcb->SwapVpb;
  2768. ExistingVcb->SwapVpb = NULL;
  2769. RtlZeroMemory( NewVpb, sizeof( VPB ) );
  2770. NewVpb->Type = IO_TYPE_VPB;
  2771. NewVpb->Size = sizeof( VPB );
  2772. NewVpb->RealDevice = DeviceToMarkBad;
  2773. NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING );
  2774. DeviceToMarkBad->Vpb = NewVpb;
  2775. }
  2776. ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL );
  2777. IoReleaseVpbSpinLock( OldIrql );
  2778. }
  2779. ExistingVcb->VcbCondition = VcbBad;
  2780. FatMarkFcbCondition( &IrpContext, ExistingVcb->RootDcb, FcbBad, TRUE );
  2781. FatPurgeReferencedFileObjects( &IrpContext,
  2782. ExistingVcb->RootDcb,
  2783. NoFlush );
  2784. //
  2785. // If the volume was not deleted, drop the resource.
  2786. //
  2787. if (Links->Blink == &ExistingVcb->VcbLinks) {
  2788. PVPB Vpb;
  2789. FatReleaseVcb( &IrpContext, ExistingVcb );
  2790. //
  2791. // If the volume does go away now, then we have to free
  2792. // up the Vpb as nobody else will.
  2793. //
  2794. Vpb = ExistingVcb->Vpb;
  2795. if (FatCheckForDismount( &IrpContext, ExistingVcb, FALSE )) {
  2796. ExFreePool( Vpb );
  2797. }
  2798. }
  2799. }
  2800. }
  2801. FatReleaseGlobal( &IrpContext );
  2802. FatCompleteRequest( FatNull, Irp, STATUS_SUCCESS );
  2803. DebugTrace(-1, Dbg, "FatInvalidateVolumes -> STATUS_SUCCESS\n", 0);
  2804. return STATUS_SUCCESS;
  2805. }
  2806. //
  2807. // Local Support routine
  2808. //
  2809. BOOLEAN
  2810. FatPerformVerifyDiskRead (
  2811. IN PIRP_CONTEXT IrpContext,
  2812. IN PVCB Vcb,
  2813. IN PVOID Buffer,
  2814. IN LBO Lbo,
  2815. IN ULONG NumberOfBytesToRead,
  2816. IN BOOLEAN ReturnOnError
  2817. )
  2818. /*++
  2819. Routine Description:
  2820. This routine is used to read in a range of bytes from the disk. It
  2821. bypasses all of the caching and regular I/O logic, and builds and issues
  2822. the requests itself. It does this operation overriding the verify
  2823. volume flag in the device object.
  2824. Arguments:
  2825. Vcb - Supplies the target device object for this operation.
  2826. Buffer - Supplies the buffer that will recieve the results of this operation
  2827. Lbo - Supplies the byte offset of where to start reading
  2828. NumberOfBytesToRead - Supplies the number of bytes to read, this must
  2829. be in multiple of bytes units acceptable to the disk driver.
  2830. ReturnOnError - Indicates that we should return on an error, instead
  2831. of raising.
  2832. Return Value:
  2833. BOOLEAN - TRUE if the operation succeded, FALSE otherwise.
  2834. --*/
  2835. {
  2836. KEVENT Event;
  2837. PIRP Irp;
  2838. LARGE_INTEGER ByteOffset;
  2839. NTSTATUS Status;
  2840. IO_STATUS_BLOCK Iosb;
  2841. DebugTrace(0, Dbg, "FatPerformVerifyDiskRead, Lbo = %08lx\n", Lbo );
  2842. //
  2843. // Initialize the event we're going to use
  2844. //
  2845. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  2846. //
  2847. // Build the irp for the operation and also set the overrride flag
  2848. //
  2849. ByteOffset.QuadPart = Lbo;
  2850. Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  2851. Vcb->TargetDeviceObject,
  2852. Buffer,
  2853. NumberOfBytesToRead,
  2854. &ByteOffset,
  2855. &Event,
  2856. &Iosb );
  2857. if ( Irp == NULL ) {
  2858. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  2859. }
  2860. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  2861. //
  2862. // Call the device to do the read and wait for it to finish.
  2863. //
  2864. Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
  2865. if (Status == STATUS_PENDING) {
  2866. (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  2867. Status = Iosb.Status;
  2868. }
  2869. ASSERT( Status != STATUS_VERIFY_REQUIRED );
  2870. //
  2871. // Special case this error code because this probably means we used
  2872. // the wrong sector size and we want to reject STATUS_WRONG_VOLUME.
  2873. //
  2874. if (Status == STATUS_INVALID_PARAMETER) {
  2875. return FALSE;
  2876. }
  2877. //
  2878. // If it doesn't succeed then either return or raise the error.
  2879. //
  2880. if (!NT_SUCCESS(Status)) {
  2881. if (ReturnOnError) {
  2882. return FALSE;
  2883. } else {
  2884. FatNormalizeAndRaiseStatus( IrpContext, Status );
  2885. }
  2886. }
  2887. //
  2888. // And return to our caller
  2889. //
  2890. return TRUE;
  2891. }
  2892. //
  2893. // Local Support Routine
  2894. //
  2895. NTSTATUS
  2896. FatQueryRetrievalPointers (
  2897. IN PIRP_CONTEXT IrpContext,
  2898. IN PIRP Irp
  2899. )
  2900. /*++
  2901. Routine Description:
  2902. This routine performs the query retrieval pointers operation.
  2903. It returns the retrieval pointers for the specified input
  2904. file from the start of the file to the request map size specified
  2905. in the input buffer.
  2906. Arguments:
  2907. Irp - Supplies the Irp to process
  2908. Return Value:
  2909. NTSTATUS - The return status for the operation
  2910. --*/
  2911. {
  2912. NTSTATUS Status;
  2913. PIO_STACK_LOCATION IrpSp;
  2914. PVCB Vcb;
  2915. PFCB Fcb;
  2916. PCCB Ccb;
  2917. PLARGE_INTEGER RequestedMapSize;
  2918. PLARGE_INTEGER *MappingPairs;
  2919. ULONG Index;
  2920. ULONG i;
  2921. ULONG SectorCount;
  2922. LBO Lbo;
  2923. ULONG Vbo;
  2924. ULONG MapSize;
  2925. //
  2926. // Get the current stack location
  2927. //
  2928. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2929. //
  2930. // Decode the file object and ensure that it is the paging file
  2931. //
  2932. // Only Kernel mode clients may query retrieval pointer information about
  2933. // a file. Ensure that this is the case for this caller.
  2934. //
  2935. (VOID)FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
  2936. if (Irp->RequestorMode != KernelMode ||
  2937. Fcb == NULL ||
  2938. !FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ) {
  2939. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2940. return STATUS_INVALID_PARAMETER;
  2941. }
  2942. //
  2943. // Extract the input and output buffer information. The input contains
  2944. // the requested size of the mappings in terms of VBO. The output
  2945. // parameter will receive a pointer to nonpaged pool where the mapping
  2946. // pairs are stored.
  2947. //
  2948. ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof(LARGE_INTEGER) );
  2949. ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength == sizeof(PVOID) );
  2950. RequestedMapSize = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  2951. MappingPairs = Irp->UserBuffer;
  2952. //
  2953. // Acquire exclusive access to the Fcb
  2954. //
  2955. if (!FatAcquireExclusiveFcb( IrpContext, Fcb )) {
  2956. return FatFsdPostRequest( IrpContext, Irp );
  2957. }
  2958. try {
  2959. //
  2960. // Verify the Fcb is still OK
  2961. //
  2962. FatVerifyFcb( IrpContext, Fcb );
  2963. //
  2964. // Check if the mapping the caller requested is too large
  2965. //
  2966. if ((*RequestedMapSize).QuadPart > Fcb->Header.FileSize.QuadPart) {
  2967. try_return( Status = STATUS_INVALID_PARAMETER );
  2968. }
  2969. //
  2970. // Now get the index for the mcb entry that will contain the
  2971. // callers request and allocate enough pool to hold the
  2972. // output mapping pairs
  2973. //
  2974. (VOID)FatLookupMcbEntry( Fcb->Vcb, &Fcb->Mcb, RequestedMapSize->LowPart - 1, &Lbo, NULL, &Index );
  2975. *MappingPairs = FsRtlAllocatePoolWithTag( NonPagedPool,
  2976. (Index + 2) * (2 * sizeof(LARGE_INTEGER)),
  2977. TAG_OUTPUT_MAPPINGPAIRS );
  2978. //
  2979. // Now copy over the mapping pairs from the mcb
  2980. // to the output buffer. We store in [sector count, lbo]
  2981. // mapping pairs and end with a zero sector count.
  2982. //
  2983. MapSize = RequestedMapSize->LowPart;
  2984. for (i = 0; i <= Index; i += 1) {
  2985. (VOID)FatGetNextMcbEntry( Fcb->Vcb, &Fcb->Mcb, i, &Vbo, &Lbo, &SectorCount );
  2986. if (SectorCount > MapSize) {
  2987. SectorCount = MapSize;
  2988. }
  2989. (*MappingPairs)[ i*2 + 0 ].QuadPart = SectorCount;
  2990. (*MappingPairs)[ i*2 + 1 ].QuadPart = Lbo;
  2991. MapSize -= SectorCount;
  2992. }
  2993. (*MappingPairs)[ i*2 + 0 ].QuadPart = 0;
  2994. Status = STATUS_SUCCESS;
  2995. try_exit: NOTHING;
  2996. } finally {
  2997. DebugUnwind( FatQueryRetrievalPointers );
  2998. //
  2999. // Release all of our resources
  3000. //
  3001. FatReleaseFcb( IrpContext, Fcb );
  3002. //
  3003. // If this is an abnormal termination then undo our work, otherwise
  3004. // complete the irp
  3005. //
  3006. if (!AbnormalTermination()) {
  3007. FatCompleteRequest( IrpContext, Irp, Status );
  3008. }
  3009. }
  3010. return Status;
  3011. }
  3012. //
  3013. // Local Support Routine
  3014. //
  3015. NTSTATUS
  3016. FatGetStatistics (
  3017. IN PIRP_CONTEXT IrpContext,
  3018. IN PIRP Irp
  3019. )
  3020. /*++
  3021. Routine Description:
  3022. This routine returns the filesystem performance counters from the
  3023. appropriate VCB.
  3024. Arguments:
  3025. Irp - Supplies the Irp to process
  3026. Return Value:
  3027. NTSTATUS - The return status for the operation
  3028. --*/
  3029. {
  3030. PIO_STACK_LOCATION IrpSp;
  3031. NTSTATUS Status;
  3032. PVCB Vcb;
  3033. PFILE_SYSTEM_STATISTICS Buffer;
  3034. ULONG BufferLength;
  3035. ULONG StatsSize;
  3036. ULONG BytesToCopy;
  3037. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3038. DebugTrace(+1, Dbg, "FatGetStatistics...\n", 0);
  3039. //
  3040. // Extract the buffer
  3041. //
  3042. Buffer = Irp->AssociatedIrp.SystemBuffer;
  3043. BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  3044. //
  3045. // Get a pointer to the output buffer.
  3046. //
  3047. Buffer = Irp->AssociatedIrp.SystemBuffer;
  3048. //
  3049. // Make sure the buffer is big enough for at least the common part.
  3050. //
  3051. if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) {
  3052. FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  3053. DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
  3054. return STATUS_BUFFER_TOO_SMALL;
  3055. }
  3056. //
  3057. // Now see how many bytes we can copy.
  3058. //
  3059. StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors;
  3060. if (BufferLength < StatsSize) {
  3061. BytesToCopy = BufferLength;
  3062. Status = STATUS_BUFFER_OVERFLOW;
  3063. } else {
  3064. BytesToCopy = StatsSize;
  3065. Status = STATUS_SUCCESS;
  3066. }
  3067. //
  3068. // Get the Vcb.
  3069. //
  3070. Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
  3071. //
  3072. // Fill in the output buffer
  3073. //
  3074. RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
  3075. Irp->IoStatus.Information = BytesToCopy;
  3076. FatCompleteRequest( IrpContext, Irp, Status );
  3077. DebugTrace(-1, Dbg, "FatGetStatistics -> %08lx\n", Status);
  3078. return Status;
  3079. }
  3080. //
  3081. // Local Support Routine
  3082. //
  3083. NTSTATUS
  3084. FatGetVolumeBitmap(
  3085. IN PIRP_CONTEXT IrpContext,
  3086. IN PIRP Irp
  3087. )
  3088. /*++
  3089. Routine Description:
  3090. This routine returns the volume allocation bitmap.
  3091. Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in
  3092. through the input buffer.
  3093. Output = the VOLUME_BITMAP_BUFFER data structure is returned through
  3094. the output buffer.
  3095. We return as much as the user buffer allows starting the specified input
  3096. LCN (trucated to a byte). If there is no input buffer, we start at zero.
  3097. Arguments:
  3098. Irp - Supplies the Irp being processed.
  3099. Return Value:
  3100. NTSTATUS - The return status for the operation.
  3101. --*/
  3102. {
  3103. NTSTATUS Status;
  3104. PIO_STACK_LOCATION IrpSp;
  3105. PVCB Vcb;
  3106. PFCB Fcb;
  3107. PCCB Ccb;
  3108. ULONG BytesToCopy;
  3109. ULONG TotalClusters;
  3110. ULONG DesiredClusters;
  3111. ULONG StartingCluster;
  3112. ULONG InputBufferLength;
  3113. ULONG OutputBufferLength;
  3114. LARGE_INTEGER StartingLcn;
  3115. PVOLUME_BITMAP_BUFFER OutputBuffer;
  3116. //
  3117. // Get the current Irp stack location and save some references.
  3118. //
  3119. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3120. DebugTrace(+1, Dbg, "FatGetVolumeBitmap, FsControlCode = %08lx\n",
  3121. IrpSp->Parameters.FileSystemControl.FsControlCode);
  3122. //
  3123. // Extract and decode the file object and check for type of open.
  3124. //
  3125. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
  3126. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3127. return STATUS_INVALID_PARAMETER;
  3128. }
  3129. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  3130. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3131. DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> %08lx\n", STATUS_INVALID_PARAMETER);
  3132. return STATUS_INVALID_PARAMETER;
  3133. }
  3134. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  3135. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  3136. OutputBuffer = (PVOLUME_BITMAP_BUFFER)FatMapUserBuffer( IrpContext, Irp );
  3137. //
  3138. // Check for a minimum length on the input and output buffers.
  3139. //
  3140. if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) ||
  3141. (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) {
  3142. FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  3143. return STATUS_BUFFER_TOO_SMALL;
  3144. }
  3145. //
  3146. // Check if a starting cluster was specified.
  3147. //
  3148. TotalClusters = Vcb->AllocationSupport.NumberOfClusters;
  3149. //
  3150. // Check for valid buffers
  3151. //
  3152. try {
  3153. if (Irp->RequestorMode != KernelMode) {
  3154. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  3155. InputBufferLength,
  3156. sizeof(UCHAR) );
  3157. ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
  3158. }
  3159. StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn;
  3160. } except( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
  3161. Status = GetExceptionCode();
  3162. FatRaiseStatus( IrpContext,
  3163. FsRtlIsNtstatusExpected(Status) ?
  3164. Status : STATUS_INVALID_USER_BUFFER );
  3165. }
  3166. if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) {
  3167. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3168. return STATUS_INVALID_PARAMETER;
  3169. } else {
  3170. StartingCluster = StartingLcn.LowPart & ~7;
  3171. }
  3172. //
  3173. // Acquire exclusive access to the Vcb and enqueue the Irp if we
  3174. // didn't get access.
  3175. //
  3176. if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
  3177. DebugTrace( 0, Dbg, "Cannot acquire Vcb\n", 0);
  3178. ASSERT( Irp->RequestorMode == KernelMode );
  3179. Status = FatFsdPostRequest( IrpContext, Irp );
  3180. DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> %08lx\n", Status);
  3181. return Status;
  3182. }
  3183. //
  3184. // Only return what will fit in the user buffer.
  3185. //
  3186. OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
  3187. DesiredClusters = TotalClusters - StartingCluster;
  3188. if (OutputBufferLength < (DesiredClusters + 7) / 8) {
  3189. BytesToCopy = OutputBufferLength;
  3190. Status = STATUS_BUFFER_OVERFLOW;
  3191. } else {
  3192. BytesToCopy = (DesiredClusters + 7) / 8;
  3193. Status = STATUS_SUCCESS;
  3194. }
  3195. //
  3196. // Use try/finally for cleanup.
  3197. //
  3198. try {
  3199. try {
  3200. //
  3201. // Verify the Vcb is still OK
  3202. //
  3203. FatQuickVerifyVcb( IrpContext, Vcb );
  3204. //
  3205. // Fill in the fixed part of the output buffer
  3206. //
  3207. OutputBuffer->StartingLcn.QuadPart = StartingCluster;
  3208. OutputBuffer->BitmapSize.QuadPart = DesiredClusters;
  3209. if (Vcb->NumberOfWindows == 1) {
  3210. //
  3211. // Just copy the volume bitmap into the user buffer.
  3212. //
  3213. ASSERT( Vcb->FreeClusterBitMap.Buffer != NULL );
  3214. RtlCopyMemory( &OutputBuffer->Buffer[0],
  3215. (PUCHAR)Vcb->FreeClusterBitMap.Buffer + StartingCluster/8,
  3216. BytesToCopy );
  3217. } else {
  3218. //
  3219. // Call out to analyze the FAT. We must bias by two to account for
  3220. // the zero base of this API and FAT's physical reality of starting
  3221. // the file heap at cluster 2.
  3222. //
  3223. // Note that the end index is inclusive - we need to subtract one to
  3224. // calculcate it.
  3225. //
  3226. // I.e.: StartingCluster 0 for one byte of bitmap means a start cluster
  3227. // of 2 and end cluster of 9, a run of eight clusters.
  3228. //
  3229. FatExamineFatEntries( IrpContext,
  3230. Vcb,
  3231. StartingCluster + 2,
  3232. StartingCluster + BytesToCopy * 8 + 2 - 1,
  3233. FALSE,
  3234. NULL,
  3235. (PULONG)&OutputBuffer->Buffer[0] );
  3236. }
  3237. } except( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
  3238. Status = GetExceptionCode();
  3239. FatRaiseStatus( IrpContext,
  3240. FsRtlIsNtstatusExpected(Status) ?
  3241. Status : STATUS_INVALID_USER_BUFFER );
  3242. }
  3243. } finally {
  3244. FatReleaseVcb( IrpContext, Vcb );
  3245. }
  3246. Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) +
  3247. BytesToCopy;
  3248. FatCompleteRequest( IrpContext, Irp, Status );
  3249. DebugTrace(-1, Dbg, "FatGetVolumeBitmap -> VOID\n", 0);
  3250. return Status;
  3251. }
  3252. //
  3253. // Local Support Routine
  3254. //
  3255. NTSTATUS
  3256. FatGetRetrievalPointers (
  3257. IN PIRP_CONTEXT IrpContext,
  3258. IN PIRP Irp
  3259. )
  3260. /*++
  3261. Routine Description:
  3262. This routine scans the MCB and builds an extent list. The first run in
  3263. the output extent list will start at the begining of the contiguous
  3264. run specified by the input parameter.
  3265. Input = STARTING_VCN_INPUT_BUFFER;
  3266. Output = RETRIEVAL_POINTERS_BUFFER.
  3267. Arguments:
  3268. Irp - Supplies the Irp being processed.
  3269. Return Value:
  3270. NTSTATUS - The return status for the operation.
  3271. --*/
  3272. {
  3273. NTSTATUS Status;
  3274. PIO_STACK_LOCATION IrpSp;
  3275. PVCB Vcb;
  3276. PFCB FcbOrDcb;
  3277. PCCB Ccb;
  3278. TYPE_OF_OPEN TypeOfOpen;
  3279. ULONG Index;
  3280. ULONG ClusterShift;
  3281. ULONG AllocationSize;
  3282. ULONG Run;
  3283. ULONG RunCount;
  3284. ULONG StartingRun;
  3285. LARGE_INTEGER StartingVcn;
  3286. ULONG InputBufferLength;
  3287. ULONG OutputBufferLength;
  3288. PRETRIEVAL_POINTERS_BUFFER OutputBuffer;
  3289. BOOLEAN FcbLocked;
  3290. //
  3291. // Get the current Irp stack location and save some references.
  3292. //
  3293. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3294. DebugTrace(+1, Dbg, "FatGetRetrievalPointers, FsControlCode = %08lx\n",
  3295. IrpSp->Parameters.FileSystemControl.FsControlCode);
  3296. //
  3297. // Extract and decode the file object and check for type of open.
  3298. //
  3299. TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb );
  3300. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  3301. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3302. return STATUS_INVALID_PARAMETER;
  3303. }
  3304. //
  3305. // Get the input and output buffer lengths and pointers.
  3306. // Initialize some variables.
  3307. //
  3308. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  3309. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  3310. OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)FatMapUserBuffer( IrpContext, Irp );
  3311. //
  3312. // Check for a minimum length on the input and ouput buffers.
  3313. //
  3314. if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) ||
  3315. (OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))) {
  3316. FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  3317. return STATUS_BUFFER_TOO_SMALL;
  3318. }
  3319. //
  3320. // Acquire the Fcb and enqueue the Irp if we didn't get access. Go for
  3321. // shared on read-only media so we can allow prototype XIP to get
  3322. // recursive, as well as recognizing this is safe anyway.
  3323. //
  3324. if (FlagOn( FcbOrDcb->Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED )) {
  3325. FcbLocked = FatAcquireSharedFcb( IrpContext, FcbOrDcb );
  3326. } else {
  3327. FcbLocked = FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
  3328. }
  3329. if (!FcbLocked) {
  3330. DebugTrace( 0, Dbg, "Cannot acquire Vcb\n", 0);
  3331. ASSERT( Irp->RequestorMode == KernelMode );
  3332. Status = FatFsdPostRequest( IrpContext, Irp );
  3333. DebugTrace(-1, Dbg, "FatGetRetrievalPointers -> %08lx\n", Status);
  3334. return Status;
  3335. }
  3336. try {
  3337. //
  3338. // Verify the Fcb is still OK
  3339. //
  3340. FatVerifyFcb( IrpContext, FcbOrDcb );
  3341. //
  3342. // If we haven't yet set the correct AllocationSize, do so.
  3343. //
  3344. if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  3345. FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
  3346. //
  3347. // If this is a non-root directory, we have a bit more to
  3348. // do since it has not gone through FatOpenDirectoryFile().
  3349. //
  3350. if (NodeType(FcbOrDcb) == FAT_NTC_DCB ||
  3351. (NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && FatIsFat32(Vcb))) {
  3352. FcbOrDcb->Header.FileSize.LowPart =
  3353. FcbOrDcb->Header.AllocationSize.LowPart;
  3354. }
  3355. }
  3356. //
  3357. // Check if a starting cluster was specified.
  3358. //
  3359. ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
  3360. AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
  3361. try {
  3362. if (Irp->RequestorMode != KernelMode) {
  3363. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  3364. InputBufferLength,
  3365. sizeof(UCHAR) );
  3366. ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
  3367. }
  3368. StartingVcn = ((PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingVcn;
  3369. } except( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
  3370. Status = GetExceptionCode();
  3371. FatRaiseStatus( IrpContext,
  3372. FsRtlIsNtstatusExpected(Status) ?
  3373. Status : STATUS_INVALID_USER_BUFFER );
  3374. }
  3375. if (StartingVcn.HighPart ||
  3376. StartingVcn.LowPart >= (AllocationSize >> ClusterShift)) {
  3377. try_return( Status = STATUS_END_OF_FILE );
  3378. } else {
  3379. //
  3380. // If we don't find the run, something is very wrong.
  3381. //
  3382. LBO Lbo;
  3383. if (!FatLookupMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb,
  3384. StartingVcn.LowPart << ClusterShift,
  3385. &Lbo,
  3386. NULL,
  3387. &StartingRun)) {
  3388. FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)&FcbOrDcb->Mcb, StartingVcn.LowPart );
  3389. }
  3390. }
  3391. //
  3392. // Now go fill in the ouput buffer with run information
  3393. //
  3394. RunCount = FsRtlNumberOfRunsInLargeMcb( &FcbOrDcb->Mcb );
  3395. for (Index = 0, Run = StartingRun; Run < RunCount; Index++, Run++) {
  3396. ULONG Vcn;
  3397. LBO Lbo;
  3398. ULONG ByteLength;
  3399. //
  3400. // Check for an exhausted output buffer.
  3401. //
  3402. if ((ULONG)FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index+1]) > OutputBufferLength) {
  3403. //
  3404. // We've run out of space, so we won't be storing as many runs to the
  3405. // user's buffer as we had originally planned. We need to return the
  3406. // number of runs that we did have room for.
  3407. //
  3408. try {
  3409. OutputBuffer->ExtentCount = Index;
  3410. } except( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
  3411. Status = GetExceptionCode();
  3412. FatRaiseStatus( IrpContext,
  3413. FsRtlIsNtstatusExpected(Status) ?
  3414. Status : STATUS_INVALID_USER_BUFFER );
  3415. }
  3416. Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]);
  3417. try_return( Status = STATUS_BUFFER_OVERFLOW );
  3418. }
  3419. //
  3420. // Get the extent. If it's not there or malformed, something is very wrong.
  3421. //
  3422. if (!FatGetNextMcbEntry(Vcb, &FcbOrDcb->Mcb, Run, &Vcn, &Lbo, &ByteLength)) {
  3423. FatBugCheck( (ULONG_PTR)FcbOrDcb, (ULONG_PTR)&FcbOrDcb->Mcb, Run );
  3424. }
  3425. //
  3426. // Fill in the next array element.
  3427. //
  3428. try {
  3429. OutputBuffer->Extents[Index].NextVcn.QuadPart = (Vcn + ByteLength) >> ClusterShift;
  3430. OutputBuffer->Extents[Index].Lcn.QuadPart = FatGetIndexFromLbo( Vcb, Lbo ) - 2;
  3431. //
  3432. // If this is the first run, fill in the starting Vcn
  3433. //
  3434. if (Index == 0) {
  3435. OutputBuffer->ExtentCount = RunCount - StartingRun;
  3436. OutputBuffer->StartingVcn.QuadPart = Vcn >> ClusterShift;
  3437. }
  3438. } except( Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH ) {
  3439. Status = GetExceptionCode();
  3440. FatRaiseStatus( IrpContext,
  3441. FsRtlIsNtstatusExpected(Status) ?
  3442. Status : STATUS_INVALID_USER_BUFFER );
  3443. }
  3444. }
  3445. //
  3446. // We successfully retrieved extent info to the end of the allocation.
  3447. //
  3448. Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[Index]);
  3449. Status = STATUS_SUCCESS;
  3450. try_exit: NOTHING;
  3451. } finally {
  3452. DebugUnwind( FatGetRetrievalPointers );
  3453. //
  3454. // Release resources
  3455. //
  3456. FatReleaseFcb( IrpContext, FcbOrDcb );
  3457. //
  3458. // If nothing raised then complete the irp.
  3459. //
  3460. if (!AbnormalTermination()) {
  3461. FatCompleteRequest( IrpContext, Irp, Status );
  3462. }
  3463. DebugTrace(-1, Dbg, "FatGetRetrievalPointers -> VOID\n", 0);
  3464. }
  3465. return Status;
  3466. }
  3467. //
  3468. // Local Support Routine
  3469. //
  3470. NTSTATUS
  3471. FatMoveFile (
  3472. IN PIRP_CONTEXT IrpContext,
  3473. IN PIRP Irp
  3474. )
  3475. /*++
  3476. Routine Description:
  3477. Routine moves a file to the requested Starting Lcn from Starting Vcn for the length
  3478. of cluster count. These values are passed in through the the input buffer as a
  3479. MOVE_DATA structure.
  3480. The call must be made with a DASD handle. The file to move is passed in as a
  3481. parameter.
  3482. Arguments:
  3483. Irp - Supplies the Irp being processed.
  3484. Return Value:
  3485. NTSTATUS - The return status for the operation.
  3486. --*/
  3487. {
  3488. NTSTATUS Status;
  3489. PIO_STACK_LOCATION IrpSp;
  3490. PFILE_OBJECT FileObject;
  3491. TYPE_OF_OPEN TypeOfOpen;
  3492. PVCB Vcb;
  3493. PFCB FcbOrDcb;
  3494. PCCB Ccb;
  3495. ULONG InputBufferLength;
  3496. PMOVE_FILE_DATA InputBuffer;
  3497. ULONG ClusterShift;
  3498. ULONG MaxClusters;
  3499. ULONG FileOffset;
  3500. LARGE_INTEGER LargeFileOffset;
  3501. LBO TargetLbo;
  3502. ULONG TargetCluster;
  3503. LARGE_INTEGER LargeTargetLbo;
  3504. ULONG ByteCount;
  3505. ULONG BytesToWrite;
  3506. ULONG BytesToReallocate;
  3507. ULONG TargetAllocation;
  3508. ULONG FirstSpliceSourceCluster;
  3509. ULONG FirstSpliceTargetCluster;
  3510. ULONG SecondSpliceSourceCluster;
  3511. ULONG SecondSpliceTargetCluster;
  3512. LARGE_MCB SourceMcb;
  3513. LARGE_MCB TargetMcb;
  3514. KEVENT StackEvent;
  3515. PBCB Bcb = NULL;
  3516. PMDL Mdl = NULL;
  3517. PVOID Buffer;
  3518. BOOLEAN SourceMcbInitialized = FALSE;
  3519. BOOLEAN TargetMcbInitialized = FALSE;
  3520. BOOLEAN CacheMapInitialized = FALSE;
  3521. BOOLEAN FcbAcquired = FALSE;
  3522. BOOLEAN LockedPages = FALSE;
  3523. BOOLEAN EventArmed = FALSE;
  3524. BOOLEAN DiskSpaceAllocated = FALSE;
  3525. PDIRENT Dirent;
  3526. PBCB DirentBcb = NULL;
  3527. #if defined(_WIN64)
  3528. MOVE_FILE_DATA LocalMoveFileData;
  3529. PMOVE_FILE_DATA32 MoveFileData32;
  3530. #endif
  3531. ULONG LocalAbnormalTermination = 0;
  3532. //
  3533. // Get the current Irp stack location and save some references.
  3534. //
  3535. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3536. DebugTrace(+1, Dbg, "FatMoveFile, FsControlCode = %08lx\n",
  3537. IrpSp->Parameters.FileSystemControl.FsControlCode);
  3538. //
  3539. // Force WAIT to true. We have a handle in the input buffer which can only
  3540. // be referenced within the originating process.
  3541. //
  3542. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  3543. //
  3544. // Extract and decode the file object and check for type of open.
  3545. //
  3546. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ) != UserVolumeOpen) {
  3547. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3548. DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
  3549. return STATUS_INVALID_PARAMETER;
  3550. }
  3551. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  3552. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3553. DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
  3554. return STATUS_INVALID_PARAMETER;
  3555. }
  3556. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  3557. InputBuffer = (PMOVE_FILE_DATA)Irp->AssociatedIrp.SystemBuffer;
  3558. //
  3559. // Do a quick check on the input buffer.
  3560. //
  3561. #if defined(_WIN64)
  3562. if (IoIs32bitProcess( Irp )) {
  3563. if (InputBuffer == NULL || InputBufferLength < sizeof(MOVE_FILE_DATA32)) {
  3564. FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  3565. return STATUS_BUFFER_TOO_SMALL;
  3566. }
  3567. MoveFileData32 = (PMOVE_FILE_DATA32) InputBuffer;
  3568. LocalMoveFileData.FileHandle = (HANDLE) LongToHandle( MoveFileData32->FileHandle );
  3569. LocalMoveFileData.StartingVcn = MoveFileData32->StartingVcn;
  3570. LocalMoveFileData.StartingLcn = MoveFileData32->StartingLcn;
  3571. LocalMoveFileData.ClusterCount = MoveFileData32->ClusterCount;
  3572. InputBuffer = &LocalMoveFileData;
  3573. } else {
  3574. #endif
  3575. if (InputBuffer == NULL || InputBufferLength < sizeof(MOVE_FILE_DATA)) {
  3576. FatCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  3577. return STATUS_BUFFER_TOO_SMALL;
  3578. }
  3579. #if defined(_WIN64)
  3580. }
  3581. #endif
  3582. MaxClusters = Vcb->AllocationSupport.NumberOfClusters;
  3583. TargetCluster = InputBuffer->StartingLcn.LowPart + 2;
  3584. if (InputBuffer->StartingVcn.HighPart ||
  3585. InputBuffer->StartingLcn.HighPart ||
  3586. (TargetCluster < 2) ||
  3587. (TargetCluster + InputBuffer->ClusterCount < TargetCluster) ||
  3588. (TargetCluster + InputBuffer->ClusterCount > MaxClusters + 2) ||
  3589. (InputBuffer->StartingVcn.LowPart >= MaxClusters)) {
  3590. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3591. DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
  3592. return STATUS_INVALID_PARAMETER;
  3593. }
  3594. //
  3595. // Try to get a pointer to the file object from the handle passed in.
  3596. //
  3597. Status = ObReferenceObjectByHandle( InputBuffer->FileHandle,
  3598. 0,
  3599. *IoFileObjectType,
  3600. Irp->RequestorMode,
  3601. &FileObject,
  3602. NULL );
  3603. if (!NT_SUCCESS(Status)) {
  3604. FatCompleteRequest( IrpContext, Irp, Status );
  3605. DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", Status);
  3606. return Status;
  3607. }
  3608. //
  3609. // There are three basic ways this could be an invalid attempt, so
  3610. // we need to
  3611. //
  3612. // - check that this file object is opened on the same volume as the
  3613. // DASD handle used to call this routine.
  3614. //
  3615. // - extract and decode the file object and check for type of open.
  3616. //
  3617. // - if this is a directory, verify that it's not the root and that
  3618. // we are not trying to move the first cluster. We cannot move the
  3619. // first cluster because sub-directories have this cluster number
  3620. // in them and there is no safe way to simultaneously update them
  3621. // all.
  3622. //
  3623. // We'll allow movefile on the root dir if its fat32, since the root dir
  3624. // is a real chained file there.
  3625. //
  3626. if (FileObject->Vpb != Vcb->Vpb) {
  3627. ObDereferenceObject( FileObject );
  3628. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3629. DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
  3630. return STATUS_INVALID_PARAMETER;
  3631. }
  3632. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &FcbOrDcb, &Ccb );
  3633. if ((TypeOfOpen != UserFileOpen &&
  3634. TypeOfOpen != UserDirectoryOpen) ||
  3635. ((TypeOfOpen == UserDirectoryOpen) &&
  3636. ((NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && !FatIsFat32(Vcb)) ||
  3637. (InputBuffer->StartingVcn.QuadPart == 0)))) {
  3638. ObDereferenceObject( FileObject );
  3639. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3640. DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
  3641. return STATUS_INVALID_PARAMETER;
  3642. }
  3643. //
  3644. // Indicate we're getting to parents of this fcb by their child, and that
  3645. // this is a sufficient assertion of our ability to by synchronized
  3646. // with respect to the parent directory going away.
  3647. //
  3648. // The defrag path is an example of one which arrives at an Fcb by
  3649. // a means which would be unreasonable to duplicate in the assertion
  3650. // code. See FatOpenDirectoryFile.
  3651. //
  3652. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD );
  3653. ClusterShift = Vcb->AllocationSupport.LogOfBytesPerCluster;
  3654. try {
  3655. //
  3656. // Initialize our state variables and the event.
  3657. //
  3658. FileOffset = InputBuffer->StartingVcn.LowPart << ClusterShift;
  3659. LargeFileOffset.QuadPart = FileOffset;
  3660. ByteCount = InputBuffer->ClusterCount << ClusterShift;
  3661. TargetLbo = FatGetLboFromIndex( Vcb, TargetCluster );
  3662. LargeTargetLbo.QuadPart = TargetLbo;
  3663. //
  3664. // Do a quick check on parameters here
  3665. //
  3666. if (FileOffset + ByteCount < FileOffset) {
  3667. try_return( Status = STATUS_INVALID_PARAMETER );
  3668. }
  3669. KeInitializeEvent( &StackEvent, NotificationEvent, FALSE );
  3670. //
  3671. // Initialize two MCBs we will be using
  3672. //
  3673. FsRtlInitializeLargeMcb( &SourceMcb, PagedPool );
  3674. SourceMcbInitialized = TRUE;
  3675. FsRtlInitializeLargeMcb( &TargetMcb, PagedPool );
  3676. TargetMcbInitialized = TRUE;
  3677. //
  3678. // Ok, now if this is a directory open we need to switch to the internal
  3679. // stream fileobject since it is set up for caching. The top-level
  3680. // fileobject has no section object pointers in order prevent folks from
  3681. // mapping it.
  3682. //
  3683. if (TypeOfOpen == UserDirectoryOpen) {
  3684. PFILE_OBJECT DirStreamFileObject;
  3685. //
  3686. // Open the stream fileobject if neccesary. We must acquire the Fcb
  3687. // now to synchronize with other operations (such as dismount ripping
  3688. // apart the allocator).
  3689. //
  3690. (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
  3691. FcbAcquired = TRUE;
  3692. FatVerifyFcb( IrpContext, FcbOrDcb );
  3693. FatOpenDirectoryFile( IrpContext, FcbOrDcb );
  3694. DirStreamFileObject = FcbOrDcb->Specific.Dcb.DirectoryFile;
  3695. //
  3696. // Transfer our reference to the internal stream and proceed. Note that
  3697. // if we dereferenced first, the user could sneak a teardown through since
  3698. // we'd have no references.
  3699. //
  3700. ObReferenceObject( DirStreamFileObject );
  3701. ObDereferenceObject( FileObject );
  3702. FileObject = DirStreamFileObject;
  3703. }
  3704. while (ByteCount) {
  3705. VBO TempVbo;
  3706. LBO TempLbo;
  3707. ULONG TempByteCount;
  3708. //
  3709. // We must throttle our writes.
  3710. //
  3711. CcCanIWrite( FileObject, 0x40000, TRUE, FALSE );
  3712. //
  3713. // Aqcuire file resource exclusive to freeze FileSize and block
  3714. // user non-cached I/O. Verify the integrity of the fcb - the
  3715. // media may have changed (or been dismounted) on us.
  3716. //
  3717. if (FcbAcquired == FALSE) {
  3718. (VOID)FatAcquireExclusiveFcb( IrpContext, FcbOrDcb );
  3719. FcbAcquired = TRUE;
  3720. FatVerifyFcb( IrpContext, FcbOrDcb );
  3721. }
  3722. //
  3723. // Analyzes the range of file allocation we are moving
  3724. // and determines the actual amount of allocation to be
  3725. // moved and how much needs to be written. In addition
  3726. // it guarantees that the Mcb in the file is large enough
  3727. // so that later MCB operations cannot fail.
  3728. //
  3729. FatComputeMoveFileParameter( IrpContext,
  3730. FcbOrDcb,
  3731. FileOffset,
  3732. &ByteCount,
  3733. &BytesToReallocate,
  3734. &BytesToWrite );
  3735. //
  3736. // If ByteCount comes back zero, break here.
  3737. //
  3738. if (ByteCount == 0) {
  3739. break;
  3740. }
  3741. //
  3742. // At this point (before actually doing anything with the disk
  3743. // meta data), calculate the FAT splice clusters and build an
  3744. // MCB describing the space to be deallocated.
  3745. //
  3746. FatComputeMoveFileSplicePoints( IrpContext,
  3747. FcbOrDcb,
  3748. FileOffset,
  3749. TargetCluster,
  3750. BytesToReallocate,
  3751. &FirstSpliceSourceCluster,
  3752. &FirstSpliceTargetCluster,
  3753. &SecondSpliceSourceCluster,
  3754. &SecondSpliceTargetCluster,
  3755. &SourceMcb );
  3756. //
  3757. // Now attempt to allocate the new disk storage using the
  3758. // Target Lcn as a hint.
  3759. //
  3760. TempByteCount = BytesToReallocate;
  3761. FatAllocateDiskSpace( IrpContext,
  3762. Vcb,
  3763. TargetCluster,
  3764. &TempByteCount,
  3765. TRUE,
  3766. &TargetMcb );
  3767. DiskSpaceAllocated = TRUE;
  3768. //
  3769. // If we didn't get EXACTLY what we wanted, return immediately.
  3770. //
  3771. if ((FsRtlNumberOfRunsInLargeMcb( &TargetMcb ) != 1) ||
  3772. !FatGetNextMcbEntry( Vcb, &TargetMcb, 0, &TempVbo, &TempLbo, &TempByteCount ) ||
  3773. (FatGetIndexFromLbo( Vcb, TempLbo) != TargetCluster ) ||
  3774. (TempByteCount != BytesToReallocate)) {
  3775. //
  3776. // It would be nice if we could be more specific, but such is life.
  3777. //
  3778. try_return( Status = STATUS_INVALID_PARAMETER );
  3779. }
  3780. #if DBG
  3781. //
  3782. // We are going to attempt a move, note it.
  3783. //
  3784. if (FatMoveFileDebug) {
  3785. DbgPrint("%lx: Vcn 0x%lx, Lcn 0x%lx, Count 0x%lx.\n",
  3786. PsGetCurrentThread(),
  3787. FileOffset >> ClusterShift,
  3788. TargetCluster,
  3789. BytesToReallocate >> ClusterShift );
  3790. }
  3791. #endif
  3792. //
  3793. // Now attempt to commit the new allocation to disk. If this
  3794. // raises, the allocation will be deallocated.
  3795. //
  3796. FatFlushFatEntries( IrpContext,
  3797. Vcb,
  3798. TargetCluster,
  3799. BytesToReallocate >> ClusterShift );
  3800. //
  3801. // If we are going to write, we have to lock the pages down BEFORE
  3802. // closing off the paging I/O path to avoid a deadlock from
  3803. // colided page faults.
  3804. //
  3805. if (BytesToWrite) {
  3806. //
  3807. // Ensure the shared cache map is set up.
  3808. //
  3809. if (FileObject->PrivateCacheMap == NULL ) {
  3810. CcInitializeCacheMap( FileObject,
  3811. (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize,
  3812. TRUE,
  3813. &FatData.CacheManagerCallbacks,
  3814. FcbOrDcb );
  3815. CacheMapInitialized = TRUE;
  3816. }
  3817. //
  3818. // Map the next range of the file.
  3819. //
  3820. CcMapData( FileObject, &LargeFileOffset, BytesToWrite, TRUE, &Bcb, &Buffer );
  3821. //
  3822. // Now attempt to allocate an Mdl to describe the mapped data.
  3823. //
  3824. Mdl = IoAllocateMdl( Buffer, (ULONG)BytesToWrite, FALSE, FALSE, NULL );
  3825. if (Mdl == NULL) {
  3826. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  3827. }
  3828. //
  3829. // Lock the data into memory so that we can safely reallocate the
  3830. // space.
  3831. //
  3832. MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess );
  3833. LockedPages = TRUE;
  3834. }
  3835. //
  3836. // Aqcuire both resources exclusive now, guaranteeing that NOBODY
  3837. // is in either the read or write paths.
  3838. //
  3839. ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
  3840. //
  3841. // This is the first part of some tricky synchronization.
  3842. //
  3843. // Set the Event pointer in the FCB. Any paging I/O will block on
  3844. // this event (if set in FCB) after acquiring the PagingIo resource.
  3845. //
  3846. // This is how I keep ALL I/O out of this path without holding the
  3847. // PagingIo resource exclusive for an extended time.
  3848. //
  3849. FcbOrDcb->MoveFileEvent = &StackEvent;
  3850. EventArmed = TRUE;
  3851. ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
  3852. //
  3853. // Now write out the data, but only if we have to. We don't have
  3854. // to copy any file data if the range being reallocated is wholly
  3855. // beyond valid data length.
  3856. //
  3857. if (BytesToWrite) {
  3858. PIRP IoIrp;
  3859. KEVENT IoEvent;
  3860. IO_STATUS_BLOCK Iosb;
  3861. KeInitializeEvent( &IoEvent, NotificationEvent, FALSE );
  3862. ASSERT( LargeTargetLbo.QuadPart >= Vcb->AllocationSupport.FileAreaLbo);
  3863. IoIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE,
  3864. Vcb->TargetDeviceObject,
  3865. Buffer,
  3866. BytesToWrite,
  3867. &LargeTargetLbo,
  3868. &IoEvent,
  3869. &Iosb );
  3870. if (!IoIrp) {
  3871. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  3872. }
  3873. //
  3874. // Set a flag indicating that we want to write through any
  3875. // cache on the controller. This eliminates the need for
  3876. // an explicit flush-device after the write.
  3877. //
  3878. SetFlag( IoGetNextIrpStackLocation(IoIrp)->Flags, SL_WRITE_THROUGH );
  3879. Status = IoCallDriver( Vcb->TargetDeviceObject, IoIrp );
  3880. if (Status == STATUS_PENDING) {
  3881. (VOID)KeWaitForSingleObject( &IoEvent, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  3882. Status = Iosb.Status;
  3883. }
  3884. if (!NT_SUCCESS(Status)) {
  3885. FatNormalizeAndRaiseStatus( IrpContext, Status );
  3886. }
  3887. //
  3888. // Now we can get rid of this Mdl.
  3889. //
  3890. MmUnlockPages( Mdl );
  3891. LockedPages = FALSE;
  3892. IoFreeMdl( Mdl );
  3893. Mdl = NULL;
  3894. //
  3895. // Now we can safely unpin.
  3896. //
  3897. CcUnpinData( Bcb );
  3898. Bcb = NULL;
  3899. }
  3900. //
  3901. // Now that the file data has been moved successfully, we'll go
  3902. // to fix up the links in the FAT table and perhaps change the
  3903. // entry in the parent directory.
  3904. //
  3905. // First we'll do the second splice and commit it. At that point,
  3906. // while the volume is in an inconsistent state, the file is
  3907. // still OK.
  3908. //
  3909. FatSetFatEntry( IrpContext,
  3910. Vcb,
  3911. SecondSpliceSourceCluster,
  3912. (FAT_ENTRY)SecondSpliceTargetCluster );
  3913. FatFlushFatEntries( IrpContext, Vcb, SecondSpliceSourceCluster, 1 );
  3914. //
  3915. // Now do the first splice OR update the dirent in the parent
  3916. // and flush the respective object. After this flush the file
  3917. // now points to the new allocation.
  3918. //
  3919. if (FirstSpliceSourceCluster == 0) {
  3920. ASSERT( NodeType(FcbOrDcb) == FAT_NTC_FCB );
  3921. //
  3922. // We are moving the first cluster of the file, so we need
  3923. // to update our parent directory.
  3924. //
  3925. FatGetDirentFromFcbOrDcb( IrpContext, FcbOrDcb, &Dirent, &DirentBcb );
  3926. Dirent->FirstClusterOfFile = (USHORT)FirstSpliceTargetCluster;
  3927. if (FatIsFat32(Vcb)) {
  3928. Dirent->FirstClusterOfFileHi =
  3929. (USHORT)(FirstSpliceTargetCluster >> 16);
  3930. }
  3931. FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
  3932. FatUnpinBcb( IrpContext, DirentBcb );
  3933. DirentBcb = NULL;
  3934. FatFlushDirentForFile( IrpContext, FcbOrDcb );
  3935. FcbOrDcb->FirstClusterOfFile = FirstSpliceTargetCluster;
  3936. } else {
  3937. FatSetFatEntry( IrpContext,
  3938. Vcb,
  3939. FirstSpliceSourceCluster,
  3940. (FAT_ENTRY)FirstSpliceTargetCluster );
  3941. FatFlushFatEntries( IrpContext, Vcb, FirstSpliceSourceCluster, 1 );
  3942. }
  3943. //
  3944. // This was successfully committed. We no longer want to free
  3945. // this allocation on error.
  3946. //
  3947. DiskSpaceAllocated = FALSE;
  3948. //
  3949. // Now we just have to free the orphaned space. We don't have
  3950. // to commit this right now as the integrity of the file doesn't
  3951. // depend on it.
  3952. //
  3953. FatDeallocateDiskSpace( IrpContext, Vcb, &SourceMcb );
  3954. FatUnpinRepinnedBcbs( IrpContext );
  3955. Status = FatHijackIrpAndFlushDevice( IrpContext,
  3956. Irp,
  3957. Vcb->TargetDeviceObject );
  3958. if (!NT_SUCCESS(Status)) {
  3959. FatNormalizeAndRaiseStatus( IrpContext, Status );
  3960. }
  3961. //
  3962. // Finally we must replace the old MCB extent information with
  3963. // the new. If this fails from pool allocation, we fix it in
  3964. // the finally clause by resetting the file's Mcb.
  3965. //
  3966. FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb,
  3967. FileOffset,
  3968. BytesToReallocate );
  3969. FatAddMcbEntry( Vcb, &FcbOrDcb->Mcb,
  3970. FileOffset,
  3971. TargetLbo,
  3972. BytesToReallocate );
  3973. //
  3974. // Now this is the second part of the tricky synchronization.
  3975. //
  3976. // We drop the paging I/O here and signal the notification
  3977. // event which allows all waiters (present or future) to proceed.
  3978. // Then we block again on the PagingIo exclusive. When
  3979. // we have it, we again know that there can be nobody in the
  3980. // read/write path and thus nobody touching the event, so we
  3981. // NULL the pointer to it and then drop the PagingIo resource.
  3982. //
  3983. // This combined with our synchronization before the write above
  3984. // guarantees that while we were moving the allocation, there
  3985. // was no other I/O to this file and because we do not hold
  3986. // the paging resource across a flush, we are not exposed to
  3987. // a deadlock.
  3988. //
  3989. KeSetEvent( &StackEvent, 0, FALSE );
  3990. ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
  3991. FcbOrDcb->MoveFileEvent = NULL;
  3992. EventArmed = FALSE;
  3993. ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
  3994. //
  3995. // Release the resources and let anyone else access the file before
  3996. // looping back.
  3997. //
  3998. FatReleaseFcb( IrpContext, FcbOrDcb );
  3999. FcbAcquired = FALSE;
  4000. //
  4001. // Advance the state variables.
  4002. //
  4003. TargetCluster += BytesToReallocate >> ClusterShift;
  4004. FileOffset += BytesToReallocate;
  4005. TargetLbo += BytesToReallocate;
  4006. ByteCount -= BytesToReallocate;
  4007. LargeFileOffset.LowPart += BytesToReallocate;
  4008. LargeTargetLbo.QuadPart += BytesToReallocate;
  4009. //
  4010. // Clear the two Mcbs
  4011. //
  4012. FatRemoveMcbEntry( Vcb, &SourceMcb, 0, 0xFFFFFFFF );
  4013. FatRemoveMcbEntry( Vcb, &TargetMcb, 0, 0xFFFFFFFF );
  4014. //
  4015. // Make the event blockable again.
  4016. //
  4017. KeClearEvent( &StackEvent );
  4018. }
  4019. Status = STATUS_SUCCESS;
  4020. try_exit: NOTHING;
  4021. } finally {
  4022. DebugUnwind( FatMoveFile );
  4023. LocalAbnormalTermination |= AbnormalTermination();
  4024. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD );
  4025. //
  4026. // Cleanup the Mdl, Bcb, and cache map as appropriate.
  4027. //
  4028. if (Mdl != NULL) {
  4029. ASSERT(LocalAbnormalTermination);
  4030. if (LockedPages) {
  4031. MmUnlockPages( Mdl );
  4032. }
  4033. IoFreeMdl( Mdl );
  4034. }
  4035. if (Bcb != NULL) {
  4036. ASSERT(LocalAbnormalTermination);
  4037. CcUnpinData( Bcb );
  4038. }
  4039. if (CacheMapInitialized) {
  4040. CcUninitializeCacheMap( FileObject, NULL, NULL );
  4041. }
  4042. //
  4043. // Use a nested try-finally for cleanup if our unpinrepinned
  4044. // encounters write-through errors. This may even be a re-raise.
  4045. //
  4046. try {
  4047. //
  4048. // If we have some new allocation hanging around, remove it. The
  4049. // pages needed to do this are guaranteed to be resident because
  4050. // we have already repinned them.
  4051. //
  4052. if (DiskSpaceAllocated) {
  4053. FatDeallocateDiskSpace( IrpContext, Vcb, &TargetMcb );
  4054. FatUnpinRepinnedBcbs( IrpContext );
  4055. }
  4056. } finally {
  4057. LocalAbnormalTermination |= AbnormalTermination();
  4058. //
  4059. // Check on the directory Bcb
  4060. //
  4061. if (DirentBcb != NULL) {
  4062. FatUnpinBcb( IrpContext, DirentBcb );
  4063. }
  4064. //
  4065. // Uninitialize our MCBs
  4066. //
  4067. if (SourceMcbInitialized) {
  4068. FsRtlUninitializeLargeMcb( &SourceMcb );
  4069. }
  4070. if (TargetMcbInitialized) {
  4071. FsRtlUninitializeLargeMcb( &TargetMcb );
  4072. }
  4073. //
  4074. // If this is an abnormal termination then presumably something
  4075. // bad happened. Set the Allocation size to unknown and clear
  4076. // the Mcb, but only if we still own the Fcb.
  4077. //
  4078. // It is important to make sure we use a 64bit form of -1. This is
  4079. // what will convince the fastIO path that it cannot extend the file
  4080. // in the cache until we have picked up the mapping pairs again.
  4081. //
  4082. // Also, we have to do this while owning PagingIo or we can tear the
  4083. // Mcb down in the midst of the noncached IO path looking up extents
  4084. // (after we drop it and let them all in).
  4085. //
  4086. if (LocalAbnormalTermination && FcbAcquired) {
  4087. FcbOrDcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
  4088. FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
  4089. }
  4090. //
  4091. // If we broke out of the loop with the Event armed, defuse it
  4092. // in the same way we do it after a write.
  4093. //
  4094. if (EventArmed) {
  4095. KeSetEvent( &StackEvent, 0, FALSE );
  4096. ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
  4097. FcbOrDcb->MoveFileEvent = NULL;
  4098. ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
  4099. }
  4100. //
  4101. // Finally release the main file resource.
  4102. //
  4103. if (FcbAcquired) {
  4104. FatReleaseFcb( IrpContext, FcbOrDcb );
  4105. }
  4106. //
  4107. // Now dereference the fileobject. If the user was a wacko they could have
  4108. // tried to nail us by closing the handle right after they threw this move
  4109. // down, so we had to keep the fileobject referenced across the entire
  4110. // operation.
  4111. //
  4112. ObDereferenceObject( FileObject );
  4113. }
  4114. }
  4115. //
  4116. // Complete the irp if we terminated normally.
  4117. //
  4118. FatCompleteRequest( IrpContext, Irp, Status );
  4119. return Status;
  4120. }
  4121. //
  4122. // Local Support Routine
  4123. //
  4124. VOID
  4125. FatComputeMoveFileParameter (
  4126. IN PIRP_CONTEXT IrpContext,
  4127. IN PFCB FcbOrDcb,
  4128. IN ULONG FileOffset,
  4129. IN OUT PULONG ByteCount,
  4130. OUT PULONG BytesToReallocate,
  4131. OUT PULONG BytesToWrite
  4132. )
  4133. /*++
  4134. Routine Description:
  4135. This is a helper routine for FatMoveFile that analyses the range of
  4136. file allocation we are moving and determines the actual amount
  4137. of allocation to be moved and how much needs to be written.
  4138. Arguments:
  4139. FcbOrDcb - Supplies the file and its various sizes.
  4140. FileOffset - Supplies the beginning Vbo of the reallocation zone.
  4141. ByteCount - Supplies the request length to reallocate. This will
  4142. be bounded by allocation size on return.
  4143. BytesToReallocate - Receives ByteCount bounded by the file allocation size
  4144. and a 0x40000 boundry.
  4145. BytesToWrite - Receives BytesToReallocate bounded by ValidDataLength.
  4146. Return Value:
  4147. VOID
  4148. --*/
  4149. {
  4150. ULONG ClusterSize;
  4151. ULONG AllocationSize;
  4152. ULONG ValidDataLength;
  4153. ULONG ClusterAlignedVDL;
  4154. //
  4155. // If we haven't yet set the correct AllocationSize, do so.
  4156. //
  4157. if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  4158. FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
  4159. //
  4160. // If this is a non-root directory, we have a bit more to
  4161. // do since it has not gone through FatOpenDirectoryFile().
  4162. //
  4163. if (NodeType(FcbOrDcb) == FAT_NTC_DCB ||
  4164. (NodeType(FcbOrDcb) == FAT_NTC_ROOT_DCB && FatIsFat32(FcbOrDcb->Vcb))) {
  4165. FcbOrDcb->Header.FileSize.LowPart =
  4166. FcbOrDcb->Header.AllocationSize.LowPart;
  4167. }
  4168. }
  4169. //
  4170. // Get the number of bytes left to write and ensure that it does
  4171. // not extend beyond allocation size. We return here if FileOffset
  4172. // is beyond AllocationSize which can happn on a truncation.
  4173. //
  4174. AllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
  4175. ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
  4176. if (FileOffset + *ByteCount > AllocationSize) {
  4177. if (FileOffset >= AllocationSize) {
  4178. *ByteCount = 0;
  4179. *BytesToReallocate = 0;
  4180. *BytesToWrite = 0;
  4181. return;
  4182. }
  4183. *ByteCount = AllocationSize - FileOffset;
  4184. }
  4185. //
  4186. // If there is more than our max, then reduce the byte count for this
  4187. // pass to our maximum. We must also align the file offset to a 0x40000
  4188. // byte boundary.
  4189. //
  4190. if ((FileOffset & 0x3ffff) + *ByteCount > 0x40000) {
  4191. *BytesToReallocate = 0x40000 - (FileOffset & 0x3ffff);
  4192. } else {
  4193. *BytesToReallocate = *ByteCount;
  4194. }
  4195. //
  4196. // We may be able to skip some (or all) of the write
  4197. // if allocation size is significantly greater than valid data length.
  4198. //
  4199. ClusterSize = 1 << FcbOrDcb->Vcb->AllocationSupport.LogOfBytesPerCluster;
  4200. ClusterAlignedVDL = (ValidDataLength + (ClusterSize - 1)) & ~(ClusterSize - 1);
  4201. if ((NodeType(FcbOrDcb) == FAT_NTC_FCB) &&
  4202. (FileOffset + *BytesToReallocate > ClusterAlignedVDL)) {
  4203. if (FileOffset > ClusterAlignedVDL) {
  4204. *BytesToWrite = 0;
  4205. } else {
  4206. *BytesToWrite = ClusterAlignedVDL - FileOffset;
  4207. }
  4208. } else {
  4209. *BytesToWrite = *BytesToReallocate;
  4210. }
  4211. }
  4212. //
  4213. // Local Support Routine
  4214. //
  4215. VOID
  4216. FatComputeMoveFileSplicePoints (
  4217. IN PIRP_CONTEXT IrpContext,
  4218. IN PFCB FcbOrDcb,
  4219. IN ULONG FileOffset,
  4220. IN ULONG TargetCluster,
  4221. IN ULONG BytesToReallocate,
  4222. OUT PULONG FirstSpliceSourceCluster,
  4223. OUT PULONG FirstSpliceTargetCluster,
  4224. OUT PULONG SecondSpliceSourceCluster,
  4225. OUT PULONG SecondSpliceTargetCluster,
  4226. IN OUT PLARGE_MCB SourceMcb
  4227. )
  4228. /*++
  4229. Routine Description:
  4230. This is a helper routine for FatMoveFile that analyzes the range of
  4231. file allocation we are moving and generates the splice points in the
  4232. FAT table.
  4233. Arguments:
  4234. FcbOrDcb - Supplies the file and thus Mcb.
  4235. FileOffset - Supplies the beginning Vbo of the reallocation zone.
  4236. TargetCluster - Supplies the beginning cluster of the reallocation target.
  4237. BytesToReallocate - Suppies the length of the reallocation zone.
  4238. FirstSpliceSourceCluster - Receives the last cluster in previous allocation
  4239. or zero if we are reallocating from VBO 0.
  4240. FirstSpliceTargetCluster - Receives the target cluster (i.e. new allocation)
  4241. SecondSpliceSourceCluster - Receives the final target cluster.
  4242. SecondSpliceTargetCluster - Receives the first cluster of the remaining
  4243. source allocation or FAT_CLUSTER_LAST if the reallocation zone
  4244. extends to the end of the file.
  4245. SourceMcb - This supplies an MCB that will be filled in with run
  4246. information describing the file allocation being replaced. The Mcb
  4247. must be initialized by the caller.
  4248. Return Value:
  4249. VOID
  4250. --*/
  4251. {
  4252. VBO SourceVbo;
  4253. LBO SourceLbo;
  4254. ULONG SourceIndex;
  4255. ULONG SourceBytesInRun;
  4256. ULONG SourceBytesRemaining;
  4257. ULONG SourceMcbVbo;
  4258. ULONG SourceMcbBytesInRun;
  4259. PVCB Vcb;
  4260. Vcb = FcbOrDcb->Vcb;
  4261. //
  4262. // Get information on the final cluster in the previous allocation and
  4263. // prepare to enumerate it in the follow loop.
  4264. //
  4265. if (FileOffset == 0) {
  4266. SourceIndex = 0;
  4267. *FirstSpliceSourceCluster = 0;
  4268. FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
  4269. 0,
  4270. &SourceVbo,
  4271. &SourceLbo,
  4272. &SourceBytesInRun );
  4273. } else {
  4274. FatLookupMcbEntry( Vcb, &FcbOrDcb->Mcb,
  4275. FileOffset-1,
  4276. &SourceLbo,
  4277. &SourceBytesInRun,
  4278. &SourceIndex);
  4279. *FirstSpliceSourceCluster = FatGetIndexFromLbo( Vcb, SourceLbo );
  4280. if (SourceBytesInRun == 1) {
  4281. SourceIndex += 1;
  4282. FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
  4283. SourceIndex,
  4284. &SourceVbo,
  4285. &SourceLbo,
  4286. &SourceBytesInRun);
  4287. } else {
  4288. SourceVbo = FileOffset;
  4289. SourceLbo += 1;
  4290. SourceBytesInRun -= 1;
  4291. }
  4292. }
  4293. //
  4294. // At this point the variables:
  4295. //
  4296. // - SourceIndex - SourceLbo - SourceBytesInRun -
  4297. //
  4298. // all correctly decribe the allocation to be removed. In the loop
  4299. // below we will start here and continue enumerating the Mcb runs
  4300. // until we are finished with the allocation to be relocated.
  4301. //
  4302. *FirstSpliceTargetCluster = TargetCluster;
  4303. *SecondSpliceSourceCluster =
  4304. *FirstSpliceTargetCluster +
  4305. (BytesToReallocate >> Vcb->AllocationSupport.LogOfBytesPerCluster) - 1;
  4306. for (SourceBytesRemaining = BytesToReallocate, SourceMcbVbo = 0;
  4307. SourceBytesRemaining > 0;
  4308. SourceIndex += 1,
  4309. SourceBytesRemaining -= SourceMcbBytesInRun,
  4310. SourceMcbVbo += SourceMcbBytesInRun) {
  4311. if (SourceMcbVbo != 0) {
  4312. FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
  4313. SourceIndex,
  4314. &SourceVbo,
  4315. &SourceLbo,
  4316. &SourceBytesInRun );
  4317. }
  4318. ASSERT( SourceVbo == SourceMcbVbo + FileOffset );
  4319. SourceMcbBytesInRun =
  4320. SourceBytesInRun < SourceBytesRemaining ?
  4321. SourceBytesInRun : SourceBytesRemaining;
  4322. FatAddMcbEntry( Vcb, SourceMcb,
  4323. SourceMcbVbo,
  4324. SourceLbo,
  4325. SourceMcbBytesInRun );
  4326. }
  4327. //
  4328. // Now compute the cluster of the target of the second
  4329. // splice. If the final run in the above loop was
  4330. // more than we needed, then we can just do arithmetic,
  4331. // otherwise we have to look up the next run.
  4332. //
  4333. if (SourceMcbBytesInRun < SourceBytesInRun) {
  4334. *SecondSpliceTargetCluster =
  4335. FatGetIndexFromLbo( Vcb, SourceLbo + SourceMcbBytesInRun );
  4336. } else {
  4337. if (FatGetNextMcbEntry( Vcb, &FcbOrDcb->Mcb,
  4338. SourceIndex,
  4339. &SourceVbo,
  4340. &SourceLbo,
  4341. &SourceBytesInRun )) {
  4342. *SecondSpliceTargetCluster = FatGetIndexFromLbo( Vcb, SourceLbo );
  4343. } else {
  4344. *SecondSpliceTargetCluster = FAT_CLUSTER_LAST;
  4345. }
  4346. }
  4347. }
  4348. NTSTATUS
  4349. FatAllowExtendedDasdIo(
  4350. IN PIRP_CONTEXT IrpContext,
  4351. IN PIRP Irp
  4352. )
  4353. /*++
  4354. Routine Description:
  4355. This routine marks the CCB to indicate that the handle
  4356. may be used to read past the end of the volume file. The
  4357. handle must be a dasd handle.
  4358. Arguments:
  4359. Irp - Supplies the Irp being processed.
  4360. Return Value:
  4361. NTSTATUS - The return status for the operation.
  4362. --*/
  4363. {
  4364. PIO_STACK_LOCATION IrpSp;
  4365. PVCB Vcb;
  4366. PFCB Fcb;
  4367. PCCB Ccb;
  4368. //
  4369. // Get the current Irp stack location and save some references.
  4370. //
  4371. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  4372. //
  4373. // Extract and decode the file object and check for type of open.
  4374. //
  4375. if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
  4376. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  4377. return STATUS_INVALID_PARAMETER;
  4378. }
  4379. if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
  4380. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  4381. DebugTrace(-1, Dbg, "FatAllowExtendedDasdIo -> %08lx\n", STATUS_INVALID_PARAMETER);
  4382. return STATUS_INVALID_PARAMETER;
  4383. }
  4384. SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO );
  4385. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  4386. return STATUS_SUCCESS;
  4387. }
  4388. VOID
  4389. FatFlushAndCleanVolume(
  4390. IN PIRP_CONTEXT IrpContext,
  4391. IN PIRP Irp,
  4392. IN PVCB Vcb,
  4393. IN FAT_FLUSH_TYPE FlushType
  4394. )
  4395. /*++
  4396. Routine Description:
  4397. This routine flushes and otherwise preparse a volume to be eligible
  4398. for deletion. The dismount and PNP paths share the need for this
  4399. common work.
  4400. The Vcb will always be valid on return from this function. It is the
  4401. caller's responsibility to attempt the dismount/deletion, and to setup
  4402. allocation support again if the volume will be brought back from the
  4403. brink.
  4404. Arguments:
  4405. Irp - Irp for the overlying request
  4406. Vcb - the volume being operated on
  4407. FlushType - specifies the kind of flushing desired
  4408. Return Value:
  4409. NTSTATUS - The return status for the operation.
  4410. --*/
  4411. {
  4412. //
  4413. // The volume must be held exclusive.
  4414. //
  4415. ASSERT( FatVcbAcquiredExclusive( IrpContext, Vcb ));
  4416. //
  4417. // There is no fail, flush everything. If invalidating, it is important
  4418. // that we invalidate as we flush (eventually, w/ paging io held) so that we
  4419. // error out the maximum number of late writes.
  4420. //
  4421. if (FlushType != NoFlush) {
  4422. (VOID) FatFlushVolume( IrpContext, Vcb, FlushType );
  4423. }
  4424. FatCloseEaFile( IrpContext, Vcb, FALSE );
  4425. //
  4426. // Now, tell the device to flush its buffers.
  4427. //
  4428. if (FlushType != NoFlush) {
  4429. (VOID)FatHijackIrpAndFlushDevice( IrpContext, Irp, Vcb->TargetDeviceObject );
  4430. }
  4431. //
  4432. // Now purge everything in sight. We're trying to provoke as many closes as
  4433. // soon as possible, this volume may be on its way out.
  4434. //
  4435. if (FlushType != FlushWithoutPurge) {
  4436. (VOID) FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, NoFlush );
  4437. }
  4438. //
  4439. // If the volume was dirty and we were allowed to flush, do the processing that
  4440. // the delayed callback would have done.
  4441. //
  4442. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
  4443. //
  4444. // Cancel any pending clean volumes.
  4445. //
  4446. (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
  4447. (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
  4448. if (FlushType != NoFlush) {
  4449. //
  4450. // The volume is now clean, note it.
  4451. //
  4452. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  4453. FatMarkVolume( IrpContext, Vcb, VolumeClean );
  4454. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  4455. }
  4456. //
  4457. // Unlock the volume if it is removable.
  4458. //
  4459. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  4460. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
  4461. FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
  4462. }
  4463. }
  4464. }
  4465. //
  4466. // Uninitialize the volume file cache map. Note that we cannot
  4467. // do a "FatSyncUninit" because of deadlock problems. However,
  4468. // since this FileObject is referenced by us, and thus included
  4469. // in the Vpb residual count, it is OK to do a normal CcUninit.
  4470. //
  4471. if (FlushType != FlushWithoutPurge) {
  4472. CcUninitializeCacheMap( Vcb->VirtualVolumeFile,
  4473. &FatLargeZero,
  4474. NULL );
  4475. FatTearDownAllocationSupport( IrpContext, Vcb );
  4476. }
  4477. }
  4478. NTSTATUS
  4479. FatSearchBufferForLabel(
  4480. IN PIRP_CONTEXT IrpContext,
  4481. IN PVPB Vpb,
  4482. IN PVOID Buffer,
  4483. IN ULONG Size,
  4484. OUT PBOOLEAN LabelFound
  4485. )
  4486. /*++
  4487. Routine Description:
  4488. Search a buffer (taken from the root directory) for a volume label
  4489. matching the label in the
  4490. Arguments:
  4491. IrpContext - Supplies our irp context
  4492. Vpb - Vpb supplying the volume label
  4493. Buffer - Supplies the buffer we'll search
  4494. Size - The size of the buffer in bytes.
  4495. LabelFound - Returns whether a label was found.
  4496. Return Value:
  4497. There are four interesting cases:
  4498. 1) Some random error occurred - that error returned as status, LabelFound
  4499. is indeterminate.
  4500. 2) No label was found - STATUS_SUCCESS returned, LabelFound is FALSE.
  4501. 3) A matching label was found - STATUS_SUCCESS returned, LabelFound is TRUE.
  4502. 4) A non-matching label found - STATUS_WRONG_VOLUME returned, LabelFound
  4503. is indeterminate.
  4504. --*/
  4505. {
  4506. NTSTATUS Status;
  4507. WCHAR UnicodeBuffer[11];
  4508. PDIRENT Dirent;
  4509. PDIRENT TerminationDirent;
  4510. ULONG VolumeLabelLength;
  4511. OEM_STRING OemString;
  4512. UNICODE_STRING UnicodeString;
  4513. Dirent = Buffer;
  4514. TerminationDirent = Dirent + Size / sizeof(DIRENT);
  4515. while ( Dirent < TerminationDirent ) {
  4516. if ( Dirent->FileName[0] == FAT_DIRENT_NEVER_USED ) {
  4517. Dirent = TerminationDirent;
  4518. break;
  4519. }
  4520. //
  4521. // If the entry is the non-deleted volume label break from the loop.
  4522. //
  4523. // Note that all out parameters are already correctly set.
  4524. //
  4525. if (((Dirent->Attributes & ~FAT_DIRENT_ATTR_ARCHIVE) ==
  4526. FAT_DIRENT_ATTR_VOLUME_ID) &&
  4527. (Dirent->FileName[0] != FAT_DIRENT_DELETED)) {
  4528. break;
  4529. }
  4530. Dirent += 1;
  4531. }
  4532. if (Dirent >= TerminationDirent) {
  4533. //
  4534. // We've run out of buffer.
  4535. //
  4536. *LabelFound = FALSE;
  4537. return STATUS_SUCCESS;
  4538. }
  4539. //
  4540. // Compute the length of the volume name
  4541. //
  4542. OemString.Buffer = &Dirent->FileName[0];
  4543. OemString.MaximumLength = 11;
  4544. for ( OemString.Length = 11;
  4545. OemString.Length > 0;
  4546. OemString.Length -= 1) {
  4547. if ( (Dirent->FileName[OemString.Length-1] != 0x00) &&
  4548. (Dirent->FileName[OemString.Length-1] != 0x20) ) { break; }
  4549. }
  4550. UnicodeString.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  4551. UnicodeString.Buffer = &UnicodeBuffer[0];
  4552. Status = RtlOemStringToCountedUnicodeString( &UnicodeString,
  4553. &OemString,
  4554. FALSE );
  4555. if ( !NT_SUCCESS( Status ) ) {
  4556. return Status;
  4557. }
  4558. VolumeLabelLength = UnicodeString.Length;
  4559. if ( (VolumeLabelLength != (ULONG)Vpb->VolumeLabelLength) ||
  4560. (!RtlEqualMemory(&UnicodeBuffer[0],
  4561. &Vpb->VolumeLabel[0],
  4562. VolumeLabelLength)) ) {
  4563. return STATUS_WRONG_VOLUME;
  4564. }
  4565. //
  4566. // We found a matching label.
  4567. //
  4568. *LabelFound = TRUE;
  4569. return STATUS_SUCCESS;
  4570. }
  4571. VOID
  4572. FatVerifyLookupFatEntry (
  4573. IN PIRP_CONTEXT IrpContext,
  4574. IN PVCB Vcb,
  4575. IN ULONG FatIndex,
  4576. IN OUT PULONG FatEntry
  4577. )
  4578. {
  4579. ULONG PageEntryOffset;
  4580. ULONG OffsetIntoVolumeFile;
  4581. PVOID Buffer;
  4582. ASSERT(Vcb->AllocationSupport.FatIndexBitSize == 32);
  4583. FatVerifyIndexIsValid( IrpContext, Vcb, FatIndex);
  4584. Buffer = FsRtlAllocatePoolWithTag( NonPagedPoolCacheAligned,
  4585. PAGE_SIZE,
  4586. TAG_ENTRY_LOOKUP_BUFFER );
  4587. OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(ULONG);
  4588. PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(ULONG);
  4589. try {
  4590. FatPerformVerifyDiskRead( IrpContext,
  4591. Vcb,
  4592. Buffer,
  4593. OffsetIntoVolumeFile & ~(PAGE_SIZE - 1),
  4594. PAGE_SIZE,
  4595. TRUE );
  4596. *FatEntry = ((PULONG)(Buffer))[PageEntryOffset];
  4597. } finally {
  4598. ExFreePool( Buffer );
  4599. }
  4600. }