Leaked source code of windows server 2003
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.

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