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

19884 lines
580 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for Ntfs called
  7. by the dispatch driver.
  8. Author:
  9. Gary Kimura [GaryKi] 29-Aug-1991
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. #ifdef NTFSDBG
  14. #include "lockorder.h"
  15. #endif
  16. #ifdef NTFS_CHECK_BITMAP
  17. BOOLEAN NtfsCopyBitmap = TRUE;
  18. #endif
  19. #ifdef SYSCACHE_DEBUG
  20. BOOLEAN NtfsDisableSyscacheLogFile = FALSE;
  21. #endif
  22. ULONG SkipNtOfs = FALSE;
  23. BOOLEAN NtfsForceUpgrade = TRUE;
  24. VOID
  25. NtOfsIndexTest (
  26. PIRP_CONTEXT IrpContext,
  27. PFCB TestFcb
  28. );
  29. //
  30. // Temporarily reference our local attribute definitions
  31. //
  32. extern ATTRIBUTE_DEFINITION_COLUMNS NtfsAttributeDefinitions[];
  33. //
  34. //**** The following variable is only for debugging and is used to disable NTFS
  35. //**** from mounting any volumes
  36. //
  37. BOOLEAN NtfsDisable = FALSE;
  38. //
  39. // The following is used to selectively not mount a particular device. Used for testing.
  40. //
  41. PDEVICE_OBJECT NtfsDisableDevice = NULL;
  42. //
  43. // The following is used to determine when to move to compressed files.
  44. //
  45. BOOLEAN NtfsDefragMftEnabled = FALSE;
  46. LARGE_INTEGER NtfsLockDelay = {(ULONG)-10000000, -1}; // 1 second
  47. //
  48. // The Bug check file id for this module
  49. //
  50. #define BugCheckFileId (NTFS_BUG_CHECK_FSCTRL)
  51. //
  52. // The local debug trace level
  53. //
  54. #define Dbg (DEBUG_TRACE_FSCTRL)
  55. #define DbgAcl (DEBUG_TRACE_FSCTRL|DEBUG_TRACE_ACLINDEX)
  56. //
  57. // Define a tag for general pool allocations from this module
  58. //
  59. #undef MODULE_POOL_TAG
  60. #define MODULE_POOL_TAG ('fFtN')
  61. //
  62. // Local procedure prototypes
  63. //
  64. NTSTATUS
  65. NtfsMountVolume (
  66. IN PIRP_CONTEXT IrpContext,
  67. IN PIRP Irp
  68. );
  69. NTSTATUS
  70. NtfsUpdateAttributeTable (
  71. IN PIRP_CONTEXT IrpContext,
  72. IN PVCB Vcb
  73. );
  74. NTSTATUS
  75. NtfsVerifyVolume (
  76. IN PIRP_CONTEXT IrpContext,
  77. IN PIRP Irp
  78. );
  79. NTSTATUS
  80. NtfsUserFsRequest (
  81. IN PIRP_CONTEXT IrpContext,
  82. IN PIRP Irp
  83. );
  84. NTSTATUS
  85. NtfsOplockRequest (
  86. IN PIRP_CONTEXT IrpContext,
  87. IN PIRP Irp
  88. );
  89. NTSTATUS
  90. NtfsLockVolume (
  91. IN PIRP_CONTEXT IrpContext,
  92. IN PIRP Irp
  93. );
  94. NTSTATUS
  95. NtfsUnlockVolume (
  96. IN PIRP_CONTEXT IrpContext,
  97. IN PIRP Irp
  98. );
  99. NTSTATUS
  100. NtfsDismountVolume (
  101. IN PIRP_CONTEXT IrpContext,
  102. IN PIRP Irp
  103. );
  104. NTSTATUS
  105. NtfsIsVolumeMounted (
  106. IN PIRP_CONTEXT IrpContext,
  107. IN PIRP Irp
  108. );
  109. NTSTATUS
  110. NtfsDirtyVolume (
  111. IN PIRP_CONTEXT IrpContext,
  112. IN PIRP Irp
  113. );
  114. BOOLEAN
  115. NtfsGetDiskGeometry (
  116. IN PIRP_CONTEXT IrpContext,
  117. IN PDEVICE_OBJECT DeviceObjectWeTalkTo,
  118. IN PDISK_GEOMETRY DiskGeometry,
  119. IN PLONGLONG PartitionSize
  120. );
  121. VOID
  122. NtfsReadBootSector (
  123. IN PIRP_CONTEXT IrpContext,
  124. IN PVCB Vcb,
  125. OUT PSCB *BootScb,
  126. OUT PBCB *BootBcb,
  127. OUT PVOID *BootSector
  128. );
  129. BOOLEAN
  130. NtfsIsBootSectorNtfs (
  131. IN PPACKED_BOOT_SECTOR BootSector,
  132. IN PVCB Vcb
  133. );
  134. VOID
  135. NtfsGetVolumeInformation (
  136. IN PIRP_CONTEXT IrpContext,
  137. IN PVPB Vpb OPTIONAL,
  138. IN PVCB Vcb,
  139. OUT PUSHORT VolumeFlags
  140. );
  141. VOID
  142. NtfsSetAndGetVolumeTimes (
  143. IN PIRP_CONTEXT IrpContext,
  144. IN PVCB Vcb,
  145. IN BOOLEAN MarkDirty,
  146. IN BOOLEAN UpdateInTransaction
  147. );
  148. VOID
  149. NtfsOpenSystemFile (
  150. IN PIRP_CONTEXT IrpContext,
  151. IN OUT PSCB *Scb,
  152. IN PVCB Vcb,
  153. IN ULONG FileNumber,
  154. IN LONGLONG Size,
  155. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  156. IN BOOLEAN ModifiedNoWrite
  157. );
  158. VOID
  159. NtfsOpenRootDirectory (
  160. IN PIRP_CONTEXT IrpContext,
  161. IN PVCB Vcb
  162. );
  163. NTSTATUS
  164. NtfsQueryRetrievalPointers (
  165. IN PIRP_CONTEXT IrpContext,
  166. IN PIRP Irp
  167. );
  168. NTSTATUS
  169. NtfsGetCompression (
  170. IN PIRP_CONTEXT IrpContext,
  171. IN PIRP Irp
  172. );
  173. VOID
  174. NtfsChangeAttributeCompression (
  175. IN PIRP_CONTEXT IrpContext,
  176. IN PSCB Scb,
  177. IN PVCB Vcb,
  178. IN PCCB Ccb,
  179. IN USHORT CompressionState
  180. );
  181. NTSTATUS
  182. NtfsSetCompression (
  183. IN PIRP_CONTEXT IrpContext,
  184. IN PIRP Irp
  185. );
  186. NTSTATUS
  187. NtfsMarkAsSystemHive (
  188. IN PIRP_CONTEXT IrpContext,
  189. IN PIRP Irp
  190. );
  191. NTSTATUS
  192. NtfsGetStatistics (
  193. IN PIRP_CONTEXT IrpContext,
  194. IN PIRP Irp
  195. );
  196. LONG
  197. NtfsWriteRawExceptionFilter (
  198. IN PIRP_CONTEXT IrpContext,
  199. IN PEXCEPTION_POINTERS ExceptionPointer
  200. );
  201. #define NtfsMapPageInBitmap(A,B,C,D,E,F) NtfsMapOrPinPageInBitmap(A,B,C,D,E,F,FALSE)
  202. #define NtfsPinPageInBitmap(A,B,C,D,E,F) NtfsMapOrPinPageInBitmap(A,B,C,D,E,F,TRUE)
  203. VOID
  204. NtfsMapOrPinPageInBitmap (
  205. IN PIRP_CONTEXT IrpContext,
  206. IN PVCB Vcb,
  207. IN LCN Lcn,
  208. OUT PLCN StartingLcn,
  209. IN OUT PRTL_BITMAP Bitmap,
  210. OUT PBCB *BitmapBcb,
  211. IN BOOLEAN AlsoPinData
  212. );
  213. #define BYTES_PER_PAGE (PAGE_SIZE)
  214. #define BITS_PER_PAGE (BYTES_PER_PAGE * 8)
  215. NTSTATUS
  216. NtfsGetVolumeData (
  217. IN PIRP_CONTEXT IrpContext,
  218. IN PIRP Irp
  219. );
  220. NTSTATUS
  221. NtfsGetVolumeBitmap (
  222. IN PIRP_CONTEXT IrpContext,
  223. IN PIRP Irp
  224. );
  225. NTSTATUS
  226. NtfsGetRetrievalPointers (
  227. IN PIRP_CONTEXT IrpContext,
  228. IN PIRP Irp
  229. );
  230. NTSTATUS
  231. NtfsGetMftRecord (
  232. IN PIRP_CONTEXT IrpContext,
  233. IN PIRP Irp
  234. );
  235. NTSTATUS
  236. NtfsIsVolumeDirty (
  237. IN PIRP_CONTEXT IrpContext,
  238. IN PIRP Irp
  239. );
  240. NTSTATUS
  241. NtfsSetExtendedDasdIo (
  242. IN PIRP_CONTEXT IrpContext,
  243. IN PIRP Irp
  244. );
  245. NTSTATUS
  246. NtfsCreateUsnJournal (
  247. IN PIRP_CONTEXT IrpContext,
  248. IN PIRP Irp
  249. );
  250. NTSTATUS
  251. NtfsReadFileRecordUsnData (
  252. IN PIRP_CONTEXT IrpContext,
  253. IN PIRP Irp
  254. );
  255. NTSTATUS
  256. NtfsReadFileUsnData (
  257. IN PIRP_CONTEXT IrpContext,
  258. IN PIRP Irp
  259. );
  260. NTSTATUS
  261. NtfsWriteUsnCloseRecord (
  262. IN PIRP_CONTEXT IrpContext,
  263. IN PIRP Irp
  264. );
  265. NTSTATUS
  266. NtfsReadUsnWorker (
  267. IN PIRP_CONTEXT IrpContext,
  268. IN PFCB Fcb,
  269. IN PVOID Context
  270. );
  271. NTSTATUS
  272. NtfsBulkSecurityIdCheck (
  273. IN PIRP_CONTEXT IrpContext,
  274. IN PIRP Irp
  275. );
  276. VOID
  277. NtfsInitializeSecurityFile (
  278. IN PIRP_CONTEXT IrpContext,
  279. IN PVCB Vcb
  280. );
  281. VOID
  282. NtfsUpgradeSecurity (
  283. IN PIRP_CONTEXT IrpContext,
  284. IN PVCB Vcb
  285. );
  286. VOID
  287. NtfsInitializeQuotaFile (
  288. IN PIRP_CONTEXT IrpContext,
  289. IN PVCB Vcb
  290. );
  291. VOID
  292. NtfsInitializeObjectIdFile (
  293. IN PIRP_CONTEXT IrpContext,
  294. IN PVCB Vcb
  295. );
  296. VOID
  297. NtfsInitializeReparseFile (
  298. IN PIRP_CONTEXT IrpContext,
  299. IN PVCB Vcb
  300. );
  301. VOID
  302. NtfsInitializeUsnJournal (
  303. IN PIRP_CONTEXT IrpContext,
  304. IN PVCB Vcb,
  305. IN ULONG CreateIfNotExist,
  306. IN ULONG Restamp,
  307. IN PCREATE_USN_JOURNAL_DATA NewJournalData
  308. );
  309. VOID
  310. NtfsInitializeExtendDirectory (
  311. IN PIRP_CONTEXT IrpContext,
  312. IN PVCB Vcb
  313. );
  314. NTSTATUS
  315. NtfsQueryAllocatedRanges (
  316. IN PIRP_CONTEXT IrpContext,
  317. IN PIRP Irp
  318. );
  319. NTSTATUS
  320. NtfsSetSparse (
  321. IN PIRP_CONTEXT IrpContext,
  322. IN PIRP Irp
  323. );
  324. NTSTATUS
  325. NtfsZeroRange (
  326. IN PIRP_CONTEXT IrpContext,
  327. IN PIRP Irp
  328. );
  329. NTSTATUS
  330. NtfsSetReparsePoint (
  331. IN PIRP_CONTEXT IrpContext,
  332. IN PIRP Irp );
  333. NTSTATUS
  334. NtfsGetReparsePoint (
  335. IN PIRP_CONTEXT IrpContext,
  336. IN PIRP Irp );
  337. NTSTATUS
  338. NtfsDeleteReparsePoint (
  339. IN PIRP_CONTEXT IrpContext,
  340. IN PIRP Irp );
  341. NTSTATUS
  342. NtfsEncryptionFsctl (
  343. IN PIRP_CONTEXT IrpContext,
  344. IN PIRP Irp
  345. );
  346. NTSTATUS
  347. NtfsSetEncryption (
  348. IN PIRP_CONTEXT IrpContext,
  349. IN PIRP Irp
  350. );
  351. NTSTATUS
  352. NtfsReadRawEncrypted (
  353. IN PIRP_CONTEXT IrpContext,
  354. IN PIRP Irp
  355. );
  356. NTSTATUS
  357. NtfsWriteRawEncrypted (
  358. IN PIRP_CONTEXT IrpContext,
  359. IN PIRP Irp
  360. );
  361. NTSTATUS
  362. NtfsFindFilesOwnedBySid (
  363. IN PIRP_CONTEXT IrpContext,
  364. IN PIRP Irp
  365. );
  366. NTSTATUS
  367. NtfsFindBySidWorker (
  368. IN PIRP_CONTEXT IrpContext,
  369. IN PFCB Fcb,
  370. IN PVOID Context
  371. );
  372. NTSTATUS
  373. NtfsExtendVolume (
  374. IN PIRP_CONTEXT IrpContext,
  375. IN PIRP Irp
  376. );
  377. NTSTATUS
  378. NtfsMarkHandle (
  379. IN PIRP_CONTEXT IrpContext,
  380. IN PIRP Irp
  381. );
  382. NTSTATUS
  383. NtfsPrefetchFile (
  384. IN PIRP_CONTEXT IrpContext,
  385. IN PIRP Irp
  386. );
  387. LONG
  388. NtfsFsctrlExceptionFilter (
  389. IN PIRP_CONTEXT IrpContext,
  390. IN PEXCEPTION_POINTERS ExceptionPointer,
  391. IN BOOLEAN AccessingUserData,
  392. IN OUT PNTSTATUS Status
  393. );
  394. #ifdef BRIANDBG
  395. LONG
  396. NtfsDismountExceptionFilter (
  397. IN PEXCEPTION_POINTERS ExceptionPointer
  398. );
  399. #endif
  400. #ifdef SYSCACHE_DEBUG
  401. VOID
  402. NtfsInitializeSyscacheLogFile (
  403. IN PIRP_CONTEXT IrpContext,
  404. IN PVCB Vcb
  405. );
  406. #endif
  407. #ifdef ALLOC_PRAGMA
  408. #pragma alloc_text(PAGE, NtfsBulkSecurityIdCheck)
  409. #pragma alloc_text(PAGE, NtfsChangeAttributeCompression)
  410. #pragma alloc_text(PAGE, NtfsCommonFileSystemControl)
  411. #pragma alloc_text(PAGE, NtfsCreateUsnJournal)
  412. #pragma alloc_text(PAGE, NtfsDeleteReparsePoint)
  413. #pragma alloc_text(PAGE, NtfsDirtyVolume)
  414. #pragma alloc_text(PAGE, NtfsDismountVolume)
  415. #pragma alloc_text(PAGE, NtfsEncryptionFsctl)
  416. #pragma alloc_text(PAGE, NtfsExtendVolume)
  417. #pragma alloc_text(PAGE, NtfsFindBySidWorker)
  418. #pragma alloc_text(PAGE, NtfsFindFilesOwnedBySid)
  419. #pragma alloc_text(PAGE, NtfsFsdFileSystemControl)
  420. #pragma alloc_text(PAGE, NtfsGetCompression)
  421. #pragma alloc_text(PAGE, NtfsGetDiskGeometry)
  422. #pragma alloc_text(PAGE, NtfsGetMftRecord)
  423. #pragma alloc_text(PAGE, NtfsGetReparsePoint)
  424. #pragma alloc_text(PAGE, NtfsGetRetrievalPointers)
  425. #pragma alloc_text(PAGE, NtfsGetStatistics)
  426. #pragma alloc_text(PAGE, NtfsGetTunneledData)
  427. #pragma alloc_text(PAGE, NtfsGetVolumeBitmap)
  428. #pragma alloc_text(PAGE, NtfsGetVolumeData)
  429. #pragma alloc_text(PAGE, NtfsGetVolumeInformation)
  430. #pragma alloc_text(PAGE, NtfsInitializeExtendDirectory)
  431. #pragma alloc_text(PAGE, NtfsInitializeObjectIdFile)
  432. #pragma alloc_text(PAGE, NtfsInitializeReparseFile)
  433. #pragma alloc_text(PAGE, NtfsInitializeQuotaFile)
  434. #pragma alloc_text(PAGE, NtfsInitializeSecurityFile)
  435. #pragma alloc_text(PAGE, NtfsInitializeUsnJournal)
  436. #pragma alloc_text(PAGE, NtfsIsBootSectorNtfs)
  437. #pragma alloc_text(PAGE, NtfsIsVolumeDirty)
  438. #pragma alloc_text(PAGE, NtfsIsVolumeMounted)
  439. #pragma alloc_text(PAGE, NtfsLockVolume)
  440. #pragma alloc_text(PAGE, NtfsMarkAsSystemHive)
  441. #pragma alloc_text(PAGE, NtfsMarkHandle)
  442. #pragma alloc_text(PAGE, NtfsMountVolume)
  443. #pragma alloc_text(PAGE, NtfsOpenRootDirectory)
  444. #pragma alloc_text(PAGE, NtfsOpenSystemFile)
  445. #pragma alloc_text(PAGE, NtfsOplockRequest)
  446. #pragma alloc_text(PAGE, NtfsPrefetchFile)
  447. #pragma alloc_text(PAGE, NtfsQueryAllocatedRanges)
  448. #pragma alloc_text(PAGE, NtfsQueryRetrievalPointers)
  449. #pragma alloc_text(PAGE, NtfsReadBootSector)
  450. #pragma alloc_text(PAGE, NtfsReadFileRecordUsnData)
  451. #pragma alloc_text(PAGE, NtfsReadFileUsnData)
  452. #pragma alloc_text(PAGE, NtfsReadRawEncrypted)
  453. #pragma alloc_text(PAGE, NtfsReadUsnWorker)
  454. #pragma alloc_text(PAGE, NtfsSetAndGetVolumeTimes)
  455. #pragma alloc_text(PAGE, NtfsSetCompression)
  456. #pragma alloc_text(PAGE, NtfsSetEncryption)
  457. #pragma alloc_text(PAGE, NtfsSetExtendedDasdIo)
  458. #pragma alloc_text(PAGE, NtfsSetReparsePoint)
  459. #pragma alloc_text(PAGE, NtfsSetSparse)
  460. #pragma alloc_text(PAGE, NtfsSetTunneledData)
  461. #pragma alloc_text(PAGE, NtfsUnlockVolume)
  462. #pragma alloc_text(PAGE, NtfsUpdateAttributeTable)
  463. #pragma alloc_text(PAGE, NtfsUpgradeSecurity)
  464. #pragma alloc_text(PAGE, NtfsUserFsRequest)
  465. #pragma alloc_text(PAGE, NtfsVerifyVolume)
  466. #pragma alloc_text(PAGE, NtfsWriteRawEncrypted)
  467. #pragma alloc_text(PAGE, NtfsWriteUsnCloseRecord)
  468. #pragma alloc_text(PAGE, NtfsZeroRange)
  469. #endif
  470. #ifdef BRIANDBG
  471. LONG
  472. NtfsDismountExceptionFilter (
  473. IN PEXCEPTION_POINTERS ExceptionPointer
  474. )
  475. {
  476. UNREFERENCED_PARAMETER( ExceptionPointer );
  477. ASSERT( ExceptionPointer->ExceptionRecord->ExceptionCode == STATUS_SUCCESS );
  478. return EXCEPTION_CONTINUE_SEARCH;
  479. }
  480. #endif
  481. NTSTATUS
  482. NtfsFsdFileSystemControl (
  483. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  484. IN PIRP Irp
  485. )
  486. /*++
  487. Routine Description:
  488. This routine implements the FSD part of File System Control.
  489. Arguments:
  490. VolumeDeviceObject - Supplies the volume device object where the
  491. file exists
  492. Irp - Supplies the Irp being processed
  493. Return Value:
  494. NTSTATUS - The FSD status for the IRP
  495. --*/
  496. {
  497. TOP_LEVEL_CONTEXT TopLevelContext;
  498. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  499. PIRP_CONTEXT IrpContext = NULL;
  500. PIO_STACK_LOCATION IrpSp;
  501. NTSTATUS Status = STATUS_SUCCESS;
  502. BOOLEAN Wait;
  503. BOOLEAN Retry = FALSE;
  504. ASSERT_IRP( Irp );
  505. PAGED_CODE();
  506. DebugTrace( +1, Dbg, ("NtfsFsdFileSystemControl\n") );
  507. //
  508. // Call the common File System Control routine, with blocking allowed if
  509. // synchronous. This opeation needs to special case the mount
  510. // and verify suboperations because we know they are allowed to block.
  511. // We identify these suboperations by looking at the file object field
  512. // and seeing if its null.
  513. //
  514. if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) {
  515. Wait = TRUE;
  516. } else {
  517. Wait = CanFsdWait( Irp );
  518. }
  519. //
  520. // Make the callback if this is not our filesystem device object (i.e., !mount)
  521. // and thus a regular fsctrl. Mounts are handled later via a seperate callback.
  522. //
  523. if (VolumeDeviceObject->DeviceObject.Size != sizeof(DEVICE_OBJECT) &&
  524. NtfsData.EncryptionCallBackTable.PreFileSystemControl != NULL) {
  525. Status = NtfsData.EncryptionCallBackTable.PreFileSystemControl( (PDEVICE_OBJECT) VolumeDeviceObject,
  526. Irp,
  527. IoGetCurrentIrpStackLocation(Irp)->FileObject );
  528. //
  529. // Raise the status if a failure.
  530. //
  531. if (Status != STATUS_SUCCESS) {
  532. NtfsCompleteRequest( NULL, Irp, Status );
  533. return Status;
  534. }
  535. }
  536. FsRtlEnterFileSystem();
  537. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  538. do {
  539. try {
  540. //
  541. // We are either initiating this request or retrying it.
  542. //
  543. if (IrpContext == NULL) {
  544. //
  545. // Allocate and initialize the Irp.
  546. //
  547. NtfsInitializeIrpContext( Irp, Wait, &IrpContext );
  548. //
  549. // Initialize the thread top level structure, if needed.
  550. //
  551. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  552. } else if (Status == STATUS_LOG_FILE_FULL) {
  553. Retry = TRUE;
  554. NtfsCheckpointForLogFileFull( IrpContext );
  555. }
  556. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  557. if (IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME) {
  558. Status = NtfsPostRequest( IrpContext, Irp );
  559. } else {
  560. //
  561. // The SetCompression control is a long-winded function that has
  562. // to rewrite the entire stream, and has to tolerate log file full
  563. // conditions. If this is the first pass through we initialize some
  564. // fields in the NextIrpSp to allow us to resume the set compression
  565. // operation.
  566. //
  567. // David Goebel 1/3/96: Changed to next stack location so that we
  568. // don't wipe out buffer length values. These Irps are never
  569. // dispatched, so the next stack location will not be disturbed.
  570. //
  571. if ((IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
  572. (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_SET_COMPRESSION)) {
  573. if (!Retry) {
  574. PIO_STACK_LOCATION NextIrpSp;
  575. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  576. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = MAXULONG;
  577. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = MAXULONG;
  578. }
  579. }
  580. Status = NtfsCommonFileSystemControl( IrpContext, Irp );
  581. }
  582. break;
  583. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  584. //
  585. // We had some trouble trying to perform the requested
  586. // operation, so we'll abort the I/O request with
  587. // the error status that we get back from the
  588. // execption code
  589. //
  590. Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
  591. }
  592. } while (Status == STATUS_CANT_WAIT ||
  593. Status == STATUS_LOG_FILE_FULL);
  594. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  595. FsRtlExitFileSystem();
  596. //
  597. // And return to our caller
  598. //
  599. DebugTrace( -1, Dbg, ("NtfsFsdFileSystemControl -> %08lx\n", Status) );
  600. return Status;
  601. }
  602. NTSTATUS
  603. NtfsCommonFileSystemControl (
  604. IN PIRP_CONTEXT IrpContext,
  605. IN PIRP Irp
  606. )
  607. /*++
  608. Routine Description:
  609. This is the common routine for File System Control called by both the
  610. fsd and fsp threads.
  611. Arguments:
  612. Irp - Supplies the Irp to process
  613. Return Value:
  614. NTSTATUS - The return status for the operation
  615. --*/
  616. {
  617. NTSTATUS Status;
  618. PIO_STACK_LOCATION IrpSp;
  619. ASSERT_IRP_CONTEXT( IrpContext );
  620. ASSERT_IRP( Irp );
  621. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  622. PAGED_CODE();
  623. //
  624. // Get the current Irp stack location
  625. //
  626. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  627. DebugTrace( +1, Dbg, ("NtfsCommonFileSystemControl\n") );
  628. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  629. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  630. //
  631. // We know this is a file system control so we'll case on the
  632. // minor function, and call a internal worker routine to complete
  633. // the irp.
  634. //
  635. switch (IrpSp->MinorFunction) {
  636. case IRP_MN_MOUNT_VOLUME:
  637. Status = NtfsMountVolume( IrpContext, Irp );
  638. break;
  639. case IRP_MN_USER_FS_REQUEST:
  640. case IRP_MN_KERNEL_CALL:
  641. Status = NtfsUserFsRequest( IrpContext, Irp );
  642. break;
  643. default:
  644. DebugTrace( -1, Dbg, ("Invalid Minor Function %08lx\n", IrpSp->MinorFunction) );
  645. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST );
  646. break;
  647. }
  648. //
  649. // And return to our caller
  650. //
  651. DebugTrace( -1, Dbg, ("NtfsCommonFileSystemControl -> %08lx\n", Status) );
  652. return Status;
  653. }
  654. //
  655. // Local Support Routine
  656. //
  657. NTSTATUS
  658. NtfsMountVolume (
  659. IN PIRP_CONTEXT IrpContext,
  660. IN PIRP Irp
  661. )
  662. /*++
  663. Routine Description:
  664. This routine performs the mount volume operation. It is responsible for
  665. either completing of enqueuing the input Irp.
  666. Its job is to verify that the volume denoted in the IRP is an NTFS volume,
  667. and create the VCB and root SCB/FCB structures. The algorithm it uses is
  668. essentially as follows:
  669. 1. Create a new Vcb Structure, and initialize it enough to do cached
  670. volume file I/O.
  671. 2. Read the disk and check if it is an NTFS volume.
  672. 3. If it is not an NTFS volume then free the cached volume file, delete
  673. the VCB, and complete the IRP with STATUS_UNRECOGNIZED_VOLUME
  674. 4. Check if the volume was previously mounted and if it was then do a
  675. remount operation. This involves freeing the cached volume file,
  676. delete the VCB, hook in the old VCB, and complete the IRP.
  677. 5. Otherwise create a root SCB, recover the volume, create Fsp threads
  678. as necessary, and complete the IRP.
  679. Arguments:
  680. Irp - Supplies the Irp to process
  681. Return Value:
  682. NTSTATUS - The return status for the operation
  683. --*/
  684. {
  685. NTSTATUS Status;
  686. PIO_STACK_LOCATION IrpSp;
  687. PATTRIBUTE_RECORD_HEADER Attribute;
  688. PDEVICE_OBJECT DeviceObjectWeTalkTo;
  689. PVPB Vpb;
  690. PVOLUME_DEVICE_OBJECT VolDo;
  691. PVCB Vcb;
  692. PFILE_OBJECT RootDirFileObject = NULL;
  693. PBCB BootBcb = NULL;
  694. PPACKED_BOOT_SECTOR BootSector;
  695. PSCB BootScb = NULL;
  696. PSCB QuotaDataScb = NULL;
  697. POBJECT_NAME_INFORMATION DeviceObjectName = NULL;
  698. ULONG DeviceObjectNameLength;
  699. PBCB Bcbs[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  700. PMDL Mdls[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  701. ULONG FirstNonMirroredCluster;
  702. ULONG MirroredMftRange;
  703. PLIST_ENTRY MftLinks;
  704. PSCB AttributeListScb;
  705. ULONG i;
  706. IO_STATUS_BLOCK IoStatus;
  707. BOOLEAN UpdatesApplied;
  708. BOOLEAN VcbAcquired = FALSE;
  709. BOOLEAN MountFailed = TRUE;
  710. BOOLEAN CloseAttributes = FALSE;
  711. BOOLEAN UpgradeVolume = FALSE;
  712. BOOLEAN WriteProtected;
  713. BOOLEAN CurrentVersion = FALSE;
  714. BOOLEAN UnrecognizedRestart;
  715. ULONG RetryRestart;
  716. USHORT VolumeFlags = 0;
  717. LONGLONG LlTemp1;
  718. ASSERT_IRP_CONTEXT( IrpContext );
  719. ASSERT_IRP( Irp );
  720. PAGED_CODE();
  721. //
  722. //**** The following code is only temporary and is used to disable NTFS
  723. //**** from mounting any volumes
  724. //
  725. if (NtfsDisable) {
  726. NtfsCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  727. return STATUS_UNRECOGNIZED_VOLUME;
  728. }
  729. //
  730. // Reject floppies
  731. //
  732. if (FlagOn( IoGetCurrentIrpStackLocation(Irp)->
  733. Parameters.MountVolume.Vpb->
  734. RealDevice->Characteristics, FILE_FLOPPY_DISKETTE ) ) {
  735. Irp->IoStatus.Information = 0;
  736. NtfsCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  737. return STATUS_UNRECOGNIZED_VOLUME;
  738. }
  739. //
  740. // Get the current Irp stack location
  741. //
  742. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  743. DebugTrace( +1, Dbg, ("NtfsMountVolume\n") );
  744. //
  745. // Save some references to make our life a little easier
  746. //
  747. DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
  748. Vpb = IrpSp->Parameters.MountVolume.Vpb;
  749. ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  750. //
  751. // TEMPCODE Perform the following test for chkdsk testing.
  752. //
  753. if (NtfsDisableDevice == IrpSp->Parameters.MountVolume.DeviceObject) {
  754. NtfsCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  755. return STATUS_UNRECOGNIZED_VOLUME;
  756. }
  757. //
  758. // Acquire exclusive global access
  759. //
  760. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  761. //
  762. // Now is a convenient time to look through the queue of Vcb's to see if there
  763. // are any which can be deleted.
  764. //
  765. try {
  766. PLIST_ENTRY Links;
  767. for (Links = NtfsData.VcbQueue.Flink;
  768. Links != &NtfsData.VcbQueue;
  769. Links = Links->Flink) {
  770. Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
  771. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  772. (Vcb->CloseCount == 0) &&
  773. FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT )) {
  774. //
  775. // Now we can check to see if we should perform the teardown
  776. // on this Vcb. The release Vcb routine below can do all of
  777. // the checks correctly. Make this appear to from a close
  778. // call since there is no special biasing for this case.
  779. //
  780. IrpContext->Vcb = Vcb;
  781. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  782. if (!FlagOn( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY )) {
  783. NtfsReleaseGlobal( IrpContext );
  784. NtfsReleaseVcbCheckDelete( IrpContext,
  785. Vcb,
  786. IRP_MJ_CLOSE,
  787. NULL );
  788. //
  789. // Only do one since we have lost our place in the Vcb list.
  790. //
  791. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  792. break;
  793. } else {
  794. NtfsReleaseVcb( IrpContext, Vcb );
  795. }
  796. }
  797. }
  798. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  799. //
  800. // Make sure we own the global resource for mount. We can only raise above
  801. // in the DeleteVcb path when we don't hold the resource.
  802. //
  803. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  804. }
  805. Vcb = NULL;
  806. try {
  807. PFILE_RECORD_SEGMENT_HEADER MftBuffer;
  808. PVOID Mft2Buffer;
  809. LONGLONG MftMirrorOverlap;
  810. //
  811. // Create a new volume device object. This will have the Vcb hanging
  812. // off of its end, and set its alignment requirement from the device
  813. // we talk to.
  814. //
  815. if (!NT_SUCCESS(Status = IoCreateDevice( NtfsData.DriverObject,
  816. sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
  817. NULL,
  818. FILE_DEVICE_DISK_FILE_SYSTEM,
  819. 0,
  820. FALSE,
  821. (PDEVICE_OBJECT *)&VolDo))) {
  822. try_return( Status );
  823. }
  824. //
  825. // Our alignment requirement is the larger of the processor alignment requirement
  826. // already in the volume device object and that in the DeviceObjectWeTalkTo
  827. //
  828. if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
  829. VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement;
  830. }
  831. ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING );
  832. //
  833. // Add one more to the stack size requirements for our device
  834. //
  835. VolDo->DeviceObject.StackSize = DeviceObjectWeTalkTo->StackSize + 1;
  836. //
  837. // Initialize the overflow queue for the volume
  838. //
  839. VolDo->OverflowQueueCount = 0;
  840. InitializeListHead( &VolDo->OverflowQueue );
  841. KeInitializeEvent( &VolDo->OverflowQueueEvent, SynchronizationEvent, FALSE );
  842. //
  843. // Get a reference to the Vcb hanging off the end of the volume device object
  844. // we just created
  845. //
  846. IrpContext->Vcb = Vcb = &VolDo->Vcb;
  847. //
  848. // Set the device object field in the vpb to point to our new volume device
  849. // object
  850. //
  851. Vpb->DeviceObject = (PDEVICE_OBJECT)VolDo;
  852. //
  853. // Initialize the Vcb. Set checkpoint
  854. // in progress (to prevent a real checkpoint from occuring until we
  855. // are done).
  856. //
  857. NtfsInitializeVcb( IrpContext, Vcb, DeviceObjectWeTalkTo, Vpb );
  858. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  859. VcbAcquired= TRUE;
  860. //
  861. // Query the device we talk to for this geometry and setup enough of the
  862. // vcb to read in the boot sectors. This is a temporary setup until
  863. // we've read in the actual boot sector and got the real cluster factor.
  864. //
  865. {
  866. DISK_GEOMETRY DiskGeometry;
  867. LONGLONG Length;
  868. ULONG BytesPerSector;
  869. WriteProtected = NtfsGetDiskGeometry( IrpContext,
  870. DeviceObjectWeTalkTo,
  871. &DiskGeometry,
  872. &Length );
  873. //
  874. // If the sector size is greater than the page size, it is probably
  875. // a bogus return, but we cannot use the device. We also verify that
  876. // the sector size is a power of two.
  877. //
  878. BytesPerSector = DiskGeometry.BytesPerSector;
  879. if ((BytesPerSector > PAGE_SIZE) ||
  880. (BytesPerSector == 0)) {
  881. NtfsRaiseStatus( IrpContext, STATUS_BAD_DEVICE_TYPE, NULL, NULL );
  882. }
  883. while (TRUE) {
  884. if (FlagOn( BytesPerSector, 1 )) {
  885. if (BytesPerSector != 1) {
  886. NtfsRaiseStatus( IrpContext, STATUS_BAD_DEVICE_TYPE, NULL, NULL );
  887. }
  888. break;
  889. }
  890. BytesPerSector >>= 1;
  891. }
  892. Vcb->BytesPerSector = DiskGeometry.BytesPerSector;
  893. Vcb->BytesPerCluster = Vcb->BytesPerSector;
  894. Vcb->NumberSectors = Length / DiskGeometry.BytesPerSector;
  895. //
  896. // Fail the mount if the number of sectors is less than 16. Otherwise our mount logic
  897. // won't work.
  898. //
  899. if (Vcb->NumberSectors <= 0x10) {
  900. try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
  901. }
  902. Vcb->ClusterMask = Vcb->BytesPerCluster - 1;
  903. Vcb->InverseClusterMask = ~Vcb->ClusterMask;
  904. for (Vcb->ClusterShift = 0, i = Vcb->BytesPerCluster; i > 1; i = i / 2) {
  905. Vcb->ClusterShift += 1;
  906. }
  907. Vcb->ClustersPerPage = PAGE_SIZE >> Vcb->ClusterShift;
  908. //
  909. // Set the sector size in our device object.
  910. //
  911. VolDo->DeviceObject.SectorSize = (USHORT) Vcb->BytesPerSector;
  912. }
  913. //
  914. // Read in the Boot sector, or spare boot sector, on exit of this try
  915. // body we will have set bootbcb and bootsector.
  916. //
  917. NtfsReadBootSector( IrpContext, Vcb, &BootScb, &BootBcb, (PVOID *)&BootSector );
  918. //
  919. // Check if this is an NTFS volume
  920. //
  921. if (!NtfsIsBootSectorNtfs( BootSector, Vcb )) {
  922. DebugTrace( 0, Dbg, ("Not an NTFS volume\n") );
  923. try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
  924. }
  925. //
  926. // Media is write protected, so we should try to mount read-only.
  927. //
  928. if (WriteProtected) {
  929. SetFlag( Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY );
  930. }
  931. //
  932. // Now that we have a real boot sector on a real NTFS volume we can
  933. // really set the proper Vcb fields.
  934. //
  935. {
  936. BIOS_PARAMETER_BLOCK Bpb;
  937. NtfsUnpackBios( &Bpb, &BootSector->PackedBpb );
  938. Vcb->BytesPerSector = Bpb.BytesPerSector;
  939. Vcb->BytesPerCluster = Bpb.BytesPerSector * Bpb.SectorsPerCluster;
  940. Vcb->NumberSectors = BootSector->NumberSectors;
  941. Vcb->MftStartLcn = BootSector->MftStartLcn;
  942. Vcb->Mft2StartLcn = BootSector->Mft2StartLcn;
  943. Vcb->ClusterMask = Vcb->BytesPerCluster - 1;
  944. Vcb->InverseClusterMask = ~Vcb->ClusterMask;
  945. for (Vcb->ClusterShift = 0, i = Vcb->BytesPerCluster; i > 1; i = i / 2) {
  946. Vcb->ClusterShift += 1;
  947. }
  948. //
  949. // If the cluster size is greater than the page size then set this value to 1.
  950. //
  951. Vcb->ClustersPerPage = PAGE_SIZE >> Vcb->ClusterShift;
  952. if (Vcb->ClustersPerPage == 0) {
  953. Vcb->ClustersPerPage = 1;
  954. }
  955. //
  956. // File records can be smaller, equal or larger than the cluster size. Initialize
  957. // both ClustersPerFileRecordSegment and FileRecordsPerCluster.
  958. //
  959. // If the value in the boot sector is positive then it signifies the
  960. // clusters/structure. If negative then it signifies the shift value
  961. // to obtain the structure size.
  962. //
  963. if (BootSector->ClustersPerFileRecordSegment < 0) {
  964. Vcb->BytesPerFileRecordSegment = 1 << (-1 * BootSector->ClustersPerFileRecordSegment);
  965. //
  966. // Initialize the other Mft/Cluster relationship numbers in the Vcb
  967. // based on whether the clusters are larger or smaller than file
  968. // records.
  969. //
  970. if (Vcb->BytesPerFileRecordSegment < Vcb->BytesPerCluster) {
  971. Vcb->FileRecordsPerCluster = Vcb->BytesPerCluster / Vcb->BytesPerFileRecordSegment;
  972. } else {
  973. Vcb->ClustersPerFileRecordSegment = Vcb->BytesPerFileRecordSegment / Vcb->BytesPerCluster;
  974. }
  975. } else {
  976. Vcb->BytesPerFileRecordSegment = BytesFromClusters( Vcb, BootSector->ClustersPerFileRecordSegment );
  977. Vcb->ClustersPerFileRecordSegment = BootSector->ClustersPerFileRecordSegment;
  978. }
  979. for (Vcb->MftShift = 0, i = Vcb->BytesPerFileRecordSegment; i > 1; i = i / 2) {
  980. Vcb->MftShift += 1;
  981. }
  982. //
  983. // We want to shift between file records and clusters regardless of which is larger.
  984. // Compute the shift value here. Anyone using this value will have to know which
  985. // way to shift.
  986. //
  987. Vcb->MftToClusterShift = Vcb->MftShift - Vcb->ClusterShift;
  988. if (Vcb->ClustersPerFileRecordSegment == 0) {
  989. Vcb->MftToClusterShift = Vcb->ClusterShift - Vcb->MftShift;
  990. }
  991. //
  992. // Remember the clusters per view section and 4 gig.
  993. //
  994. Vcb->ClustersPer4Gig = (ULONG) LlClustersFromBytesTruncate( Vcb, 0x100000000 );
  995. //
  996. // Compute the default index allocation buffer size.
  997. //
  998. if (BootSector->DefaultClustersPerIndexAllocationBuffer < 0) {
  999. Vcb->DefaultBytesPerIndexAllocationBuffer = 1 << (-1 * BootSector->DefaultClustersPerIndexAllocationBuffer);
  1000. //
  1001. // Determine whether the index allocation buffer is larger/smaller
  1002. // than the cluster size to determine the block size.
  1003. //
  1004. if (Vcb->DefaultBytesPerIndexAllocationBuffer < Vcb->BytesPerCluster) {
  1005. Vcb->DefaultBlocksPerIndexAllocationBuffer = Vcb->DefaultBytesPerIndexAllocationBuffer / DEFAULT_INDEX_BLOCK_SIZE;
  1006. } else {
  1007. Vcb->DefaultBlocksPerIndexAllocationBuffer = Vcb->DefaultBytesPerIndexAllocationBuffer / Vcb->BytesPerCluster;
  1008. }
  1009. } else {
  1010. Vcb->DefaultBlocksPerIndexAllocationBuffer = BootSector->DefaultClustersPerIndexAllocationBuffer;
  1011. Vcb->DefaultBytesPerIndexAllocationBuffer = BytesFromClusters( Vcb, Vcb->DefaultBlocksPerIndexAllocationBuffer );
  1012. }
  1013. //
  1014. // Now compute our volume specific constants that are stored in
  1015. // the Vcb. The total number of clusters is:
  1016. //
  1017. // (NumberSectors * BytesPerSector) / BytesPerCluster
  1018. //
  1019. Vcb->PreviousTotalClusters =
  1020. Vcb->TotalClusters = LlClustersFromBytesTruncate( Vcb,
  1021. Vcb->NumberSectors * Vcb->BytesPerSector );
  1022. //
  1023. // Compute the maximum clusters for a file.
  1024. //
  1025. Vcb->MaxClusterCount = LlClustersFromBytesTruncate( Vcb, MAXFILESIZE );
  1026. //
  1027. // Compute the attribute flags mask for this volume for this volume.
  1028. //
  1029. Vcb->AttributeFlagsMask = 0xffff;
  1030. if (Vcb->BytesPerCluster > 0x1000) {
  1031. ClearFlag( Vcb->AttributeFlagsMask, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  1032. }
  1033. //
  1034. // For now, an attribute is considered "moveable" if it is at
  1035. // least 5/16 of the file record. This constant should only
  1036. // be changed i conjunction with the MAX_MOVEABLE_ATTRIBUTES
  1037. // constant. (The product of the two should be a little less
  1038. // than or equal to 1.)
  1039. //
  1040. Vcb->BigEnoughToMove = Vcb->BytesPerFileRecordSegment * 5 / 16;
  1041. //
  1042. // Set the serial number in the Vcb
  1043. //
  1044. Vcb->VolumeSerialNumber = BootSector->SerialNumber;
  1045. Vpb->SerialNumber = ((ULONG)BootSector->SerialNumber);
  1046. //
  1047. // Compute the sparse file values.
  1048. //
  1049. Vcb->SparseFileUnit = NTFS_SPARSE_FILE_UNIT;
  1050. Vcb->SparseFileClusters = ClustersFromBytes( Vcb, Vcb->SparseFileUnit );
  1051. //
  1052. // If this is the system boot partition, we need to remember to
  1053. // not allow this volume to be dismounted.
  1054. //
  1055. if (FlagOn( Vpb->RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION )) {
  1056. SetFlag( Vcb->VcbState, VCB_STATE_DISALLOW_DISMOUNT );
  1057. }
  1058. //
  1059. // We should never see the BOOT flag in the device we talk to unless it
  1060. // is in the real device.
  1061. //
  1062. ASSERT( !FlagOn( DeviceObjectWeTalkTo->Flags, DO_SYSTEM_BOOT_PARTITION ) ||
  1063. FlagOn( Vpb->RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION ));
  1064. }
  1065. //
  1066. // Initialize recovery state.
  1067. //
  1068. NtfsInitializeRestartTable( sizeof( OPEN_ATTRIBUTE_ENTRY ),
  1069. INITIAL_NUMBER_ATTRIBUTES,
  1070. &Vcb->OpenAttributeTable );
  1071. NtfsUpdateOatVersion( Vcb, NtfsDefaultRestartVersion );
  1072. NtfsInitializeRestartTable( sizeof( TRANSACTION_ENTRY ),
  1073. INITIAL_NUMBER_TRANSACTIONS,
  1074. &Vcb->TransactionTable );
  1075. //
  1076. // Now start preparing to restart the volume.
  1077. //
  1078. //
  1079. // Create the Mft and Log File Scbs and prepare to read them.
  1080. // The Mft and mirror length will be the first 4 file records or
  1081. // the first cluster.
  1082. //
  1083. FirstNonMirroredCluster = ClustersFromBytes( Vcb, 4 * Vcb->BytesPerFileRecordSegment );
  1084. MirroredMftRange = 4 * Vcb->BytesPerFileRecordSegment;
  1085. if (MirroredMftRange < Vcb->BytesPerCluster) {
  1086. MirroredMftRange = Vcb->BytesPerCluster;
  1087. }
  1088. //
  1089. // Check the case where the boot sector has an invalid value for either the
  1090. // beginning of the Mft or the beginning of the Mft mirror. Specifically
  1091. // check the they don't overlap. Otherwise we can corrupt the valid one
  1092. // as we read and possibly try to correct the invalid one.
  1093. //
  1094. if (Vcb->MftStartLcn > Vcb->Mft2StartLcn) {
  1095. MftMirrorOverlap = Vcb->MftStartLcn - Vcb->Mft2StartLcn;
  1096. } else {
  1097. MftMirrorOverlap = Vcb->Mft2StartLcn - Vcb->MftStartLcn;
  1098. }
  1099. MftMirrorOverlap = LlBytesFromClusters( Vcb, MftMirrorOverlap );
  1100. //
  1101. // Don't raise corrupt since we don't want to attempt to write the
  1102. // disk in this state. Someone who knows how will need to
  1103. // restore the correct boot sector.
  1104. //
  1105. if (MftMirrorOverlap < (LONGLONG) MirroredMftRange) {
  1106. DebugTrace( 0, Dbg, ("Not an NTFS volume\n") );
  1107. try_return( Status = STATUS_UNRECOGNIZED_VOLUME );
  1108. }
  1109. NtfsOpenSystemFile( IrpContext,
  1110. &Vcb->MftScb,
  1111. Vcb,
  1112. MASTER_FILE_TABLE_NUMBER,
  1113. MirroredMftRange,
  1114. $DATA,
  1115. TRUE );
  1116. CcSetAdditionalCacheAttributes( Vcb->MftScb->FileObject, TRUE, TRUE );
  1117. LlTemp1 = FirstNonMirroredCluster;
  1118. (VOID)NtfsAddNtfsMcbEntry( &Vcb->MftScb->Mcb,
  1119. (LONGLONG)0,
  1120. Vcb->MftStartLcn,
  1121. (LONGLONG)FirstNonMirroredCluster,
  1122. FALSE );
  1123. //
  1124. // Now the same for Mft2
  1125. //
  1126. NtfsOpenSystemFile( IrpContext,
  1127. &Vcb->Mft2Scb,
  1128. Vcb,
  1129. MASTER_FILE_TABLE2_NUMBER,
  1130. MirroredMftRange,
  1131. $DATA,
  1132. TRUE );
  1133. CcSetAdditionalCacheAttributes( Vcb->Mft2Scb->FileObject, TRUE, TRUE );
  1134. (VOID)NtfsAddNtfsMcbEntry( &Vcb->Mft2Scb->Mcb,
  1135. (LONGLONG)0,
  1136. Vcb->Mft2StartLcn,
  1137. (LONGLONG)FirstNonMirroredCluster,
  1138. FALSE );
  1139. //
  1140. // Create the dasd system file, we do it here because we need to dummy
  1141. // up the mcb for it, and that way everything else in NTFS won't need
  1142. // to know that it is a special file. We need to do this after
  1143. // cluster allocation initialization because that computes the total
  1144. // clusters on the volume. Also for verification purposes we will
  1145. // set and get the times off of the volume.
  1146. //
  1147. // Open it now before the Log File, because that is the first time
  1148. // anyone may want to mark the volume corrupt.
  1149. //
  1150. NtfsOpenSystemFile( IrpContext,
  1151. &Vcb->VolumeDasdScb,
  1152. Vcb,
  1153. VOLUME_DASD_NUMBER,
  1154. LlBytesFromClusters( Vcb, Vcb->TotalClusters ),
  1155. $DATA,
  1156. FALSE );
  1157. (VOID)NtfsAddNtfsMcbEntry( &Vcb->VolumeDasdScb->Mcb,
  1158. (LONGLONG)0,
  1159. (LONGLONG)0,
  1160. Vcb->TotalClusters,
  1161. FALSE );
  1162. SetFlag( Vcb->VolumeDasdScb->Fcb->FcbState, FCB_STATE_DUP_INITIALIZED );
  1163. Vcb->VolumeDasdScb->Fcb->LinkCount =
  1164. Vcb->VolumeDasdScb->Fcb->TotalLinks = 1;
  1165. //
  1166. // We want to read the first four record segments of each of these
  1167. // files. We do this so that we don't have a cache miss when we
  1168. // look up the real allocation below.
  1169. //
  1170. for (i = 0; i < 4; i++) {
  1171. FILE_REFERENCE FileReference;
  1172. BOOLEAN ValidRecord;
  1173. ULONG CorruptHint;
  1174. NtfsSetSegmentNumber( &FileReference, 0, i );
  1175. if (i > 0) {
  1176. FileReference.SequenceNumber = (USHORT)i;
  1177. } else {
  1178. FileReference.SequenceNumber = 1;
  1179. }
  1180. NtfsReadMftRecord( IrpContext,
  1181. Vcb,
  1182. &FileReference,
  1183. FALSE,
  1184. &Bcbs[i*2],
  1185. &MftBuffer,
  1186. NULL );
  1187. NtfsMapStream( IrpContext,
  1188. Vcb->Mft2Scb,
  1189. (LONGLONG)(i * Vcb->BytesPerFileRecordSegment),
  1190. Vcb->BytesPerFileRecordSegment,
  1191. &Bcbs[i*2 + 1],
  1192. &Mft2Buffer );
  1193. //
  1194. // First validate the record and if its valid and record 0
  1195. // do an extra check for whether its the mft.
  1196. //
  1197. ValidRecord = NtfsCheckFileRecord( Vcb, MftBuffer, &FileReference, &CorruptHint );
  1198. if (ValidRecord && (i == 0)) {
  1199. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  1200. NtfsInitializeAttributeContext( &Context );
  1201. try {
  1202. if (!NtfsLookupAttributeByCode( IrpContext, Vcb->MftScb->Fcb, &Vcb->MftScb->Fcb->FileReference, $ATTRIBUTE_LIST, &Context )) {
  1203. if (NtfsLookupAttributeByCode( IrpContext, Vcb->MftScb->Fcb, &Vcb->MftScb->Fcb->FileReference, $FILE_NAME, &Context )) {
  1204. PFILE_NAME FileName;
  1205. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &Context ) );
  1206. if ((FileName->FileNameLength != wcslen( L"MFT" )) ||
  1207. (!RtlEqualMemory( FileName->FileName, L"$MFT", FileName->FileNameLength * sizeof( WCHAR )))) {
  1208. ValidRecord = FALSE;
  1209. }
  1210. }
  1211. }
  1212. } finally {
  1213. NtfsCleanupAttributeContext( IrpContext, &Context );
  1214. }
  1215. }
  1216. //
  1217. // If any of these file records are bad then try the mirror
  1218. // (unless we are already looking at the mirror). If we
  1219. // can't find a valid record then fail the mount.
  1220. //
  1221. if (!ValidRecord) {
  1222. if ((MftBuffer != Mft2Buffer) &&
  1223. NtfsCheckFileRecord( Vcb, Mft2Buffer, &FileReference, &CorruptHint )) {
  1224. LlTemp1 = MAXLONGLONG;
  1225. //
  1226. // Put a BaadSignature in this file record,
  1227. // mark it dirty and then read it again.
  1228. // The baad signature should force us to bring
  1229. // in the mirror and we can correct the problem.
  1230. //
  1231. NtfsPinMappedData( IrpContext,
  1232. Vcb->MftScb,
  1233. i * Vcb->BytesPerFileRecordSegment,
  1234. Vcb->BytesPerFileRecordSegment,
  1235. &Bcbs[i*2] );
  1236. RtlCopyMemory( MftBuffer, Mft2Buffer, Vcb->BytesPerFileRecordSegment );
  1237. CcSetDirtyPinnedData( Bcbs[i*2], (PLARGE_INTEGER) &LlTemp1 );
  1238. } else {
  1239. NtfsMarkVolumeDirty( IrpContext, Vcb, FALSE );
  1240. try_return( Status = STATUS_DISK_CORRUPT_ERROR );
  1241. }
  1242. }
  1243. }
  1244. //
  1245. // The last file record was the Volume Dasd, so check the version number.
  1246. //
  1247. Attribute = NtfsFirstAttribute(MftBuffer);
  1248. while (TRUE) {
  1249. Attribute = NtfsGetNextRecord(Attribute);
  1250. if (Attribute->TypeCode == $VOLUME_INFORMATION) {
  1251. PVOLUME_INFORMATION VolumeInformation;
  1252. VolumeInformation = (PVOLUME_INFORMATION)NtfsAttributeValue(Attribute);
  1253. VolumeFlags = VolumeInformation->VolumeFlags;
  1254. //
  1255. // Upgrading the disk on NT 5.0 will use version number 3.0. Version
  1256. // number 2.0 was used temporarily when the upgrade was automatic.
  1257. //
  1258. // NOTE - We use the presence of the version number to indicate
  1259. // that the first four file records have been validated. We won't
  1260. // flush the MftMirror if we can't verify these records. Otherwise
  1261. // we might corrupt a valid mirror.
  1262. //
  1263. Vcb->MajorVersion = VolumeInformation->MajorVersion;
  1264. Vcb->MinorVersion = VolumeInformation->MinorVersion;
  1265. if ((Vcb->MajorVersion < 1) || (Vcb->MajorVersion > 3)) {
  1266. NtfsRaiseStatus( IrpContext, STATUS_WRONG_VOLUME, NULL, NULL );
  1267. }
  1268. if (Vcb->MajorVersion > 1) {
  1269. CurrentVersion = TRUE;
  1270. ASSERT( VolumeInformation->MajorVersion != 2 || !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED ) );
  1271. if (NtfsDefragMftEnabled) {
  1272. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_PERMITTED );
  1273. }
  1274. }
  1275. break;
  1276. }
  1277. if (Attribute->TypeCode == $END) {
  1278. NtfsRaiseStatus( IrpContext, STATUS_WRONG_VOLUME, NULL, NULL );
  1279. }
  1280. }
  1281. //
  1282. // Create the log file Scb and really look up its size.
  1283. //
  1284. NtfsOpenSystemFile( IrpContext,
  1285. &Vcb->LogFileScb,
  1286. Vcb,
  1287. LOG_FILE_NUMBER,
  1288. 0,
  1289. $DATA,
  1290. TRUE );
  1291. Vcb->LogFileObject = Vcb->LogFileScb->FileObject;
  1292. CcSetAdditionalCacheAttributes( Vcb->LogFileScb->FileObject, TRUE, TRUE );
  1293. //
  1294. // Lookup the log file mapping now, since we will not go to the
  1295. // disk for allocation information any more once we set restart
  1296. // in progress.
  1297. //
  1298. (VOID)NtfsPreloadAllocation( IrpContext, Vcb->LogFileScb, 0, MAXLONGLONG );
  1299. //
  1300. // Now we have to unpin everything before restart, because it generally
  1301. // has to uninitialize everything.
  1302. //
  1303. NtfsUnpinBcb( IrpContext, &BootBcb );
  1304. for (i = 0; i < 8; i++) {
  1305. NtfsUnpinBcb( IrpContext, &Bcbs[i] );
  1306. }
  1307. NtfsPurgeFileRecordCache( IrpContext );
  1308. //
  1309. // Purge the Mft, since we only read the first four file
  1310. // records, not necessarily an entire page!
  1311. //
  1312. CcPurgeCacheSection( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, FALSE );
  1313. //
  1314. // Now start up the log file and perform Restart. This calls will
  1315. // unpin and remap the Mft Bcb's. The MftBuffer variables above
  1316. // may no longer point to the correct range of bytes. This is OK
  1317. // if they are never referenced.
  1318. //
  1319. // Put a try-except around this to catch any restart failures.
  1320. // This is important in order to allow us to limp along until
  1321. // autochk gets a chance to run.
  1322. //
  1323. // We set restart in progress first, to prevent us from looking up any
  1324. // more run information (now that we know where the log file is!)
  1325. //
  1326. SetFlag(Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS);
  1327. //
  1328. // See if we are in the retry process due to an earlier failure
  1329. // in processing the restart area
  1330. //
  1331. RetryRestart = FlagOn( IrpContext->State, IRP_CONTEXT_STATE_BAD_RESTART );
  1332. if (RetryRestart) {
  1333. //
  1334. // Pass the bad restart info further down the chain
  1335. // and mark the volume dirty.
  1336. // We mark the volume dirty on retry because the
  1337. // dirty bit will not get flush to the disk thru
  1338. // NtfsRaiseStatus. Also LFS calls ExRaiseStatus
  1339. // directly.
  1340. //
  1341. SetFlag( Vcb->VcbState, VCB_STATE_BAD_RESTART );
  1342. NtfsMarkVolumeDirty( IrpContext, Vcb, FALSE );
  1343. }
  1344. try {
  1345. Status = STATUS_SUCCESS;
  1346. UnrecognizedRestart = FALSE;
  1347. NtfsStartLogFile( Vcb->LogFileScb,
  1348. Vcb );
  1349. //
  1350. // We call the cache manager again with the stream files for the Mft and
  1351. // Mft mirror as we didn't have a log handle for the first call.
  1352. //
  1353. CcSetLogHandleForFile( Vcb->MftScb->FileObject,
  1354. Vcb->LogHandle,
  1355. &LfsFlushToLsn );
  1356. CcSetLogHandleForFile( Vcb->Mft2Scb->FileObject,
  1357. Vcb->LogHandle,
  1358. &LfsFlushToLsn );
  1359. CloseAttributes = TRUE;
  1360. if (!NtfsIsVolumeReadOnly( Vcb )) {
  1361. UpdatesApplied = NtfsRestartVolume( IrpContext, Vcb, &UnrecognizedRestart );
  1362. }
  1363. //
  1364. // For right now, we will charge ahead with a dirty volume, no
  1365. // matter what the exception was. Later we will have to be
  1366. // defensive and use a filter.
  1367. //
  1368. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1369. Status = GetExceptionCode();
  1370. if ((Status == STATUS_DISK_CORRUPT_ERROR) ||
  1371. (Status == STATUS_FILE_CORRUPT_ERROR)) {
  1372. //
  1373. // If this is the first time we hit this error during restart,
  1374. // we will remember it in the irp context so that we can retry
  1375. // from the top by raising STATUS_CANT_WAIT.
  1376. //
  1377. if (!RetryRestart) {
  1378. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_BAD_RESTART );
  1379. NtfsFailedLfsRestart += 1;
  1380. }
  1381. }
  1382. //
  1383. // If the error is STATUS_LOG_FILE_FULL then it means that
  1384. // we couldn't complete the restart. Mark the volume dirty in
  1385. // this case. Don't return this error code.
  1386. //
  1387. if (Status == STATUS_LOG_FILE_FULL) {
  1388. Status = STATUS_DISK_CORRUPT_ERROR;
  1389. IrpContext->ExceptionStatus = STATUS_DISK_CORRUPT_ERROR;
  1390. }
  1391. }
  1392. //
  1393. // If we hit a corruption exception while processing the
  1394. // logfile, we need to retry and avoid those errors.
  1395. //
  1396. if (!RetryRestart &&
  1397. FlagOn( IrpContext->State, IRP_CONTEXT_STATE_BAD_RESTART )) {
  1398. IrpContext->ExceptionStatus = STATUS_CANT_WAIT;
  1399. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  1400. }
  1401. //
  1402. // If we hit an error trying to mount this as a readonly volume,
  1403. // fail the mount. We don't want to do any writes.
  1404. //
  1405. if (Status == STATUS_MEDIA_WRITE_PROTECTED) {
  1406. ASSERT(FlagOn( Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY ));
  1407. ClearFlag( Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY );
  1408. try_return( Status );
  1409. }
  1410. //
  1411. // Mark the volume dirty if we hit an error during restart or if we didn't
  1412. // recognize the restart area. In that case also mark the volume dirty but
  1413. // continue to run.
  1414. //
  1415. if (!NT_SUCCESS( Status ) || UnrecognizedRestart) {
  1416. LONGLONG VolumeDasdOffset;
  1417. NtfsSetAndGetVolumeTimes( IrpContext, Vcb, TRUE, FALSE );
  1418. //
  1419. // Now flush it out, so chkdsk can see it with Dasd.
  1420. // Clear the error in the IrpContext so that this
  1421. // flush will succeed. Otherwise CommonWrite will
  1422. // return FILE_LOCK_CONFLICT.
  1423. //
  1424. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  1425. VolumeDasdOffset = VOLUME_DASD_NUMBER << Vcb->MftShift;
  1426. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject,
  1427. (PLARGE_INTEGER)&VolumeDasdOffset,
  1428. Vcb->BytesPerFileRecordSegment,
  1429. NULL );
  1430. if (!NT_SUCCESS( Status )) {
  1431. try_return( Status );
  1432. }
  1433. }
  1434. //
  1435. // Now flush the Mft copies, because we are going to shut the real
  1436. // one down and reopen it for real.
  1437. //
  1438. CcFlushCache( &Vcb->Mft2Scb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1439. if (NT_SUCCESS( IoStatus.Status )) {
  1440. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1441. }
  1442. if (!NT_SUCCESS( IoStatus.Status )) {
  1443. NtfsNormalizeAndRaiseStatus( IrpContext,
  1444. IoStatus.Status,
  1445. STATUS_UNEXPECTED_IO_ERROR );
  1446. }
  1447. //
  1448. // Show that the restart is complete, and it is safe to go to
  1449. // the disk for the Mft allocation.
  1450. //
  1451. ClearFlag( Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS );
  1452. //
  1453. // Set the Mft sizes back down to the part which is guaranteed to
  1454. // be contiguous for now. Important on large page size systems!
  1455. //
  1456. Vcb->MftScb->Header.AllocationSize.QuadPart =
  1457. Vcb->MftScb->Header.FileSize.QuadPart =
  1458. Vcb->MftScb->Header.ValidDataLength.QuadPart = FirstNonMirroredCluster << Vcb->ClusterShift;
  1459. //
  1460. // Pin the first four file records. We need to lock the pages to
  1461. // absolutely guarantee they stay in memory, otherwise we may
  1462. // generate a recursive page fault, forcing MM to block.
  1463. //
  1464. for (i = 0; i < 4; i++) {
  1465. FILE_REFERENCE FileReference;
  1466. ULONG CorruptHint;
  1467. NtfsSetSegmentNumber( &FileReference, 0, i );
  1468. if (i > 0) {
  1469. FileReference.SequenceNumber = (USHORT)i;
  1470. } else {
  1471. FileReference.SequenceNumber = 1;
  1472. }
  1473. NtfsPinStream( IrpContext,
  1474. Vcb->MftScb,
  1475. (LONGLONG)(i << Vcb->MftShift),
  1476. Vcb->BytesPerFileRecordSegment,
  1477. &Bcbs[i*2],
  1478. (PVOID *)&MftBuffer );
  1479. Mdls[i*2] = IoAllocateMdl( MftBuffer,
  1480. Vcb->BytesPerFileRecordSegment,
  1481. FALSE,
  1482. FALSE,
  1483. NULL );
  1484. //
  1485. // Verify that we got an Mdl.
  1486. //
  1487. if (Mdls[i*2] == NULL) {
  1488. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  1489. }
  1490. MmProbeAndLockPages( Mdls[i*2], KernelMode, IoReadAccess );
  1491. NtfsPinStream( IrpContext,
  1492. Vcb->Mft2Scb,
  1493. (LONGLONG)(i << Vcb->MftShift),
  1494. Vcb->BytesPerFileRecordSegment,
  1495. &Bcbs[i*2 + 1],
  1496. &Mft2Buffer );
  1497. Mdls[i*2 + 1] = IoAllocateMdl( Mft2Buffer,
  1498. Vcb->BytesPerFileRecordSegment,
  1499. FALSE,
  1500. FALSE,
  1501. NULL );
  1502. //
  1503. // Verify that we got an Mdl.
  1504. //
  1505. if (Mdls[i*2 + 1] == NULL) {
  1506. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  1507. }
  1508. MmProbeAndLockPages( Mdls[i*2 + 1], KernelMode, IoReadAccess );
  1509. //
  1510. // If any of these file records are bad then try the mirror
  1511. // (unless we are already looking at the mirror). If we
  1512. // can't find a valid record then fail the mount.
  1513. //
  1514. if (!NtfsCheckFileRecord( Vcb, MftBuffer, &FileReference, &CorruptHint )) {
  1515. if ((MftBuffer != Mft2Buffer) &&
  1516. NtfsCheckFileRecord( Vcb, Mft2Buffer, &FileReference, &CorruptHint )) {
  1517. LlTemp1 = MAXLONGLONG;
  1518. //
  1519. // Put a BaadSignature in this file record,
  1520. // mark it dirty and then read it again.
  1521. // The baad signature should force us to bring
  1522. // in the mirror and we can correct the problem.
  1523. //
  1524. RtlCopyMemory( MftBuffer, Mft2Buffer, Vcb->BytesPerFileRecordSegment );
  1525. CcSetDirtyPinnedData( Bcbs[i*2], (PLARGE_INTEGER) &LlTemp1 );
  1526. } else {
  1527. NtfsMarkVolumeDirty( IrpContext, Vcb, FALSE );
  1528. try_return( Status = STATUS_DISK_CORRUPT_ERROR );
  1529. }
  1530. }
  1531. }
  1532. //
  1533. // Now we need to uninitialize and purge the Mft and Mft2. This is
  1534. // because we could have only a partially filled page at the end, and
  1535. // we need to do real reads of whole pages now.
  1536. //
  1537. //
  1538. // Uninitialize and reinitialize the large mcbs so that we can reload
  1539. // it from the File Record.
  1540. //
  1541. NtfsUnloadNtfsMcbRange( &Vcb->MftScb->Mcb, (LONGLONG) 0, MAXLONGLONG, TRUE, FALSE );
  1542. NtfsUnloadNtfsMcbRange( &Vcb->Mft2Scb->Mcb, (LONGLONG) 0, MAXLONGLONG, TRUE, FALSE );
  1543. //
  1544. // Mark both of them as uninitialized.
  1545. //
  1546. ClearFlag( Vcb->MftScb->ScbState, SCB_STATE_FILE_SIZE_LOADED );
  1547. ClearFlag( Vcb->Mft2Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED );
  1548. //
  1549. // We need to deal with a rare case where the Scb for a non-resident attribute
  1550. // list for the Mft has been created but the size is not correct. This could
  1551. // happen if we logged part of the stream but not the whole stream. In that
  1552. // case we really want to load the correct numbers into the Scb. We will need the
  1553. // full attribute list if we are to look up the allocation for the Mft
  1554. // immediately after this.
  1555. //
  1556. MftLinks = Vcb->MftScb->Fcb->ScbQueue.Flink;
  1557. while (MftLinks != &Vcb->MftScb->Fcb->ScbQueue) {
  1558. AttributeListScb = CONTAINING_RECORD( MftLinks,
  1559. SCB,
  1560. FcbLinks );
  1561. if (AttributeListScb->AttributeTypeCode == $ATTRIBUTE_LIST) {
  1562. //
  1563. // Clear the flags so we can reload the information from disk.
  1564. // Also unload the allocation. If we have a log record for a
  1565. // change to the attribute list for the Mft then the allocation
  1566. // may only be partially loaded. Looking up the allocation for the
  1567. // Mft below could easily hit one of the holes. This way we will
  1568. // reload all of the allocation.
  1569. //
  1570. NtfsUnloadNtfsMcbRange( &AttributeListScb->Mcb, 0, MAXLONGLONG, TRUE, FALSE );
  1571. ClearFlag( AttributeListScb->ScbState, SCB_STATE_FILE_SIZE_LOADED | SCB_STATE_HEADER_INITIALIZED );
  1572. NtfsUpdateScbFromAttribute( IrpContext, AttributeListScb, NULL );
  1573. //
  1574. // Let the cache manager know the sizes if this is cached.
  1575. //
  1576. if (AttributeListScb->FileObject != NULL) {
  1577. CcSetFileSizes( AttributeListScb->FileObject,
  1578. (PCC_FILE_SIZES) &AttributeListScb->Header.AllocationSize );
  1579. }
  1580. break;
  1581. }
  1582. MftLinks = MftLinks->Flink;
  1583. }
  1584. //
  1585. // Now load up the real allocation from just the first file record.
  1586. //
  1587. if (Vcb->FileRecordsPerCluster == 0) {
  1588. NtfsPreloadAllocation( IrpContext,
  1589. Vcb->MftScb,
  1590. 0,
  1591. (FIRST_USER_FILE_NUMBER - 1) << Vcb->MftToClusterShift );
  1592. } else {
  1593. NtfsPreloadAllocation( IrpContext,
  1594. Vcb->MftScb,
  1595. 0,
  1596. (FIRST_USER_FILE_NUMBER - 1) >> Vcb->MftToClusterShift );
  1597. }
  1598. NtfsPreloadAllocation( IrpContext, Vcb->Mft2Scb, 0, MAXLONGLONG );
  1599. //
  1600. // We update the Mft and the Mft mirror before we delete the current
  1601. // stream file for the Mft. We know we can read the true attributes
  1602. // for the Mft and the Mirror because we initialized their sizes
  1603. // above through the first few records in the Mft.
  1604. //
  1605. NtfsUpdateScbFromAttribute( IrpContext, Vcb->MftScb, NULL );
  1606. //
  1607. // We will attempt to upgrade the version only if this isn't already
  1608. // a version 2 or 3 volume, the upgrade bit is set, and we aren't
  1609. // retrying the mount because the upgrade failed last time.
  1610. // We will always upgrade a new volume
  1611. //
  1612. if ((Vcb->MajorVersion == 1) &&
  1613. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED ) &&
  1614. (NtfsForceUpgrade ?
  1615. (!FlagOn( NtfsData.Flags, NTFS_FLAGS_DISABLE_UPGRADE ) ||
  1616. (Vcb->MftScb->Header.FileSize.QuadPart <= FIRST_USER_FILE_NUMBER * Vcb->BytesPerFileRecordSegment))
  1617. :
  1618. FlagOn( VolumeFlags, VOLUME_UPGRADE_ON_MOUNT ))) {
  1619. //
  1620. // We can't upgrade R/O volumes, so we can't proceed either.
  1621. //
  1622. if (NtfsIsVolumeReadOnly( Vcb )) {
  1623. Status = STATUS_MEDIA_WRITE_PROTECTED;
  1624. try_return( Status );
  1625. }
  1626. UpgradeVolume = TRUE;
  1627. }
  1628. ClearFlag( Vcb->MftScb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  1629. ClearFlag( Vcb->MftScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  1630. if (!FlagOn( Vcb->MftScb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  1631. Vcb->MftScb->CompressionUnit = 0;
  1632. Vcb->MftScb->CompressionUnitShift = 0;
  1633. }
  1634. NtfsUpdateScbFromAttribute( IrpContext, Vcb->Mft2Scb, NULL );
  1635. ClearFlag( Vcb->Mft2Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  1636. ClearFlag( Vcb->Mft2Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  1637. if (!FlagOn( Vcb->Mft2Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  1638. Vcb->Mft2Scb->CompressionUnit = 0;
  1639. Vcb->Mft2Scb->CompressionUnitShift = 0;
  1640. }
  1641. //
  1642. // Unpin the Bcb's for the Mft files before uninitializing.
  1643. //
  1644. for (i = 0; i < 8; i++) {
  1645. NtfsUnpinBcb( IrpContext, &Bcbs[i] );
  1646. //
  1647. // Now we can get rid of these Mdls.
  1648. //
  1649. MmUnlockPages( Mdls[i] );
  1650. IoFreeMdl( Mdls[i] );
  1651. Mdls[i] = NULL;
  1652. }
  1653. //
  1654. // Before we call CcSetAdditionalCacheAttributes to disable write behind,
  1655. // we need to flush what we can now.
  1656. //
  1657. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1658. //
  1659. // Now close and purge the Mft, and recreate its stream so that
  1660. // the Mft is in a normal state, and we can close the rest of
  1661. // the attributes from restart. We need to bump the close count
  1662. // to keep the scb around while we do this little bit of trickery
  1663. //
  1664. {
  1665. Vcb->MftScb->CloseCount += 1;
  1666. NtfsPurgeFileRecordCache( IrpContext );
  1667. NtfsDeleteInternalAttributeStream( Vcb->MftScb, TRUE, FALSE );
  1668. NtfsCreateInternalAttributeStream( IrpContext,
  1669. Vcb->MftScb,
  1670. FALSE,
  1671. &NtfsSystemFiles[MASTER_FILE_TABLE_NUMBER] );
  1672. //
  1673. // Tell the cache manager the file sizes for the MFT. It is possible
  1674. // that the shared cache map did not go away on the DeleteInternalAttributeStream
  1675. // call above. In that case the Cache Manager has the file sizes from
  1676. // restart.
  1677. //
  1678. CcSetFileSizes( Vcb->MftScb->FileObject,
  1679. (PCC_FILE_SIZES) &Vcb->MftScb->Header.AllocationSize );
  1680. CcSetAdditionalCacheAttributes( Vcb->MftScb->FileObject, TRUE, FALSE );
  1681. Vcb->MftScb->CloseCount -= 1;
  1682. }
  1683. //
  1684. // We want to read all of the file records for the Mft to put
  1685. // its complete mapping into the Mcb.
  1686. //
  1687. SetFlag( Vcb->VcbState, VCB_STATE_PRELOAD_MFT );
  1688. NtfsPreloadAllocation( IrpContext, Vcb->MftScb, 0, MAXLONGLONG );
  1689. ClearFlag( Vcb->VcbState, VCB_STATE_PRELOAD_MFT );
  1690. //
  1691. // Close the boot file (get rid of it because we do not know its proper
  1692. // size, and the Scb may be inconsistent).
  1693. //
  1694. NtfsDeleteInternalAttributeStream( BootScb, TRUE, FALSE );
  1695. BootScb = NULL;
  1696. //
  1697. // Closing the attributes from restart has to occur here after
  1698. // the Mft is clean, because flushing these files will cause
  1699. // file size updates to occur, etc.
  1700. //
  1701. Status = NtfsCloseAttributesFromRestart( IrpContext, Vcb );
  1702. CloseAttributes = FALSE;
  1703. if (!NT_SUCCESS( Status )) {
  1704. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  1705. }
  1706. //
  1707. // The CHECKPOINT flags function the same way whether the volume is mounted
  1708. // read-only or not. We just ignore the actual checkpointing process.
  1709. //
  1710. NtfsAcquireCheckpoint( IrpContext, Vcb );
  1711. //
  1712. // Show that it is ok to checkpoint now.
  1713. //
  1714. ClearFlag( Vcb->CheckpointFlags, VCB_CHECKPOINT_SYNC_FLAGS | VCB_LAST_CHECKPOINT_CLEAN );
  1715. //
  1716. // Clear the flag indicating that we won't defrag the volume.
  1717. //
  1718. ClearFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_ENABLED );
  1719. NtfsSetCheckpointNotify( IrpContext, Vcb );
  1720. NtfsReleaseCheckpoint( IrpContext, Vcb );
  1721. //
  1722. // We always need to write a checkpoint record so that we have
  1723. // a checkpoint on the disk before we modify any files.
  1724. //
  1725. NtfsCheckpointVolume( IrpContext,
  1726. Vcb,
  1727. FALSE,
  1728. UpdatesApplied,
  1729. UpdatesApplied,
  1730. 0,
  1731. Vcb->LastRestartArea );
  1732. //
  1733. // Now set the defrag enabled flag.
  1734. //
  1735. NtfsAcquireCheckpoint( IrpContext, Vcb );
  1736. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_ENABLED );
  1737. NtfsReleaseCheckpoint( IrpContext, Vcb );
  1738. /* Format is using wrong attribute definitions
  1739. //
  1740. // At this point we are ready to use the volume normally. We could
  1741. // open the remaining system files by name, but for now we will go
  1742. // ahead and open them by file number.
  1743. //
  1744. NtfsOpenSystemFile( IrpContext,
  1745. &Vcb->AttributeDefTableScb,
  1746. Vcb,
  1747. ATTRIBUTE_DEF_TABLE_NUMBER,
  1748. 0,
  1749. $DATA,
  1750. FALSE );
  1751. //
  1752. // Read in the attribute definitions.
  1753. //
  1754. {
  1755. IO_STATUS_BLOCK IoStatus;
  1756. PSCB Scb = Vcb->AttributeDefTableScb;
  1757. if ((Scb->Header.FileSize.HighPart != 0) || (Scb->Header.FileSize.LowPart == 0)) {
  1758. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1759. }
  1760. Vcb->AttributeDefinitions = NtfsAllocatePool(PagedPool, Scb->Header.FileSize.LowPart );
  1761. CcCopyRead( Scb->FileObject,
  1762. &Li0,
  1763. Scb->Header.FileSize.LowPart,
  1764. TRUE,
  1765. Vcb->AttributeDefinitions,
  1766. &IoStatus );
  1767. if (!NT_SUCCESS(IoStatus.Status)) {
  1768. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1769. }
  1770. }
  1771. */
  1772. //
  1773. // Just point to our own attribute definitions for now.
  1774. //
  1775. Vcb->AttributeDefinitions = NtfsAttributeDefinitions;
  1776. //
  1777. // Open the upcase table.
  1778. //
  1779. NtfsOpenSystemFile( IrpContext,
  1780. &Vcb->UpcaseTableScb,
  1781. Vcb,
  1782. UPCASE_TABLE_NUMBER,
  1783. 0,
  1784. $DATA,
  1785. FALSE );
  1786. //
  1787. // Read in the upcase table.
  1788. //
  1789. {
  1790. IO_STATUS_BLOCK IoStatus;
  1791. PSCB Scb = Vcb->UpcaseTableScb;
  1792. if ((Scb->Header.FileSize.HighPart != 0) || (Scb->Header.FileSize.LowPart < 512)) {
  1793. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1794. }
  1795. Vcb->UpcaseTable = NtfsAllocatePool(PagedPool, Scb->Header.FileSize.LowPart );
  1796. Vcb->UpcaseTableSize = Scb->Header.FileSize.LowPart / sizeof( WCHAR );
  1797. CcCopyRead( Scb->FileObject,
  1798. &Li0,
  1799. Scb->Header.FileSize.LowPart,
  1800. TRUE,
  1801. Vcb->UpcaseTable,
  1802. &IoStatus );
  1803. if (!NT_SUCCESS(IoStatus.Status)) {
  1804. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1805. }
  1806. //
  1807. // If we do not have a global upcase table yet then make this one the global one
  1808. //
  1809. if (NtfsData.UpcaseTable == NULL) {
  1810. NtfsData.UpcaseTable = Vcb->UpcaseTable;
  1811. NtfsData.UpcaseTableSize = Vcb->UpcaseTableSize;
  1812. //
  1813. // Otherwise if this one perfectly matches the global upcase table then throw
  1814. // this one back and use the global one
  1815. //
  1816. } else if ((NtfsData.UpcaseTableSize == Vcb->UpcaseTableSize)
  1817. &&
  1818. (RtlCompareMemory( NtfsData.UpcaseTable,
  1819. Vcb->UpcaseTable,
  1820. Vcb->UpcaseTableSize) == Vcb->UpcaseTableSize)) {
  1821. NtfsFreePool( Vcb->UpcaseTable );
  1822. Vcb->UpcaseTable = NtfsData.UpcaseTable;
  1823. }
  1824. }
  1825. NtfsOpenSystemFile( IrpContext,
  1826. &Vcb->BitmapScb,
  1827. Vcb,
  1828. BIT_MAP_FILE_NUMBER,
  1829. 0,
  1830. $DATA,
  1831. TRUE );
  1832. NtfsOpenSystemFile( IrpContext,
  1833. &Vcb->BadClusterFileScb,
  1834. Vcb,
  1835. BAD_CLUSTER_FILE_NUMBER,
  1836. 0,
  1837. $DATA,
  1838. TRUE );
  1839. NtfsOpenSystemFile( IrpContext,
  1840. &Vcb->MftBitmapScb,
  1841. Vcb,
  1842. MASTER_FILE_TABLE_NUMBER,
  1843. 0,
  1844. $BITMAP,
  1845. TRUE );
  1846. //
  1847. // Initialize the bitmap support
  1848. //
  1849. NtfsInitializeClusterAllocation( IrpContext, Vcb );
  1850. NtfsSetAndGetVolumeTimes( IrpContext, Vcb, FALSE, TRUE );
  1851. //
  1852. // Initialize the Mft record allocation
  1853. //
  1854. {
  1855. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  1856. BOOLEAN FoundAttribute;
  1857. ULONG ExtendGranularity;
  1858. //
  1859. // Lookup the bitmap allocation for the Mft file.
  1860. //
  1861. NtfsInitializeAttributeContext( &AttrContext );
  1862. //
  1863. // Use a try finally to cleanup the attribute context.
  1864. //
  1865. try {
  1866. //
  1867. // CODENOTE Is the Mft Fcb fully initialized at this point??
  1868. //
  1869. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  1870. Vcb->MftScb->Fcb,
  1871. &Vcb->MftScb->Fcb->FileReference,
  1872. $BITMAP,
  1873. &AttrContext );
  1874. //
  1875. // Error if we don't find the bitmap
  1876. //
  1877. if (!FoundAttribute) {
  1878. DebugTrace( 0, 0, ("Couldn't find bitmap attribute for Mft\n") );
  1879. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1880. }
  1881. //
  1882. // If there is no file object for the Mft Scb, we create it now.
  1883. //
  1884. if (Vcb->MftScb->FileObject == NULL) {
  1885. NtfsCreateInternalAttributeStream( IrpContext, Vcb->MftScb, TRUE, NULL );
  1886. }
  1887. //
  1888. // TEMPCODE We need a better way to determine the optimal
  1889. // truncate and extend granularity.
  1890. //
  1891. ExtendGranularity = MFT_EXTEND_GRANULARITY;
  1892. if ((ExtendGranularity * Vcb->BytesPerFileRecordSegment) < Vcb->BytesPerCluster) {
  1893. ExtendGranularity = Vcb->FileRecordsPerCluster;
  1894. }
  1895. NtfsInitializeRecordAllocation( IrpContext,
  1896. Vcb->MftScb,
  1897. &AttrContext,
  1898. Vcb->BytesPerFileRecordSegment,
  1899. ExtendGranularity,
  1900. ExtendGranularity,
  1901. &Vcb->MftScb->ScbType.Index.RecordAllocationContext );
  1902. } finally {
  1903. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  1904. }
  1905. }
  1906. //
  1907. // Get the serial number and volume label for the volume
  1908. //
  1909. NtfsGetVolumeInformation( IrpContext, Vpb, Vcb, &VolumeFlags );
  1910. //
  1911. // Get the Device Name for this volume.
  1912. //
  1913. Status = ObQueryNameString( Vpb->RealDevice,
  1914. NULL,
  1915. 0,
  1916. &DeviceObjectNameLength );
  1917. ASSERT( Status != STATUS_SUCCESS );
  1918. //
  1919. // Unlike the rest of the system, ObQueryNameString returns
  1920. // STATUS_INFO_LENGTH_MISMATCH instead of STATUS_BUFFER_TOO_SMALL when
  1921. // passed too small a buffer.
  1922. //
  1923. // We expect to get this error here. Anything else we can't handle.
  1924. //
  1925. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  1926. DeviceObjectName = NtfsAllocatePool( PagedPool, DeviceObjectNameLength );
  1927. Status = ObQueryNameString( Vpb->RealDevice,
  1928. DeviceObjectName,
  1929. DeviceObjectNameLength,
  1930. &DeviceObjectNameLength );
  1931. }
  1932. if (!NT_SUCCESS( Status )) {
  1933. try_return( NOTHING );
  1934. }
  1935. //
  1936. // Now that we are successfully mounting, let us see if we should
  1937. // enable balanced reads.
  1938. //
  1939. if (!FlagOn(Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY)) {
  1940. FsRtlBalanceReads( DeviceObjectWeTalkTo );
  1941. }
  1942. ASSERT( DeviceObjectName->Name.Length != 0 );
  1943. Vcb->DeviceName.MaximumLength =
  1944. Vcb->DeviceName.Length = DeviceObjectName->Name.Length;
  1945. Vcb->DeviceName.Buffer = NtfsAllocatePool( PagedPool, DeviceObjectName->Name.Length );
  1946. RtlCopyMemory( Vcb->DeviceName.Buffer,
  1947. DeviceObjectName->Name.Buffer,
  1948. DeviceObjectName->Name.Length );
  1949. //
  1950. // Now we want to initialize the remaining defrag status values.
  1951. //
  1952. Vcb->MftHoleGranularity = MFT_HOLE_GRANULARITY;
  1953. Vcb->MftClustersPerHole = Vcb->MftHoleGranularity << Vcb->MftToClusterShift;
  1954. if (MFT_HOLE_GRANULARITY < Vcb->FileRecordsPerCluster) {
  1955. Vcb->MftHoleGranularity = Vcb->FileRecordsPerCluster;
  1956. Vcb->MftClustersPerHole = 1;
  1957. }
  1958. Vcb->MftHoleMask = Vcb->MftHoleGranularity - 1;
  1959. Vcb->MftHoleInverseMask = ~(Vcb->MftHoleMask);
  1960. Vcb->MftHoleClusterMask = Vcb->MftClustersPerHole - 1;
  1961. Vcb->MftHoleClusterInverseMask = ~(Vcb->MftHoleClusterMask);
  1962. //
  1963. // Our maximum reserved Mft space is 0x140, we will try to
  1964. // get an extra 40 bytes if possible.
  1965. //
  1966. Vcb->MftReserved = Vcb->BytesPerFileRecordSegment / 8;
  1967. if (Vcb->MftReserved > 0x140) {
  1968. Vcb->MftReserved = 0x140;
  1969. }
  1970. Vcb->MftCushion = Vcb->MftReserved - 0x20;
  1971. NtfsScanMftBitmap( IrpContext, Vcb );
  1972. #ifdef NTFS_CHECK_BITMAP
  1973. {
  1974. ULONG BitmapSize;
  1975. ULONG Count;
  1976. BitmapSize = Vcb->BitmapScb->Header.FileSize.LowPart;
  1977. //
  1978. // Allocate a buffer for the bitmap copy and each individual bitmap.
  1979. //
  1980. Vcb->BitmapPages = (BitmapSize + PAGE_SIZE - 1) / PAGE_SIZE;
  1981. Vcb->BitmapCopy = NtfsAllocatePool(PagedPool, Vcb->BitmapPages * sizeof( RTL_BITMAP ));
  1982. RtlZeroMemory( Vcb->BitmapCopy, Vcb->BitmapPages * sizeof( RTL_BITMAP ));
  1983. //
  1984. // Now get a buffer for each page.
  1985. //
  1986. for (Count = 0; Count < Vcb->BitmapPages; Count += 1) {
  1987. (Vcb->BitmapCopy + Count)->Buffer = NtfsAllocatePool(PagedPool, PAGE_SIZE );
  1988. RtlInitializeBitMap( Vcb->BitmapCopy + Count, (Vcb->BitmapCopy + Count)->Buffer, PAGE_SIZE * 8 );
  1989. }
  1990. if (NtfsCopyBitmap) {
  1991. PUCHAR NextPage;
  1992. PBCB BitmapBcb = NULL;
  1993. ULONG BytesToCopy;
  1994. LONGLONG FileOffset = 0;
  1995. Count = 0;
  1996. while (BitmapSize) {
  1997. BytesToCopy = PAGE_SIZE;
  1998. if (BytesToCopy > BitmapSize) {
  1999. BytesToCopy = BitmapSize;
  2000. }
  2001. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  2002. NtfsMapStream( IrpContext, Vcb->BitmapScb, FileOffset, BytesToCopy, &BitmapBcb, &NextPage );
  2003. RtlCopyMemory( (Vcb->BitmapCopy + Count)->Buffer,
  2004. NextPage,
  2005. BytesToCopy );
  2006. BitmapSize -= BytesToCopy;
  2007. FileOffset += BytesToCopy;
  2008. Count += 1;
  2009. }
  2010. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  2011. //
  2012. // Otherwise we will want to scan the entire Mft and compare the mapping pairs
  2013. // with the current volume bitmap.
  2014. //
  2015. }
  2016. }
  2017. #endif
  2018. //
  2019. // Whether this was already an upgraded volume or we want it to
  2020. // be one now, we need to open all the new indices.
  2021. //
  2022. if ((CurrentVersion || UpgradeVolume) &&
  2023. !SkipNtOfs) {
  2024. BOOLEAN UpdatedVolumeVersion = FALSE;
  2025. try {
  2026. //
  2027. // Create/open the security file and initialize security on the volume.
  2028. //
  2029. NtfsInitializeSecurityFile( IrpContext, Vcb );
  2030. //
  2031. // Open the Root Directory.
  2032. //
  2033. NtfsOpenRootDirectory( IrpContext, Vcb );
  2034. //
  2035. // Create/open the $Extend directory.
  2036. //
  2037. NtfsInitializeExtendDirectory( IrpContext, Vcb );
  2038. //
  2039. // Create/open the Quota File and initialize quotas.
  2040. //
  2041. NtfsInitializeQuotaFile( IrpContext, Vcb );
  2042. //
  2043. // Create/open the Object Id File and initialize object ids.
  2044. //
  2045. NtfsInitializeObjectIdFile( IrpContext, Vcb );
  2046. //
  2047. // Create/open the Mount Points File and initialize it.
  2048. //
  2049. NtfsInitializeReparseFile( IrpContext, Vcb );
  2050. //
  2051. // Open the Usn Journal only if it is there. If the volume was mounted
  2052. // on a 4.0 system then we want to restamp the journal. Skip the
  2053. // initialization if the volume flags indicate that the journal
  2054. // delete has started.
  2055. // No USN journal if we're mounting Read Only.
  2056. //
  2057. if (FlagOn( VolumeFlags, VOLUME_DELETE_USN_UNDERWAY )) {
  2058. SetFlag( Vcb->VcbState, VCB_STATE_USN_DELETE );
  2059. } else if (!NtfsIsVolumeReadOnly( Vcb )) {
  2060. NtfsInitializeUsnJournal( IrpContext,
  2061. Vcb,
  2062. FALSE,
  2063. FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 ),
  2064. (PCREATE_USN_JOURNAL_DATA) &Vcb->UsnJournalInstance.MaximumSize );
  2065. if (FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 )) {
  2066. NtfsSetVolumeInfoFlagState( IrpContext,
  2067. Vcb,
  2068. VOLUME_MOUNTED_ON_40,
  2069. FALSE,
  2070. TRUE );
  2071. }
  2072. }
  2073. //
  2074. // Upgrade all security information
  2075. //
  2076. NtfsUpgradeSecurity( IrpContext, Vcb );
  2077. //
  2078. // If we haven't opened the root directory, do so
  2079. //
  2080. if (Vcb->RootIndexScb == NULL) {
  2081. NtfsOpenRootDirectory( IrpContext, Vcb );
  2082. }
  2083. NtfsCleanupTransaction( IrpContext, STATUS_SUCCESS, FALSE );
  2084. //
  2085. // Update version numbers in volinfo
  2086. //
  2087. if (!NtfsIsVolumeReadOnly( Vcb )) {
  2088. UpdatedVolumeVersion = NtfsUpdateVolumeInfo( IrpContext, Vcb, NTFS_MAJOR_VERSION, NTFS_MINOR_VERSION );
  2089. }
  2090. //
  2091. // If we've gotten this far during the mount, it's safe to
  2092. // update the version number on disk if necessary.
  2093. //
  2094. if (UpgradeVolume) {
  2095. //
  2096. // Now enable defragging.
  2097. //
  2098. if (NtfsDefragMftEnabled) {
  2099. NtfsAcquireCheckpoint( IrpContext, Vcb );
  2100. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_PERMITTED );
  2101. NtfsReleaseCheckpoint( IrpContext, Vcb );
  2102. }
  2103. //
  2104. // Update the on-disk attribute definition table to include the
  2105. // new attributes for an upgraded volume.
  2106. //
  2107. NtfsUpdateAttributeTable( IrpContext, Vcb );
  2108. }
  2109. } finally {
  2110. if (!NT_SUCCESS( IrpContext->ExceptionStatus ) && UpgradeVolume) {
  2111. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED );
  2112. }
  2113. }
  2114. if (UpdatedVolumeVersion) {
  2115. //
  2116. // If we've upgraded successfully, we should clear the upgrade
  2117. // bit now so we can use it again in the future.
  2118. //
  2119. NtfsSetVolumeInfoFlagState( IrpContext,
  2120. Vcb,
  2121. VOLUME_UPGRADE_ON_MOUNT,
  2122. FALSE,
  2123. TRUE );
  2124. }
  2125. } else {
  2126. //
  2127. // If we haven't opened the root directory, do so
  2128. //
  2129. if (Vcb->RootIndexScb == NULL) {
  2130. NtfsOpenRootDirectory( IrpContext, Vcb );
  2131. }
  2132. NtfsCleanupTransaction( IrpContext, STATUS_SUCCESS, FALSE );
  2133. }
  2134. //
  2135. // Start the usn journal delete operation if the vcb flag is specified.
  2136. //
  2137. if (FlagOn( Vcb->VcbState, VCB_STATE_USN_DELETE )) {
  2138. NtfsPostSpecial( IrpContext, Vcb, NtfsDeleteUsnSpecial, &Vcb->DeleteUsnData );
  2139. }
  2140. //
  2141. // If the last mount was on a 4.0 volume then we need to clean up the quota
  2142. // and object id indices.
  2143. //
  2144. if ((Vcb->MajorVersion >= 3) &&
  2145. FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 )) {
  2146. NtfsSetVolumeInfoFlagState( IrpContext,
  2147. Vcb,
  2148. VOLUME_REPAIR_OBJECT_ID,
  2149. TRUE,
  2150. TRUE );
  2151. SetFlag( VolumeFlags, VOLUME_REPAIR_OBJECT_ID );
  2152. //
  2153. // Fire off the quota cleanup if quotas are enabled.
  2154. //
  2155. if (FlagOn( Vcb->QuotaFlags, (QUOTA_FLAG_TRACKING_REQUESTED |
  2156. QUOTA_FLAG_TRACKING_ENABLED |
  2157. QUOTA_FLAG_ENFORCEMENT_ENABLED ))) {
  2158. NtfsMarkQuotaCorrupt( IrpContext, Vcb );
  2159. }
  2160. }
  2161. //
  2162. // Start the object ID cleanup if we were mounted on 4.0 or had started
  2163. // in a previous mount.
  2164. //
  2165. if (FlagOn( VolumeFlags, VOLUME_REPAIR_OBJECT_ID )) {
  2166. NtfsPostSpecial( IrpContext, Vcb, NtfsRepairObjectId, NULL );
  2167. }
  2168. //
  2169. // Clear the MOUNTED_ON_40 and CHKDSK_MODIFIED flags if set.
  2170. //
  2171. if (FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 | VOLUME_MODIFIED_BY_CHKDSK )) {
  2172. NtfsSetVolumeInfoFlagState( IrpContext,
  2173. Vcb,
  2174. VOLUME_MOUNTED_ON_40 | VOLUME_MODIFIED_BY_CHKDSK,
  2175. FALSE,
  2176. TRUE );
  2177. }
  2178. //
  2179. // Looks like this mount will succeed. Remember the root directory fileobject
  2180. // so we can use it for the notification later.
  2181. //
  2182. RootDirFileObject = Vcb->RootIndexScb->FileObject;
  2183. //
  2184. // Dereference the root file object if present. The absence of this doesn't
  2185. // indicate whether the volume was upgraded. Older 4K Mft records can contain
  2186. // all of the new streams.
  2187. //
  2188. if (RootDirFileObject != NULL) {
  2189. ObReferenceObject( RootDirFileObject );
  2190. }
  2191. //
  2192. //
  2193. // Set our return status and say that the mount succeeded
  2194. //
  2195. Status = STATUS_SUCCESS;
  2196. MountFailed = FALSE;
  2197. SetFlag( Vcb->VcbState, VCB_STATE_MOUNT_COMPLETED );
  2198. #ifdef SYSCACHE_DEBUG
  2199. if (!NtfsIsVolumeReadOnly( Vcb ) && !NtfsDisableSyscacheLogFile) {
  2200. NtfsInitializeSyscacheLogFile( IrpContext, Vcb );
  2201. }
  2202. #endif
  2203. try_exit: NOTHING;
  2204. } finally {
  2205. DebugUnwind( NtfsMountVolume );
  2206. NtfsUnpinBcb( IrpContext, &BootBcb );
  2207. if (DeviceObjectName != NULL) {
  2208. NtfsFreePool( DeviceObjectName );
  2209. }
  2210. if (CloseAttributes) { NtfsCloseAttributesFromRestart( IrpContext, Vcb ); }
  2211. for (i = 0; i < 8; i++) {
  2212. NtfsUnpinBcb( IrpContext, &Bcbs[i] );
  2213. //
  2214. // Get rid of the Mdls, if we haven't already.
  2215. //
  2216. if (Mdls[i] != NULL) {
  2217. if (FlagOn(Mdls[i]->MdlFlags, MDL_PAGES_LOCKED )) {
  2218. MmUnlockPages( Mdls[i] );
  2219. }
  2220. IoFreeMdl( Mdls[i] );
  2221. Mdls[i] = NULL;
  2222. }
  2223. }
  2224. if (BootScb != NULL) { NtfsDeleteInternalAttributeStream( BootScb, TRUE, FALSE ); }
  2225. if (Vcb != NULL) {
  2226. if (Vcb->MftScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->MftScb ); }
  2227. if (Vcb->Mft2Scb != NULL) { NtfsReleaseScb( IrpContext, Vcb->Mft2Scb ); }
  2228. if (Vcb->LogFileScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->LogFileScb ); }
  2229. if (Vcb->VolumeDasdScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->VolumeDasdScb ); }
  2230. if (Vcb->AttributeDefTableScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->AttributeDefTableScb );
  2231. NtfsDeleteInternalAttributeStream( Vcb->AttributeDefTableScb, TRUE, FALSE );
  2232. Vcb->AttributeDefTableScb = NULL;}
  2233. if (Vcb->UpcaseTableScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->UpcaseTableScb );
  2234. NtfsDeleteInternalAttributeStream( Vcb->UpcaseTableScb, TRUE, FALSE );
  2235. Vcb->UpcaseTableScb = NULL;}
  2236. if (Vcb->RootIndexScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->RootIndexScb ); }
  2237. if (Vcb->BitmapScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->BitmapScb ); }
  2238. if (Vcb->BadClusterFileScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->BadClusterFileScb ); }
  2239. if (Vcb->MftBitmapScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->MftBitmapScb ); }
  2240. //
  2241. // Drop the security data
  2242. //
  2243. if (Vcb->SecurityDescriptorStream != NULL) { NtfsReleaseScb( IrpContext, Vcb->SecurityDescriptorStream ); }
  2244. if (Vcb->UsnJournal != NULL) { NtfsReleaseScb( IrpContext, Vcb->UsnJournal ); }
  2245. if (Vcb->ExtendDirectory != NULL) { NtfsReleaseScb( IrpContext, Vcb->ExtendDirectory ); }
  2246. if (QuotaDataScb != NULL) {
  2247. NtfsReleaseScb( IrpContext, QuotaDataScb );
  2248. NtfsDeleteInternalAttributeStream( QuotaDataScb, TRUE, FALSE );
  2249. }
  2250. if (MountFailed) {
  2251. PVPB NewVpb;
  2252. NtfsPerformDismountOnVcb( IrpContext, Vcb, TRUE, &NewVpb );
  2253. //
  2254. // If the version upgrade failed, we will be coming back in here soon
  2255. // and we need to have the right vpb when we do. This is true if the
  2256. // upgrade failed or if we are processing a log file full condition.
  2257. //
  2258. if ((FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED ) ||
  2259. (IrpContext->TopLevelIrpContext->ExceptionStatus == STATUS_LOG_FILE_FULL) ||
  2260. (IrpContext->TopLevelIrpContext->ExceptionStatus == STATUS_CANT_WAIT)) &&
  2261. (NewVpb != NULL)) {
  2262. IrpSp->Parameters.MountVolume.Vpb = NewVpb;
  2263. }
  2264. //
  2265. // On abnormal termination, someone will try to abort a transaction on
  2266. // this Vcb if we do not clear these fields.
  2267. //
  2268. IrpContext->TransactionId = 0;
  2269. IrpContext->Vcb = NULL;
  2270. }
  2271. }
  2272. if (VcbAcquired) {
  2273. NtfsReleaseVcbCheckDelete( IrpContext, Vcb, IRP_MJ_FILE_SYSTEM_CONTROL, NULL );
  2274. }
  2275. NtfsReleaseGlobal( IrpContext );
  2276. }
  2277. NtfsCompleteRequest( IrpContext, Irp, Status );
  2278. if (RootDirFileObject != NULL) {
  2279. FsRtlNotifyVolumeEvent( RootDirFileObject, FSRTL_VOLUME_MOUNT );
  2280. ObDereferenceObject( RootDirFileObject );
  2281. }
  2282. if (NT_SUCCESS( Status )) {
  2283. //
  2284. // Remove the extra object reference to the target device object
  2285. // because I/O system has already made one for this mount.
  2286. //
  2287. ObDereferenceObject( Vcb->TargetDeviceObject );
  2288. }
  2289. DebugTrace( -1, Dbg, ("NtfsMountVolume -> %08lx\n", Status) );
  2290. return Status;
  2291. }
  2292. //
  2293. // Local Support Routine
  2294. //
  2295. NTSTATUS
  2296. NtfsUpdateAttributeTable (
  2297. IN PIRP_CONTEXT IrpContext,
  2298. IN PVCB Vcb
  2299. )
  2300. /*++
  2301. Routine Description:
  2302. This routine updates the on-disk attribute definition table.
  2303. Arguments:
  2304. Vcb - Supplies the Vcb whose attribute table should be updated.
  2305. Return Value:
  2306. NTSTATUS - The return status for the operation
  2307. --*/
  2308. {
  2309. NTSTATUS Status = STATUS_SUCCESS;
  2310. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  2311. PATTRIBUTE_DEFINITION_COLUMNS AttrDefs = NULL;
  2312. PFCB AttributeTableFcb;
  2313. BOOLEAN FoundAttribute;
  2314. ASSERT_IRP_CONTEXT( IrpContext );
  2315. ASSERT_VCB( Vcb );
  2316. ASSERT( Vcb->AttributeDefTableScb == NULL );
  2317. PAGED_CODE();
  2318. DebugTrace( +1, Dbg, ("NtfsUpdateAttributeTable\n") );
  2319. NtfsOpenSystemFile( IrpContext,
  2320. &Vcb->AttributeDefTableScb,
  2321. Vcb,
  2322. ATTRIBUTE_DEF_TABLE_NUMBER,
  2323. 0,
  2324. $DATA,
  2325. FALSE );
  2326. AttributeTableFcb = Vcb->AttributeDefTableScb->Fcb;
  2327. NtfsInitializeAttributeContext( &AttrContext );
  2328. try {
  2329. //
  2330. // First, we find and delete the old attribute definition table.
  2331. //
  2332. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  2333. AttributeTableFcb,
  2334. &AttributeTableFcb->FileReference,
  2335. $DATA,
  2336. &AttrContext );
  2337. if (!FoundAttribute) {
  2338. try_return( Status = STATUS_DISK_CORRUPT_ERROR );
  2339. }
  2340. NtfsDeleteAttributeRecord( IrpContext,
  2341. AttributeTableFcb,
  2342. DELETE_LOG_OPERATION | DELETE_RELEASE_ALLOCATION,
  2343. &AttrContext );
  2344. //
  2345. // Now we write the current attribute definition table to disk.
  2346. //
  2347. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  2348. NtfsInitializeAttributeContext( &AttrContext );
  2349. //
  2350. // chkdsk for whistler doesn't recognize the attribute table in its current state
  2351. // so munge it so it does - move the last entry $EFS into the unused piece of the
  2352. // table 0xF0
  2353. //
  2354. AttrDefs = NtfsAllocatePool( PagedPool, sizeof( ATTRIBUTE_DEFINITION_COLUMNS ) * NtfsAttributeDefinitionsCount );
  2355. RtlCopyMemory( AttrDefs, NtfsAttributeDefinitions, sizeof( ATTRIBUTE_DEFINITION_COLUMNS ) * NtfsAttributeDefinitionsCount );
  2356. RtlMoveMemory( &AttrDefs[ NtfsAttributeDefinitionsCount - 3], &AttrDefs[ NtfsAttributeDefinitionsCount - 2], sizeof( ATTRIBUTE_DEFINITION_COLUMNS ) * 2);
  2357. NtfsCreateAttributeWithValue( IrpContext,
  2358. AttributeTableFcb,
  2359. $DATA,
  2360. NULL,
  2361. AttrDefs,
  2362. (NtfsAttributeDefinitionsCount - 1) * sizeof(*NtfsAttributeDefinitions),
  2363. 0,
  2364. NULL,
  2365. TRUE,
  2366. &AttrContext );
  2367. try_exit: NOTHING;
  2368. } finally {
  2369. if (AttrDefs != NULL) {
  2370. NtfsFreePool( AttrDefs );
  2371. }
  2372. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  2373. }
  2374. //
  2375. // And return to our caller
  2376. //
  2377. DebugTrace( -1, Dbg, ("NtfsUpdateAttributeTable -> %08lx\n", Status) );
  2378. return Status;
  2379. }
  2380. //
  2381. // Local Support Routine
  2382. //
  2383. NTSTATUS
  2384. NtfsVerifyVolume (
  2385. IN PIRP_CONTEXT IrpContext,
  2386. IN PIRP Irp
  2387. )
  2388. /*++
  2389. Routine Description:
  2390. This routine performs the verify volume operation. It is responsible for
  2391. either completing of enqueuing the input Irp.
  2392. Arguments:
  2393. Irp - Supplies the Irp to process
  2394. Return Value:
  2395. NTSTATUS - The return status for the operation
  2396. --*/
  2397. {
  2398. NTSTATUS Status;
  2399. PIO_STACK_LOCATION IrpSp;
  2400. ASSERT_IRP_CONTEXT( IrpContext );
  2401. ASSERT_IRP( Irp );
  2402. PAGED_CODE();
  2403. //
  2404. // Get the current Irp stack location
  2405. //
  2406. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2407. DebugTrace( +1, Dbg, ("NtfsVerifyVolume\n") );
  2408. //
  2409. // Do nothing for now
  2410. //
  2411. KdPrint(("NtfsVerifyVolume is not yet implemented\n")); //**** DbgBreakPoint();
  2412. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_NOT_IMPLEMENTED );
  2413. //
  2414. // And return to our caller
  2415. //
  2416. DebugTrace( -1, Dbg, ("NtfsVerifyVolume -> %08lx\n", Status) );
  2417. return Status;
  2418. }
  2419. //
  2420. // Local Support Routine
  2421. //
  2422. NTSTATUS
  2423. NtfsUserFsRequest (
  2424. IN PIRP_CONTEXT IrpContext,
  2425. IN PIRP Irp
  2426. )
  2427. /*++
  2428. Routine Description:
  2429. This is the common routine for implementing the user's requests made
  2430. through NtFsControlFile.
  2431. Arguments:
  2432. Irp - Supplies the Irp being processed
  2433. Wait - Indicates if the thread can block for a resource or I/O
  2434. Return Value:
  2435. NTSTATUS - The return status for the operation
  2436. --*/
  2437. {
  2438. NTSTATUS Status;
  2439. ULONG FsControlCode;
  2440. PIO_STACK_LOCATION IrpSp;
  2441. ASSERT_IRP_CONTEXT( IrpContext );
  2442. ASSERT_IRP( Irp );
  2443. PAGED_CODE();
  2444. //
  2445. // Get the current Irp stack location, and save some references
  2446. // to make our life a little easier.
  2447. //
  2448. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2449. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  2450. DebugTrace( +1, Dbg, ("NtfsUserFsRequest, FsControlCode = %08lx\n", FsControlCode) );
  2451. //
  2452. // Case on the control code.
  2453. //
  2454. switch ( FsControlCode ) {
  2455. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  2456. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  2457. case FSCTL_REQUEST_BATCH_OPLOCK:
  2458. case FSCTL_REQUEST_FILTER_OPLOCK:
  2459. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  2460. case FSCTL_OPLOCK_BREAK_NOTIFY:
  2461. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  2462. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  2463. Status = NtfsOplockRequest( IrpContext, Irp );
  2464. break;
  2465. case FSCTL_LOCK_VOLUME:
  2466. Status = NtfsLockVolume( IrpContext, Irp );
  2467. break;
  2468. case FSCTL_UNLOCK_VOLUME:
  2469. Status = NtfsUnlockVolume( IrpContext, Irp );
  2470. break;
  2471. case FSCTL_DISMOUNT_VOLUME:
  2472. Status = NtfsDismountVolume( IrpContext, Irp );
  2473. break;
  2474. case FSCTL_IS_VOLUME_MOUNTED:
  2475. Status = NtfsIsVolumeMounted( IrpContext, Irp );
  2476. break;
  2477. case FSCTL_MARK_VOLUME_DIRTY:
  2478. Status = NtfsDirtyVolume( IrpContext, Irp );
  2479. break;
  2480. case FSCTL_IS_PATHNAME_VALID:
  2481. //
  2482. // All names are potentially valid NTFS names
  2483. //
  2484. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_SUCCESS );
  2485. break;
  2486. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  2487. Status = NtfsQueryRetrievalPointers( IrpContext, Irp );
  2488. break;
  2489. case FSCTL_GET_COMPRESSION:
  2490. Status = NtfsGetCompression( IrpContext, Irp );
  2491. break;
  2492. case FSCTL_SET_COMPRESSION:
  2493. //
  2494. // Post this request if we can't wait.
  2495. //
  2496. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  2497. Status = NtfsPostRequest( IrpContext, Irp );
  2498. } else {
  2499. Status = NtfsSetCompression( IrpContext, Irp );
  2500. }
  2501. break;
  2502. case FSCTL_MARK_AS_SYSTEM_HIVE:
  2503. Status = NtfsMarkAsSystemHive( IrpContext, Irp );
  2504. break;
  2505. case FSCTL_FILESYSTEM_GET_STATISTICS:
  2506. Status = NtfsGetStatistics( IrpContext, Irp );
  2507. break;
  2508. case FSCTL_GET_NTFS_VOLUME_DATA:
  2509. Status = NtfsGetVolumeData( IrpContext, Irp );
  2510. break;
  2511. case FSCTL_GET_VOLUME_BITMAP:
  2512. Status = NtfsGetVolumeBitmap( IrpContext, Irp );
  2513. break;
  2514. case FSCTL_GET_RETRIEVAL_POINTERS:
  2515. Status = NtfsGetRetrievalPointers( IrpContext, Irp );
  2516. break;
  2517. case FSCTL_GET_NTFS_FILE_RECORD:
  2518. Status = NtfsGetMftRecord( IrpContext, Irp );
  2519. break;
  2520. case FSCTL_MOVE_FILE:
  2521. Status = NtfsDefragFile( IrpContext, Irp );
  2522. break;
  2523. case FSCTL_IS_VOLUME_DIRTY:
  2524. Status = NtfsIsVolumeDirty( IrpContext, Irp );
  2525. break;
  2526. case FSCTL_ALLOW_EXTENDED_DASD_IO:
  2527. Status = NtfsSetExtendedDasdIo( IrpContext, Irp );
  2528. break;
  2529. case FSCTL_SET_REPARSE_POINT:
  2530. Status = NtfsSetReparsePoint( IrpContext, Irp );
  2531. break;
  2532. case FSCTL_GET_REPARSE_POINT:
  2533. Status = NtfsGetReparsePoint( IrpContext, Irp );
  2534. break;
  2535. case FSCTL_DELETE_REPARSE_POINT:
  2536. Status = NtfsDeleteReparsePoint( IrpContext, Irp );
  2537. break;
  2538. case FSCTL_SET_OBJECT_ID:
  2539. Status = NtfsSetObjectId( IrpContext, Irp ); // In ObjIdSup.c
  2540. break;
  2541. case FSCTL_GET_OBJECT_ID:
  2542. Status = NtfsGetObjectId( IrpContext, Irp ); // In ObjIdSup.c
  2543. break;
  2544. case FSCTL_DELETE_OBJECT_ID:
  2545. Status = NtfsDeleteObjectId( IrpContext, Irp ); // In ObjIdSup.c
  2546. break;
  2547. case FSCTL_SET_OBJECT_ID_EXTENDED:
  2548. Status = NtfsSetObjectIdExtendedInfo( IrpContext, Irp ); // In ObjIdSup.c
  2549. break;
  2550. case FSCTL_CREATE_OR_GET_OBJECT_ID:
  2551. Status = NtfsCreateOrGetObjectId( IrpContext, Irp );
  2552. break;
  2553. case FSCTL_READ_USN_JOURNAL:
  2554. Status = NtfsReadUsnJournal( IrpContext, Irp, TRUE ); // In UsnSup.c
  2555. break;
  2556. case FSCTL_CREATE_USN_JOURNAL:
  2557. Status = NtfsCreateUsnJournal( IrpContext, Irp );
  2558. break;
  2559. case FSCTL_ENUM_USN_DATA:
  2560. Status = NtfsReadFileRecordUsnData( IrpContext, Irp );
  2561. break;
  2562. case FSCTL_READ_FILE_USN_DATA:
  2563. Status = NtfsReadFileUsnData( IrpContext, Irp );
  2564. break;
  2565. case FSCTL_WRITE_USN_CLOSE_RECORD:
  2566. Status = NtfsWriteUsnCloseRecord( IrpContext, Irp );
  2567. break;
  2568. case FSCTL_QUERY_USN_JOURNAL:
  2569. Status = NtfsQueryUsnJournal( IrpContext, Irp );
  2570. break;
  2571. case FSCTL_DELETE_USN_JOURNAL:
  2572. Status = NtfsDeleteUsnJournal( IrpContext, Irp );
  2573. break;
  2574. case FSCTL_MARK_HANDLE:
  2575. Status = NtfsMarkHandle( IrpContext, Irp );
  2576. break;
  2577. case FSCTL_SECURITY_ID_CHECK:
  2578. Status = NtfsBulkSecurityIdCheck( IrpContext, Irp );
  2579. break;
  2580. case FSCTL_FIND_FILES_BY_SID:
  2581. Status = NtfsFindFilesOwnedBySid( IrpContext, Irp );
  2582. break;
  2583. case FSCTL_SET_SPARSE :
  2584. Status = NtfsSetSparse( IrpContext, Irp );
  2585. break;
  2586. case FSCTL_SET_ZERO_DATA :
  2587. Status = NtfsZeroRange( IrpContext, Irp );
  2588. break;
  2589. case FSCTL_QUERY_ALLOCATED_RANGES :
  2590. Status = NtfsQueryAllocatedRanges( IrpContext, Irp );
  2591. break;
  2592. case FSCTL_ENCRYPTION_FSCTL_IO :
  2593. Status = NtfsEncryptionFsctl( IrpContext, Irp );
  2594. break;
  2595. case FSCTL_SET_ENCRYPTION :
  2596. Status = NtfsSetEncryption( IrpContext, Irp );
  2597. break;
  2598. case FSCTL_READ_RAW_ENCRYPTED:
  2599. Status = NtfsReadRawEncrypted( IrpContext, Irp );
  2600. break;
  2601. case FSCTL_WRITE_RAW_ENCRYPTED:
  2602. Status = NtfsWriteRawEncrypted( IrpContext, Irp );
  2603. break;
  2604. case FSCTL_EXTEND_VOLUME:
  2605. Status = NtfsExtendVolume( IrpContext, Irp );
  2606. break;
  2607. case FSCTL_READ_FROM_PLEX:
  2608. Status = NtfsReadFromPlex( IrpContext, Irp );
  2609. break;
  2610. case FSCTL_FILE_PREFETCH:
  2611. Status = NtfsPrefetchFile( IrpContext, Irp );
  2612. break;
  2613. default :
  2614. DebugTrace( 0, Dbg, ("Invalid control code -> %08lx\n", FsControlCode) );
  2615. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST );
  2616. break;
  2617. }
  2618. //
  2619. // And return to our caller
  2620. //
  2621. DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) );
  2622. return Status;
  2623. }
  2624. //
  2625. // Local support routine
  2626. //
  2627. NTSTATUS
  2628. NtfsOplockRequest (
  2629. IN PIRP_CONTEXT IrpContext,
  2630. IN PIRP Irp
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. This is the common routine to handle oplock requests made via the
  2635. NtFsControlFile call.
  2636. Arguments:
  2637. Irp - Supplies the Irp being processed
  2638. Return Value:
  2639. NTSTATUS - The return status for the operation
  2640. --*/
  2641. {
  2642. NTSTATUS Status;
  2643. PIO_STACK_LOCATION IrpSp;
  2644. ULONG FsControlCode;
  2645. ULONG OplockCount = 0;
  2646. PFILE_OBJECT FileObject;
  2647. TYPE_OF_OPEN TypeOfOpen;
  2648. PVCB Vcb;
  2649. PFCB Fcb;
  2650. PSCB Scb;
  2651. PCCB Ccb;
  2652. ASSERT_IRP_CONTEXT( IrpContext );
  2653. ASSERT_IRP( Irp );
  2654. PAGED_CODE();
  2655. //
  2656. // Get the current Irp stack location, and save some reference to
  2657. // make life easier
  2658. //
  2659. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2660. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  2661. DebugTrace( +1, Dbg, ("NtfsOplockRequest, FsControlCode = %08lx\n", FsControlCode) );
  2662. //
  2663. // Extract and decode the file object
  2664. //
  2665. FileObject = IrpSp->FileObject;
  2666. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  2667. //
  2668. // We only permit oplock requests on files.
  2669. //
  2670. if ((TypeOfOpen != UserFileOpen) ||
  2671. (SafeNodeType( Scb ) == NTFS_NTC_SCB_MFT)) {
  2672. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2673. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  2674. return STATUS_INVALID_PARAMETER;
  2675. }
  2676. //
  2677. // There should be no output buffer
  2678. //
  2679. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength > 0) {
  2680. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2681. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  2682. return STATUS_INVALID_PARAMETER;
  2683. }
  2684. //
  2685. // We jam Wait to TRUE in the IrpContext. This prevents us from returning
  2686. // STATUS_PENDING if we can't acquire the file. The caller would
  2687. // interpret that as having acquired an oplock.
  2688. //
  2689. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  2690. //
  2691. // Switch on the function control code. We grab the Fcb exclusively
  2692. // for oplock requests, shared for oplock break acknowledgement.
  2693. //
  2694. switch ( FsControlCode ) {
  2695. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  2696. case FSCTL_REQUEST_BATCH_OPLOCK:
  2697. case FSCTL_REQUEST_FILTER_OPLOCK:
  2698. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  2699. NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, 0 );
  2700. if (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
  2701. if (Scb->ScbType.Data.FileLock != NULL) {
  2702. OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Scb->ScbType.Data.FileLock );
  2703. }
  2704. } else {
  2705. OplockCount = Scb->CleanupCount;
  2706. }
  2707. break;
  2708. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  2709. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  2710. case FSCTL_OPLOCK_BREAK_NOTIFY:
  2711. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  2712. NtfsAcquireSharedFcb( IrpContext, Fcb, Scb, 0 );
  2713. break;
  2714. default:
  2715. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2716. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  2717. return STATUS_INVALID_PARAMETER;
  2718. }
  2719. //
  2720. // Use a try finally to free the Fcb.
  2721. //
  2722. try {
  2723. //
  2724. // Call the FsRtl routine to grant/acknowledge oplock.
  2725. //
  2726. Status = FsRtlOplockFsctrl( &Scb->ScbType.Data.Oplock,
  2727. Irp,
  2728. OplockCount );
  2729. //
  2730. // Set the flag indicating if Fast I/O is possible
  2731. //
  2732. NtfsAcquireFsrtlHeader( Scb );
  2733. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  2734. NtfsReleaseFsrtlHeader( Scb );
  2735. } finally {
  2736. DebugUnwind( NtfsOplockRequest );
  2737. //
  2738. // Release all of our resources
  2739. //
  2740. NtfsReleaseFcb( IrpContext, Fcb );
  2741. //
  2742. // If this is not an abnormal termination then complete the irp
  2743. //
  2744. if (!AbnormalTermination()) {
  2745. NtfsCompleteRequest( IrpContext, NULL, 0 );
  2746. }
  2747. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> %08lx\n", Status) );
  2748. }
  2749. return Status;
  2750. }
  2751. NTSTATUS
  2752. NtfsLockVolumeInternal (
  2753. IN PIRP_CONTEXT IrpContext,
  2754. IN PVCB Vcb,
  2755. IN PFILE_OBJECT FileObjectWithVcbLocked,
  2756. IN OUT PULONG Retrying
  2757. )
  2758. /*++
  2759. Routine Description:
  2760. This routine performs the lock volume operation. You should be synchronized
  2761. with checkpoints before calling it
  2762. Arguments:
  2763. Vcb - Supplies the Vcb to lock
  2764. Return Value:
  2765. NTSTATUS - The return status for the operation
  2766. --*/
  2767. {
  2768. NTSTATUS Status = STATUS_SUCCESS;
  2769. BOOLEAN VcbAcquired = FALSE;
  2770. ASSERT_IRP_CONTEXT( IrpContext );
  2771. PAGED_CODE();
  2772. DebugTrace( +1, Dbg, ("NtfsLockVolumeInternal...\n") );
  2773. try {
  2774. #ifdef SYSCACHE_DEBUG
  2775. ULONG SystemHandleCount = 0;
  2776. #endif
  2777. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  2778. VcbAcquired = TRUE;
  2779. #ifdef SYSCACHE_DEBUG
  2780. if (Vcb->SyscacheScb != NULL) {
  2781. SystemHandleCount = Vcb->SyscacheScb->CleanupCount;
  2782. }
  2783. #endif
  2784. //
  2785. // Check if the Vcb is already locked, or if the open file count
  2786. // is greater than 1 (which implies that someone else also is
  2787. // currently using the volume, or a file on the volume). We also fail
  2788. // this request if the volume has already gone through the dismount
  2789. // vcb process.
  2790. //
  2791. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) ||
  2792. #ifdef SYSCACHE_DEBUG
  2793. (Vcb->CleanupCount > 1 + SystemHandleCount)) {
  2794. #else
  2795. (Vcb->CleanupCount > 1)) {
  2796. #endif
  2797. DebugTrace( 0, Dbg, ("Volume is currently in use\n") );
  2798. Status = STATUS_ACCESS_DENIED;
  2799. //
  2800. // If the volume is already locked then it might have been the result of an
  2801. // exclusive DASD open. Allow that user to explictly lock the volume.
  2802. //
  2803. } else if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
  2804. if (FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_LOCK )) {
  2805. DebugTrace( 0, Dbg, ("User has already locked volume\n") );
  2806. Status = STATUS_ACCESS_DENIED;
  2807. } else {
  2808. SetFlag( Vcb->VcbState, VCB_STATE_EXPLICIT_LOCK );
  2809. Status = STATUS_SUCCESS;
  2810. }
  2811. //
  2812. // We can take this path if the volume has already been locked via
  2813. // create but has not taken the PerformDismountOnVcb path. We checked
  2814. // for this above by looking at the VOLUME_MOUNTED flag in the Vcb.
  2815. //
  2816. } else {
  2817. //
  2818. // There better be system files objects only at this point.
  2819. //
  2820. SetFlag( Vcb->VcbState, VCB_STATE_LOCK_IN_PROGRESS );
  2821. if (!NT_SUCCESS( NtfsFlushVolume( IrpContext, Vcb, TRUE, TRUE, TRUE, FALSE ))) {
  2822. DebugTrace( 0, Dbg, ("Volume has user file objects\n") );
  2823. Status = STATUS_ACCESS_DENIED;
  2824. //
  2825. // If there are still user files then try another flush. We're just being kind
  2826. // here. If the lazy writer has a flush queued then the file object can't go
  2827. // away. Let's raise CANT_WAIT and try one more time.
  2828. //
  2829. } else if (Vcb->CloseCount - Vcb->SystemFileCloseCount > 1) {
  2830. //
  2831. // Fail this request if we have already gone through before.
  2832. // Use the next stack location in the Irp as a convenient
  2833. // place to store this information.
  2834. //
  2835. if (*Retrying != 0) {
  2836. DebugTrace( 0, Dbg, ("Volume has user file objects\n") );
  2837. Status = STATUS_ACCESS_DENIED;
  2838. } else {
  2839. *Retrying = 1;
  2840. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  2841. }
  2842. } else {
  2843. //
  2844. // We don't really want to do all of the perform dismount here because
  2845. // that will cause us to remount a new volume before we're ready.
  2846. // At this time we only want to stop the log file and close up our
  2847. // internal attribute streams. When the user (i.e., chkdsk) does an
  2848. // unlock then we'll finish up with the dismount call
  2849. //
  2850. NtfsPerformDismountOnVcb( IrpContext, Vcb, FALSE, NULL );
  2851. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_EXPLICIT_LOCK );
  2852. Vcb->FileObjectWithVcbLocked = FileObjectWithVcbLocked;
  2853. Status = STATUS_SUCCESS;
  2854. }
  2855. }
  2856. } finally {
  2857. DebugUnwind( NtfsLockVolumeInternal );
  2858. if (VcbAcquired) {
  2859. ClearFlag( Vcb->VcbState, VCB_STATE_LOCK_IN_PROGRESS );
  2860. NtfsReleaseVcb( IrpContext, Vcb );
  2861. }
  2862. DebugTrace( -1, Dbg, ("NtfsLockVolumeInternal -> %08lx\n", Status) );
  2863. }
  2864. return Status;
  2865. }
  2866. //
  2867. // Local Support Routine
  2868. //
  2869. NTSTATUS
  2870. NtfsLockVolume (
  2871. IN PIRP_CONTEXT IrpContext,
  2872. IN PIRP Irp
  2873. )
  2874. /*++
  2875. Routine Description:
  2876. This routine performs the lock volume operation. It is responsible for
  2877. either completing of enqueuing the input Irp.
  2878. Arguments:
  2879. Irp - Supplies the Irp to process
  2880. Return Value:
  2881. NTSTATUS - The return status for the operation
  2882. --*/
  2883. {
  2884. NTSTATUS Status = STATUS_SUCCESS;
  2885. PIO_STACK_LOCATION IrpSp;
  2886. PIO_STACK_LOCATION NextIrpSp;
  2887. PFILE_OBJECT FileObject;
  2888. TYPE_OF_OPEN TypeOfOpen;
  2889. PVCB Vcb;
  2890. PFCB Fcb;
  2891. PSCB Scb;
  2892. PCCB Ccb;
  2893. ASSERT_IRP_CONTEXT( IrpContext );
  2894. ASSERT_IRP( Irp );
  2895. PAGED_CODE();
  2896. //
  2897. // Get the current Irp stack location
  2898. //
  2899. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2900. DebugTrace( +1, Dbg, ("NtfsLockVolume...\n") );
  2901. //
  2902. // Extract and decode the file object, and only permit user volume opens
  2903. //
  2904. FileObject = IrpSp->FileObject;
  2905. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  2906. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  2907. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  2908. DebugTrace( -1, Dbg, ("NtfsLockVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  2909. return STATUS_ACCESS_DENIED;
  2910. }
  2911. //
  2912. // If this is the retry path then perform a short delay so that the
  2913. // lazy writer can finish any queued writes.
  2914. //
  2915. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  2916. if (NextIrpSp->Parameters.FileSystemControl.FsControlCode != 0) {
  2917. DebugTrace( 0, Dbg, ("Pausing for retry\n") );
  2918. KeDelayExecutionThread( KernelMode, FALSE, &NtfsLockDelay );
  2919. } else {
  2920. //
  2921. // Notify anyone who wants to close their handles when a lock operation
  2922. // is attempted. We should only do this once per lock request, so don't
  2923. // do it in the retry case.
  2924. //
  2925. DebugTrace( 0, Dbg, ("Sending lock notification\n") );
  2926. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK );
  2927. }
  2928. try {
  2929. NtfsAcquireCheckpointSynchronization( IrpContext, Vcb );
  2930. Status = NtfsLockVolumeInternal( IrpContext,
  2931. Vcb,
  2932. ((PFILE_OBJECT)(((UINT_PTR)IrpSp->FileObject) + 1)),
  2933. &(NextIrpSp->Parameters.FileSystemControl.FsControlCode) );
  2934. } finally {
  2935. DebugUnwind( NtfsLockVolume );
  2936. NtfsReleaseCheckpointSynchronization( IrpContext, Vcb );
  2937. if ((AbnormalTermination() &&
  2938. IrpContext->ExceptionStatus != STATUS_CANT_WAIT &&
  2939. IrpContext->ExceptionStatus != STATUS_LOG_FILE_FULL) ||
  2940. !NT_SUCCESS( Status )) {
  2941. //
  2942. // This lock operation has failed either by raising a status that
  2943. // will keep us from retrying, or else by returning an unsuccessful
  2944. // status. Notify anyone who wants to reopen their handles now.
  2945. // If we're about to retry the lock, we can notify everyone when/if
  2946. // the retry fails.
  2947. //
  2948. DebugTrace( 0, Dbg, ("Sending lock_failed notification\n") );
  2949. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK_FAILED );
  2950. }
  2951. }
  2952. DebugTrace( -1, Dbg, ("NtfsLockVolume -> %08lx\n", Status) );
  2953. NtfsCompleteRequest( IrpContext, Irp, Status );
  2954. return Status;
  2955. }
  2956. NTSTATUS
  2957. NtfsUnlockVolumeInternal (
  2958. IN PIRP_CONTEXT IrpContext,
  2959. IN PVCB Vcb
  2960. )
  2961. /*++
  2962. Routine Description:
  2963. This routine performs the unlock volume operation.
  2964. Arguments:
  2965. Vcb - Supplies the Vcb to unlock
  2966. Return Value:
  2967. NTSTATUS - The return status for the operation
  2968. --*/
  2969. {
  2970. NTSTATUS Status;
  2971. ASSERT_IRP_CONTEXT( IrpContext );
  2972. PAGED_CODE();
  2973. //
  2974. // Acquire exclusive access to the Vcb
  2975. //
  2976. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  2977. try {
  2978. if (FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_LOCK )) {
  2979. NtfsPerformDismountOnVcb( IrpContext, Vcb, TRUE, NULL );
  2980. //
  2981. // Unlock the volume and complete the Irp
  2982. //
  2983. ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_EXPLICIT_LOCK );
  2984. Vcb->FileObjectWithVcbLocked = NULL;
  2985. Status = STATUS_SUCCESS;
  2986. } else {
  2987. Status = STATUS_NOT_LOCKED;
  2988. }
  2989. } finally {
  2990. DebugUnwind( NtfsUnlockVolumeInternal );
  2991. //
  2992. // Release all of our resources
  2993. //
  2994. NtfsReleaseVcb( IrpContext, Vcb );
  2995. DebugTrace( -1, Dbg, ("NtfsUnlockVolumeInternal -> %08lx\n", Status) );
  2996. }
  2997. return Status;
  2998. }
  2999. //
  3000. // Local Support Routine
  3001. //
  3002. NTSTATUS
  3003. NtfsUnlockVolume (
  3004. IN PIRP_CONTEXT IrpContext,
  3005. IN PIRP Irp
  3006. )
  3007. /*++
  3008. Routine Description:
  3009. This routine performs the unlock volume operation. It is responsible for
  3010. either completing of enqueuing the input Irp.
  3011. Arguments:
  3012. Irp - Supplies the Irp to process
  3013. Return Value:
  3014. NTSTATUS - The return status for the operation
  3015. --*/
  3016. {
  3017. NTSTATUS Status;
  3018. PIO_STACK_LOCATION IrpSp;
  3019. PFILE_OBJECT FileObject;
  3020. TYPE_OF_OPEN TypeOfOpen;
  3021. PVCB Vcb;
  3022. PFCB Fcb;
  3023. PSCB Scb;
  3024. PCCB Ccb;
  3025. ASSERT_IRP_CONTEXT( IrpContext );
  3026. ASSERT_IRP( Irp );
  3027. PAGED_CODE();
  3028. //
  3029. // Get the current Irp stack location
  3030. //
  3031. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3032. DebugTrace( +1, Dbg, ("NtfsUnlockVolume...\n") );
  3033. //
  3034. // Extract and decode the file object, and only permit user volume opens
  3035. //
  3036. FileObject = IrpSp->FileObject;
  3037. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3038. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  3039. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  3040. DebugTrace( -1, Dbg, ("NtfsUnlockVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  3041. return STATUS_ACCESS_DENIED;
  3042. }
  3043. Status = NtfsUnlockVolumeInternal( IrpContext, Vcb );
  3044. //
  3045. // Notify anyone who wants to reopen their handles when after the
  3046. // volume is unlocked.
  3047. //
  3048. if (NT_SUCCESS(Status)) {
  3049. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
  3050. }
  3051. NtfsCompleteRequest( IrpContext, Irp, Status );
  3052. DebugTrace( -1, Dbg, ("NtfsUnlockVolume -> %08lx\n", Status) );
  3053. return Status;
  3054. }
  3055. //
  3056. // Local Support Routine
  3057. //
  3058. NTSTATUS
  3059. NtfsDismountVolume (
  3060. IN PIRP_CONTEXT IrpContext,
  3061. IN PIRP Irp
  3062. )
  3063. /*++
  3064. Routine Description:
  3065. This routine performs the dismount volume operation. It is responsible for
  3066. either completing of enqueuing the input Irp.
  3067. Arguments:
  3068. Irp - Supplies the Irp to process
  3069. Return Value:
  3070. NTSTATUS - The return status for the operation
  3071. --*/
  3072. {
  3073. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  3074. PIO_STACK_LOCATION IrpSp;
  3075. BOOLEAN VcbAcquired = FALSE;
  3076. BOOLEAN ExplicitDismount = FALSE;
  3077. PFILE_OBJECT FileObject;
  3078. TYPE_OF_OPEN TypeOfOpen;
  3079. PVCB Vcb;
  3080. PFCB Fcb;
  3081. PSCB Scb;
  3082. PCCB Ccb;
  3083. BOOLEAN ClearCheckpointActive = FALSE;
  3084. ASSERT_IRP_CONTEXT( IrpContext );
  3085. ASSERT_IRP( Irp );
  3086. PAGED_CODE();
  3087. //
  3088. // Get the current Irp stack location
  3089. //
  3090. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3091. DebugTrace( +1, Dbg, ("NtfsDismountVolume...\n") );
  3092. //
  3093. // Extract and decode the file object, and only permit user volume opens
  3094. //
  3095. FileObject = IrpSp->FileObject;
  3096. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3097. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  3098. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  3099. DebugTrace( -1, Dbg, ("NtfsDismountVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  3100. return STATUS_ACCESS_DENIED;
  3101. }
  3102. //
  3103. // Don't notify if we are retrying due to log file full.
  3104. //
  3105. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH )) {
  3106. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT );
  3107. }
  3108. try {
  3109. //
  3110. // Serialize this with the volume checkpoints.
  3111. //
  3112. NtfsAcquireCheckpoint( IrpContext, Vcb );
  3113. while (FlagOn( Vcb->CheckpointFlags, VCB_STOP_LOG_CHECKPOINT )) {
  3114. //
  3115. // Release the checkpoint event because we cannot stop the log file now.
  3116. //
  3117. NtfsReleaseCheckpoint( IrpContext, Vcb );
  3118. NtfsWaitOnCheckpointNotify( IrpContext, Vcb );
  3119. NtfsAcquireCheckpoint( IrpContext, Vcb );
  3120. }
  3121. SetFlag( Vcb->CheckpointFlags, VCB_STOP_LOG_CHECKPOINT );
  3122. NtfsResetCheckpointNotify( IrpContext, Vcb );
  3123. NtfsReleaseCheckpoint( IrpContext, Vcb );
  3124. ClearCheckpointActive = TRUE;
  3125. //
  3126. // Acquire the Vcb exclusively.
  3127. //
  3128. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  3129. VcbAcquired = TRUE;
  3130. //
  3131. // Take special action if there's a pagefile on this volume, or if this is the
  3132. // system volume.
  3133. //
  3134. if (FlagOn( Vcb->VcbState, VCB_STATE_DISALLOW_DISMOUNT )) {
  3135. //
  3136. // If the volume is not locked then fail immediately.
  3137. //
  3138. if (!FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
  3139. try_return( Status = STATUS_ACCESS_DENIED );
  3140. //
  3141. // If there are read-only files only then noop the request. This
  3142. // allows autochk to access the root volume.
  3143. //
  3144. } else if (Vcb->ReadOnlyCloseCount == ((Vcb->CloseCount - Vcb->SystemFileCloseCount) - 1)) {
  3145. DebugTrace( 0, Dbg, ("Volume has readonly files opened\n") );
  3146. try_return( Status = STATUS_SUCCESS );
  3147. }
  3148. }
  3149. //
  3150. // Remember that this is an explicit dismount.
  3151. //
  3152. ExplicitDismount = TRUE;
  3153. //
  3154. // Naturally, we can't dismount the volume if it's already dismounted.
  3155. //
  3156. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3157. //
  3158. // Return success if the user hasn't done an explicit dismount.
  3159. //
  3160. if (!FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_DISMOUNT )) {
  3161. Status = STATUS_SUCCESS;
  3162. } else {
  3163. Status = STATUS_VOLUME_DISMOUNTED;
  3164. }
  3165. try_return( NOTHING );
  3166. }
  3167. //
  3168. // Raise LogFile full once per dismount to force a clean checkpoint
  3169. // freeing logfile space.
  3170. //
  3171. if ((!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH )) &&
  3172. (!NtfsIsVolumeReadOnly( Vcb ))) {
  3173. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH );
  3174. NtfsRaiseStatus( IrpContext, STATUS_LOG_FILE_FULL, NULL, NULL );
  3175. }
  3176. //
  3177. // Get as many cached writes out to disk as we can and mark
  3178. // all the streams for dismount.
  3179. //
  3180. #ifdef BRIANDBG
  3181. try {
  3182. #endif
  3183. NtfsFlushVolume( IrpContext, Vcb, TRUE, TRUE, TRUE, TRUE );
  3184. //
  3185. // Call the function that does the real work. We leave the volume locked
  3186. // so the complete teardown occurs when the handle closes
  3187. //
  3188. NtfsPerformDismountOnVcb( IrpContext, Vcb, FALSE, NULL );
  3189. #ifdef BRIANDBG
  3190. } except( NtfsDismountExceptionFilter( GetExceptionInformation() )) {
  3191. NOTHING
  3192. }
  3193. #endif
  3194. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
  3195. Vcb->FileObjectWithVcbLocked = (PFILE_OBJECT)(((ULONG_PTR)FileObject)+1);
  3196. //
  3197. // Once we get this far the volume is really dismounted. We
  3198. // can ignore errors generated by recursive failures.
  3199. //
  3200. Status = STATUS_SUCCESS;
  3201. //
  3202. // Mark the volume as needs to be verified.
  3203. //
  3204. SetFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  3205. try_exit: NOTHING;
  3206. //
  3207. // Remember that the user did an explicit dismount.
  3208. //
  3209. if ((Status == STATUS_SUCCESS) && ExplicitDismount) {
  3210. SetFlag( Vcb->VcbState, VCB_STATE_EXPLICIT_DISMOUNT );
  3211. }
  3212. } finally {
  3213. DebugUnwind( NtfsDismountVolume );
  3214. if (ClearCheckpointActive) {
  3215. NtfsAcquireCheckpoint( IrpContext, Vcb );
  3216. ClearFlag( Vcb->CheckpointFlags, VCB_STOP_LOG_CHECKPOINT );
  3217. NtfsSetCheckpointNotify( IrpContext, Vcb );
  3218. NtfsReleaseCheckpoint( IrpContext, Vcb );
  3219. }
  3220. //
  3221. // Release all of our resources
  3222. //
  3223. if (VcbAcquired) {
  3224. NtfsReleaseVcb( IrpContext, Vcb );
  3225. }
  3226. if (!NT_SUCCESS( Status ) &&
  3227. (Status != STATUS_VOLUME_DISMOUNTED)) {
  3228. //
  3229. // No need to report the error if this is a retryable error.
  3230. //
  3231. if (!AbnormalTermination() ||
  3232. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH ) ||
  3233. ((IrpContext->ExceptionStatus != STATUS_LOG_FILE_FULL) &&
  3234. (IrpContext->ExceptionStatus != STATUS_CANT_WAIT))) {
  3235. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT_FAILED );
  3236. }
  3237. }
  3238. //
  3239. // If this is an abnormal termination then undo our work, otherwise
  3240. // complete the irp
  3241. //
  3242. if (!AbnormalTermination()) {
  3243. NtfsCompleteRequest( IrpContext, Irp, Status );
  3244. }
  3245. DebugTrace( -1, Dbg, ("NtfsDismountVolume -> %08lx\n", Status) );
  3246. }
  3247. return Status;
  3248. }
  3249. //
  3250. // Local Support Routine
  3251. //
  3252. NTSTATUS
  3253. NtfsIsVolumeMounted (
  3254. IN PIRP_CONTEXT IrpContext,
  3255. IN PIRP Irp
  3256. )
  3257. /*++
  3258. Routine Description:
  3259. This routine returns whether the volume is mounted. It is responsible for
  3260. either completing of enqueuing the input Irp.
  3261. Arguments:
  3262. Irp - Supplies the Irp to process
  3263. Return Value:
  3264. NTSTATUS - The return status for the operation
  3265. --*/
  3266. {
  3267. NTSTATUS Status = STATUS_SUCCESS;
  3268. PIO_STACK_LOCATION IrpSp;
  3269. TYPE_OF_OPEN TypeOfOpen;
  3270. PFILE_OBJECT FileObject;
  3271. PVCB Vcb;
  3272. PFCB Fcb;
  3273. PSCB Scb;
  3274. PCCB Ccb;
  3275. BOOLEAN AcquiredVcb = FALSE;
  3276. ASSERT_IRP_CONTEXT( IrpContext );
  3277. ASSERT_IRP( Irp );
  3278. PAGED_CODE();
  3279. //
  3280. // Get the current Irp stack location
  3281. //
  3282. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3283. DebugTrace( +1, Dbg, ("NtfsIsVolumeMounted...\n") );
  3284. //
  3285. // Extract and decode the file object.
  3286. //
  3287. FileObject = IrpSp->FileObject;
  3288. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3289. if (TypeOfOpen == UnopenedFileObject) {
  3290. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3291. return STATUS_INVALID_PARAMETER;
  3292. }
  3293. //
  3294. // Use a try-finally to release the Vcb if necessary.
  3295. //
  3296. try {
  3297. //
  3298. // If we know the volume is dismounted, we're all done.
  3299. // OK to do this without synchronization as the state can
  3300. // change to unmounted on return to the user.
  3301. //
  3302. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3303. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  3304. }
  3305. //
  3306. // Verify the volume if necessary.
  3307. //
  3308. NtfsPingVolume( IrpContext, Vcb, &AcquiredVcb );
  3309. try_exit: NOTHING;
  3310. } finally {
  3311. DebugUnwind( NtfsIsVolumeMounted );
  3312. //
  3313. // Release the Vcb.
  3314. //
  3315. if (AcquiredVcb) {
  3316. NtfsReleaseVcb( IrpContext, Vcb );
  3317. }
  3318. DebugTrace( -1, Dbg, ("NtfsIsVolumeMounted -> %08lx\n", Status) );
  3319. }
  3320. NtfsCompleteRequest( IrpContext, Irp, Status );
  3321. return Status;
  3322. }
  3323. //
  3324. // Local Support Routine
  3325. //
  3326. NTSTATUS
  3327. NtfsDirtyVolume (
  3328. IN PIRP_CONTEXT IrpContext,
  3329. IN PIRP Irp
  3330. )
  3331. /*++
  3332. Routine Description:
  3333. This routine marks the specified volume dirty.
  3334. Arguments:
  3335. Irp - Supplies the Irp to process
  3336. Return Value:
  3337. NTSTATUS - The return status for the operation
  3338. --*/
  3339. {
  3340. PIO_STACK_LOCATION IrpSp;
  3341. NTSTATUS Status = STATUS_SUCCESS;
  3342. PFILE_OBJECT FileObject;
  3343. TYPE_OF_OPEN TypeOfOpen;
  3344. PVCB Vcb;
  3345. PFCB Fcb;
  3346. PSCB Scb;
  3347. PCCB Ccb;
  3348. ASSERT_IRP_CONTEXT( IrpContext );
  3349. ASSERT_IRP( Irp );
  3350. PAGED_CODE();
  3351. //
  3352. // Get the current Irp stack location
  3353. //
  3354. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3355. DebugTrace( +1, Dbg, ("NtfsDirtyVolume...\n") );
  3356. //
  3357. // Extract and decode the file object, and only permit user volume opens
  3358. //
  3359. FileObject = IrpSp->FileObject;
  3360. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3361. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  3362. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  3363. DebugTrace( -1, Dbg, ("NtfsDirtyVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  3364. return STATUS_ACCESS_DENIED;
  3365. }
  3366. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  3367. try {
  3368. //
  3369. // Fail this request if the volume is not mounted.
  3370. //
  3371. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3372. Status = STATUS_VOLUME_DISMOUNTED;
  3373. } else if (NtfsIsVolumeReadOnly( Vcb )) {
  3374. Status = STATUS_MEDIA_WRITE_PROTECTED;
  3375. } else {
  3376. NtfsPostVcbIsCorrupt( IrpContext, 0, NULL, NULL );
  3377. }
  3378. } finally {
  3379. NtfsReleaseVcb( IrpContext, Vcb );
  3380. }
  3381. NtfsCompleteRequest( IrpContext, Irp, Status );
  3382. DebugTrace( -1, Dbg, ("NtfsDirtyVolume -> STATUS_SUCCESS\n") );
  3383. return Status;
  3384. }
  3385. //
  3386. // Local support routine
  3387. //
  3388. BOOLEAN
  3389. NtfsGetDiskGeometry (
  3390. IN PIRP_CONTEXT IrpContext,
  3391. IN PDEVICE_OBJECT RealDevice,
  3392. IN PDISK_GEOMETRY DiskGeometry,
  3393. IN PLONGLONG Length
  3394. )
  3395. /*++
  3396. Routine Description:
  3397. This procedure gets the disk geometry of the specified device
  3398. Arguments:
  3399. RealDevice - Supplies the real device that is being queried
  3400. DiskGeometry - Receives the disk geometry
  3401. Length - Receives the number of bytes in the partition
  3402. Return Value:
  3403. BOOLEAN - TRUE if the media is write protected, FALSE otherwise
  3404. --*/
  3405. {
  3406. NTSTATUS Status;
  3407. PREVENT_MEDIA_REMOVAL Prevent;
  3408. BOOLEAN WriteProtected = FALSE;
  3409. GET_LENGTH_INFORMATION LengthInfo;
  3410. PAGED_CODE();
  3411. DebugTrace( +1, Dbg, ("NtfsGetDiskGeometry:\n") );
  3412. DebugTrace( 0, Dbg, ("RealDevice = %08lx\n", RealDevice) );
  3413. DebugTrace( 0, Dbg, ("DiskGeometry = %08lx\n", DiskGeometry) );
  3414. //
  3415. // Attempt to lock any removable media, ignoring status.
  3416. //
  3417. Prevent.PreventMediaRemoval = TRUE;
  3418. (VOID)NtfsDeviceIoControl( IrpContext,
  3419. RealDevice,
  3420. IOCTL_DISK_MEDIA_REMOVAL,
  3421. &Prevent,
  3422. sizeof(PREVENT_MEDIA_REMOVAL),
  3423. NULL,
  3424. 0,
  3425. NULL );
  3426. //
  3427. // See if the media is write protected. On success or any kind
  3428. // of error (possibly illegal device function), assume it is
  3429. // writeable, and only complain if he tells us he is write protected.
  3430. //
  3431. Status = NtfsDeviceIoControl( IrpContext,
  3432. RealDevice,
  3433. IOCTL_DISK_IS_WRITABLE,
  3434. NULL,
  3435. 0,
  3436. NULL,
  3437. 0,
  3438. NULL );
  3439. //
  3440. // Remember if the media is write protected but don't raise the error now.
  3441. // If the volume is not Ntfs then let another filesystem try.
  3442. //
  3443. if (Status == STATUS_MEDIA_WRITE_PROTECTED) {
  3444. WriteProtected = TRUE;
  3445. Status = STATUS_SUCCESS;
  3446. }
  3447. Status = NtfsDeviceIoControl( IrpContext,
  3448. RealDevice,
  3449. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  3450. NULL,
  3451. 0,
  3452. DiskGeometry,
  3453. sizeof(DISK_GEOMETRY),
  3454. NULL );
  3455. if (!NT_SUCCESS(Status)) {
  3456. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  3457. }
  3458. Status = NtfsDeviceIoControl( IrpContext,
  3459. RealDevice,
  3460. IOCTL_DISK_GET_LENGTH_INFO,
  3461. NULL,
  3462. 0,
  3463. &LengthInfo,
  3464. sizeof( LengthInfo ),
  3465. NULL );
  3466. if (!NT_SUCCESS(Status)) {
  3467. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  3468. }
  3469. *Length = LengthInfo.Length.QuadPart;
  3470. DebugTrace( -1, Dbg, ("NtfsGetDiskGeometry->VOID\n") );
  3471. return WriteProtected;
  3472. }
  3473. NTSTATUS
  3474. NtfsDeviceIoControl (
  3475. IN PIRP_CONTEXT IrpContext,
  3476. IN PDEVICE_OBJECT DeviceObject,
  3477. IN ULONG IoCtl,
  3478. IN PVOID InputBuffer OPTIONAL,
  3479. IN ULONG InputBufferLength,
  3480. IN PVOID OutputBuffer OPTIONAL,
  3481. IN ULONG OutputBufferLength,
  3482. OUT PULONG_PTR IosbInformation OPTIONAL
  3483. )
  3484. /*++
  3485. Routine Description:
  3486. This procedure issues an Ioctl to the lower device, and waits
  3487. for the answer.
  3488. Arguments:
  3489. DeviceObject - Supplies the device to issue the request to
  3490. IoCtl - Gives the IoCtl to be used
  3491. XxBuffer - Gives the buffer pointer for the ioctl, if any
  3492. XxBufferLength - Gives the length of the buffer, if any
  3493. Return Value:
  3494. None.
  3495. --*/
  3496. {
  3497. PIRP Irp;
  3498. KEVENT Event;
  3499. IO_STATUS_BLOCK Iosb;
  3500. NTSTATUS Status;
  3501. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  3502. Irp = IoBuildDeviceIoControlRequest( IoCtl,
  3503. DeviceObject,
  3504. InputBuffer,
  3505. InputBufferLength,
  3506. OutputBuffer,
  3507. OutputBufferLength,
  3508. FALSE,
  3509. &Event,
  3510. &Iosb );
  3511. if (Irp == NULL) {
  3512. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  3513. }
  3514. Status = IoCallDriver( DeviceObject, Irp );
  3515. if (Status == STATUS_PENDING) {
  3516. (VOID)KeWaitForSingleObject( &Event,
  3517. Executive,
  3518. KernelMode,
  3519. FALSE,
  3520. (PLARGE_INTEGER)NULL );
  3521. Status = Iosb.Status;
  3522. }
  3523. //
  3524. // Get the information field from the completed Irp.
  3525. //
  3526. if ((NT_SUCCESS( Status )) && ARGUMENT_PRESENT( IosbInformation )) {
  3527. *IosbInformation = Iosb.Information;
  3528. }
  3529. return Status;
  3530. }
  3531. //
  3532. // Local support routine
  3533. //
  3534. VOID
  3535. NtfsReadBootSector (
  3536. IN PIRP_CONTEXT IrpContext,
  3537. IN PVCB Vcb,
  3538. OUT PSCB *BootScb,
  3539. OUT PBCB *BootBcb,
  3540. OUT PVOID *BootSector
  3541. )
  3542. /*++
  3543. Routine Description:
  3544. This routine reads and returns a pointer to the boot sector for the volume.
  3545. Volumes formatted under 3.51 and earlier will have a boot sector at sector
  3546. 0 and another halfway through the disk. Volumes formatted with NT 4.0
  3547. will have a boot sector at the end of the disk, in the sector beyond the
  3548. stated size of the volume in the boot sector. When this call is made the
  3549. Vcb has the sector count from the device driver so we subtract one to find
  3550. the last sector.
  3551. Arguments:
  3552. Vcb - Supplies the Vcb for the operation
  3553. BootScb - Receives the Scb for the boot file
  3554. BootBcb - Receives the bcb for the boot sector
  3555. BootSector - Receives a pointer to the boot sector
  3556. Return Value:
  3557. None.
  3558. --*/
  3559. {
  3560. PSCB Scb = NULL;
  3561. BOOLEAN Error = FALSE;
  3562. FILE_REFERENCE FileReference = { BOOT_FILE_NUMBER, 0, BOOT_FILE_NUMBER };
  3563. PAGED_CODE();
  3564. DebugTrace( +1, Dbg, ("NtfsReadBootSector:\n") );
  3565. DebugTrace( 0, Dbg, ("Vcb = %08lx\n", Vcb) );
  3566. //
  3567. // Create a temporary scb for reading in the boot sector and initialize the
  3568. // mcb for it.
  3569. //
  3570. Scb = NtfsCreatePrerestartScb( IrpContext,
  3571. Vcb,
  3572. &FileReference,
  3573. $DATA,
  3574. NULL,
  3575. 0 );
  3576. *BootScb = Scb;
  3577. Scb->Header.AllocationSize.QuadPart =
  3578. Scb->Header.FileSize.QuadPart =
  3579. Scb->Header.ValidDataLength.QuadPart = (PAGE_SIZE * 2) + Vcb->BytesPerSector;
  3580. //
  3581. // We don't want to look up the size for this Scb.
  3582. //
  3583. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  3584. SetFlag( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED );
  3585. (VOID)NtfsAddNtfsMcbEntry( &Scb->Mcb,
  3586. (LONGLONG)0,
  3587. (LONGLONG)0,
  3588. (LONGLONG)Vcb->ClustersPerPage,
  3589. FALSE );
  3590. (VOID)NtfsAddNtfsMcbEntry( &Scb->Mcb,
  3591. (LONGLONG)Vcb->ClustersPerPage,
  3592. Vcb->NumberSectors >> 1,
  3593. (LONGLONG)Vcb->ClustersPerPage,
  3594. FALSE );
  3595. (VOID)NtfsAddNtfsMcbEntry( &Scb->Mcb,
  3596. Int64ShllMod32( (LONGLONG) Vcb->ClustersPerPage, 1 ),
  3597. Vcb->NumberSectors - 1,
  3598. 1,
  3599. FALSE );
  3600. //
  3601. // Try reading in the first boot sector
  3602. //
  3603. try {
  3604. NtfsMapStream( IrpContext,
  3605. Scb,
  3606. (LONGLONG)0,
  3607. Vcb->BytesPerSector,
  3608. BootBcb,
  3609. BootSector );
  3610. //
  3611. // If we got an exception trying to read the first boot sector,
  3612. // then handle the exception by trying to read the second boot
  3613. // sector. If that faults too, then we just allow ourselves to
  3614. // unwind and return the error.
  3615. //
  3616. } except (FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  3617. EXCEPTION_EXECUTE_HANDLER :
  3618. EXCEPTION_CONTINUE_SEARCH) {
  3619. Error = TRUE;
  3620. }
  3621. //
  3622. // Get out if we didn't get an error. Otherwise try the middle sector.
  3623. // We want to read this next because we know that 4.0 format will clear
  3624. // this before writing the last sector. Otherwise we could see a
  3625. // stale boot sector in the last sector even though a 3.51 format was
  3626. // the last to run.
  3627. //
  3628. if (!Error) { return; }
  3629. Error = FALSE;
  3630. try {
  3631. NtfsMapStream( IrpContext,
  3632. Scb,
  3633. (LONGLONG)PAGE_SIZE,
  3634. Vcb->BytesPerSector,
  3635. BootBcb,
  3636. BootSector );
  3637. //
  3638. // Ignore this sector if not Ntfs. This could be the case for
  3639. // a bad sector 0 on a FAT volume.
  3640. //
  3641. if (!NtfsIsBootSectorNtfs( *BootSector, Vcb )) {
  3642. NtfsUnpinBcb( IrpContext, BootBcb );
  3643. Error = TRUE;
  3644. }
  3645. //
  3646. // If we got an exception trying to read the first boot sector,
  3647. // then handle the exception by trying to read the second boot
  3648. // sector. If that faults too, then we just allow ourselves to
  3649. // unwind and return the error.
  3650. //
  3651. } except (FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  3652. EXCEPTION_EXECUTE_HANDLER :
  3653. EXCEPTION_CONTINUE_SEARCH) {
  3654. Error = TRUE;
  3655. }
  3656. //
  3657. // Get out if we didn't get an error. Otherwise try the middle sector.
  3658. //
  3659. if (!Error) { return; }
  3660. NtfsMapStream( IrpContext,
  3661. Scb,
  3662. (LONGLONG) (PAGE_SIZE * 2),
  3663. Vcb->BytesPerSector,
  3664. BootBcb,
  3665. BootSector );
  3666. //
  3667. // Clear the header flag in the Scb.
  3668. //
  3669. ClearFlag( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED );
  3670. //
  3671. // And return to our caller
  3672. //
  3673. DebugTrace( 0, Dbg, ("BootScb > %08lx\n", *BootScb) );
  3674. DebugTrace( 0, Dbg, ("BootBcb > %08lx\n", *BootBcb) );
  3675. DebugTrace( 0, Dbg, ("BootSector > %08lx\n", *BootSector) );
  3676. DebugTrace( -1, Dbg, ("NtfsReadBootSector->VOID\n") );
  3677. return;
  3678. }
  3679. //
  3680. // Local support routine
  3681. //
  3682. //
  3683. // First define a local macro to number the tests for the debug case.
  3684. //
  3685. #ifdef NTFSDBG
  3686. #define NextTest ++CheckNumber &&
  3687. #else
  3688. #define NextTest TRUE &&
  3689. #endif
  3690. BOOLEAN
  3691. NtfsIsBootSectorNtfs (
  3692. IN PPACKED_BOOT_SECTOR BootSector,
  3693. IN PVCB Vcb
  3694. )
  3695. /*++
  3696. Routine Description:
  3697. This routine checks the boot sector to determine if it is an NTFS partition.
  3698. The Vcb must alread be initialized from the device object to contain the
  3699. parts of the device geometry we care about here: bytes per sector and
  3700. total number of sectors in the partition.
  3701. Arguments:
  3702. BootSector - Pointer to the boot sector which has been read in.
  3703. Vcb - Pointer to a Vcb which has been initialized with sector size and
  3704. number of sectors on the partition.
  3705. Return Value:
  3706. FALSE - If the boot sector is not for Ntfs.
  3707. TRUE - If the boot sector is for Ntfs.
  3708. --*/
  3709. {
  3710. #ifdef NTFSDBG
  3711. ULONG CheckNumber = 0;
  3712. #endif
  3713. // PULONG l;
  3714. // ULONG Checksum = 0;
  3715. PAGED_CODE();
  3716. DebugTrace( +1, Dbg, ("NtfsIsBootSectorNtfs\n") );
  3717. DebugTrace( 0, Dbg, ("BootSector = %08lx\n", BootSector) );
  3718. //
  3719. // First calculate the boot sector checksum
  3720. //
  3721. //
  3722. // for (l = (PULONG)BootSector; l < (PULONG)&BootSector->Checksum; l++) {
  3723. // Checksum += *l;
  3724. // }
  3725. //
  3726. // Now perform all the checks, starting with the Name and Checksum.
  3727. // The remaining checks should be obvious, including some fields which
  3728. // must be 0 and other fields which must be a small power of 2.
  3729. //
  3730. if (NextTest
  3731. (BootSector->Oem[0] == 'N') &&
  3732. (BootSector->Oem[1] == 'T') &&
  3733. (BootSector->Oem[2] == 'F') &&
  3734. (BootSector->Oem[3] == 'S') &&
  3735. (BootSector->Oem[4] == ' ') &&
  3736. (BootSector->Oem[5] == ' ') &&
  3737. (BootSector->Oem[6] == ' ') &&
  3738. (BootSector->Oem[7] == ' ')
  3739. &&
  3740. // NextTest
  3741. // (BootSector->Checksum == Checksum)
  3742. //
  3743. // &&
  3744. //
  3745. // Check number of bytes per sector. The low order byte of this
  3746. // number must be zero (smallest sector size = 0x100) and the
  3747. // high order byte shifted must equal the bytes per sector gotten
  3748. // from the device and stored in the Vcb. And just to be sure,
  3749. // sector size must be less than page size.
  3750. //
  3751. NextTest
  3752. (BootSector->PackedBpb.BytesPerSector[0] == 0)
  3753. &&
  3754. NextTest
  3755. ((ULONG)(BootSector->PackedBpb.BytesPerSector[1] << 8) == Vcb->BytesPerSector)
  3756. &&
  3757. NextTest
  3758. (BootSector->PackedBpb.BytesPerSector[1] << 8 <= PAGE_SIZE)
  3759. &&
  3760. //
  3761. // Sectors per cluster must be a power of 2.
  3762. //
  3763. NextTest
  3764. ((BootSector->PackedBpb.SectorsPerCluster[0] == 0x1) ||
  3765. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x2) ||
  3766. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x4) ||
  3767. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x8) ||
  3768. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x10) ||
  3769. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x20) ||
  3770. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x40) ||
  3771. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x80))
  3772. &&
  3773. //
  3774. // These fields must all be zero. For both Fat and HPFS, some of
  3775. // these fields must be nonzero.
  3776. //
  3777. NextTest
  3778. (BootSector->PackedBpb.ReservedSectors[0] == 0) &&
  3779. (BootSector->PackedBpb.ReservedSectors[1] == 0) &&
  3780. (BootSector->PackedBpb.Fats[0] == 0) &&
  3781. (BootSector->PackedBpb.RootEntries[0] == 0) &&
  3782. (BootSector->PackedBpb.RootEntries[1] == 0) &&
  3783. (BootSector->PackedBpb.Sectors[0] == 0) &&
  3784. (BootSector->PackedBpb.Sectors[1] == 0) &&
  3785. (BootSector->PackedBpb.SectorsPerFat[0] == 0) &&
  3786. (BootSector->PackedBpb.SectorsPerFat[1] == 0) &&
  3787. // (BootSector->PackedBpb.HiddenSectors[0] == 0) &&
  3788. // (BootSector->PackedBpb.HiddenSectors[1] == 0) &&
  3789. // (BootSector->PackedBpb.HiddenSectors[2] == 0) &&
  3790. // (BootSector->PackedBpb.HiddenSectors[3] == 0) &&
  3791. (BootSector->PackedBpb.LargeSectors[0] == 0) &&
  3792. (BootSector->PackedBpb.LargeSectors[1] == 0) &&
  3793. (BootSector->PackedBpb.LargeSectors[2] == 0) &&
  3794. (BootSector->PackedBpb.LargeSectors[3] == 0)
  3795. &&
  3796. //
  3797. // Number of Sectors cannot be greater than the number of sectors
  3798. // on the partition.
  3799. //
  3800. NextTest
  3801. (BootSector->NumberSectors <= Vcb->NumberSectors)
  3802. &&
  3803. //
  3804. // Check that both Lcn values are for sectors within the partition.
  3805. //
  3806. NextTest
  3807. ((BootSector->MftStartLcn * BootSector->PackedBpb.SectorsPerCluster[0]) <=
  3808. Vcb->NumberSectors)
  3809. &&
  3810. NextTest
  3811. ((BootSector->Mft2StartLcn * BootSector->PackedBpb.SectorsPerCluster[0]) <=
  3812. Vcb->NumberSectors)
  3813. &&
  3814. //
  3815. // Clusters per file record segment and default clusters for Index
  3816. // Allocation Buffers must be a power of 2. A zero indicates that the
  3817. // size of these structures is the default size.
  3818. //
  3819. NextTest
  3820. (((BootSector->ClustersPerFileRecordSegment >= -31) &&
  3821. (BootSector->ClustersPerFileRecordSegment <= -9)) ||
  3822. (BootSector->ClustersPerFileRecordSegment == 0x1) ||
  3823. (BootSector->ClustersPerFileRecordSegment == 0x2) ||
  3824. (BootSector->ClustersPerFileRecordSegment == 0x4) ||
  3825. (BootSector->ClustersPerFileRecordSegment == 0x8) ||
  3826. (BootSector->ClustersPerFileRecordSegment == 0x10) ||
  3827. (BootSector->ClustersPerFileRecordSegment == 0x20) ||
  3828. (BootSector->ClustersPerFileRecordSegment == 0x40))
  3829. &&
  3830. NextTest
  3831. (((BootSector->DefaultClustersPerIndexAllocationBuffer >= -31) &&
  3832. (BootSector->DefaultClustersPerIndexAllocationBuffer <= -9)) ||
  3833. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x1) ||
  3834. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x2) ||
  3835. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x4) ||
  3836. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x8) ||
  3837. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x10) ||
  3838. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x20) ||
  3839. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x40))) {
  3840. DebugTrace( -1, Dbg, ("NtfsIsBootSectorNtfs->TRUE\n") );
  3841. return TRUE;
  3842. } else {
  3843. //
  3844. // If a check failed, print its check number with Debug Trace.
  3845. //
  3846. DebugTrace( 0, Dbg, ("Boot Sector failed test number %08lx\n", CheckNumber) );
  3847. DebugTrace( -1, Dbg, ("NtfsIsBootSectorNtfs->FALSE\n") );
  3848. return FALSE;
  3849. }
  3850. }
  3851. //
  3852. // Local support routine
  3853. //
  3854. VOID
  3855. NtfsGetVolumeInformation (
  3856. IN PIRP_CONTEXT IrpContext,
  3857. IN PVPB Vpb OPTIONAL,
  3858. IN PVCB Vcb,
  3859. OUT PUSHORT VolumeFlags
  3860. )
  3861. /*++
  3862. Routine Description:
  3863. This routine gets the serial number and volume label for an NTFS volume. It also
  3864. returns the current volume flags for the volume.
  3865. Arguments:
  3866. Vpb - Supplies the Vpb for the volume. The Vpb will receive a copy of
  3867. the volume label and serial number, if a Vpb is specified.
  3868. Vcb - Supplies the Vcb for the operation.
  3869. VolumeFlags - Address to store the current volume flags.
  3870. Return Value:
  3871. None.
  3872. --*/
  3873. {
  3874. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  3875. PVOLUME_INFORMATION VolumeInformation;
  3876. PAGED_CODE();
  3877. DebugTrace( 0, Dbg, ("NtfsGetVolumeInformation...\n") );
  3878. *VolumeFlags = 0;
  3879. //
  3880. // We read in the volume label attribute to get the volume label.
  3881. //
  3882. try {
  3883. if (ARGUMENT_PRESENT(Vpb)) {
  3884. NtfsInitializeAttributeContext( &AttributeContext );
  3885. if (NtfsLookupAttributeByCode( IrpContext,
  3886. Vcb->VolumeDasdScb->Fcb,
  3887. &Vcb->VolumeDasdScb->Fcb->FileReference,
  3888. $VOLUME_NAME,
  3889. &AttributeContext )) {
  3890. Vpb->VolumeLabelLength = (USHORT)
  3891. NtfsFoundAttribute( &AttributeContext )->Form.Resident.ValueLength;
  3892. if ( Vpb->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH) {
  3893. Vpb->VolumeLabelLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  3894. }
  3895. RtlCopyMemory( &Vpb->VolumeLabel[0],
  3896. NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ) ),
  3897. Vpb->VolumeLabelLength );
  3898. } else {
  3899. Vpb->VolumeLabelLength = 0;
  3900. }
  3901. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  3902. }
  3903. NtfsInitializeAttributeContext( &AttributeContext );
  3904. //
  3905. // Remember if the volume is dirty when we are mounting it.
  3906. //
  3907. if (NtfsLookupAttributeByCode( IrpContext,
  3908. Vcb->VolumeDasdScb->Fcb,
  3909. &Vcb->VolumeDasdScb->Fcb->FileReference,
  3910. $VOLUME_INFORMATION,
  3911. &AttributeContext )) {
  3912. VolumeInformation =
  3913. (PVOLUME_INFORMATION)NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  3914. if (FlagOn(VolumeInformation->VolumeFlags, VOLUME_DIRTY)) {
  3915. SetFlag( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY );
  3916. } else {
  3917. ClearFlag( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY );
  3918. }
  3919. *VolumeFlags = VolumeInformation->VolumeFlags;
  3920. }
  3921. } finally {
  3922. DebugUnwind( NtfsGetVolumeInformation );
  3923. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  3924. }
  3925. //
  3926. // And return to our caller
  3927. //
  3928. return;
  3929. }
  3930. //
  3931. // Local support routine
  3932. //
  3933. VOID
  3934. NtfsSetAndGetVolumeTimes (
  3935. IN PIRP_CONTEXT IrpContext,
  3936. IN PVCB Vcb,
  3937. IN BOOLEAN MarkDirty,
  3938. IN BOOLEAN UpdateInTransaction
  3939. )
  3940. /*++
  3941. Routine Description:
  3942. This routine reads in the volume times from the standard information attribute
  3943. of the volume file and also updates the access time to be the current
  3944. time
  3945. Arguments:
  3946. Vcb - Supplies the vcb for the operation.
  3947. MarkDirty - Supplies TRUE if volume is to be marked dirty
  3948. UpdateInTransaction - Indicates if we should mark the volume dirty in a transaction.
  3949. Return Value:
  3950. None.
  3951. --*/
  3952. {
  3953. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  3954. PSTANDARD_INFORMATION StandardInformation;
  3955. LONGLONG MountTime;
  3956. PAGED_CODE();
  3957. DebugTrace( 0, Dbg, ("NtfsSetAndGetVolumeTimes...\n") );
  3958. try {
  3959. //
  3960. // Lookup the standard information attribute of the dasd file
  3961. //
  3962. NtfsInitializeAttributeContext( &AttributeContext );
  3963. if (!NtfsLookupAttributeByCode( IrpContext,
  3964. Vcb->VolumeDasdScb->Fcb,
  3965. &Vcb->VolumeDasdScb->Fcb->FileReference,
  3966. $STANDARD_INFORMATION,
  3967. &AttributeContext )) {
  3968. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  3969. }
  3970. StandardInformation = (PSTANDARD_INFORMATION)NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  3971. //
  3972. // Get the current time and make sure it differs from the time stored
  3973. // in last access time and then store the new last access time
  3974. //
  3975. NtfsGetCurrentTime( IrpContext, MountTime );
  3976. if (MountTime == StandardInformation->LastAccessTime) {
  3977. MountTime = MountTime + 1;
  3978. }
  3979. //****
  3980. //**** Hold back on the update for now.
  3981. //****
  3982. //**** NtfsChangeAttributeValue( IrpContext,
  3983. //**** Vcb->VolumeDasdScb->Fcb,
  3984. //**** FIELD_OFFSET(STANDARD_INFORMATION, LastAccessTime),
  3985. //**** &MountTime,
  3986. //**** sizeof(MountTime),
  3987. //**** FALSE,
  3988. //**** FALSE,
  3989. //**** &AttributeContext );
  3990. //
  3991. // Now save all the time fields in our vcb
  3992. //
  3993. Vcb->VolumeCreationTime = StandardInformation->CreationTime;
  3994. Vcb->VolumeLastModificationTime = StandardInformation->LastModificationTime;
  3995. Vcb->VolumeLastChangeTime = StandardInformation->LastChangeTime;
  3996. Vcb->VolumeLastAccessTime = StandardInformation->LastAccessTime; //****Also hold back = MountTime;
  3997. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  3998. //
  3999. // If the volume was mounted dirty, then set the dirty bit here.
  4000. //
  4001. if (MarkDirty) {
  4002. NtfsMarkVolumeDirty( IrpContext, Vcb, UpdateInTransaction );
  4003. }
  4004. } finally {
  4005. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  4006. }
  4007. //
  4008. // And return to our caller
  4009. //
  4010. return;
  4011. }
  4012. //
  4013. // Local support routine
  4014. //
  4015. VOID
  4016. NtfsOpenSystemFile (
  4017. IN PIRP_CONTEXT IrpContext,
  4018. IN OUT PSCB *Scb,
  4019. IN PVCB Vcb,
  4020. IN ULONG FileNumber,
  4021. IN LONGLONG Size,
  4022. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  4023. IN BOOLEAN ModifiedNoWrite
  4024. )
  4025. /*++
  4026. Routine Description:
  4027. This routine is called to open one of the system files by its file number
  4028. during the mount process. An initial allocation is looked up for the file,
  4029. unless the optional initial size is specified (in which case this size is
  4030. used).
  4031. Parameters:
  4032. Scb - Pointer to where the Scb pointer is to be stored. If Scb pointer
  4033. pointed to is NULL, then a PreRestart Scb is created, otherwise the
  4034. existing Scb is used and only the stream file is set up.
  4035. FileNumber - Number of the system file to open.
  4036. Size - If nonzero, this size is used as the initial size, rather
  4037. than consulting the file record in the Mft.
  4038. AttributeTypeCode - Supplies the attribute to open, e.g., $DATA or $BITMAP
  4039. ModifiedNoWrite - Indicates if the Memory Manager is not to write this
  4040. attribute to disk. Applies to streams under transaction
  4041. control.
  4042. Return Value:
  4043. None.
  4044. --*/
  4045. {
  4046. FILE_REFERENCE FileReference;
  4047. UNICODE_STRING $BadName;
  4048. PUNICODE_STRING AttributeName = NULL;
  4049. PAGED_CODE();
  4050. DebugTrace( +1, Dbg, ("NtfsOpenSystemFile:\n") );
  4051. DebugTrace( 0, Dbg, ("*Scb = %08lx\n", *Scb) );
  4052. DebugTrace( 0, Dbg, ("FileNumber = %08lx\n", FileNumber) );
  4053. DebugTrace( 0, Dbg, ("ModifiedNoWrite = %04x\n", ModifiedNoWrite) );
  4054. //
  4055. // The Bad Cluster data attribute has a name.
  4056. //
  4057. if (FileNumber == BAD_CLUSTER_FILE_NUMBER) {
  4058. RtlInitUnicodeString( &$BadName, L"$Bad" );
  4059. AttributeName = &$BadName;
  4060. }
  4061. //
  4062. // If the Scb does not already exist, create it.
  4063. //
  4064. if (*Scb == NULL) {
  4065. NtfsSetSegmentNumber( &FileReference, 0, FileNumber );
  4066. FileReference.SequenceNumber = (FileNumber == 0 ? 1 : (USHORT)FileNumber);
  4067. //
  4068. // Create the Scb.
  4069. //
  4070. *Scb = NtfsCreatePrerestartScb( IrpContext,
  4071. Vcb,
  4072. &FileReference,
  4073. AttributeTypeCode,
  4074. AttributeName,
  4075. 0 );
  4076. NtfsAcquireExclusiveScb( IrpContext, *Scb );
  4077. }
  4078. //
  4079. // Set the modified-no-write bit in the Scb if necessary.
  4080. //
  4081. if (ModifiedNoWrite) {
  4082. SetFlag( (*Scb)->ScbState, SCB_STATE_MODIFIED_NO_WRITE );
  4083. }
  4084. //
  4085. // Lookup the file sizes.
  4086. //
  4087. if (Size == 0) {
  4088. NtfsUpdateScbFromAttribute( IrpContext, *Scb, NULL );
  4089. //
  4090. // Make sure the file size isn't larger than allocation size.
  4091. //
  4092. if ((*Scb)->Header.FileSize.QuadPart > (*Scb)->Header.AllocationSize.QuadPart) {
  4093. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, (*Scb)->Fcb );
  4094. }
  4095. //
  4096. // Otherwise, just set the size we were given.
  4097. //
  4098. } else {
  4099. (*Scb)->Header.FileSize.QuadPart =
  4100. (*Scb)->Header.ValidDataLength.QuadPart = Size;
  4101. (*Scb)->Header.AllocationSize.QuadPart = LlClustersFromBytes( Vcb, Size );
  4102. (*Scb)->Header.AllocationSize.QuadPart = LlBytesFromClusters( Vcb,
  4103. (*Scb)->Header.AllocationSize.QuadPart );
  4104. SetFlag( (*Scb)->ScbState, SCB_STATE_HEADER_INITIALIZED );
  4105. }
  4106. //
  4107. // Make sure that our system streams are not marked as compressed.
  4108. //
  4109. if (AttributeTypeCode != $INDEX_ALLOCATION) {
  4110. ClearFlag( (*Scb)->ScbState, SCB_STATE_WRITE_COMPRESSED );
  4111. ClearFlag( (*Scb)->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  4112. if (!FlagOn( (*Scb)->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  4113. (*Scb)->CompressionUnit = 0;
  4114. (*Scb)->CompressionUnitShift = 0;
  4115. }
  4116. }
  4117. //
  4118. // Finally, create the stream, if not already there.
  4119. // And check if we should increment the counters
  4120. // If this is the volume file or the bad cluster file, we only increment the counts.
  4121. //
  4122. if ((FileNumber == VOLUME_DASD_NUMBER) ||
  4123. (FileNumber == BAD_CLUSTER_FILE_NUMBER)) {
  4124. if ((*Scb)->FileObject == 0) {
  4125. NtfsIncrementCloseCounts( *Scb, TRUE, FALSE );
  4126. (*Scb)->FileObject = (PFILE_OBJECT) 1;
  4127. }
  4128. } else {
  4129. NtfsCreateInternalAttributeStream( IrpContext,
  4130. *Scb,
  4131. TRUE,
  4132. &NtfsSystemFiles[FileNumber] );
  4133. }
  4134. DebugTrace( 0, Dbg, ("*Scb > %08lx\n", *Scb) );
  4135. DebugTrace( -1, Dbg, ("NtfsOpenSystemFile -> VOID\n") );
  4136. return;
  4137. }
  4138. //
  4139. // Local support routine
  4140. //
  4141. VOID
  4142. NtfsOpenRootDirectory (
  4143. IN PIRP_CONTEXT IrpContext,
  4144. IN PVCB Vcb
  4145. )
  4146. /*++
  4147. Routine Description:
  4148. This routine opens the root directory by file number, and fills in the
  4149. related pointers in the Vcb.
  4150. Arguments:
  4151. Vcb - Pointer to the Vcb for the volume
  4152. Return Value:
  4153. None.
  4154. --*/
  4155. {
  4156. PFCB RootFcb;
  4157. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  4158. FILE_REFERENCE FileReference;
  4159. BOOLEAN MustBeFalse;
  4160. PAGED_CODE();
  4161. //
  4162. // Put special code here to do initial open of Root Index.
  4163. //
  4164. RootFcb = NtfsCreateRootFcb( IrpContext, Vcb );
  4165. NtfsSetSegmentNumber( &FileReference, 0, ROOT_FILE_NAME_INDEX_NUMBER );
  4166. FileReference.SequenceNumber = ROOT_FILE_NAME_INDEX_NUMBER;
  4167. //
  4168. // Now create its Scb and acquire it exclusive.
  4169. //
  4170. Vcb->RootIndexScb = NtfsCreateScb( IrpContext,
  4171. RootFcb,
  4172. $INDEX_ALLOCATION,
  4173. &NtfsFileNameIndex,
  4174. FALSE,
  4175. &MustBeFalse );
  4176. //
  4177. // Now allocate a buffer to hold the normalized name for the root.
  4178. //
  4179. Vcb->RootIndexScb->ScbType.Index.NormalizedName.Buffer = NtfsAllocatePool( PagedPool, 2 );
  4180. Vcb->RootIndexScb->ScbType.Index.NormalizedName.MaximumLength =
  4181. Vcb->RootIndexScb->ScbType.Index.NormalizedName.Length = 2;
  4182. Vcb->RootIndexScb->ScbType.Index.NormalizedName.Buffer[0] = '\\';
  4183. Vcb->RootIndexScb->ScbType.Index.HashValue = 0;
  4184. NtfsConvertNameToHash( Vcb->RootIndexScb->ScbType.Index.NormalizedName.Buffer,
  4185. sizeof( WCHAR ),
  4186. Vcb->UpcaseTable,
  4187. &Vcb->RootIndexScb->ScbType.Index.HashValue );
  4188. NtfsAcquireExclusiveScb( IrpContext, Vcb->RootIndexScb );
  4189. //
  4190. // Lookup the attribute and it better be there
  4191. //
  4192. NtfsInitializeAttributeContext( &Context );
  4193. //
  4194. // Use a try-finally to facilitate cleanup.
  4195. //
  4196. try {
  4197. if (!NtfsLookupAttributeByCode( IrpContext,
  4198. RootFcb,
  4199. &FileReference,
  4200. $INDEX_ROOT,
  4201. &Context ) ) {
  4202. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  4203. }
  4204. //
  4205. // We need to update the duplicated information in the
  4206. // Fcb.
  4207. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, RootFcb, NULL );
  4208. //
  4209. // Initialize the Scb. Force it to refer to a file name.
  4210. //
  4211. NtfsUpdateIndexScbFromAttribute( IrpContext,
  4212. Vcb->RootIndexScb,
  4213. NtfsFoundAttribute( &Context ),
  4214. TRUE );
  4215. } finally {
  4216. NtfsCleanupAttributeContext( IrpContext, &Context );
  4217. }
  4218. return;
  4219. }
  4220. //
  4221. // Local support routine
  4222. //
  4223. VOID
  4224. NtfsInitializeSecurityFile (
  4225. IN PIRP_CONTEXT IrpContext,
  4226. IN PVCB Vcb
  4227. )
  4228. /*++
  4229. Routine Description:
  4230. This routine creates/opens the security file, and initializes the security
  4231. support.
  4232. Arguments:
  4233. Vcb - Pointer to the Vcb for the volume
  4234. Return Value:
  4235. None.
  4236. --*/
  4237. {
  4238. PFCB Fcb;
  4239. FILE_REFERENCE FileReference;
  4240. //
  4241. // Set the file number for the security file.
  4242. //
  4243. NtfsSetSegmentNumber( &FileReference, 0, SECURITY_FILE_NUMBER );
  4244. FileReference.SequenceNumber = SECURITY_FILE_NUMBER;
  4245. //
  4246. // Create the Fcb.
  4247. //
  4248. Fcb = NtfsCreateFcb( IrpContext,
  4249. Vcb,
  4250. FileReference,
  4251. FALSE,
  4252. TRUE,
  4253. NULL );
  4254. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  4255. //
  4256. // Use a try-finally to facilitate cleanup.
  4257. //
  4258. try {
  4259. //
  4260. // Now call the Security system to initialize itself.
  4261. //
  4262. NtfsInitializeSecurity( IrpContext, Vcb, Fcb );
  4263. } finally {
  4264. //
  4265. // If some error caused him to not get any Scbs created, then delete
  4266. // the Fcb, because we are the only ones who will.
  4267. //
  4268. if (IsListEmpty(&Fcb->ScbQueue)) {
  4269. BOOLEAN AcquiredFcbTable = TRUE;
  4270. NtfsAcquireFcbTable( IrpContext, Vcb );
  4271. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4272. ASSERT(!AcquiredFcbTable);
  4273. }
  4274. }
  4275. }
  4276. //
  4277. // Local support routine
  4278. //
  4279. VOID
  4280. NtfsUpgradeSecurity (
  4281. IN PIRP_CONTEXT IrpContext,
  4282. IN PVCB Vcb
  4283. )
  4284. /*++
  4285. Routine Description:
  4286. This routine upgrades the security descriptors and names for system
  4287. scbs.
  4288. Arguments:
  4289. Vcb - Pointer to the Vcb for the volume
  4290. Return Value:
  4291. None.
  4292. --*/
  4293. {
  4294. PFCB Fcb = Vcb->SecurityDescriptorStream->Fcb;
  4295. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  4296. PSCB *ScbPtr;
  4297. //
  4298. // Get set for some attribute lookups/creates
  4299. //
  4300. NtfsInitializeAttributeContext( &Context );
  4301. //
  4302. // Use a try-finally to facilitate cleanup.
  4303. //
  4304. try {
  4305. struct {
  4306. FILE_NAME FileName;
  4307. WCHAR FileNameChars[10];
  4308. } FileNameAttr;
  4309. PFILE_NAME CurrentFileName;
  4310. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  4311. //
  4312. // Initialize a FileName attribute for this file.
  4313. //
  4314. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  4315. FileNameAttr.FileName.ParentDirectory = Fcb->FileReference;
  4316. FileNameAttr.FileName.FileNameLength = 7;
  4317. RtlCopyMemory( FileNameAttr.FileName.FileName, L"$Secure", 14 );
  4318. ASSERT_EXCLUSIVE_FCB( Fcb );
  4319. //
  4320. // If this file still has an unnamed data attribute from format, delete it.
  4321. //
  4322. if (NtfsLookupAttributeByName( IrpContext,
  4323. Fcb,
  4324. &Fcb->FileReference,
  4325. $DATA,
  4326. &NoName,
  4327. NULL,
  4328. FALSE,
  4329. &Context ) ) {
  4330. NtfsDeleteAttributeRecord( IrpContext,
  4331. Fcb,
  4332. DELETE_LOG_OPERATION |
  4333. DELETE_RELEASE_FILE_RECORD |
  4334. DELETE_RELEASE_ALLOCATION,
  4335. &Context );
  4336. }
  4337. NtfsCleanupAttributeContext( IrpContext, &Context );
  4338. //
  4339. // If there is an old name from format, remove it and put the right one there.
  4340. //
  4341. NtfsInitializeAttributeContext( &Context );
  4342. if (NtfsLookupAttributeByCode( IrpContext,
  4343. Fcb,
  4344. &Fcb->FileReference,
  4345. $FILE_NAME,
  4346. &Context ) &&
  4347. (((CurrentFileName = (PFILE_NAME)NtfsAttributeValue(NtfsFoundAttribute(&Context)))->FileNameLength != 7) ||
  4348. (RtlCompareMemory(CurrentFileName->FileName, FileNameAttr.FileName.FileName, 14) != 14))) {
  4349. UCHAR FileNameFlags;
  4350. UNICODE_STRING LinkName;
  4351. LinkName.Length = LinkName.MaximumLength = CurrentFileName->FileNameLength * sizeof( WCHAR );
  4352. LinkName.Buffer = CurrentFileName->FileName;
  4353. //
  4354. // Yank the old name.
  4355. //
  4356. NtfsRemoveLink( IrpContext, Fcb, Vcb->RootIndexScb, LinkName, NULL, NULL );
  4357. //
  4358. // Create the new name.
  4359. //
  4360. NtfsAddLink( IrpContext,
  4361. TRUE,
  4362. Vcb->RootIndexScb,
  4363. Fcb,
  4364. (PFILE_NAME)&FileNameAttr,
  4365. NULL,
  4366. &FileNameFlags,
  4367. NULL,
  4368. NULL,
  4369. NULL );
  4370. }
  4371. } finally {
  4372. NtfsCleanupAttributeContext( IrpContext, &Context );
  4373. }
  4374. //
  4375. // To free some space in our system file records, let's verify that their security
  4376. // is converted.
  4377. //
  4378. // **** conditionalize now until chkdsk supports the new security.
  4379. //
  4380. for (ScbPtr = &Vcb->MftScb; ScbPtr < &Vcb->MftBitmapScb; ScbPtr++) {
  4381. PFCB SystemFcb;
  4382. //
  4383. // Do only Scb's that are currently open
  4384. //
  4385. if (*ScbPtr == NULL)
  4386. continue;
  4387. SystemFcb = (*ScbPtr)->Fcb;
  4388. //
  4389. // Skip the root index and volume dasd for backwards compatibility.
  4390. //
  4391. if (SystemFcb == NULL ||
  4392. ScbPtr == &Vcb->RootIndexScb ||
  4393. ScbPtr == &Vcb->VolumeDasdScb) {
  4394. continue;
  4395. }
  4396. //
  4397. // Initialize the Fcb and load the security descriptor.
  4398. //
  4399. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, SystemFcb, NULL );
  4400. //
  4401. // Skip this Fcb if we've already given it an Id or if it has no
  4402. // security whatsoever.
  4403. //
  4404. if (SystemFcb->SecurityId != SECURITY_ID_INVALID ||
  4405. SystemFcb->SharedSecurity == NULL) {
  4406. continue;
  4407. }
  4408. //
  4409. // Delete the $SECURITY_DESCRIPTOR attribute if it has one
  4410. //
  4411. NtfsInitializeAttributeContext( &Context );
  4412. try {
  4413. //
  4414. // Find the $SECURITY_DESCRIPTOR attribute.
  4415. //
  4416. if (NtfsLookupAttributeByCode( IrpContext,
  4417. SystemFcb,
  4418. &SystemFcb->FileReference,
  4419. $SECURITY_DESCRIPTOR,
  4420. &Context )) {
  4421. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  4422. PSCB Scb;
  4423. DebugTrace( 0, DbgAcl, ("NtfsUpgradeSecurity deleting existing Security Descriptor\n") );
  4424. NtfsDeleteAttributeRecord( IrpContext,
  4425. SystemFcb,
  4426. DELETE_LOG_OPERATION |
  4427. DELETE_RELEASE_FILE_RECORD |
  4428. DELETE_RELEASE_ALLOCATION,
  4429. &Context );
  4430. //
  4431. // If the $SECURITY_DESCRIPTOR was non resident, the above
  4432. // delete call created one for us under the covers. We
  4433. // need to mark it as deleted otherwise, we detect the
  4434. // volume as being corrupt.
  4435. //
  4436. Scb = NtfsCreateScb( IrpContext,
  4437. SystemFcb,
  4438. $SECURITY_DESCRIPTOR,
  4439. &NoName,
  4440. TRUE,
  4441. NULL );
  4442. if (Scb != NULL) {
  4443. ASSERT_EXCLUSIVE_SCB( Scb );
  4444. SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  4445. }
  4446. }
  4447. } finally {
  4448. NtfsCleanupAttributeContext( IrpContext, &Context );
  4449. }
  4450. //
  4451. // Make sure we have a large $STANDARD_INFORMATION for this file
  4452. //
  4453. if (!FlagOn( SystemFcb->FcbState, FCB_STATE_LARGE_STD_INFO) ) {
  4454. DebugTrace( 0, DbgAcl, ("NtfsUpgradeSecurity growing standard information\n") );
  4455. NtfsGrowStandardInformation( IrpContext, SystemFcb );
  4456. }
  4457. //
  4458. // Assign a security Id if we don't have one already
  4459. //
  4460. if (SystemFcb->SharedSecurity->Header.HashKey.SecurityId == SECURITY_ID_INVALID) {
  4461. NtfsAcquireFcbSecurity( Vcb );
  4462. try {
  4463. GetSecurityIdFromSecurityDescriptorUnsafe( IrpContext, SystemFcb->SharedSecurity );
  4464. } finally {
  4465. NtfsReleaseFcbSecurity( Vcb );
  4466. }
  4467. ASSERT( SystemFcb->SharedSecurity->Header.HashKey.SecurityId != SECURITY_ID_INVALID );
  4468. }
  4469. //
  4470. // Copy the security Id into the Fcb so we can store it out
  4471. //
  4472. SystemFcb->SecurityId = SystemFcb->SharedSecurity->Header.HashKey.SecurityId;
  4473. //
  4474. // Update the $STANDARD_INFORMATION for the operation
  4475. //
  4476. NtfsUpdateStandardInformation( IrpContext, SystemFcb );
  4477. }
  4478. }
  4479. //
  4480. // Local support routine
  4481. //
  4482. VOID
  4483. NtfsInitializeExtendDirectory (
  4484. IN PIRP_CONTEXT IrpContext,
  4485. IN PVCB Vcb
  4486. )
  4487. /*++
  4488. Routine Description:
  4489. This routine opens the $Extend directory by file number, and fills in the
  4490. related pointers in the Vcb.
  4491. Arguments:
  4492. Vcb - Pointer to the Vcb for the volume
  4493. Return Value:
  4494. None.
  4495. --*/
  4496. {
  4497. struct {
  4498. FILE_NAME FileName;
  4499. WCHAR FileNameChars[10];
  4500. } FileNameAttr;
  4501. PFCB Fcb;
  4502. PFCB PreviousFcb = NULL;
  4503. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  4504. FILE_REFERENCE FileReference;
  4505. PBCB FileRecordBcb = NULL;
  4506. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  4507. LONGLONG FileRecordOffset;
  4508. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  4509. UNICODE_STRING ExtendName;
  4510. PFILE_NAME ExtendFileNameAttr;
  4511. USHORT ExtendFileNameAttrLength;
  4512. PINDEX_ENTRY IndexEntry;
  4513. PBCB IndexEntryBcb = NULL;
  4514. PSTANDARD_INFORMATION StandardInformation;
  4515. ULONG CorruptHint;
  4516. //
  4517. // Initialize with the known FileReference and name.
  4518. //
  4519. FileReference = ExtendFileReference;
  4520. //
  4521. // Now create the Fcb.
  4522. //
  4523. Fcb = NtfsCreateFcb( IrpContext,
  4524. Vcb,
  4525. FileReference,
  4526. FALSE,
  4527. TRUE,
  4528. NULL );
  4529. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  4530. //
  4531. // Get ready for some attribute lookups/creates.
  4532. //
  4533. NtfsInitializeAttributeContext( &Context );
  4534. //
  4535. // Use a try-finally to facilitate cleanup.
  4536. //
  4537. try {
  4538. //
  4539. // Check to see if there is an existing $Extend entry in the root.
  4540. //
  4541. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  4542. RtlCopyMemory( FileNameAttr.FileName.FileName, NtfsExtendName.Buffer, NtfsExtendName.Length );
  4543. ExtendName.MaximumLength = ExtendName.Length = NtfsExtendName.Length;
  4544. ExtendName.Buffer = FileNameAttr.FileName.FileName;
  4545. ExtendFileNameAttr = (PFILE_NAME) &FileNameAttr;
  4546. ExtendFileNameAttrLength = sizeof( FileNameAttr );
  4547. if (NtfsLookupEntry( IrpContext,
  4548. Vcb->RootIndexScb,
  4549. TRUE,
  4550. &ExtendName,
  4551. &ExtendFileNameAttr,
  4552. &ExtendFileNameAttrLength,
  4553. NULL,
  4554. &IndexEntry,
  4555. &IndexEntryBcb,
  4556. NULL )) {
  4557. //
  4558. // If this is not for file record 11 then we want to orphan this entry.
  4559. // The user will have to use chkdsk to recover to a FOUND directory.
  4560. //
  4561. if (NtfsSegmentNumber( &IndexEntry->FileReference ) != EXTEND_NUMBER) {
  4562. //
  4563. // Now create the Fcb for the previous link.
  4564. //
  4565. PreviousFcb = NtfsCreateFcb( IrpContext,
  4566. Vcb,
  4567. IndexEntry->FileReference,
  4568. FALSE,
  4569. FALSE,
  4570. NULL );
  4571. ExtendName.Buffer = ((PFILE_NAME) NtfsFoundIndexEntry( IndexEntry ))->FileName;
  4572. NtfsRemoveLink( IrpContext,
  4573. PreviousFcb,
  4574. Vcb->RootIndexScb,
  4575. ExtendName,
  4576. NULL,
  4577. NULL );
  4578. }
  4579. }
  4580. //
  4581. // We better not be trying to deallocate the file name attribute on the stack.
  4582. //
  4583. ASSERT( ExtendFileNameAttr == (PFILE_NAME) &FileNameAttr );
  4584. //
  4585. // Reinitialize the file name attribute for the FileRecord fixup.
  4586. //
  4587. //
  4588. // If this file still has an unnamed data attribute from format, delete it.
  4589. //
  4590. if (NtfsLookupAttributeByName( IrpContext,
  4591. Fcb,
  4592. &FileReference,
  4593. $DATA,
  4594. &NoName,
  4595. NULL,
  4596. FALSE,
  4597. &Context ) ) {
  4598. NtfsDeleteAttributeRecord( IrpContext,
  4599. Fcb,
  4600. DELETE_LOG_OPERATION |
  4601. DELETE_RELEASE_FILE_RECORD |
  4602. DELETE_RELEASE_ALLOCATION,
  4603. &Context );
  4604. }
  4605. NtfsCleanupAttributeContext( IrpContext, &Context );
  4606. //
  4607. // Capture the standard information values in the Fcb and set the file name index
  4608. // flag if necessary.
  4609. //
  4610. NtfsInitializeAttributeContext( &Context );
  4611. if (!NtfsLookupAttributeByCode( IrpContext,
  4612. Fcb,
  4613. &FileReference,
  4614. $STANDARD_INFORMATION,
  4615. &Context )) {
  4616. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, &FileReference, NULL );
  4617. }
  4618. //
  4619. // Check that the $Extend file record is valid.
  4620. //
  4621. if (!NtfsCheckFileRecord( Vcb, NtfsContainingFileRecord( &Context ), &FileReference, &CorruptHint)) {
  4622. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, &FileReference, NULL );
  4623. }
  4624. //
  4625. // Copy the existing standard information into the Fcb and set the file name
  4626. // index flag.
  4627. //
  4628. StandardInformation = (PSTANDARD_INFORMATION) NtfsAttributeValue( NtfsFoundAttribute( &Context ));
  4629. Fcb->Info.CreationTime = StandardInformation->CreationTime;
  4630. Fcb->Info.LastModificationTime = StandardInformation->LastModificationTime;
  4631. Fcb->Info.LastChangeTime = StandardInformation->LastChangeTime;
  4632. Fcb->Info.LastAccessTime = StandardInformation->LastAccessTime;
  4633. Fcb->CurrentLastAccess = Fcb->Info.LastAccessTime;
  4634. Fcb->Info.FileAttributes = StandardInformation->FileAttributes;
  4635. NtfsCleanupAttributeContext( IrpContext, &Context );
  4636. SetFlag( Fcb->Info.FileAttributes, DUP_FILE_NAME_INDEX_PRESENT );
  4637. //
  4638. // If the name isn't there yet, add it.
  4639. //
  4640. NtfsInitializeAttributeContext( &Context );
  4641. if (!NtfsLookupAttributeByCode( IrpContext,
  4642. Fcb,
  4643. &FileReference,
  4644. $FILE_NAME,
  4645. &Context )) {
  4646. UCHAR FileNameFlags;
  4647. //
  4648. // Update the file name attribute for the create.
  4649. //
  4650. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  4651. FileNameAttr.FileName.FileNameLength = NtfsExtendName.Length/2;
  4652. RtlCopyMemory( FileNameAttr.FileName.FileName, NtfsExtendName.Buffer, NtfsExtendName.Length );
  4653. NtfsAddLink( IrpContext,
  4654. TRUE,
  4655. Vcb->RootIndexScb,
  4656. Fcb,
  4657. (PFILE_NAME)&FileNameAttr,
  4658. NULL,
  4659. &FileNameFlags,
  4660. NULL,
  4661. NULL,
  4662. NULL );
  4663. }
  4664. //
  4665. // Now see if the file name index is there, and if not create it.
  4666. //
  4667. NtfsCleanupAttributeContext( IrpContext, &Context );
  4668. NtfsInitializeAttributeContext( &Context );
  4669. if (!NtfsLookupAttributeByCode( IrpContext,
  4670. Fcb,
  4671. &FileReference,
  4672. $INDEX_ROOT,
  4673. &Context ) ) {
  4674. NtfsCreateIndex( IrpContext,
  4675. Fcb,
  4676. $FILE_NAME,
  4677. COLLATION_FILE_NAME,
  4678. Vcb->DefaultBytesPerIndexAllocationBuffer,
  4679. (UCHAR)Vcb->DefaultBlocksPerIndexAllocationBuffer,
  4680. NULL,
  4681. 0,
  4682. TRUE,
  4683. TRUE );
  4684. //
  4685. // We have to set the index present bit, so read it, save the old data
  4686. // and set the flag here.
  4687. //
  4688. NtfsPinMftRecord( IrpContext,
  4689. Vcb,
  4690. &FileReference,
  4691. FALSE,
  4692. &FileRecordBcb,
  4693. &FileRecord,
  4694. &FileRecordOffset );
  4695. //
  4696. // We have to be very careful when using the InitialzeFileRecordSegment
  4697. // log record. This action is applied unconditionally. DoAction doesn't
  4698. // check the previous LSN in the page. It may be garbage on a newly initialized
  4699. // file record. We log the entire file record to avoid the case where we
  4700. // might overwrite a later Lsn with this earlier Lsn during restart.
  4701. //
  4702. //
  4703. // Log the existing file record as the undo action.
  4704. //
  4705. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  4706. Vcb->MftScb,
  4707. FileRecordBcb,
  4708. Noop,
  4709. NULL,
  4710. 0,
  4711. InitializeFileRecordSegment,
  4712. FileRecord,
  4713. FileRecord->FirstFreeByte,
  4714. FileRecordOffset,
  4715. 0,
  4716. 0,
  4717. Vcb->BytesPerFileRecordSegment );
  4718. //
  4719. // Now update the record in place.
  4720. //
  4721. SetFlag( FileRecord->Flags, FILE_FILE_NAME_INDEX_PRESENT );
  4722. //
  4723. // Log the new file record.
  4724. //
  4725. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  4726. Vcb->MftScb,
  4727. FileRecordBcb,
  4728. InitializeFileRecordSegment,
  4729. FileRecord,
  4730. FileRecord->FirstFreeByte,
  4731. Noop,
  4732. NULL,
  4733. 0,
  4734. FileRecordOffset,
  4735. 0,
  4736. 0,
  4737. Vcb->BytesPerFileRecordSegment );
  4738. //
  4739. // Reload it so we can pass the attribute when initializing the Scb.
  4740. //
  4741. NtfsCleanupAttributeContext( IrpContext, &Context );
  4742. NtfsInitializeAttributeContext( &Context );
  4743. NtfsLookupAttributeByCode( IrpContext,
  4744. Fcb,
  4745. &FileReference,
  4746. $INDEX_ROOT,
  4747. &Context );
  4748. }
  4749. //
  4750. // Initialize the Fcb and load the security descriptor.
  4751. //
  4752. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, Fcb, NULL );
  4753. if (Fcb->SharedSecurity == NULL) {
  4754. NtfsLoadSecurityDescriptor( IrpContext, Fcb );
  4755. }
  4756. ASSERT( Fcb->SharedSecurity != NULL );
  4757. //
  4758. // Now create its Scb and store it.
  4759. //
  4760. Vcb->ExtendDirectory = NtfsCreateScb( IrpContext,
  4761. Fcb,
  4762. $INDEX_ALLOCATION,
  4763. &NtfsFileNameIndex,
  4764. FALSE,
  4765. NULL );
  4766. NtfsUpdateIndexScbFromAttribute( IrpContext,
  4767. Vcb->ExtendDirectory,
  4768. NtfsFoundAttribute( &Context ),
  4769. TRUE );
  4770. NtfsCreateInternalAttributeStream( IrpContext,
  4771. Vcb->ExtendDirectory,
  4772. FALSE,
  4773. NULL );
  4774. } finally {
  4775. NtfsCleanupAttributeContext( IrpContext, &Context );
  4776. NtfsUnpinBcb( IrpContext, &FileRecordBcb );
  4777. NtfsUnpinBcb( IrpContext, &IndexEntryBcb );
  4778. //
  4779. // If some error caused us to not get the Scb created, then delete
  4780. // the Fcb, because we are the only ones who will.
  4781. //
  4782. if (Vcb->ExtendDirectory == NULL) {
  4783. BOOLEAN AcquiredFcbTable = TRUE;
  4784. NtfsAcquireFcbTable( IrpContext, Vcb );
  4785. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4786. ASSERT(!AcquiredFcbTable);
  4787. }
  4788. }
  4789. }
  4790. //
  4791. // Local support routine
  4792. //
  4793. VOID
  4794. NtfsInitializeQuotaFile (
  4795. IN PIRP_CONTEXT IrpContext,
  4796. IN PVCB Vcb
  4797. )
  4798. /*++
  4799. Routine Description:
  4800. This routine creates/opens the quota file, and initializes the quota support.
  4801. Arguments:
  4802. Vcb - Pointer to the Vcb for the volume
  4803. Return Value:
  4804. None.
  4805. --*/
  4806. {
  4807. PFCB Fcb;
  4808. //
  4809. // Create/open the quota file in $Extend
  4810. //
  4811. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsQuotaName, TRUE, TRUE );
  4812. try {
  4813. //
  4814. // Initialize the Quota subsystem.
  4815. //
  4816. NtfsInitializeQuotaIndex( IrpContext, Fcb, Vcb );
  4817. } finally {
  4818. //
  4819. // If some error caused him to not get any Scbs created, then delete
  4820. // the Fcb, because we are the only ones who will.
  4821. //
  4822. if (IsListEmpty(&Fcb->ScbQueue)) {
  4823. BOOLEAN AcquiredFcbTable = TRUE;
  4824. NtfsAcquireFcbTable( IrpContext, Vcb );
  4825. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4826. ASSERT(!AcquiredFcbTable);
  4827. }
  4828. }
  4829. }
  4830. //
  4831. // Local support routine
  4832. //
  4833. VOID
  4834. NtfsInitializeObjectIdFile (
  4835. IN PIRP_CONTEXT IrpContext,
  4836. IN PVCB Vcb
  4837. )
  4838. /*++
  4839. Routine Description:
  4840. This routine creates/opens the object Id table, and initializes Object Ids.
  4841. Arguments:
  4842. Vcb - Pointer to the Vcb for the volume
  4843. Return Value:
  4844. None.
  4845. --*/
  4846. {
  4847. PFCB Fcb;
  4848. //
  4849. // Create/open the quota file in $Extend
  4850. //
  4851. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsObjectIdName, TRUE, TRUE );
  4852. try {
  4853. //
  4854. // Initialize the Object Id subsystem.
  4855. //
  4856. NtfsInitializeObjectIdIndex( IrpContext, Fcb, Vcb );
  4857. } finally {
  4858. //
  4859. // If some error caused him to not get any Scbs created, then delete
  4860. // the Fcb, because we are the only ones who will.
  4861. //
  4862. if (IsListEmpty(&Fcb->ScbQueue)) {
  4863. BOOLEAN AcquiredFcbTable = TRUE;
  4864. NtfsAcquireFcbTable( IrpContext, Vcb );
  4865. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4866. ASSERT(!AcquiredFcbTable);
  4867. }
  4868. }
  4869. }
  4870. //
  4871. // Local support routine
  4872. //
  4873. VOID
  4874. NtfsInitializeReparseFile (
  4875. IN PIRP_CONTEXT IrpContext,
  4876. IN PVCB Vcb
  4877. )
  4878. /*++
  4879. Routine Description:
  4880. This routine creates/opens the mount file table, creating it if it does not exist.
  4881. Arguments:
  4882. Vcb - Pointer to the Vcb for the volume
  4883. Return Value:
  4884. None.
  4885. --*/
  4886. {
  4887. PFCB Fcb;
  4888. //
  4889. // Create/open the quota file in $Extend
  4890. //
  4891. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsMountTableName, TRUE, TRUE );
  4892. try {
  4893. //
  4894. // Initialize the Object Id subsystem.
  4895. //
  4896. NtfsInitializeReparsePointIndex( IrpContext, Fcb, Vcb );
  4897. } finally {
  4898. //
  4899. // If some error caused her to not get any Scbs created, then delete
  4900. // the Fcb, because we are the only ones who will.
  4901. //
  4902. if (IsListEmpty(&Fcb->ScbQueue)) {
  4903. BOOLEAN AcquiredFcbTable = TRUE;
  4904. NtfsAcquireFcbTable( IrpContext, Vcb );
  4905. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4906. ASSERT(!AcquiredFcbTable);
  4907. }
  4908. }
  4909. }
  4910. //
  4911. // Local support routine
  4912. //
  4913. VOID
  4914. NtfsInitializeUsnJournal (
  4915. IN PIRP_CONTEXT IrpContext,
  4916. IN PVCB Vcb,
  4917. IN ULONG CreateIfNotExist,
  4918. IN ULONG Restamp,
  4919. IN PCREATE_USN_JOURNAL_DATA JournalData
  4920. )
  4921. /*++
  4922. Routine Description:
  4923. This routine creates/opens the Usn journal, and initializes it.
  4924. Arguments:
  4925. Vcb - Pointer to the Vcb for the volume
  4926. CreateIfNotExist - Supplies TRUE if file should be created if it does not
  4927. already exist, or FALSE if file should not be created.
  4928. Restamp - Indicates if we want to restamp the journal.
  4929. JournalData - This is the allocation and delta to use for the journal, unless
  4930. we read it from disk.
  4931. Return Value:
  4932. None.
  4933. --*/
  4934. {
  4935. FILE_REFERENCE PriorFileReference;
  4936. PFCB Fcb = NULL;
  4937. BOOLEAN ReleaseExtend = FALSE;
  4938. PriorFileReference = Vcb->UsnJournalReference;
  4939. try {
  4940. //
  4941. // Acquire Mft now to preserve locking order
  4942. //
  4943. NtfsAcquireExclusiveScb( IrpContext, Vcb->MftScb );
  4944. //
  4945. // Create/open the USN file in $Extend
  4946. //
  4947. if ( Vcb->UsnJournal) {
  4948. Fcb = Vcb->UsnJournal->Fcb;
  4949. //
  4950. // Acquire in canonical order
  4951. //
  4952. NtfsAcquireExclusiveScb( IrpContext, Vcb->UsnJournal );
  4953. } else {
  4954. NtfsAcquireExclusiveScb( IrpContext, Vcb->ExtendDirectory );
  4955. ReleaseExtend = TRUE;
  4956. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsUsnJrnlName, FALSE, CreateIfNotExist );
  4957. #ifdef NTFSDBG
  4958. //
  4959. // Compensate for misclassification of usnjournal during real create
  4960. //
  4961. if (IrpContext->OwnershipState == NtfsOwns_ExVcb_Mft_Extend_File) {
  4962. IrpContext->OwnershipState = NtfsOwns_ExVcb_Mft_Extend_Journal;
  4963. }
  4964. #endif
  4965. }
  4966. //
  4967. // We are done if it is not there.
  4968. //
  4969. if (Fcb != NULL) {
  4970. Vcb->UsnJournalReference = Fcb->FileReference;
  4971. //
  4972. // If we only want to open an existing journal then this is mount. Make sure
  4973. // to note that there is a journal on the disk. We can't depend on the next
  4974. // call to succeed in that case.
  4975. //
  4976. if (!CreateIfNotExist) {
  4977. ASSERT( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  4978. (IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) );
  4979. SetFlag( Vcb->VcbState, VCB_STATE_USN_JOURNAL_PRESENT );
  4980. }
  4981. //
  4982. // Open or create the the Usn Journal.
  4983. //
  4984. NtfsSetupUsnJournal( IrpContext, Vcb, Fcb, CreateIfNotExist, Restamp, JournalData );
  4985. }
  4986. } finally {
  4987. if (ReleaseExtend) {
  4988. NtfsReleaseScb( IrpContext, Vcb->ExtendDirectory );
  4989. }
  4990. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  4991. if (AbnormalTermination()) {
  4992. Vcb->UsnJournalReference = PriorFileReference;
  4993. }
  4994. }
  4995. }
  4996. //
  4997. // Local Support Routine
  4998. //
  4999. NTSTATUS
  5000. NtfsQueryRetrievalPointers (
  5001. IN PIRP_CONTEXT IrpContext,
  5002. IN PIRP Irp
  5003. )
  5004. /*++
  5005. Routine Description:
  5006. This routine performs the query retrieval pointers operation.
  5007. It returns the retrieval pointers for the specified input
  5008. file from the start of the file to the request map size specified
  5009. in the input buffer.
  5010. Arguments:
  5011. Irp - Supplies the Irp to process
  5012. Return Value:
  5013. NTSTATUS - The return status for the operation
  5014. --*/
  5015. {
  5016. NTSTATUS Status;
  5017. PIO_STACK_LOCATION IrpSp;
  5018. PVCB Vcb;
  5019. PFCB Fcb;
  5020. PSCB Scb;
  5021. PCCB Ccb;
  5022. PLONGLONG RequestedMapSize;
  5023. PLONGLONG *MappingPairs;
  5024. PVOID RangePtr;
  5025. ULONG Index;
  5026. ULONG i;
  5027. LONGLONG SectorCount;
  5028. LONGLONG Lbo;
  5029. LONGLONG Vbo;
  5030. LONGLONG Vcn;
  5031. LONGLONG MapSize;
  5032. //
  5033. // Always make this synchronous.
  5034. //
  5035. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  5036. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  5037. //
  5038. // Only Kernel mode clients may query retrieval pointer information about
  5039. // a file, and then only the paging file. Ensure that this is the case
  5040. // for this caller.
  5041. //
  5042. if (Irp->RequestorMode != KernelMode) {
  5043. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5044. return STATUS_INVALID_PARAMETER;
  5045. }
  5046. //
  5047. // Get the current stack location and extract the input and output
  5048. // buffer information. The input contains the requested size of
  5049. // the mappings in terms of VBO. The output parameter will receive
  5050. // a pointer to nonpaged pool where the mapping pairs are stored.
  5051. //
  5052. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  5053. ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof(LARGE_INTEGER) );
  5054. ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength == sizeof(PVOID) );
  5055. RequestedMapSize = (PLONGLONG)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  5056. MappingPairs = (PLONGLONG *)Irp->UserBuffer;
  5057. //
  5058. // Decode the file object and assert that it is the paging file
  5059. //
  5060. //
  5061. (VOID)NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  5062. if (!FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  5063. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5064. return STATUS_INVALID_PARAMETER;
  5065. }
  5066. //
  5067. // Acquire exclusive access to the Scb
  5068. //
  5069. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5070. try {
  5071. //
  5072. // Check if the mapping the caller requested is too large
  5073. //
  5074. if (*RequestedMapSize > Scb->Header.FileSize.QuadPart) {
  5075. try_return( Status = STATUS_INVALID_PARAMETER );
  5076. }
  5077. //
  5078. // Now get the index for the mcb entry that will contain the
  5079. // callers request and allocate enough pool to hold the
  5080. // output mapping pairs.
  5081. //
  5082. //
  5083. // Compute the Vcn which contains the byte just before the offset size
  5084. // passed in.
  5085. //
  5086. MapSize = *RequestedMapSize - 1;
  5087. if (*RequestedMapSize == 0) {
  5088. Index = 0;
  5089. } else {
  5090. Vcn = Int64ShraMod32( MapSize, Vcb->ClusterShift );
  5091. (VOID)NtfsLookupNtfsMcbEntry( &Scb->Mcb, Vcn, NULL, NULL, NULL, NULL, &RangePtr, &Index );
  5092. }
  5093. *MappingPairs = NtfsAllocatePool( NonPagedPool, (Index + 2) * (2 * sizeof(LARGE_INTEGER)) );
  5094. //
  5095. // Now copy over the mapping pairs from the mcb
  5096. // to the output buffer. We store in [sector count, lbo]
  5097. // mapping pairs and end with a zero sector count.
  5098. //
  5099. MapSize = *RequestedMapSize;
  5100. i = 0;
  5101. if (MapSize != 0) {
  5102. for (; i <= Index; i += 1) {
  5103. (VOID)NtfsGetNextNtfsMcbEntry( &Scb->Mcb, &RangePtr, i, &Vbo, &Lbo, &SectorCount );
  5104. SectorCount = LlBytesFromClusters( Vcb, SectorCount );
  5105. if (SectorCount > MapSize) {
  5106. SectorCount = MapSize;
  5107. }
  5108. (*MappingPairs)[ i*2 + 0 ] = SectorCount;
  5109. (*MappingPairs)[ i*2 + 1 ] = LlBytesFromClusters( Vcb, Lbo );
  5110. MapSize = MapSize - SectorCount;
  5111. }
  5112. }
  5113. (*MappingPairs)[ i*2 + 0 ] = 0;
  5114. Status = STATUS_SUCCESS;
  5115. try_exit: NOTHING;
  5116. } finally {
  5117. DebugUnwind( NtfsQueryRetrievalPointers );
  5118. //
  5119. // Release all of our resources
  5120. //
  5121. NtfsReleaseScb( IrpContext, Scb );
  5122. //
  5123. // If this is an abnormal termination then undo our work, otherwise
  5124. // complete the irp
  5125. //
  5126. if (!AbnormalTermination()) {
  5127. NtfsCompleteRequest( IrpContext, Irp, Status );
  5128. }
  5129. }
  5130. return Status;
  5131. }
  5132. //
  5133. // Local Support Routine
  5134. //
  5135. NTSTATUS
  5136. NtfsGetCompression (
  5137. IN PIRP_CONTEXT IrpContext,
  5138. IN PIRP Irp
  5139. )
  5140. /*++
  5141. Routine Description:
  5142. This routine returns the compression state of the opened file/directory
  5143. Arguments:
  5144. Irp - Supplies the Irp to process
  5145. Return Value:
  5146. NTSTATUS - The return status for the operation
  5147. --*/
  5148. {
  5149. PIO_STACK_LOCATION IrpSp;
  5150. TYPE_OF_OPEN TypeOfOpen;
  5151. PVCB Vcb;
  5152. PFCB Fcb;
  5153. PSCB Scb;
  5154. PCCB Ccb;
  5155. PUSHORT CompressionState;
  5156. PAGED_CODE();
  5157. //
  5158. // Get the current stack location and extract the output
  5159. // buffer information. The output parameter will receive
  5160. // the compressed state of the file/directory.
  5161. //
  5162. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  5163. //
  5164. // Get a pointer to the output buffer. Look at the system buffer field in th
  5165. // irp first. Then the Irp Mdl.
  5166. //
  5167. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  5168. CompressionState = Irp->AssociatedIrp.SystemBuffer;
  5169. } else if (Irp->MdlAddress != NULL) {
  5170. CompressionState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  5171. if (CompressionState == NULL) {
  5172. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  5173. return STATUS_INSUFFICIENT_RESOURCES;
  5174. }
  5175. } else {
  5176. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  5177. return STATUS_INVALID_USER_BUFFER;
  5178. }
  5179. //
  5180. // Make sure the output buffer is large enough and then initialize
  5181. // the answer to be that the file isn't compressed
  5182. //
  5183. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(USHORT)) {
  5184. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5185. return STATUS_INVALID_PARAMETER;
  5186. }
  5187. *CompressionState = 0;
  5188. //
  5189. // Decode the file object
  5190. //
  5191. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  5192. if ((TypeOfOpen != UserFileOpen) &&
  5193. (TypeOfOpen != UserDirectoryOpen)) {
  5194. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5195. return STATUS_INVALID_PARAMETER;
  5196. }
  5197. //
  5198. // Acquire shared access to the Scb
  5199. //
  5200. NtfsAcquireSharedScb( IrpContext, Scb );
  5201. //
  5202. // If this is the index allocation Scb and it has not been initialized then
  5203. // lookup the index root and perform the initialization.
  5204. //
  5205. if ((Scb->AttributeTypeCode == $INDEX_ALLOCATION) &&
  5206. (Scb->ScbType.Index.BytesPerIndexBuffer == 0)) {
  5207. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  5208. NtfsInitializeAttributeContext( &Context );
  5209. //
  5210. // Use a try-finally to perform cleanup.
  5211. //
  5212. try {
  5213. if (!NtfsLookupAttributeByName( IrpContext,
  5214. Scb->Fcb,
  5215. &Scb->Fcb->FileReference,
  5216. $INDEX_ROOT,
  5217. &Scb->AttributeName,
  5218. NULL,
  5219. FALSE,
  5220. &Context )) {
  5221. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  5222. }
  5223. NtfsUpdateIndexScbFromAttribute( IrpContext,
  5224. Scb,
  5225. NtfsFoundAttribute( &Context ),
  5226. FALSE );
  5227. } finally {
  5228. NtfsCleanupAttributeContext( IrpContext, &Context );
  5229. if (AbnormalTermination()) { NtfsReleaseScb( IrpContext, Scb ); }
  5230. }
  5231. }
  5232. //
  5233. // Return the compression state and the size of the returned data.
  5234. //
  5235. *CompressionState = (USHORT)(Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK);
  5236. if (*CompressionState != 0) {
  5237. *CompressionState += 1;
  5238. }
  5239. Irp->IoStatus.Information = sizeof( USHORT );
  5240. //
  5241. // Release all of our resources
  5242. //
  5243. NtfsReleaseScb( IrpContext, Scb );
  5244. //
  5245. // If this is an abnormal termination then undo our work, otherwise
  5246. // complete the irp
  5247. //
  5248. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  5249. return STATUS_SUCCESS;
  5250. }
  5251. //
  5252. // Local Support Routine
  5253. //
  5254. VOID
  5255. NtfsChangeAttributeCompression (
  5256. IN PIRP_CONTEXT IrpContext,
  5257. IN PSCB Scb,
  5258. IN PVCB Vcb,
  5259. IN PCCB Ccb,
  5260. IN USHORT CompressionState
  5261. )
  5262. /*++
  5263. Routine Description:
  5264. This routine changes the compression state of an attribute on disk,
  5265. from not compressed to compressed, or visa versa.
  5266. To turn compression off, the caller must already have the Scb acquired
  5267. exclusive, and guarantee that the entire file is not compressed.
  5268. Arguments:
  5269. Scb - Scb for affected stream
  5270. Vcb - Vcb for volume
  5271. Ccb - Ccb for the open handle
  5272. CompressionState - 0 for no compression or nonzero for Rtl compression code - 1
  5273. Return Value:
  5274. None.
  5275. --*/
  5276. {
  5277. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  5278. ATTRIBUTE_RECORD_HEADER NewAttribute;
  5279. PATTRIBUTE_RECORD_HEADER Attribute;
  5280. ULONG AttributeSizeChange;
  5281. ULONG OriginalFileAttributes;
  5282. UCHAR OriginalCompressionUnitShift;
  5283. ULONG OriginalCompressionUnit;
  5284. PFCB Fcb = Scb->Fcb;
  5285. ULONG NewCompressionUnit;
  5286. UCHAR NewCompressionUnitShift;
  5287. PAGED_CODE( );
  5288. //
  5289. // Prepare to lookup and change attribute.
  5290. //
  5291. NtfsInitializeAttributeContext( &AttrContext );
  5292. ASSERT( (Scb->Header.PagingIoResource == NULL) ||
  5293. (IrpContext->CleanupStructure == Fcb) ||
  5294. (IrpContext->CleanupStructure == Scb) );
  5295. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5296. OriginalFileAttributes = Fcb->Info.FileAttributes;
  5297. OriginalCompressionUnitShift = Scb->CompressionUnitShift;
  5298. OriginalCompressionUnit = Scb->CompressionUnit;
  5299. //
  5300. // Capture the ccb source information.
  5301. //
  5302. if (Ccb != NULL) {
  5303. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  5304. }
  5305. try {
  5306. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  5307. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  5308. }
  5309. //
  5310. // Post the change to the Usn Journal (on errors change is backed out)
  5311. //
  5312. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_COMPRESSION_CHANGE );
  5313. //
  5314. // Lookup the attribute and pin it so that we can modify it.
  5315. //
  5316. if ((Scb->Header.NodeTypeCode == NTFS_NTC_SCB_INDEX) ||
  5317. (Scb->Header.NodeTypeCode == NTFS_NTC_SCB_ROOT_INDEX)) {
  5318. //
  5319. // Lookup the attribute record from the Scb.
  5320. //
  5321. if (!NtfsLookupAttributeByName( IrpContext,
  5322. Fcb,
  5323. &Fcb->FileReference,
  5324. $INDEX_ROOT,
  5325. &Scb->AttributeName,
  5326. NULL,
  5327. FALSE,
  5328. &AttrContext )) {
  5329. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, NULL );
  5330. }
  5331. } else {
  5332. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &AttrContext );
  5333. }
  5334. NtfsPinMappedAttribute( IrpContext, Vcb, &AttrContext );
  5335. Attribute = NtfsFoundAttribute( &AttrContext );
  5336. if ((CompressionState != 0) &&
  5337. !NtfsIsAttributeResident(Attribute) &&
  5338. !FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5339. LONGLONG Temp;
  5340. ULONG CompressionUnitInClusters;
  5341. //
  5342. // If we are turning compression on, then we need to fill out the
  5343. // allocation of the compression unit containing file size, or else
  5344. // it will be interpreted as compressed when we fault it in. This
  5345. // is peanuts compared to the dual copies of clusters we keep around
  5346. // in the loop below when we rewrite the file. We don't do this
  5347. // work if the file is sparse because the allocation has already
  5348. // been rounded up.
  5349. //
  5350. CompressionUnitInClusters =
  5351. ClustersFromBytes( Vcb, Vcb->BytesPerCluster << NTFS_CLUSTERS_PER_COMPRESSION );
  5352. Temp = LlClustersFromBytes(Vcb, Scb->Header.AllocationSize.QuadPart);
  5353. //
  5354. // If FileSize is not already at a cluster boundary, then add
  5355. // allocation.
  5356. //
  5357. if ((ULONG)Temp & (CompressionUnitInClusters - 1)) {
  5358. NtfsAddAllocation( IrpContext,
  5359. NULL,
  5360. Scb,
  5361. Temp,
  5362. CompressionUnitInClusters - ((ULONG)Temp & (CompressionUnitInClusters - 1)),
  5363. FALSE,
  5364. NULL );
  5365. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  5366. Scb->Fcb->Info.AllocatedLength = Scb->TotalAllocated;
  5367. SetFlag( Scb->Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
  5368. }
  5369. NtfsWriteFileSizes( IrpContext,
  5370. Scb,
  5371. &Scb->Header.ValidDataLength.QuadPart,
  5372. FALSE,
  5373. TRUE,
  5374. TRUE );
  5375. //
  5376. // The attribute may have moved. We will cleanup the attribute
  5377. // context and look it up again.
  5378. //
  5379. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  5380. NtfsInitializeAttributeContext( &AttrContext );
  5381. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &AttrContext );
  5382. NtfsPinMappedAttribute( IrpContext, Vcb, &AttrContext );
  5383. Attribute = NtfsFoundAttribute( &AttrContext );
  5384. }
  5385. }
  5386. //
  5387. // Remember the current compression values.
  5388. //
  5389. NewCompressionUnit = Scb->CompressionUnit;
  5390. NewCompressionUnitShift = Scb->CompressionUnitShift;
  5391. //
  5392. // If the attribute is resident, copy it here and remember its
  5393. // header size.
  5394. //
  5395. if (NtfsIsAttributeResident(Attribute)) {
  5396. RtlCopyMemory( &NewAttribute, Attribute, SIZEOF_RESIDENT_ATTRIBUTE_HEADER );
  5397. AttributeSizeChange = SIZEOF_RESIDENT_ATTRIBUTE_HEADER;
  5398. //
  5399. // Set the correct compression unit but only for data streams. We
  5400. // don't want to change this value for the Index Root.
  5401. //
  5402. if (NtfsIsTypeCodeCompressible( Attribute->TypeCode ) &&
  5403. !FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5404. if (CompressionState != 0) {
  5405. NewCompressionUnit = BytesFromClusters( Scb->Vcb, 1 << NTFS_CLUSTERS_PER_COMPRESSION );
  5406. NewCompressionUnitShift = NTFS_CLUSTERS_PER_COMPRESSION;
  5407. } else {
  5408. NewCompressionUnit = 0;
  5409. NewCompressionUnitShift = 0;
  5410. }
  5411. }
  5412. //
  5413. // Else if it is nonresident, copy it here, set the compression parameter,
  5414. // and remember its size.
  5415. //
  5416. } else {
  5417. AttributeSizeChange = Attribute->Form.Nonresident.MappingPairsOffset;
  5418. if (Attribute->NameOffset != 0) {
  5419. AttributeSizeChange = Attribute->NameOffset;
  5420. }
  5421. RtlCopyMemory( &NewAttribute, Attribute, AttributeSizeChange );
  5422. //
  5423. // The compression numbers are already correct if the file is compressed.
  5424. //
  5425. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5426. if (CompressionState != 0) {
  5427. NewAttribute.Form.Nonresident.CompressionUnit = NTFS_CLUSTERS_PER_COMPRESSION;
  5428. NewCompressionUnit = Vcb->BytesPerCluster << NTFS_CLUSTERS_PER_COMPRESSION;
  5429. NewCompressionUnitShift = NTFS_CLUSTERS_PER_COMPRESSION;
  5430. } else {
  5431. NewAttribute.Form.Nonresident.CompressionUnit = 0;
  5432. NewCompressionUnit = 0;
  5433. NewCompressionUnitShift = 0;
  5434. }
  5435. }
  5436. ASSERT((NewCompressionUnit == 0) ||
  5437. (Scb->AttributeTypeCode == $INDEX_ALLOCATION) ||
  5438. NtfsIsTypeCodeCompressible( Scb->AttributeTypeCode ));
  5439. }
  5440. //
  5441. // Turn compression on/off.
  5442. //
  5443. NewAttribute.Flags = Scb->AttributeFlags & ~ATTRIBUTE_FLAG_COMPRESSION_MASK;
  5444. SetFlag( NewAttribute.Flags, CompressionState );
  5445. //
  5446. // Now, log the changed attribute.
  5447. //
  5448. (VOID)NtfsWriteLog( IrpContext,
  5449. Vcb->MftScb,
  5450. NtfsFoundBcb(&AttrContext),
  5451. UpdateResidentValue,
  5452. &NewAttribute,
  5453. AttributeSizeChange,
  5454. UpdateResidentValue,
  5455. Attribute,
  5456. AttributeSizeChange,
  5457. NtfsMftOffset( &AttrContext ),
  5458. PtrOffset(NtfsContainingFileRecord(&AttrContext), Attribute),
  5459. 0,
  5460. Vcb->BytesPerFileRecordSegment );
  5461. //
  5462. // Change the attribute by calling the same routine called at restart.
  5463. //
  5464. NtfsRestartChangeValue( IrpContext,
  5465. NtfsContainingFileRecord(&AttrContext),
  5466. PtrOffset(NtfsContainingFileRecord(&AttrContext), Attribute),
  5467. 0,
  5468. &NewAttribute,
  5469. AttributeSizeChange,
  5470. FALSE );
  5471. //
  5472. // If this is the main stream for a file we want to change the file attribute
  5473. // for this stream in both the standard information and duplicate
  5474. // information structure.
  5475. //
  5476. if (FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
  5477. if (CompressionState != 0) {
  5478. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_COMPRESSED );
  5479. } else {
  5480. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_COMPRESSED );
  5481. }
  5482. ASSERTMSG( "conflict with flush",
  5483. ExIsResourceAcquiredSharedLite( Fcb->Resource ) ||
  5484. (Fcb->PagingIoResource != NULL &&
  5485. ExIsResourceAcquiredSharedLite( Fcb->PagingIoResource )));
  5486. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  5487. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5488. }
  5489. //
  5490. // Now lets add or remove the total allocated field in the attribute
  5491. // header. Add if going to uncompressed, non-sparse. Remove if going
  5492. // to compressed and non-sparse.
  5493. //
  5494. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5495. NtfsSetTotalAllocatedField( IrpContext, Scb, CompressionState );
  5496. }
  5497. //
  5498. // At this point we will change the compression unit in the Scb.
  5499. //
  5500. Scb->CompressionUnit = NewCompressionUnit;
  5501. Scb->CompressionUnitShift = NewCompressionUnitShift;
  5502. if (FlagOn( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  5503. NtfsUpdateStandardInformation( IrpContext, Fcb );
  5504. ClearFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5505. }
  5506. //
  5507. // Checkpoint the transaction now to secure this change.
  5508. //
  5509. NtfsCheckpointCurrentTransaction( IrpContext );
  5510. //
  5511. // Update the FastIoField.
  5512. //
  5513. NtfsAcquireFsrtlHeader( Scb );
  5514. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  5515. NtfsReleaseFsrtlHeader( Scb );
  5516. //
  5517. // Cleanup on the way out.
  5518. //
  5519. } finally {
  5520. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  5521. //
  5522. // If this requests aborts then we want to back out any changes to the
  5523. // in-memory structures.
  5524. //
  5525. if (AbnormalTermination()) {
  5526. Fcb->Info.FileAttributes = OriginalFileAttributes;
  5527. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5528. Scb->CompressionUnitShift = OriginalCompressionUnitShift;
  5529. Scb->CompressionUnit = OriginalCompressionUnit;
  5530. }
  5531. //
  5532. // This routine is self contained - it commits a transaction and we don't
  5533. // want to leave with anything extra acquired
  5534. //
  5535. NtfsReleaseScb( IrpContext, Scb );
  5536. }
  5537. }
  5538. //
  5539. // Local Support Routine
  5540. //
  5541. NTSTATUS
  5542. NtfsSetCompression (
  5543. IN PIRP_CONTEXT IrpContext,
  5544. IN PIRP Irp
  5545. )
  5546. /*++
  5547. Routine Description:
  5548. This routine compresses or decompresses an entire stream in place,
  5549. by walking through the stream and forcing it to be written with the
  5550. new compression parameters. As it writes the stream it sets a flag
  5551. in the Scb to tell NtfsCommonWrite to delete all allocation at the
  5552. outset, to force the space to be reallocated.
  5553. Arguments:
  5554. Irp - Irp describing the compress or decompress change.
  5555. Return Value:
  5556. NSTATUS - Status of the request.
  5557. --*/
  5558. {
  5559. PIO_STACK_LOCATION IrpSp;
  5560. PIO_STACK_LOCATION NextIrpSp;
  5561. TYPE_OF_OPEN TypeOfOpen;
  5562. PVCB Vcb;
  5563. PFCB Fcb;
  5564. PSCB Scb;
  5565. PCCB Ccb;
  5566. PUSHORT CompressionStatePtr;
  5567. PFILE_OBJECT FileObject;
  5568. LONGLONG FileOffset;
  5569. LONGLONG ByteCount;
  5570. USHORT CompressionState = 0;
  5571. BOOLEAN PagingIoAcquired = FALSE;
  5572. BOOLEAN FsRtlHeaderLocked = FALSE;
  5573. ULONG ScbRestoreState = SCB_STATE_WRITE_COMPRESSED;
  5574. IO_STATUS_BLOCK Iosb;
  5575. PMDL ReadMdl;
  5576. PMDL WriteMdl;
  5577. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  5578. PAGED_CODE( );
  5579. //
  5580. // Get the current stack location and extract the output
  5581. // buffer information. The output parameter will receive
  5582. // the compressed state of the file/directory.
  5583. //
  5584. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  5585. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  5586. FileObject = IrpSp->FileObject;
  5587. CompressionStatePtr = Irp->AssociatedIrp.SystemBuffer;
  5588. //
  5589. // Make sure the input buffer is big enough
  5590. //
  5591. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(USHORT)) {
  5592. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5593. return STATUS_INVALID_PARAMETER;
  5594. }
  5595. //
  5596. // Decode the file object. We don't care to raise on dismounts here
  5597. // because we check for that further down anyway. So send FALSE.
  5598. //
  5599. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  5600. if (((TypeOfOpen != UserFileOpen) &&
  5601. (TypeOfOpen != UserDirectoryOpen)) ||
  5602. FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  5603. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5604. return STATUS_INVALID_PARAMETER;
  5605. }
  5606. //
  5607. // See if we are compressing, and only accept the default case or
  5608. // lznt1.
  5609. //
  5610. if (*CompressionStatePtr != 0) {
  5611. if ((*CompressionStatePtr == COMPRESSION_FORMAT_DEFAULT) ||
  5612. (*CompressionStatePtr == COMPRESSION_FORMAT_LZNT1)) {
  5613. CompressionState = COMPRESSION_FORMAT_LZNT1 - 1;
  5614. //
  5615. // Check that we can compress on this volume.
  5616. //
  5617. if (!FlagOn( Vcb->AttributeFlagsMask, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  5618. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  5619. return STATUS_INVALID_DEVICE_REQUEST;
  5620. }
  5621. } else {
  5622. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5623. return STATUS_INVALID_PARAMETER;
  5624. }
  5625. }
  5626. //
  5627. // Readonly mount should be just that: read only.
  5628. //
  5629. if (NtfsIsVolumeReadOnly( Vcb )) {
  5630. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  5631. return STATUS_MEDIA_WRITE_PROTECTED;
  5632. }
  5633. try {
  5634. //
  5635. // We now want to acquire the Scb to check if we can continue.
  5636. //
  5637. if (Scb->Header.PagingIoResource != NULL) {
  5638. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  5639. PagingIoAcquired = TRUE;
  5640. }
  5641. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5642. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  5643. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  5644. }
  5645. //
  5646. // compression not allowed on encrypted streams - this mirrors
  5647. // the error code efs gives for this kind of attempt - initially we
  5648. // precall efs to weed these out but that still leaves a race that this
  5649. // plugs
  5650. //
  5651. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  5652. try_return( Status = STATUS_INVALID_DEVICE_REQUEST );
  5653. }
  5654. //
  5655. // Handle the simple directory case here.
  5656. //
  5657. if ((Scb->Header.NodeTypeCode == NTFS_NTC_SCB_INDEX) ||
  5658. (Scb->Header.NodeTypeCode == NTFS_NTC_SCB_ROOT_INDEX)) {
  5659. NtfsChangeAttributeCompression( IrpContext, Scb, Vcb, Ccb, CompressionState );
  5660. ClearFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  5661. SetFlag( Scb->AttributeFlags, CompressionState );
  5662. try_return( Status = STATUS_SUCCESS );
  5663. }
  5664. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  5665. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  5666. }
  5667. //
  5668. // Set the WRITE_ACCESS_SEEN flag so that we will enforce the
  5669. // reservation strategy.
  5670. //
  5671. if (!FlagOn( Scb->ScbState, SCB_STATE_WRITE_ACCESS_SEEN )) {
  5672. LONGLONG ClusterCount;
  5673. NtfsAcquireReservedClusters( Vcb );
  5674. //
  5675. // Does this Scb have reserved space that causes us to exceed the free
  5676. // space on the volume?
  5677. //
  5678. ClusterCount = LlClustersFromBytesTruncate( Vcb, Scb->ScbType.Data.TotalReserved );
  5679. if ((Scb->ScbType.Data.TotalReserved != 0) &&
  5680. ((ClusterCount + Vcb->TotalReserved) > Vcb->FreeClusters)) {
  5681. NtfsReleaseReservedClusters( Vcb );
  5682. try_return( Status = STATUS_DISK_FULL );
  5683. }
  5684. //
  5685. // Otherwise tally in the reserved space now for this Scb, and
  5686. // remember that we have seen write access.
  5687. //
  5688. Vcb->TotalReserved += ClusterCount;
  5689. SetFlag( Scb->ScbState, SCB_STATE_WRITE_ACCESS_SEEN );
  5690. NtfsReleaseReservedClusters( Vcb );
  5691. }
  5692. //
  5693. // If this is the first pass through SetCompression we need to set this
  5694. // request up as the top-level change compression operation. This means
  5695. // setting the REALLOCATE_ON_WRITE flag, changing the attribute state
  5696. // and putting the SCB_STATE_WRITE_COMPRESSED flag in the correct state.
  5697. //
  5698. if (NextIrpSp->Parameters.FileSystemControl.OutputBufferLength == MAXULONG) {
  5699. //
  5700. // If the REALLOCATE_ON_WRITE flag is set it means that someone is
  5701. // already changing the compression state. Return STATUS_SUCCESS in
  5702. // that case.
  5703. //
  5704. if (FlagOn( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE )) {
  5705. try_return( Status = STATUS_SUCCESS );
  5706. }
  5707. //
  5708. // If we are turning off compression and the file is uncompressed then
  5709. // we can just get out.
  5710. //
  5711. if ((CompressionState == 0) && ((Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) == 0)) {
  5712. try_return( Status = STATUS_SUCCESS );
  5713. }
  5714. //
  5715. // If we are compressing, change the compressed state now.
  5716. //
  5717. if (CompressionState != 0) {
  5718. //
  5719. // See if we have to create an internal attribute stream. Do this first even though
  5720. // we don't need it for the next operation. We want to find out if we can't
  5721. // create the stream object (maybe the file is so large mm can't cache it) before
  5722. // changing the compression state. Otherwise the user will never be able to
  5723. // access the file.
  5724. //
  5725. if (Scb->FileObject == NULL) {
  5726. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  5727. }
  5728. NtfsChangeAttributeCompression( IrpContext, Scb, Vcb, Ccb, CompressionState );
  5729. Scb->AttributeFlags = (USHORT)((Scb->AttributeFlags & ~ATTRIBUTE_FLAG_COMPRESSION_MASK) |
  5730. CompressionState);
  5731. SetFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  5732. //
  5733. // Otherwise, we must clear the compress flag in the Scb to
  5734. // start writing decompressed.
  5735. //
  5736. } else {
  5737. ClearFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  5738. }
  5739. //
  5740. // Set ourselves up as the top level request.
  5741. //
  5742. SetFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  5743. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
  5744. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = 0;
  5745. //
  5746. // If we are turning off compression and the file is uncompressed then
  5747. // we can just get out. Even if we raised while decompressing. If
  5748. // the state is now uncompressed then we have committed the change.
  5749. //
  5750. } else if (CompressionState == 0) {
  5751. ASSERT( !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ));
  5752. //
  5753. // If the flag is set then make sure to start back at offset zero in
  5754. // the file.
  5755. //
  5756. if (FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED )) {
  5757. ClearFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  5758. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
  5759. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = 0;
  5760. }
  5761. if ((Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) == 0) {
  5762. try_return( Status = STATUS_SUCCESS );
  5763. }
  5764. }
  5765. //
  5766. // In the Fsd entry we clear the following two parameter fields in the Irp,
  5767. // and then we update them to our current position on all abnormal terminations.
  5768. // That way if we get a log file full, we only have to resume where we left
  5769. // off.
  5770. //
  5771. ((PLARGE_INTEGER)&FileOffset)->LowPart = NextIrpSp->Parameters.FileSystemControl.OutputBufferLength;
  5772. ((PLARGE_INTEGER)&FileOffset)->HighPart = NextIrpSp->Parameters.FileSystemControl.InputBufferLength;
  5773. //
  5774. // Make sure to flush and purge the compressed stream if present.
  5775. //
  5776. #ifdef COMPRESS_ON_WIRE
  5777. if (Scb->Header.FileObjectC != NULL) {
  5778. PCOMPRESSION_SYNC CompressionSync = NULL;
  5779. //
  5780. // Use a try-finally to clean up the compression sync.
  5781. //
  5782. try {
  5783. Status = NtfsSynchronizeUncompressedIo( Scb,
  5784. NULL,
  5785. 0,
  5786. TRUE,
  5787. &CompressionSync );
  5788. } finally {
  5789. NtfsReleaseCompressionSync( CompressionSync );
  5790. }
  5791. NtfsNormalizeAndCleanupTransaction( IrpContext, &Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  5792. NtfsDeleteInternalAttributeStream( Scb, TRUE, TRUE );
  5793. ASSERT( Scb->Header.FileObjectC == NULL );
  5794. }
  5795. #endif
  5796. //
  5797. // If the stream is resident there is no need rewrite any of the data.
  5798. //
  5799. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  5800. //
  5801. // Release all of the files held by this Irp Context. The Mft
  5802. // may have been grabbed to make space for the TotalAllocated field.
  5803. // This will automatically also release the pageingio
  5804. //
  5805. ASSERT(IrpContext->TransactionId == 0);
  5806. NtfsReleaseAllResources( IrpContext );
  5807. PagingIoAcquired = FALSE;
  5808. while (TRUE) {
  5809. //
  5810. // We must throttle our writes.
  5811. //
  5812. CcCanIWrite( FileObject, 0x40000, TRUE, FALSE );
  5813. //
  5814. // Lock the FsRtl header so we can freeze FileSize.
  5815. // Acquire paging io exclusive if uncompressing so
  5816. // we can guarantee that all of the pages get written
  5817. // before we mark the file as uncompressed. Otherwise a
  5818. // a competing LazyWrite in a range may block after
  5819. // going through Mm and Mm will report to this routine
  5820. // that the flush has occurred.
  5821. //
  5822. if (CompressionState == 0) {
  5823. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  5824. } else {
  5825. ExAcquireResourceSharedLite( Scb->Header.PagingIoResource, TRUE );
  5826. }
  5827. FsRtlLockFsRtlHeader( &Scb->Header );
  5828. IrpContext->CleanupStructure = Scb;
  5829. FsRtlHeaderLocked = TRUE;
  5830. //
  5831. // Also check if the volume is mounted.
  5832. //
  5833. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  5834. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  5835. }
  5836. //
  5837. // Jump out right here if the attribute is resident.
  5838. //
  5839. if (FlagOn(Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT)) {
  5840. break;
  5841. }
  5842. //
  5843. // Let's round the file offset down to a sparse unit boundary to
  5844. // clean up the sparse file support.
  5845. //
  5846. if (Scb->CompressionUnit != 0) {
  5847. ((PLARGE_INTEGER)&FileOffset)->LowPart &= ~(Vcb->SparseFileUnit - 1);
  5848. }
  5849. //
  5850. // See if we have to create an internal attribute stream. We do
  5851. // it in the loop, because the Scb must be acquired.
  5852. //
  5853. if (Scb->FileObject == NULL) {
  5854. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  5855. }
  5856. //
  5857. // Loop through the current view looking for deallocated ranges.
  5858. //
  5859. do {
  5860. //
  5861. // Calculate the bytes left in the file to write.
  5862. //
  5863. ByteCount = Scb->Header.FileSize.QuadPart - FileOffset;
  5864. //
  5865. // This is how we exit, seeing that we have finally rewritten
  5866. // everything. It is possible that the file was truncated
  5867. // between passes through this loop so we test for 0 bytes or
  5868. // a negative value.
  5869. //
  5870. // Note that we exit with the Scb still acquired,
  5871. // so that we can reliably turn compression off.
  5872. //
  5873. if (ByteCount <= 0) {
  5874. break;
  5875. }
  5876. //
  5877. // If there is more than our max, then reduce the byte count for this
  5878. // pass to our maximum.
  5879. //
  5880. if (((ULONG)FileOffset & 0x3ffff) + ByteCount > 0x40000) {
  5881. ByteCount = 0x40000 - ((ULONG)FileOffset & 0x3ffff);
  5882. }
  5883. //
  5884. // If the file is sparse then skip any deallocated regions. Note that
  5885. // this is safe even if there are dirty pages in the data section.
  5886. // Space will be correctly allocated when the writes occur at some point.
  5887. // We are only concerned with ranges that need to be reallocated.
  5888. //
  5889. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5890. VCN RangeStartVcn;
  5891. LONGLONG RangeClusterCount;
  5892. VCN RangeFinalVcn;
  5893. ULONG RangeByteCount;
  5894. RangeStartVcn = LlClustersFromBytesTruncate( Vcb, FileOffset );
  5895. RangeFinalVcn = LlClustersFromBytes( Vcb, FileOffset + ByteCount );
  5896. //
  5897. // Preload the allocation to check for sparse ranges.
  5898. //
  5899. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5900. NtfsPreloadAllocation( IrpContext,
  5901. Scb,
  5902. RangeStartVcn,
  5903. RangeFinalVcn - 1 );
  5904. do {
  5905. BOOLEAN IsAllocated;
  5906. //
  5907. // If the current block is allocated then perform
  5908. // the compression operation on this range.
  5909. //
  5910. IsAllocated = NtfsIsRangeAllocated( Scb,
  5911. RangeStartVcn,
  5912. RangeFinalVcn,
  5913. TRUE,
  5914. &RangeClusterCount );
  5915. RangeByteCount = BytesFromClusters( Vcb, (ULONG) RangeClusterCount );
  5916. //
  5917. // Remember if the number of bytes to change
  5918. // the compression on has shrunk.
  5919. //
  5920. if (IsAllocated) {
  5921. if (ByteCount > RangeByteCount) {
  5922. ByteCount = RangeByteCount;
  5923. }
  5924. //
  5925. // Break out to the outer loop.
  5926. //
  5927. break;
  5928. }
  5929. //
  5930. // Extend ValidDataLength if we the current range leaves no
  5931. // gaps. This will prevent the next write from reallocating
  5932. // a previous range in a ZeroData call.
  5933. //
  5934. if ((FileOffset + RangeByteCount > Scb->Header.ValidDataLength.QuadPart) &&
  5935. (FileOffset <= Scb->Header.ValidDataLength.QuadPart)) {
  5936. Scb->Header.ValidDataLength.QuadPart = FileOffset + RangeByteCount;
  5937. if (Scb->Header.ValidDataLength.QuadPart > Scb->Header.FileSize.QuadPart) {
  5938. Scb->Header.ValidDataLength.QuadPart = Scb->Header.FileSize.QuadPart;
  5939. }
  5940. #ifdef SYSCACHE_DEBUG
  5941. if (ScbIsBeingLogged( Scb )) {
  5942. FsRtlLogSyscacheEvent( Scb, SCE_SETCOMPRESS, SCE_FLAG_SET_VDL, FileOffset, RangeByteCount, Scb->Header.ValidDataLength.QuadPart );
  5943. }
  5944. #endif
  5945. }
  5946. //
  5947. // If we have found the last requested cluster then break out.
  5948. //
  5949. if ((RangeFinalVcn - RangeStartVcn) <= RangeClusterCount) {
  5950. ByteCount = 0;
  5951. FileOffset += LlBytesFromClusters( Vcb, RangeFinalVcn - RangeStartVcn );
  5952. break;
  5953. //
  5954. // The range is not allocated but we need to check whether
  5955. // there are any dirty pages in this range.
  5956. //
  5957. } else if (NtfsCheckForReservedClusters( Scb,
  5958. RangeStartVcn,
  5959. &RangeClusterCount ) &&
  5960. (RangeClusterCount < Vcb->SparseFileClusters)) {
  5961. if (ByteCount > Vcb->SparseFileUnit) {
  5962. ByteCount = Vcb->SparseFileUnit;
  5963. }
  5964. break;
  5965. }
  5966. //
  5967. // There is a hole at the current location. Move
  5968. // to the next block to consider.
  5969. //
  5970. RangeStartVcn += RangeClusterCount;
  5971. RangeByteCount = BytesFromClusters( Vcb, (ULONG) RangeClusterCount );
  5972. ByteCount -= RangeByteCount;
  5973. FileOffset += RangeByteCount;
  5974. } while (ByteCount != 0);
  5975. NtfsReleaseScb( IrpContext, Scb );
  5976. }
  5977. } while (ByteCount == 0);
  5978. //
  5979. // Check if have reached the end of the file.
  5980. // Note that we exit with the Scb still acquired,
  5981. // so that we can reliably turn compression off.
  5982. //
  5983. if (ByteCount <= 0) {
  5984. break;
  5985. }
  5986. //
  5987. // Make sure there are enough available clusters in the range
  5988. // we want to rewrite.
  5989. //
  5990. NtfsPurgeFileRecordCache( IrpContext );
  5991. if (!NtfsReserveClusters( IrpContext, Scb, FileOffset, (ULONG) ByteCount )) {
  5992. //
  5993. // If this transaction has already deallocated clusters
  5994. // then raise log file full to allow those to become
  5995. // available.
  5996. //
  5997. if (IrpContext->DeallocatedClusters != 0) {
  5998. NtfsRaiseStatus( IrpContext, STATUS_LOG_FILE_FULL, NULL, NULL );
  5999. //
  6000. // Otherwise there is insufficient space to guarantee
  6001. // we can perform the compression operation.
  6002. //
  6003. } else {
  6004. NtfsRaiseStatus( IrpContext, STATUS_DISK_FULL, NULL, NULL );
  6005. }
  6006. }
  6007. //
  6008. // Map the next range of the file, and make the pages dirty.
  6009. //
  6010. #ifdef BENL_DBG
  6011. ASSERT( (FileOffset % Scb->CompressionUnit == 0) && (ByteCount % Scb->CompressionUnit == 0 || FileOffset + ByteCount == Scb->Header.FileSize.QuadPart) );
  6012. #endif
  6013. //
  6014. // Do an empty MDL read and write to lock the range down and set it dirty for the subsequent flushcache
  6015. //
  6016. try {
  6017. ReadMdl = NULL;
  6018. WriteMdl = NULL;
  6019. //
  6020. // Page it all in
  6021. //
  6022. CcMdlRead( Scb->FileObject, (PLARGE_INTEGER)&FileOffset, (ULONG)ByteCount, &ReadMdl, &Iosb );
  6023. ASSERT( STATUS_SUCCESS == Iosb.Status );
  6024. //
  6025. // Mark it as modified
  6026. //
  6027. CcPrepareMdlWrite( Scb->FileObject, (PLARGE_INTEGER)&FileOffset, (ULONG)ByteCount, &WriteMdl, &Iosb );
  6028. ASSERT( STATUS_SUCCESS == Iosb.Status );
  6029. } finally {
  6030. if (WriteMdl) {
  6031. CcMdlWriteComplete( Scb->FileObject, (PLARGE_INTEGER)&FileOffset, WriteMdl );
  6032. }
  6033. if (ReadMdl) {
  6034. CcMdlReadComplete( Scb->FileObject, ReadMdl );
  6035. }
  6036. }
  6037. #ifdef SYSCACHE
  6038. //
  6039. // Clear write mask before the flush
  6040. //
  6041. {
  6042. PULONG WriteMask;
  6043. ULONG Len;
  6044. ULONG Off = (ULONG)FileOffset;
  6045. WriteMask = Scb->ScbType.Data.WriteMask;
  6046. if (WriteMask == NULL) {
  6047. WriteMask = NtfsAllocatePool( NonPagedPool, (((0x2000000) / PAGE_SIZE) / 8) );
  6048. Scb->ScbType.Data.WriteMask = WriteMask;
  6049. RtlZeroMemory(WriteMask, (((0x2000000) / PAGE_SIZE) / 8));
  6050. }
  6051. if (Off < 0x2000000) {
  6052. Len = (ULONG)ByteCount;
  6053. if ((Off + Len) > 0x2000000) {
  6054. Len = 0x2000000 - Off;
  6055. }
  6056. while (Len != 0) {
  6057. ASSERT( !FlagOn( Scb->ScbState, SCB_STATE_SYSCACHE_FILE ) ||
  6058. (WriteMask[(Off / PAGE_SIZE)/32] & (1 << ((Off / PAGE_SIZE) % 32))));
  6059. Off += PAGE_SIZE;
  6060. if (Len <= PAGE_SIZE) {
  6061. break;
  6062. }
  6063. Len -= PAGE_SIZE;
  6064. }
  6065. }
  6066. #endif
  6067. //
  6068. // Now flush these pages to reallocate them.
  6069. //
  6070. Irp->IoStatus.Status = NtfsFlushUserStream( IrpContext,
  6071. Scb,
  6072. &FileOffset,
  6073. (ULONG)ByteCount );
  6074. //
  6075. // On error get out.
  6076. //
  6077. NtfsNormalizeAndCleanupTransaction( IrpContext,
  6078. &Irp->IoStatus.Status,
  6079. TRUE,
  6080. STATUS_UNEXPECTED_IO_ERROR );
  6081. #ifdef SYSCACHE
  6082. //
  6083. // Verify writes occurred after the flush
  6084. //
  6085. Off = (ULONG)FileOffset;
  6086. WriteMask = Scb->ScbType.Data.WriteMask;
  6087. if (Off < 0x2000000) {
  6088. Len = (ULONG)ByteCount;
  6089. if ((Off + Len) > 0x2000000) {
  6090. Len = 0x2000000 - Off;
  6091. }
  6092. while (Len != 0) {
  6093. ASSERT(WriteMask[(Off / PAGE_SIZE)/32] & (1 << ((Off / PAGE_SIZE) % 32)));
  6094. Off += PAGE_SIZE;
  6095. if (Len <= PAGE_SIZE) {
  6096. break;
  6097. }
  6098. Len -= PAGE_SIZE;
  6099. }
  6100. }
  6101. }
  6102. #endif
  6103. //
  6104. // Release any remaing reserved clusters in this range.
  6105. //
  6106. NtfsFreeReservedClusters( Scb, FileOffset, (ULONG) ByteCount );
  6107. //
  6108. // Advance the FileOffset.
  6109. //
  6110. FileOffset += ByteCount;
  6111. //
  6112. // If we hit the end of the file then exit while holding the
  6113. // resource so we can turn compression off.
  6114. //
  6115. if (FileOffset == Scb->Header.FileSize.QuadPart) {
  6116. break;
  6117. }
  6118. //
  6119. // Unlock the header an let anyone else access the file before
  6120. // looping back.
  6121. //
  6122. FsRtlUnlockFsRtlHeader( &Scb->Header );
  6123. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  6124. IrpContext->CleanupStructure = NULL;
  6125. FsRtlHeaderLocked = FALSE;
  6126. }
  6127. }
  6128. //
  6129. // We have finished the conversion. Now is the time to turn compression
  6130. // off. Note that the compression flag in the Scb is already off.
  6131. //
  6132. if (CompressionState == 0) {
  6133. VCN StartingCluster;
  6134. //
  6135. // The paging Io resource may already be acquired.
  6136. //
  6137. if (!PagingIoAcquired && !FsRtlHeaderLocked) {
  6138. if (Scb->Header.PagingIoResource != NULL) {
  6139. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  6140. PagingIoAcquired = TRUE;
  6141. }
  6142. }
  6143. NtfsAcquireExclusiveScb( IrpContext, Scb );
  6144. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6145. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  6146. }
  6147. //
  6148. // Changing the compression state to uncompressed is a ticklish thing.
  6149. // We need to make sure that all of the compression units are valid for
  6150. // the entire allocation for the file. For non-sparse files all compression
  6151. // units should be fully allocation. For sparse files all compression
  6152. // units should be either fully allocated or fully unallocated. The interesting
  6153. // case is typically when the file size of a compressed file is dropped but
  6154. // the allocation remains. The allocation in that range may be in the compressed
  6155. // format. We need to proactively remove it.
  6156. //
  6157. // In the non-sparse case we have already rewritten the data all the way
  6158. // through file size. We only have to remove the allocation past the
  6159. // cluster containing Eof.
  6160. //
  6161. // In the sparse case we actually have to deal with allocated ranges
  6162. // in the range between valid data length and file size as well. We
  6163. // didn't rewrite this in the flush path above because we don't want
  6164. // to allocate clusters for zeroes.
  6165. //
  6166. // The action of deallocating the clusters past file size must be tied
  6167. // in with the transaction of flipping the compression state.
  6168. //
  6169. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  6170. //
  6171. // In all cases we can remove the clusters in the compression
  6172. // units past that containing Eof.
  6173. //
  6174. StartingCluster = Scb->Header.FileSize.QuadPart + Scb->CompressionUnit - 1;
  6175. ((PLARGE_INTEGER) &StartingCluster)->LowPart &= ~(Scb->CompressionUnit - 1);
  6176. if (StartingCluster < Scb->Header.AllocationSize.QuadPart) {
  6177. //
  6178. // Deallocate the space past the filesize
  6179. //
  6180. NtfsDeleteAllocation( IrpContext,
  6181. IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->FileObject,
  6182. Scb,
  6183. LlClustersFromBytesTruncate( Vcb, StartingCluster ),
  6184. MAXLONGLONG,
  6185. TRUE,
  6186. TRUE );
  6187. }
  6188. //
  6189. // For sparse files we need to handle the allocation between valid data length
  6190. // and allocation size.
  6191. //
  6192. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  6193. //
  6194. // Assume that the data up to either ValidDataLength or ValidDataToDisk
  6195. // is valid. Start at the compression unit after that.
  6196. //
  6197. StartingCluster = Scb->Header.ValidDataLength.QuadPart;
  6198. if (Scb->ValidDataToDisk > StartingCluster) {
  6199. StartingCluster = Scb->ValidDataToDisk;
  6200. }
  6201. StartingCluster += Scb->CompressionUnit - 1;
  6202. ((PLARGE_INTEGER) &StartingCluster)->LowPart &= ~(Scb->CompressionUnit - 1);
  6203. if (StartingCluster < Scb->Header.AllocationSize.QuadPart) {
  6204. NtfsDeleteAllocation( IrpContext,
  6205. IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->FileObject,
  6206. Scb,
  6207. LlClustersFromBytesTruncate( Vcb, StartingCluster ),
  6208. LlClustersFromBytesTruncate( Vcb, Scb->Header.AllocationSize.QuadPart ) - 1,
  6209. TRUE,
  6210. TRUE );
  6211. }
  6212. }
  6213. //
  6214. // If total allocated has changed then remember to report it.
  6215. //
  6216. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
  6217. (Scb->Fcb->Info.AllocatedLength != Scb->TotalAllocated)) {
  6218. Scb->Fcb->Info.AllocatedLength = Scb->TotalAllocated;
  6219. SetFlag( Scb->Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
  6220. }
  6221. //
  6222. // Check whether there is more to be truncated when the handle is closed.
  6223. //
  6224. SetFlag( Scb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE );
  6225. }
  6226. NtfsChangeAttributeCompression( IrpContext, Scb, Vcb, Ccb, 0 );
  6227. Scb->AttributeFlags &= (USHORT)~ATTRIBUTE_FLAG_COMPRESSION_MASK;
  6228. //
  6229. // Reset the VDD since its not used for uncompressed files
  6230. //
  6231. Scb->ValidDataToDisk = 0;
  6232. //
  6233. // No need to set the WRITE_COMPRESSED flag on error.
  6234. //
  6235. ClearFlag( ScbRestoreState, SCB_STATE_WRITE_COMPRESSED );
  6236. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT ) &&
  6237. (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE ))) {
  6238. if (Scb->ScbType.Data.ReservedBitMap != NULL) {
  6239. NtfsDeleteReservedBitmap( Scb );
  6240. }
  6241. }
  6242. //
  6243. // Now clear the REALLOCATE_ON_WRITE flag while holding both resources.
  6244. //
  6245. ClearFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  6246. }
  6247. //
  6248. // Unlock the header if we locked it.
  6249. //
  6250. if (FsRtlHeaderLocked) {
  6251. FsRtlUnlockFsRtlHeader( &Scb->Header );
  6252. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  6253. IrpContext->CleanupStructure = NULL;
  6254. FsRtlHeaderLocked = FALSE;
  6255. }
  6256. Status = STATUS_SUCCESS;
  6257. #ifdef SYSCACHE_DEBUG
  6258. if (ScbIsBeingLogged( Scb )) {
  6259. FsRtlLogSyscacheEvent( Scb, SCE_SETCOMPRESS, 0, Scb->ValidDataToDisk, Scb->Header.ValidDataLength.QuadPart, 0 );
  6260. }
  6261. #endif
  6262. try_exit: NOTHING;
  6263. //
  6264. // Now clear the reallocate flag in the Scb if we set it.
  6265. //
  6266. if (NextIrpSp->Parameters.FileSystemControl.OutputBufferLength != MAXULONG) {
  6267. ClearFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  6268. }
  6269. } finally {
  6270. DebugUnwind( NtfsSetCompression );
  6271. //
  6272. // NtfsCompleteRequest will clean up the Fsrtl header but
  6273. // we still need to release the paging resource if held.
  6274. //
  6275. if (FsRtlHeaderLocked) {
  6276. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  6277. }
  6278. //
  6279. // If this is an abnormal termination then undo our work
  6280. //
  6281. if (AbnormalTermination()) {
  6282. //
  6283. // If we have started the transformation and are in the exception path
  6284. // we are either going to continue the operation after a clean
  6285. // checkpoint or we are done.
  6286. //
  6287. if (NextIrpSp->Parameters.FileSystemControl.OutputBufferLength != MAXULONG) {
  6288. //
  6289. // If we are continuing the operation, save the current file offset.
  6290. //
  6291. if (IrpContext->ExceptionStatus == STATUS_LOG_FILE_FULL ||
  6292. IrpContext->ExceptionStatus == STATUS_CANT_WAIT) {
  6293. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = (ULONG)FileOffset;
  6294. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = ((PLARGE_INTEGER)&FileOffset)->HighPart;
  6295. //
  6296. // Otherwise clear the REALLOCATE_ON_WRITE flag and set the
  6297. // COMPRESSED flag if needed.
  6298. //
  6299. } else {
  6300. ClearFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  6301. SetFlag( Scb->ScbState, ScbRestoreState );
  6302. ASSERT( !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) ||
  6303. (Scb->CompressionUnit != 0) );
  6304. }
  6305. }
  6306. }
  6307. }
  6308. NtfsCompleteRequest( IrpContext, Irp, Status );
  6309. ASSERT( !NT_SUCCESS( Status ) ||
  6310. (CompressionState != 0) ||
  6311. !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) ||
  6312. (Scb->CompressionUnit != 0) );
  6313. return Status;
  6314. }
  6315. //
  6316. // Local Support Routine
  6317. //
  6318. NTSTATUS
  6319. NtfsMarkAsSystemHive (
  6320. IN PIRP_CONTEXT IrpContext,
  6321. IN PIRP Irp
  6322. )
  6323. /*++
  6324. Routine Description:
  6325. This routine is called by the registry to identify the registry handles. We
  6326. will mark this in the Ccb and use it during FlushBuffers to know to do a
  6327. careful flush.
  6328. Arguments:
  6329. Irp - Supplies the Irp being processed.
  6330. Return Value:
  6331. NTSTATUS - The return status for the operation
  6332. --*/
  6333. {
  6334. PIO_STACK_LOCATION IrpSp;
  6335. TYPE_OF_OPEN TypeOfOpen;
  6336. PVCB Vcb;
  6337. PFCB Fcb;
  6338. PSCB Scb;
  6339. PCCB Ccb;
  6340. PAGED_CODE();
  6341. //
  6342. // Always make this synchronous.
  6343. //
  6344. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6345. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  6346. //
  6347. // Extract and decode the file object
  6348. //
  6349. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6350. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  6351. //
  6352. // We only permit this request on files and we must be called from kernel mode.
  6353. //
  6354. if (Irp->RequestorMode != KernelMode ||
  6355. TypeOfOpen != UserFileOpen) {
  6356. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6357. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  6358. return STATUS_INVALID_PARAMETER;
  6359. }
  6360. //
  6361. // Now acquire the file and mark the Ccb and return SUCCESS.
  6362. //
  6363. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6364. NtfsAcquireExclusiveScb( IrpContext, Scb );
  6365. SetFlag( Ccb->Flags, CCB_FLAG_SYSTEM_HIVE );
  6366. NtfsReleaseScb( IrpContext, Scb );
  6367. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  6368. return STATUS_SUCCESS;
  6369. }
  6370. //
  6371. // Local Support Routine
  6372. //
  6373. NTSTATUS
  6374. NtfsGetStatistics (
  6375. IN PIRP_CONTEXT IrpContext,
  6376. IN PIRP Irp
  6377. )
  6378. /*++
  6379. Routine Description:
  6380. This routine returns the filesystem performance counters for the
  6381. volume referred to.
  6382. Arguments:
  6383. Irp - Supplies the Irp being processed.
  6384. Return Value:
  6385. NTSTATUS - The return status for the operation
  6386. --*/
  6387. {
  6388. PIO_STACK_LOCATION IrpSp;
  6389. NTSTATUS Status;
  6390. TYPE_OF_OPEN TypeOfOpen;
  6391. PVCB Vcb;
  6392. PFCB Fcb;
  6393. PSCB Scb;
  6394. PCCB Ccb;
  6395. PFILE_SYSTEM_STATISTICS Buffer;
  6396. ULONG BufferLength;
  6397. ULONG StatsSize;
  6398. ULONG BytesToCopy;
  6399. PAGED_CODE();
  6400. //
  6401. // Get the current stack location and extract the output
  6402. // buffer information. The output parameter will receive
  6403. // the performance counters.
  6404. //
  6405. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6406. //
  6407. // Extract the buffer
  6408. //
  6409. Buffer = Irp->AssociatedIrp.SystemBuffer;
  6410. BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6411. //
  6412. // Get a pointer to the output buffer.
  6413. //
  6414. Buffer = Irp->AssociatedIrp.SystemBuffer;
  6415. //
  6416. // Make sure the buffer is big enough for at least the common part.
  6417. //
  6418. if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) {
  6419. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6420. return STATUS_BUFFER_TOO_SMALL;
  6421. }
  6422. //
  6423. // Now see how many bytes we can copy.
  6424. //
  6425. StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors;
  6426. if (BufferLength < StatsSize) {
  6427. BytesToCopy = BufferLength;
  6428. Status = STATUS_BUFFER_OVERFLOW;
  6429. } else {
  6430. BytesToCopy = StatsSize;
  6431. Status = STATUS_SUCCESS;
  6432. }
  6433. //
  6434. // Decode the file object
  6435. //
  6436. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb,
  6437. &Fcb, &Scb, &Ccb, TRUE );
  6438. if (TypeOfOpen == UnopenedFileObject) {
  6439. Status = STATUS_INVALID_PARAMETER;
  6440. } else {
  6441. //
  6442. // Fill in the output buffer
  6443. //
  6444. RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
  6445. Irp->IoStatus.Information = BytesToCopy;
  6446. }
  6447. NtfsCompleteRequest( IrpContext, Irp, Status );
  6448. return Status;
  6449. }
  6450. //
  6451. // Local Support Routine
  6452. //
  6453. NTSTATUS
  6454. NtfsGetVolumeData (
  6455. IN PIRP_CONTEXT IrpContext,
  6456. IN PIRP Irp
  6457. )
  6458. /*++
  6459. Routine Description:
  6460. Returns a filled in VOLUME_DATA structure in the user output buffer.
  6461. Arguments:
  6462. Irp - Supplies the Irp being processed.
  6463. Return Value:
  6464. NTSTATUS - The return status for the operation.
  6465. --*/
  6466. {
  6467. PIO_STACK_LOCATION IrpSp;
  6468. ULONG FsControlCode;
  6469. NTSTATUS Status = STATUS_SUCCESS;
  6470. PFILE_OBJECT FileObject;
  6471. TYPE_OF_OPEN TypeOfOpen;
  6472. PVCB Vcb;
  6473. PFCB Fcb;
  6474. PSCB Scb;
  6475. PCCB Ccb;
  6476. BOOLEAN AcquiredScb = FALSE;
  6477. BOOLEAN AcquiredVcb = FALSE;
  6478. PNTFS_VOLUME_DATA_BUFFER VolumeData;
  6479. PNTFS_EXTENDED_VOLUME_DATA ExtendedBuffer;
  6480. ULONG ExtendedBufferLength;
  6481. ULONG VolumeDataLength;
  6482. //
  6483. // Get the current Irp stack location and save some references.
  6484. //
  6485. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6486. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  6487. DebugTrace( +1, Dbg, ("NtfsGetVolumeData, FsControlCode = %08lx\n", FsControlCode) );
  6488. //
  6489. // Extract and decode the file object and check for type of open.
  6490. //
  6491. FileObject = IrpSp->FileObject;
  6492. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  6493. if (TypeOfOpen == UnopenedFileObject) {
  6494. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6495. return STATUS_INVALID_PARAMETER;
  6496. }
  6497. //
  6498. // Get the output buffer length and pointer.
  6499. //
  6500. VolumeDataLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6501. VolumeData = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  6502. //
  6503. // Check for a minimum length on the ouput buffer.
  6504. //
  6505. if (VolumeDataLength < sizeof(NTFS_VOLUME_DATA_BUFFER)) {
  6506. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6507. return STATUS_BUFFER_TOO_SMALL;
  6508. }
  6509. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  6510. AcquiredVcb = TRUE;
  6511. try {
  6512. //
  6513. // Make sure the volume is still mounted.
  6514. //
  6515. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  6516. Status = STATUS_VOLUME_DISMOUNTED;
  6517. leave;
  6518. }
  6519. //
  6520. // Acquire the volume bitmap and fill in the volume data structure.
  6521. //
  6522. NtfsAcquireExclusiveScb( IrpContext, Vcb->BitmapScb );
  6523. AcquiredScb = TRUE;
  6524. NtfsReleaseVcb( IrpContext, Vcb );
  6525. AcquiredVcb = FALSE;
  6526. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6527. Status = STATUS_VOLUME_DISMOUNTED;
  6528. leave;
  6529. }
  6530. //
  6531. // We may need to rescan the bitmap if there is a chance we have
  6532. // performed the upgrade to get an accurate count of free clusters.
  6533. //
  6534. if (FlagOn( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS ) &&
  6535. FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  6536. NtfsScanEntireBitmap( IrpContext, Vcb, FALSE );
  6537. }
  6538. VolumeData->VolumeSerialNumber.QuadPart = Vcb->VolumeSerialNumber;
  6539. VolumeData->NumberSectors.QuadPart = Vcb->NumberSectors;
  6540. VolumeData->TotalClusters.QuadPart = Vcb->TotalClusters;
  6541. VolumeData->FreeClusters.QuadPart = Vcb->FreeClusters;
  6542. VolumeData->TotalReserved.QuadPart = Vcb->TotalReserved;
  6543. VolumeData->BytesPerSector = Vcb->BytesPerSector;
  6544. VolumeData->BytesPerCluster = Vcb->BytesPerCluster;
  6545. VolumeData->BytesPerFileRecordSegment = Vcb->BytesPerFileRecordSegment;
  6546. VolumeData->ClustersPerFileRecordSegment = Vcb->ClustersPerFileRecordSegment;
  6547. VolumeData->MftValidDataLength = Vcb->MftScb->Header.ValidDataLength;
  6548. VolumeData->MftStartLcn.QuadPart = Vcb->MftStartLcn;
  6549. VolumeData->Mft2StartLcn.QuadPart = Vcb->Mft2StartLcn;
  6550. VolumeData->MftZoneStart.QuadPart = Vcb->MftZoneStart;
  6551. VolumeData->MftZoneEnd.QuadPart = Vcb->MftZoneEnd;
  6552. if (VolumeData->MftZoneEnd.QuadPart > Vcb->TotalClusters) {
  6553. VolumeData->MftZoneEnd.QuadPart = Vcb->TotalClusters;
  6554. }
  6555. //
  6556. // Check if there is anything to add in the extended data.
  6557. //
  6558. ExtendedBufferLength = VolumeDataLength - sizeof( NTFS_VOLUME_DATA_BUFFER );
  6559. VolumeDataLength = sizeof( NTFS_VOLUME_DATA_BUFFER );
  6560. ExtendedBuffer = (PNTFS_EXTENDED_VOLUME_DATA) Add2Ptr( VolumeData, sizeof( NTFS_VOLUME_DATA_BUFFER ));
  6561. if (ExtendedBufferLength >= sizeof( NTFS_EXTENDED_VOLUME_DATA )) {
  6562. ExtendedBuffer->ByteCount = sizeof( NTFS_EXTENDED_VOLUME_DATA );
  6563. ExtendedBuffer->MajorVersion = Vcb->MajorVersion;
  6564. ExtendedBuffer->MinorVersion = Vcb->MinorVersion;
  6565. } else if (ExtendedBufferLength >= FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MinorVersion )) {
  6566. ExtendedBuffer->ByteCount = FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MinorVersion );
  6567. ExtendedBuffer->MajorVersion = Vcb->MajorVersion;
  6568. } else if (ExtendedBufferLength >= FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MajorVersion )) {
  6569. ExtendedBuffer->ByteCount = FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MajorVersion );
  6570. } else {
  6571. leave;
  6572. }
  6573. VolumeDataLength += ExtendedBuffer->ByteCount;
  6574. } finally {
  6575. if (AcquiredScb) {
  6576. NtfsReleaseScb( IrpContext, Vcb->BitmapScb );
  6577. }
  6578. if (AcquiredVcb) {
  6579. NtfsReleaseVcb( IrpContext, Vcb );
  6580. }
  6581. }
  6582. //
  6583. // If nothing raised then complete the irp.
  6584. //
  6585. Irp->IoStatus.Information = VolumeDataLength;
  6586. NtfsCompleteRequest( IrpContext, Irp, Status );
  6587. DebugTrace( -1, Dbg, ("NtfsGetVolumeData -> VOID\n") );
  6588. return Status;
  6589. }
  6590. //
  6591. // Local Support Routine
  6592. //
  6593. NTSTATUS
  6594. NtfsGetVolumeBitmap (
  6595. IN PIRP_CONTEXT IrpContext,
  6596. IN PIRP Irp
  6597. )
  6598. /*++
  6599. Routine Description:
  6600. This routine scans volume bitmap and returns the requested range.
  6601. Input = the GET_BITMAP data structure is passed in through the input buffer.
  6602. Output = the VOLUME_BITMAP data structure is returned through the output buffer.
  6603. Arguments:
  6604. Irp - Supplies the Irp being processed.
  6605. Return Value:
  6606. NTSTATUS - The return status for the operation.
  6607. --*/
  6608. {
  6609. NTSTATUS Status = STATUS_SUCCESS;
  6610. PIO_STACK_LOCATION IrpSp;
  6611. ULONG FsControlCode;
  6612. PFILE_OBJECT FileObject;
  6613. TYPE_OF_OPEN TypeOfOpen;
  6614. PVCB Vcb;
  6615. PFCB Fcb;
  6616. PSCB Scb;
  6617. PCCB Ccb;
  6618. PSTARTING_LCN_INPUT_BUFFER GetBitmap;
  6619. ULONG GetBitmapLength;
  6620. PVOLUME_BITMAP_BUFFER VolumeBitmap;
  6621. ULONG VolumeBitmapLength;
  6622. ULONG BitsWritten;
  6623. LCN Lcn;
  6624. LCN StartingLcn;
  6625. ULONG Offset;
  6626. RTL_BITMAP Bitmap;
  6627. PBCB BitmapBcb = NULL;
  6628. BOOLEAN AccessingUserBuffer = FALSE;
  6629. BOOLEAN ReleaseScb = FALSE;
  6630. //
  6631. // Don't post this request, we can't lock both input and output buffers.
  6632. //
  6633. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6634. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  6635. //
  6636. // Get the current Irp stack location and save some references.
  6637. //
  6638. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6639. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  6640. DebugTrace( +1, Dbg, ("NtfsGetVolumeBitmap, FsControlCode = %08lx\n", FsControlCode) );
  6641. //
  6642. // Extract and decode the file object and check for type of open.
  6643. // Send FALSE to indicate that we don't want to raise on dismounts
  6644. // because we'll check for that further down anyway.
  6645. //
  6646. FileObject = IrpSp->FileObject;
  6647. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  6648. //
  6649. // Get the input & output buffer lengths and pointers.
  6650. //
  6651. GetBitmapLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  6652. GetBitmap = (PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  6653. VolumeBitmapLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6654. VolumeBitmap = (PVOLUME_BITMAP_BUFFER)NtfsMapUserBuffer( Irp );
  6655. //
  6656. // Check the type of open and minimum requirements for the IO buffers.
  6657. //
  6658. if ((Ccb == NULL) ||
  6659. !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  6660. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  6661. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_ACCESS_DENIED\n") );
  6662. return STATUS_ACCESS_DENIED;
  6663. } else if (VolumeBitmapLength < sizeof( VOLUME_BITMAP_BUFFER )) {
  6664. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6665. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_BUFFER_TOO_SMALL\n") );
  6666. return STATUS_BUFFER_TOO_SMALL;
  6667. } else if (GetBitmapLength < sizeof( STARTING_LCN_INPUT_BUFFER )) {
  6668. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6669. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_INVALID_PARAMETER\n") );
  6670. return STATUS_INVALID_PARAMETER;
  6671. }
  6672. //
  6673. // Probe the user's buffers and capture the input values.
  6674. //
  6675. try {
  6676. if (Irp->RequestorMode != KernelMode) {
  6677. ProbeForRead( GetBitmap, GetBitmapLength, sizeof( UCHAR ));
  6678. ProbeForWrite( VolumeBitmap, VolumeBitmapLength, sizeof( UCHAR ));
  6679. }
  6680. StartingLcn = GetBitmap->StartingLcn.QuadPart;
  6681. } except(EXCEPTION_EXECUTE_HANDLER) {
  6682. NtfsRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER, NULL, NULL);
  6683. }
  6684. //
  6685. // Acquire the volume bitmap and check for a valid requested Lcn.
  6686. //
  6687. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  6688. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  6689. NtfsReleaseVcb( IrpContext, Vcb );
  6690. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  6691. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_VOLUME_DISMOUNTED\n") );
  6692. return STATUS_VOLUME_DISMOUNTED;
  6693. }
  6694. try {
  6695. //
  6696. // Acquire the volume bitmap and check for a valid requested Lcn.
  6697. // We no longer care about the Scb we were called with.
  6698. //
  6699. Scb = Vcb->BitmapScb;
  6700. NtfsAcquireSharedScb( IrpContext, Scb );
  6701. NtfsReleaseVcb( IrpContext, Vcb );
  6702. //
  6703. // Setting this flag to TRUE indicates we have the Scb but not the Vcb.
  6704. //
  6705. ReleaseScb = TRUE;
  6706. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6707. Status = STATUS_VOLUME_DISMOUNTED;
  6708. leave;
  6709. }
  6710. if ((StartingLcn < 0L) ||
  6711. (StartingLcn >= Vcb->TotalClusters)) {
  6712. Status = STATUS_INVALID_PARAMETER;
  6713. leave;
  6714. }
  6715. //
  6716. // Read in the volume bitmap page by page and copy it into the UserBuffer.
  6717. //
  6718. VolumeBitmapLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
  6719. //
  6720. // Use a try-except to catch user buffer problems.
  6721. //
  6722. try {
  6723. for (Lcn = StartingLcn, BitsWritten = 0;
  6724. Lcn < Vcb->TotalClusters;
  6725. Lcn = Lcn + Bitmap.SizeOfBitMap) {
  6726. ULONG BytesToCopy;
  6727. //
  6728. // Read in the bitmap page and make sure that we haven't messed up the math.
  6729. //
  6730. DebugTrace( 0, Dbg, ("Mapping bitmap from Lcn %I64x\n", (LONGLONG) Lcn) );
  6731. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  6732. NtfsMapPageInBitmap( IrpContext, Vcb, Lcn, &Lcn, &Bitmap, &BitmapBcb );
  6733. //
  6734. // If this is first iteration, update StartingLcn with actual
  6735. // starting cluster returned.
  6736. //
  6737. if (BitsWritten == 0) {
  6738. Offset = (ULONG)(StartingLcn - Lcn) / 8;
  6739. }
  6740. //
  6741. // Check to see if we have enough user buffer. If have some but
  6742. // not enough, copy what we can and return STATUS_BUFFER_OVERFLOW.
  6743. // If we are down to 0 (i.e. previous iteration used all the
  6744. // buffer), break right now.
  6745. //
  6746. BytesToCopy = ((Bitmap.SizeOfBitMap + 7) / 8) - Offset;
  6747. if (BytesToCopy > VolumeBitmapLength) {
  6748. BytesToCopy = VolumeBitmapLength;
  6749. Status = STATUS_BUFFER_OVERFLOW;
  6750. if (BytesToCopy == 0) {
  6751. break;
  6752. }
  6753. }
  6754. //
  6755. // Now copy it into the UserBuffer.
  6756. //
  6757. AccessingUserBuffer = TRUE;
  6758. RtlCopyMemory(&VolumeBitmap->Buffer[BitsWritten / 8], (PUCHAR)Bitmap.Buffer + Offset, BytesToCopy);
  6759. AccessingUserBuffer = FALSE;
  6760. //
  6761. // If this was an overflow, bump up bits written and continue
  6762. //
  6763. if (Status != STATUS_BUFFER_OVERFLOW) {
  6764. BitsWritten += Bitmap.SizeOfBitMap - (Offset * 8);
  6765. VolumeBitmapLength -= BytesToCopy;
  6766. } else {
  6767. BitsWritten += BytesToCopy * 8;
  6768. break;
  6769. }
  6770. Offset = 0;
  6771. }
  6772. AccessingUserBuffer = TRUE;
  6773. //
  6774. // Lower StartingLcn to the byte we started on
  6775. //
  6776. VolumeBitmap->StartingLcn.QuadPart = StartingLcn & ~7L;
  6777. VolumeBitmap->BitmapSize.QuadPart = Vcb->TotalClusters - VolumeBitmap->StartingLcn.QuadPart;
  6778. AccessingUserBuffer = FALSE;
  6779. Irp->IoStatus.Information =
  6780. FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + (BitsWritten + 7) / 8;
  6781. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  6782. //
  6783. // Convert any unexpected error to INVALID_USER_BUFFER if we
  6784. // are writing in the user's buffer.
  6785. //
  6786. NtfsRaiseStatus( IrpContext,
  6787. STATUS_INVALID_USER_BUFFER,
  6788. NULL,
  6789. NULL );
  6790. }
  6791. } finally {
  6792. DebugUnwind( NtfsGetVolumeBitmap );
  6793. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  6794. if (ReleaseScb) {
  6795. NtfsReleaseScb( IrpContext, Scb );
  6796. } else {
  6797. NtfsReleaseVcb( IrpContext, Vcb );
  6798. }
  6799. }
  6800. //
  6801. // If nothing raised then complete the irp.
  6802. //
  6803. NtfsCompleteRequest( IrpContext, Irp, Status );
  6804. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> VOID\n") );
  6805. return Status;
  6806. }
  6807. //
  6808. // Local Support Routine
  6809. //
  6810. NTSTATUS
  6811. NtfsGetRetrievalPointers (
  6812. IN PIRP_CONTEXT IrpContext,
  6813. IN PIRP Irp
  6814. )
  6815. /*++
  6816. Routine Description:
  6817. This routine scans the array of MCBs for the given SCB and builds an extent
  6818. list. The first run in the output extent list will start at the begining
  6819. of the contiguous run specified by the input parameter.
  6820. Input = STARTING_VCN_INPUT_BUFFER;
  6821. Output = RETRIEVAL_POINTERS_BUFFER.
  6822. Arguments:
  6823. Irp - Supplies the Irp being processed.
  6824. Return Value:
  6825. NTSTATUS - The return status for the operation.
  6826. --*/
  6827. {
  6828. NTSTATUS Status;
  6829. PIO_STACK_LOCATION IrpSp;
  6830. TYPE_OF_OPEN TypeOfOpen;
  6831. PVCB Vcb;
  6832. PFCB Fcb;
  6833. PSCB Scb;
  6834. PCCB Ccb;
  6835. VCN Vcn;
  6836. VCN LastVcnInFile;
  6837. LCN Lcn;
  6838. LONGLONG ClusterCount;
  6839. LONGLONG CountFromStartingVcn;
  6840. LONGLONG StartingVcn;
  6841. ULONG FileRunIndex = 0;
  6842. ULONG RangeRunIndex;
  6843. ULONG InputBufferLength;
  6844. ULONG OutputBufferLength;
  6845. PVOID RangePtr;
  6846. PRETRIEVAL_POINTERS_BUFFER OutputBuffer;
  6847. BOOLEAN AccessingUserBuffer = FALSE;
  6848. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  6849. BOOLEAN CleanupAttributeContext = FALSE;
  6850. //
  6851. // Don't post this request, we can't lock both input and output buffers.
  6852. //
  6853. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6854. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  6855. //
  6856. // Get the current Irp stack location and save some references.
  6857. //
  6858. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6859. DebugTrace( +1, Dbg, ("NtfsGetRetrievalPointers\n") );
  6860. //
  6861. // Extract and decode the file object and check for type of open.
  6862. // If we ever decide to support UserDirectoryOpen also, make sure
  6863. // to check for Scb->AttributeTypeCode != $INDEX_ALLOCATION when
  6864. // checking whether the Scb header is initialized. Otherwise we'll
  6865. // have trouble with phantom Scbs created for small directories.
  6866. //
  6867. //
  6868. // Get the input and output buffer lengths and pointers.
  6869. // Initialize some variables.
  6870. //
  6871. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  6872. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6873. OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)NtfsMapUserBuffer( Irp );
  6874. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  6875. if (((TypeOfOpen != UserFileOpen) &&
  6876. (TypeOfOpen != UserDirectoryOpen) &&
  6877. (TypeOfOpen != UserViewIndexOpen)) ||
  6878. (InputBufferLength < sizeof( STARTING_VCN_INPUT_BUFFER ))) {
  6879. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6880. return STATUS_INVALID_PARAMETER;
  6881. }
  6882. if (OutputBufferLength < sizeof( RETRIEVAL_POINTERS_BUFFER )) {
  6883. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6884. return STATUS_BUFFER_TOO_SMALL;
  6885. }
  6886. //
  6887. // Acquire exclusive access to the Scb. We don't want other threads
  6888. // to extend or move the file while we're trying to return the
  6889. // retrieval pointers for it. We need it exclusve to call PreloadAllocation.
  6890. //
  6891. NtfsAcquireExclusiveScb( IrpContext, Scb );
  6892. try {
  6893. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6894. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  6895. }
  6896. //
  6897. // There are three separate places inside this try/except where we
  6898. // access the user-supplied buffer. We want to handle exceptions
  6899. // differently if they happen while we are trying to access the user
  6900. // buffer than if they happen elsewhere in the try/except. We set
  6901. // this boolean immediately before touching the user buffer, and
  6902. // clear it immediately after.
  6903. //
  6904. try {
  6905. AccessingUserBuffer = TRUE;
  6906. if (Irp->RequestorMode != KernelMode) {
  6907. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  6908. InputBufferLength,
  6909. sizeof(UCHAR) );
  6910. ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
  6911. }
  6912. StartingVcn = ((PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingVcn.QuadPart;
  6913. //
  6914. // While we have AccessingUserBuffer set to TRUE, let's initialize the
  6915. // extentcount. We increment this for each run in the mcb, so we need
  6916. // to initialize it outside the main do while loop.
  6917. //
  6918. OutputBuffer->ExtentCount = 0;
  6919. OutputBuffer->StartingVcn.QuadPart = 0;
  6920. AccessingUserBuffer = FALSE;
  6921. //
  6922. // If the Scb is uninitialized, we initialize it now.
  6923. //
  6924. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  6925. //
  6926. // Non-index Scb's are trivial to initialize; index Scb's
  6927. // do not necessarily have an attribute to back them up:
  6928. // the index Scb is for the index allocation attribute which
  6929. // may not be present if the entire index fits in the $INDEX_ROOT.
  6930. //
  6931. // We look for the attribute on disk. If it is there, we
  6932. // update from it. Otherwise, if it is $INDEX_ALLOCATION we
  6933. // treat it as a resident attribute. Finally, we fail it.
  6934. //
  6935. NtfsInitializeAttributeContext( &AttributeContext );
  6936. CleanupAttributeContext = TRUE;
  6937. if (!NtfsLookupAttributeByName( IrpContext,
  6938. Scb->Fcb,
  6939. &Scb->Fcb->FileReference,
  6940. Scb->AttributeTypeCode,
  6941. &Scb->AttributeName,
  6942. NULL,
  6943. FALSE,
  6944. &AttributeContext )) {
  6945. //
  6946. // Verify that this is an index allocation attribute.
  6947. // If not, raise an error.
  6948. //
  6949. if (Scb->AttributeTypeCode != $INDEX_ALLOCATION) {
  6950. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  6951. }
  6952. Irp->IoStatus.Information = 0;
  6953. Status = STATUS_SUCCESS;
  6954. leave;
  6955. } else {
  6956. NtfsUpdateScbFromAttribute( IrpContext,
  6957. Scb,
  6958. NtfsFoundAttribute( &AttributeContext ));
  6959. }
  6960. }
  6961. //
  6962. // If the data attribute is resident (typically for a small file),
  6963. // it is not safe to call NtfsPreloadAllocation. There won't be
  6964. // any runs, and we've already set ExtentCount to 0, so we're done.
  6965. // FAT returns STATUS_END_OF_FILE for a zero-length file, so for
  6966. // consistency's sake, we'll return that in the resident case.
  6967. //
  6968. if (FlagOn(Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT)) {
  6969. Irp->IoStatus.Information = 0;
  6970. Status = STATUS_END_OF_FILE;
  6971. leave;
  6972. }
  6973. //
  6974. // Check if a starting cluster was specified.
  6975. //
  6976. LastVcnInFile = LlClustersFromBytesTruncate( Vcb, Scb->Header.AllocationSize.QuadPart ) - 1;
  6977. if (StartingVcn > LastVcnInFile) {
  6978. //
  6979. // It's possible that the Vcn we were given is past the end of the file.
  6980. //
  6981. Status = STATUS_END_OF_FILE;
  6982. leave;
  6983. } else if (StartingVcn < 0) {
  6984. //
  6985. // It's possible that the Vcn we were given is negative, and
  6986. // NtfsMcbLookupArrayIndex doesn't handle that very well.
  6987. //
  6988. Status = STATUS_INVALID_PARAMETER;
  6989. leave;
  6990. } else {
  6991. //
  6992. // We need to call NtfsPreloadAllocation to make sure all the
  6993. // ranges in this NtfsMcb are loaded.
  6994. //
  6995. NtfsPreloadAllocation( IrpContext,
  6996. Scb,
  6997. StartingVcn,
  6998. LastVcnInFile );
  6999. //
  7000. // Decide which Mcb contains the starting Vcn.
  7001. //
  7002. (VOID)NtfsLookupNtfsMcbEntry( &Scb->Mcb,
  7003. StartingVcn,
  7004. NULL,
  7005. &CountFromStartingVcn,
  7006. &Lcn,
  7007. &ClusterCount,
  7008. &RangePtr,
  7009. &RangeRunIndex );
  7010. }
  7011. //
  7012. // Fill in the Vcn where the run containing StartingVcn truly starts.
  7013. //
  7014. AccessingUserBuffer = TRUE;
  7015. OutputBuffer->StartingVcn.QuadPart = Vcn = StartingVcn - (ClusterCount - CountFromStartingVcn);
  7016. AccessingUserBuffer = FALSE;
  7017. //
  7018. // FileRunIndex is the index of a given run within an entire
  7019. // file, as opposed to RangeRunIndex which is the index of a
  7020. // given run within its range. RangeRunIndex is reset to 0 for
  7021. // each range, where FileRunIndex is set to 0 once out here.
  7022. //
  7023. FileRunIndex = 0;
  7024. do {
  7025. //
  7026. // Now copy over the mapping pairs from the mcb
  7027. // to the output buffer. We store in [sector count, lbo]
  7028. // mapping pairs and end with a zero sector count.
  7029. //
  7030. //
  7031. // Check for an exhausted output buffer.
  7032. //
  7033. if ((ULONG)FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[FileRunIndex+1]) > OutputBufferLength) {
  7034. //
  7035. // We know that we're out of room in the output buffer, so we won't be looking up
  7036. // any more runs. ExtentCount currently reflects how many runs we stored in the
  7037. // user buffer, so we can safely quit. There are indeed ExtentCount extents stored
  7038. // in the array, and returning STATUS_BUFFER_OVERFLOW informs our caller that we
  7039. // didn't have enough room to return all the runs.
  7040. //
  7041. Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[FileRunIndex]);
  7042. Status = STATUS_BUFFER_OVERFLOW;
  7043. leave;
  7044. }
  7045. //
  7046. // Here's the interesting part -- we fill in the next array element in the ouput buffer
  7047. // with the current run's information.
  7048. //
  7049. AccessingUserBuffer = TRUE;
  7050. OutputBuffer->Extents[FileRunIndex].NextVcn.QuadPart = Vcn + ClusterCount;
  7051. OutputBuffer->Extents[FileRunIndex].Lcn.QuadPart = Lcn;
  7052. OutputBuffer->ExtentCount += 1;
  7053. AccessingUserBuffer = FALSE;
  7054. FileRunIndex += 1;
  7055. RangeRunIndex += 1;
  7056. } while (NtfsGetSequentialMcbEntry( &Scb->Mcb, &RangePtr, RangeRunIndex, &Vcn, &Lcn, &ClusterCount));
  7057. //
  7058. // We successfully retrieved extent info to the end of the allocation.
  7059. //
  7060. Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[FileRunIndex]);
  7061. Status = STATUS_SUCCESS;
  7062. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  7063. NtfsRaiseStatus( IrpContext,
  7064. STATUS_INVALID_USER_BUFFER,
  7065. NULL,
  7066. NULL );
  7067. }
  7068. } finally {
  7069. DebugUnwind( NtfsGetRetrievalPointers );
  7070. //
  7071. // Release resources.
  7072. //
  7073. NtfsReleaseScb( IrpContext, Scb );
  7074. if (CleanupAttributeContext) {
  7075. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  7076. }
  7077. DebugTrace( -1, Dbg, ("NtfsGetRetrievalPointers -> VOID\n") );
  7078. }
  7079. //
  7080. // If nothing raised then complete the irp.
  7081. //
  7082. NtfsCompleteRequest( IrpContext, Irp, Status );
  7083. return Status;
  7084. }
  7085. //
  7086. // Local Support Routine
  7087. //
  7088. NTSTATUS
  7089. NtfsGetMftRecord (
  7090. IN PIRP_CONTEXT IrpContext,
  7091. IN PIRP Irp
  7092. )
  7093. /*++
  7094. Routine Description:
  7095. This routine returns a copy of the requested File Record Segment. A
  7096. hint File Reference Number is passed in. If the hint File Record
  7097. Segment is "not in use" then the MFT bitmap is scanned backwards
  7098. from the hint until an "in use" File Record Segment is found. This
  7099. File Record Segment is then returned along with the identifying File Reference Number.
  7100. Input = the LONGLONG File Reference Number is passed in through the input buffer.
  7101. Output = the FILE_RECORD data structure is returned through the output buffer.
  7102. Arguments:
  7103. Irp - Supplies the Irp being processed.
  7104. Return Value:
  7105. NTSTATUS - The return status for the operation.
  7106. --*/
  7107. {
  7108. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  7109. PIO_STACK_LOCATION IrpSp;
  7110. ULONG FsControlCode;
  7111. PFILE_OBJECT FileObject;
  7112. TYPE_OF_OPEN TypeOfOpen;
  7113. PVCB Vcb;
  7114. PFCB Fcb;
  7115. PSCB Scb;
  7116. PCCB Ccb;
  7117. PNTFS_FILE_RECORD_INPUT_BUFFER GetFileRecord;
  7118. ULONG GetFileRecordLength;
  7119. PNTFS_FILE_RECORD_OUTPUT_BUFFER FileRecord;
  7120. ULONG FileRecordLength;
  7121. ULONG FileReferenceNumber;
  7122. PFILE_RECORD_SEGMENT_HEADER MftBuffer;
  7123. PBCB Bcb = NULL;
  7124. PBCB BitmapBcb = NULL;
  7125. BOOLEAN AcquiredMft = FALSE;
  7126. RTL_BITMAP Bitmap;
  7127. LONG BaseIndex;
  7128. LONG Index;
  7129. LONGLONG StartingByte;
  7130. PUCHAR BitmapBuffer;
  7131. ULONG SizeToMap;
  7132. ULONG BytesToCopy;
  7133. //
  7134. // Get the current Irp stack location and save some references.
  7135. //
  7136. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7137. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  7138. DebugTrace( +1, Dbg, ("NtfsGetMftRecord, FsControlCode = %08lx\n", FsControlCode) );
  7139. //
  7140. // Extract and decode the file object and check for type of open.
  7141. //
  7142. FileObject = IrpSp->FileObject;
  7143. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  7144. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  7145. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  7146. return STATUS_ACCESS_DENIED;
  7147. }
  7148. //
  7149. // Get the input & output buffer lengths and pointers.
  7150. //
  7151. GetFileRecordLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  7152. GetFileRecord = (PNTFS_FILE_RECORD_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  7153. FileRecordLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  7154. FileRecord = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;;
  7155. //
  7156. // Check for a minimum length on the input and ouput buffers.
  7157. //
  7158. if ((GetFileRecordLength < sizeof(NTFS_FILE_RECORD_INPUT_BUFFER)) ||
  7159. (FileRecordLength < sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER))) {
  7160. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  7161. return STATUS_BUFFER_TOO_SMALL;
  7162. }
  7163. FileRecordLength -= FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer);
  7164. FileReferenceNumber = GetFileRecord->FileReferenceNumber.LowPart;
  7165. //
  7166. // Make this request synchronous.
  7167. //
  7168. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  7169. //
  7170. // Acquire the vcb to test for dismounted volume
  7171. //
  7172. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  7173. try {
  7174. LONGLONG ValidDataLength;
  7175. //
  7176. // Synchronize the lookup by acquiring the Mft. First test the vcb we were
  7177. // called with in order to check for dismount. The MftScb may have already been
  7178. // torn down.
  7179. //
  7180. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  7181. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  7182. }
  7183. NtfsAcquireSharedScb( IrpContext, Vcb->MftScb );
  7184. AcquiredMft = TRUE;
  7185. //
  7186. // Raise if the File Reference Number is not within the MFT valid data length.
  7187. //
  7188. ValidDataLength = Vcb->MftScb->Header.ValidDataLength.QuadPart;
  7189. if (FileReferenceNumber >= (ValidDataLength / Vcb->BytesPerFileRecordSegment)) {
  7190. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  7191. }
  7192. //
  7193. // Fill in the record size and determine how much of it we can copy.
  7194. //
  7195. FileRecord->FileRecordLength = Vcb->BytesPerFileRecordSegment;
  7196. if (FileRecordLength >= Vcb->BytesPerFileRecordSegment) {
  7197. BytesToCopy = Vcb->BytesPerFileRecordSegment;
  7198. Status = STATUS_SUCCESS;
  7199. } else {
  7200. BytesToCopy = FileRecordLength;
  7201. Status = STATUS_BUFFER_OVERFLOW;
  7202. }
  7203. //
  7204. // If it is the MFT file record then just get it and we are done.
  7205. //
  7206. if (FileReferenceNumber == 0) {
  7207. NTSTATUS ErrorStatus;
  7208. try {
  7209. NtfsMapStream( IrpContext,
  7210. Vcb->MftScb,
  7211. 0,
  7212. Vcb->BytesPerFileRecordSegment,
  7213. &Bcb,
  7214. (PVOID *)&MftBuffer );
  7215. } except ( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &ErrorStatus )) {
  7216. //
  7217. // Clear the status field in the IrpContext. We're going to retry in the mirror
  7218. //
  7219. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  7220. NtfsMapStream( IrpContext,
  7221. Vcb->Mft2Scb,
  7222. 0,
  7223. Vcb->BytesPerFileRecordSegment,
  7224. &Bcb,
  7225. (PVOID *)&MftBuffer );
  7226. }
  7227. //
  7228. // Return the File Reference Number and the File Record.
  7229. //
  7230. RtlCopyMemory(FileRecord->FileRecordBuffer, MftBuffer, BytesToCopy);
  7231. FileRecord->FileReferenceNumber.QuadPart = 0;
  7232. try_return( Status );
  7233. }
  7234. //
  7235. // Scan through the MFT Bitmap to find an "in use" file.
  7236. //
  7237. while (FileReferenceNumber > 0) {
  7238. //
  7239. // Compute some values for the bitmap, convert the index to the offset of
  7240. // this page and get the base index for the File Reference number. Then
  7241. // map the page in the bitmap that contains the file record. Note we have to convert
  7242. // from bits to bytes to find it.
  7243. //
  7244. Index = FileReferenceNumber & (BITS_PER_PAGE - 1);
  7245. BaseIndex = FileReferenceNumber - Index;
  7246. StartingByte = BlockAlignTruncate( FileReferenceNumber / 8 , PAGE_SIZE );
  7247. SizeToMap = min( PAGE_SIZE, (ULONG)(Vcb->MftBitmapScb->Header.ValidDataLength.QuadPart - StartingByte) );
  7248. NtfsMapStream( IrpContext,
  7249. Vcb->MftBitmapScb,
  7250. StartingByte,
  7251. SizeToMap,
  7252. &BitmapBcb,
  7253. &BitmapBuffer );
  7254. RtlInitializeBitMap(&Bitmap, (PULONG)BitmapBuffer, SizeToMap * 8);
  7255. //
  7256. // Scan thru this page for an "in use" File Record.
  7257. //
  7258. for (; Index >= 0; Index --) {
  7259. if (RtlCheckBit(&Bitmap, Index)) {
  7260. NTSTATUS ErrorStatus;
  7261. //
  7262. // Found one "in use" on this page so get it and we are done.
  7263. //
  7264. try {
  7265. NtfsMapStream( IrpContext,
  7266. Vcb->MftScb,
  7267. Int64ShllMod32(BaseIndex + Index, Vcb->MftShift),
  7268. Vcb->BytesPerFileRecordSegment,
  7269. &Bcb,
  7270. (PVOID *)&MftBuffer );
  7271. } except (NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &ErrorStatus)) {
  7272. //
  7273. // Reset status for retry in the mirror
  7274. //
  7275. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  7276. NtfsMapStream( IrpContext,
  7277. Vcb->Mft2Scb,
  7278. Int64ShllMod32(BaseIndex + Index, Vcb->MftShift),
  7279. Vcb->BytesPerFileRecordSegment,
  7280. &Bcb,
  7281. (PVOID *)&MftBuffer );
  7282. }
  7283. //
  7284. // Return the File Reference Number and the File Record.
  7285. //
  7286. RtlCopyMemory(FileRecord->FileRecordBuffer, MftBuffer, BytesToCopy);
  7287. FileRecord->FileReferenceNumber.QuadPart = BaseIndex + Index;
  7288. try_return( Status );
  7289. }
  7290. }
  7291. //
  7292. // Cleanup for next time through and decrement the File Reference Number.
  7293. //
  7294. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  7295. FileReferenceNumber = BaseIndex - 1;
  7296. }
  7297. try_exit: NOTHING;
  7298. Irp->IoStatus.Information =
  7299. FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) +
  7300. BytesToCopy;
  7301. } finally {
  7302. //
  7303. // Release resources and exit.
  7304. //
  7305. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  7306. NtfsUnpinBcb( IrpContext, &Bcb );
  7307. if (AcquiredMft) {
  7308. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  7309. }
  7310. NtfsReleaseVcb( IrpContext, Vcb );
  7311. DebugTrace( -1, Dbg, ("NtfsGetMftRecord: Exit\n") );
  7312. }
  7313. //
  7314. // If nothing raised then complete the Irp.
  7315. //
  7316. NtfsCompleteRequest( IrpContext, Irp, Status );
  7317. DebugTrace( -1, Dbg, ("NtfsGetMftRecord -> VOID\n") );
  7318. return Status;
  7319. }
  7320. //
  7321. // Local support routine
  7322. //
  7323. NTSTATUS
  7324. NtfsIsVolumeDirty (
  7325. IN PIRP_CONTEXT IrpContext,
  7326. IN PIRP Irp
  7327. )
  7328. /*++
  7329. Routine Description:
  7330. This routine returns the dirty state of the volume.
  7331. Arguments:
  7332. Irp - Supplies the Irp to process
  7333. Return Value:
  7334. NTSTATUS - The return status for the operation
  7335. --*/
  7336. {
  7337. PIO_STACK_LOCATION IrpSp;
  7338. TYPE_OF_OPEN TypeOfOpen;
  7339. PVCB Vcb;
  7340. PFCB Fcb;
  7341. PSCB Scb;
  7342. PCCB Ccb;
  7343. PULONG VolumeState;
  7344. PVOLUME_INFORMATION VolumeInfo;
  7345. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  7346. //
  7347. // Get the current stack location and extract the output
  7348. // buffer information.
  7349. //
  7350. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7351. //
  7352. // Get a pointer to the output buffer. Look at the system buffer field in the
  7353. // irp first. Then the Irp Mdl.
  7354. //
  7355. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  7356. VolumeState = Irp->AssociatedIrp.SystemBuffer;
  7357. } else if (Irp->MdlAddress != NULL) {
  7358. VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  7359. if (VolumeState == NULL) {
  7360. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  7361. return STATUS_INSUFFICIENT_RESOURCES;
  7362. }
  7363. } else {
  7364. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  7365. return STATUS_INVALID_USER_BUFFER;
  7366. }
  7367. //
  7368. // Make sure the output buffer is large enough and then initialize
  7369. // the answer to be that the volume isn't corrupt.
  7370. //
  7371. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
  7372. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  7373. return STATUS_INVALID_PARAMETER;
  7374. }
  7375. *VolumeState = 0;
  7376. //
  7377. // Decode the file object. We don't care to raise on dismounts here
  7378. // because we check for that further down anyway. Hence, RaiseOnError=FALSE.
  7379. //
  7380. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  7381. if (TypeOfOpen != UserVolumeOpen) {
  7382. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  7383. return STATUS_INVALID_PARAMETER;
  7384. }
  7385. //
  7386. // Acquire the Scb shared.
  7387. //
  7388. NtfsAcquireSharedScb( IrpContext, Scb );
  7389. //
  7390. // Make sure the volume is still mounted.
  7391. //
  7392. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  7393. NtfsReleaseScb( IrpContext, Scb );
  7394. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  7395. return STATUS_VOLUME_DISMOUNTED;
  7396. }
  7397. //
  7398. // Look up the VOLUME_INFORMATION attribute.
  7399. //
  7400. NtfsInitializeAttributeContext( &Context );
  7401. //
  7402. // Use a try-finally to perform cleanup.
  7403. //
  7404. try {
  7405. if (!NtfsLookupAttributeByCode( IrpContext,
  7406. Vcb->VolumeDasdScb->Fcb,
  7407. &Vcb->VolumeDasdScb->Fcb->FileReference,
  7408. $VOLUME_INFORMATION,
  7409. &Context )) {
  7410. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  7411. }
  7412. //
  7413. // Return the volume state and the size of the returned data.
  7414. //
  7415. VolumeInfo = (PVOLUME_INFORMATION) NtfsAttributeValue( NtfsFoundAttribute( &Context ));
  7416. if (FlagOn( VolumeInfo->VolumeFlags, VOLUME_DIRTY )) {
  7417. SetFlag( *VolumeState, VOLUME_IS_DIRTY );
  7418. }
  7419. if (FlagOn( VolumeInfo->VolumeFlags, VOLUME_UPGRADE_ON_MOUNT )) {
  7420. SetFlag( *VolumeState, VOLUME_UPGRADE_SCHEDULED );
  7421. }
  7422. Irp->IoStatus.Information = sizeof( ULONG );
  7423. } finally {
  7424. NtfsReleaseScb( IrpContext, Scb );
  7425. NtfsCleanupAttributeContext( IrpContext, &Context );
  7426. DebugUnwind( NtfsIsVolumeDirty );
  7427. }
  7428. //
  7429. // If this is an abnormal termination then undo our work, otherwise
  7430. // complete the irp
  7431. //
  7432. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  7433. return STATUS_SUCCESS;
  7434. }
  7435. //
  7436. // Local support routine
  7437. //
  7438. NTSTATUS
  7439. NtfsSetExtendedDasdIo (
  7440. IN PIRP_CONTEXT IrpContext,
  7441. IN PIRP Irp
  7442. )
  7443. /*++
  7444. Routine Description:
  7445. This routine will mark a Dasd handle to perform IO outside the logical bounds of
  7446. the partition. Any subsequent IO will be passed to the driver which can either
  7447. complete it or return an error.
  7448. Arguments:
  7449. Irp - Supplies the Irp to process
  7450. Return Value:
  7451. NTSTATUS - The return status for the operation
  7452. --*/
  7453. {
  7454. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7455. TYPE_OF_OPEN TypeOfOpen;
  7456. PVCB Vcb;
  7457. PFCB Fcb;
  7458. PSCB Scb;
  7459. PCCB Ccb;
  7460. PAGED_CODE();
  7461. //
  7462. // Decode the file object
  7463. //
  7464. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  7465. //
  7466. // Make sure this is a volume open.
  7467. //
  7468. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  7469. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  7470. return STATUS_ACCESS_DENIED;
  7471. }
  7472. //
  7473. // Mark the Ccb for extended Io and return.
  7474. //
  7475. SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_XTENDED_DASD_IO );
  7476. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  7477. return STATUS_SUCCESS;
  7478. }
  7479. //
  7480. // Local support routine
  7481. //
  7482. NTSTATUS
  7483. NtfsSetReparsePoint (
  7484. IN PIRP_CONTEXT IrpContext,
  7485. IN PIRP Irp
  7486. )
  7487. /*++
  7488. Routine Description:
  7489. This routine sets the reparse point attribute at the file object entry
  7490. specified in the IRP.
  7491. NtfsSetReparsePoint does not care whether the base file object is a user file or a
  7492. user directory.
  7493. If the file object has the FILE_ATTRIBUTE_REPARSE_POINT bit set then the
  7494. $REPARSE_POINT attribute is expected to be in the file.
  7495. If this file object already is a reparse point, and the tag of the incomming
  7496. reparse point request coincides with that present in existing $REPARSE_POINT,
  7497. then the contents of the $REPARSE_POINT attribute present will be overwritten.
  7498. There is to be an IN buffer to bring the caller's data for the call.
  7499. This function inserts an entry into the reparse point table.
  7500. Arguments:
  7501. IrpContext - Supplies the Irp context of the call
  7502. Irp - Supplies the Irp to process
  7503. Return Value:
  7504. NTSTATUS - The return status for the operation
  7505. --*/
  7506. {
  7507. NTSTATUS Status = STATUS_SUCCESS;
  7508. PIO_STACK_LOCATION IrpSp;
  7509. ULONG FsControlCode;
  7510. TYPE_OF_OPEN TypeOfOpen;
  7511. PVCB Vcb;
  7512. PFCB Fcb;
  7513. PSCB Scb;
  7514. PCCB Ccb;
  7515. PBCB Bcb = NULL; // does not get initialized below in NtfsDecodeFileObject
  7516. PREPARSE_DATA_BUFFER ReparseBuffer = NULL;
  7517. PREPARSE_GUID_DATA_BUFFER ReparseGuidBuffer = NULL;
  7518. ULONG ReparseTag;
  7519. USHORT ReparseDataLength = 0; // invalid value as it denotes no data
  7520. ULONG InputBufferLength = 0; // invalid value as we need an input buffer
  7521. ULONG OutputBufferLength = 0; // only valid value as we have no output buffer
  7522. ULONG IncomingFileAttributes = 0; // invalid value
  7523. ULONG IncomingReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; // invalid value
  7524. BOOLEAN CleanupAttributeContext = FALSE;
  7525. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  7526. BOOLEAN PagingIoAcquired = FALSE;
  7527. ASSERT_IRP_CONTEXT( IrpContext );
  7528. ASSERT_IRP( Irp );
  7529. PAGED_CODE();
  7530. //
  7531. // Get the current Irp stack location
  7532. //
  7533. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7534. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  7535. DebugTrace( +1, Dbg, ("NtfsSetReparsePoint, FsControlCode = %08lx\n", FsControlCode) );
  7536. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  7537. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  7538. //
  7539. // Decode all the relevant File System data structures.
  7540. //
  7541. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  7542. IrpSp->FileObject,
  7543. &Vcb,
  7544. &Fcb,
  7545. &Scb,
  7546. &Ccb,
  7547. TRUE ); // Raise an exeption if error is encountered
  7548. //
  7549. // Check for the correct type of open.
  7550. //
  7551. //
  7552. // See that we have a file or a directory open.
  7553. //
  7554. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  7555. //
  7556. // Return an invalid parameter error.
  7557. //
  7558. Status = STATUS_INVALID_PARAMETER;
  7559. //
  7560. // Return to caller.
  7561. //
  7562. NtfsCompleteRequest( IrpContext, Irp, Status );
  7563. DebugTrace( 0, Dbg, ("Invalid parameter passed by caller.\n") );
  7564. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7565. return Status;
  7566. }
  7567. //
  7568. // The caller has FILE_SPECIAL_ACCESS. The NTFS driver enforces access checks more stringent
  7569. // than FILE_ANY_ACCESS:
  7570. // (a) FILE_WRITE_DATA or FILE_WRITE_ATTRIBUTES_ACCESS
  7571. //
  7572. if (!FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS ) &&
  7573. //
  7574. // Temporary KLUDGE for DavePr.
  7575. // The Ccb->AccessFlags and the FileObject->WriteAccess may not coincide as a
  7576. // filter may change the "visible" file object after the open. The Ccb flags do
  7577. // not change after open.
  7578. //
  7579. !IrpSp->FileObject->WriteAccess) {
  7580. //
  7581. // Return access denied.
  7582. //
  7583. Status = STATUS_ACCESS_DENIED;
  7584. //
  7585. // Return to caller.
  7586. //
  7587. NtfsCompleteRequest( IrpContext, Irp, Status );
  7588. DebugTrace( 0, Dbg, ("Ccb->AccessFlags %x\n", Ccb->AccessFlags) );
  7589. DebugTrace( 0, Dbg, ("Caller did not have the appropriate access rights.\n") );
  7590. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7591. return Status;
  7592. }
  7593. ASSERT_VCB( Vcb );
  7594. ASSERT_FCB( Fcb );
  7595. ASSERT_SCB( Scb );
  7596. ASSERT_CCB( Ccb );
  7597. //
  7598. // Read only volumes stay read only.
  7599. //
  7600. if (NtfsIsVolumeReadOnly( Vcb )) {
  7601. Status = STATUS_MEDIA_WRITE_PROTECTED;
  7602. NtfsCompleteRequest( IrpContext, Irp, Status );
  7603. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7604. return Status;
  7605. }
  7606. if (!NtfsVolumeVersionCheck( Vcb, NTFS_REPARSE_POINT_VERSION )) {
  7607. //
  7608. // Return a volume not upgraded error.
  7609. //
  7610. Status = STATUS_VOLUME_NOT_UPGRADED;
  7611. //
  7612. // Return to caller.
  7613. //
  7614. NtfsCompleteRequest( IrpContext, Irp, Status );
  7615. DebugTrace( 0, Dbg, ("Non-upgraded volume passed by caller.\n") );
  7616. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7617. return Status;
  7618. }
  7619. //
  7620. // Get the length of the input and output buffers.
  7621. //
  7622. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  7623. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  7624. DebugTrace( 0, Dbg, ("InputBufferLength %08lx [d]%08d OutputBufferLength %08lx\n", InputBufferLength, InputBufferLength, OutputBufferLength) );
  7625. //
  7626. // Do not allow output buffer in the set command.
  7627. //
  7628. if (OutputBufferLength > 0) {
  7629. //
  7630. // Return an invalid parameter error.
  7631. //
  7632. Status = STATUS_INVALID_PARAMETER;
  7633. //
  7634. // Return to caller.
  7635. //
  7636. NtfsCompleteRequest( IrpContext, Irp, Status );
  7637. DebugTrace( 0, Dbg, ("Non-null output buffer.\n") );
  7638. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7639. return Status;
  7640. }
  7641. //
  7642. // Zero the Information field in IoStatus.
  7643. //
  7644. Irp->IoStatus.Information = 0;
  7645. //
  7646. // Verify that we have the required system input buffer.
  7647. //
  7648. if (Irp->AssociatedIrp.SystemBuffer == NULL) {
  7649. //
  7650. // Return an invalid buffer error.
  7651. //
  7652. Status = STATUS_INVALID_BUFFER_SIZE;
  7653. //
  7654. // Return to caller.
  7655. //
  7656. NtfsCompleteRequest( IrpContext, Irp, Status );
  7657. DebugTrace( 0, Dbg, ("Null buffer passed by system.\n") );
  7658. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7659. return Status;
  7660. }
  7661. //
  7662. // Be defensive about the length of the incomming buffer before re-referencing it.
  7663. //
  7664. ASSERT( REPARSE_DATA_BUFFER_HEADER_SIZE < REPARSE_GUID_DATA_BUFFER_HEADER_SIZE );
  7665. if (InputBufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE) {
  7666. //
  7667. // Return invalid buffer parameter error.
  7668. //
  7669. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7670. //
  7671. // Return to caller.
  7672. //
  7673. NtfsCompleteRequest( IrpContext, Irp, Status );
  7674. DebugTrace( 0, Dbg, ("Data in input buffer is too short.\n") );
  7675. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7676. return Status;
  7677. }
  7678. //
  7679. // Return if the input buffer is too long.
  7680. //
  7681. if (InputBufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  7682. //
  7683. // Return invalid buffer parameter error.
  7684. //
  7685. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7686. //
  7687. // Return to caller.
  7688. //
  7689. NtfsCompleteRequest( IrpContext, Irp, Status );
  7690. DebugTrace( 0, Dbg, ("Data in system buffer is too long.\n") );
  7691. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7692. return Status;
  7693. }
  7694. //
  7695. // Get the header information brought in the input buffer.
  7696. // While all the headers coincide in the layout of the first three fields we are home free.
  7697. //
  7698. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseTag) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseTag) );
  7699. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseDataLength) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseDataLength) );
  7700. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, Reserved) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, Reserved) );
  7701. ReparseBuffer = (PREPARSE_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  7702. ReparseTag = ReparseBuffer->ReparseTag;
  7703. ReparseDataLength = ReparseBuffer->ReparseDataLength;
  7704. ReparseGuidBuffer = (PREPARSE_GUID_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  7705. DebugTrace( 0, Dbg, ("ReparseTag = %08lx, ReparseDataLength = [x]%08lx [d]%08ld\n", ReparseTag, ReparseDataLength, ReparseDataLength) );
  7706. //
  7707. // Check for invalid conditions in the parameters.
  7708. // First, parameter validation for the amounts of user-controlled data.
  7709. //
  7710. //
  7711. // Verify that the user buffer and the data length in its header are
  7712. // internally consistent. We need to have a REPARSE_DATA_BUFFER or a
  7713. // REPARSE_GUID_DATA_BUFFER.
  7714. //
  7715. if (((ULONG)(ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE) != InputBufferLength) &&
  7716. ((ULONG)(ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE) != InputBufferLength)) {
  7717. //
  7718. // Return invalid buffer parameter error.
  7719. //
  7720. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7721. //
  7722. // Return to caller.
  7723. //
  7724. NtfsCompleteRequest( IrpContext, Irp, Status );
  7725. DebugTrace( 0, Dbg, ("User-controlled data in buffer is not self-consistent.\n") );
  7726. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7727. return Status;
  7728. }
  7729. //
  7730. // Sanity check the buffer size combination reserved for Microsoft tags.
  7731. //
  7732. if ((ULONG)(ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE) == InputBufferLength) {
  7733. //
  7734. // This buffer length can only be used with Microsoft tags.
  7735. //
  7736. if (!IsReparseTagMicrosoft( ReparseTag )) {
  7737. //
  7738. // Return invalid buffer parameter error.
  7739. //
  7740. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7741. //
  7742. // Return to caller.
  7743. //
  7744. NtfsCompleteRequest( IrpContext, Irp, Status );
  7745. DebugTrace( 0, Dbg, ("Wrong tag in Microsoft buffer.\n") );
  7746. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7747. return Status;
  7748. }
  7749. }
  7750. //
  7751. // Sanity check the buffer size combination that has a GUID.
  7752. //
  7753. if ((ULONG)(ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE) == InputBufferLength) {
  7754. //
  7755. // If the tag is a non-Microsoft tag, then the GUID cannot be NULL
  7756. //
  7757. if (!IsReparseTagMicrosoft( ReparseTag )) {
  7758. if ((ReparseGuidBuffer->ReparseGuid.Data1 == 0) &&
  7759. (ReparseGuidBuffer->ReparseGuid.Data2 == 0) &&
  7760. (ReparseGuidBuffer->ReparseGuid.Data3 == 0) &&
  7761. (ReparseGuidBuffer->ReparseGuid.Data4[0] == 0) &&
  7762. (ReparseGuidBuffer->ReparseGuid.Data4[1] == 0) &&
  7763. (ReparseGuidBuffer->ReparseGuid.Data4[2] == 0) &&
  7764. (ReparseGuidBuffer->ReparseGuid.Data4[3] == 0) &&
  7765. (ReparseGuidBuffer->ReparseGuid.Data4[4] == 0) &&
  7766. (ReparseGuidBuffer->ReparseGuid.Data4[5] == 0) &&
  7767. (ReparseGuidBuffer->ReparseGuid.Data4[6] == 0) &&
  7768. (ReparseGuidBuffer->ReparseGuid.Data4[7] == 0)) {
  7769. //
  7770. // Return invalid buffer parameter error.
  7771. //
  7772. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7773. //
  7774. // Return to caller.
  7775. //
  7776. NtfsCompleteRequest( IrpContext, Irp, Status );
  7777. DebugTrace( 0, Dbg, ("The GUID is null for a non-Microsoft tag.\n") );
  7778. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7779. return Status;
  7780. }
  7781. }
  7782. //
  7783. // This kind of buffer cannot be used for name grafting operations.
  7784. //
  7785. if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  7786. //
  7787. // Return invalid buffer parameter error.
  7788. //
  7789. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7790. //
  7791. // Return to caller.
  7792. //
  7793. NtfsCompleteRequest( IrpContext, Irp, Status );
  7794. DebugTrace( 0, Dbg, ("Attempt to use the GUID buffer for name grafting.\n") );
  7795. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7796. return Status;
  7797. }
  7798. }
  7799. //
  7800. // We verify that the caller has zeroes in all the reserved bits and that she
  7801. // sets one of the non-reserved tags. Also fail if the tag is the retired NSS
  7802. // flag.
  7803. //
  7804. if ((ReparseTag & ~IO_REPARSE_TAG_VALID_VALUES) ||
  7805. (ReparseTag == IO_REPARSE_TAG_RESERVED_ZERO) ||
  7806. (ReparseTag == IO_REPARSE_TAG_RESERVED_ONE)) {
  7807. Status = STATUS_IO_REPARSE_TAG_INVALID;
  7808. //
  7809. // Return to caller.
  7810. //
  7811. NtfsCompleteRequest( IrpContext, Irp, Status );
  7812. DebugTrace( 0, Dbg, ("Caller passed in a reserved tag for the reparse data.\n") );
  7813. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7814. return Status;
  7815. }
  7816. //
  7817. // NTFS directory junctions are only to be set at directories and have a valid buffer.
  7818. //
  7819. if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  7820. HANDLE TestHandle;
  7821. OBJECT_ATTRIBUTES Oa;
  7822. IO_STATUS_BLOCK Iosb;
  7823. UNICODE_STRING Path;
  7824. //
  7825. // The tag needs to come together with a UserDirectoryOpen mode.
  7826. //
  7827. if (TypeOfOpen != UserDirectoryOpen) {
  7828. Status = STATUS_NOT_A_DIRECTORY;
  7829. //
  7830. // Return to caller.
  7831. //
  7832. NtfsCompleteRequest( IrpContext, Irp, Status );
  7833. DebugTrace( 0, Dbg, ("Cannot set a mount point at a non-directory.\n") );
  7834. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7835. return Status;
  7836. }
  7837. //
  7838. // Valid MountPointBuffer must have
  7839. //
  7840. // 1) Enough space for the length fields
  7841. // 2) A correct substitute name offset
  7842. // 3) A print name offset following the substitute name
  7843. // 4) enough space for the path name and substitute name
  7844. //
  7845. if ((ReparseBuffer->ReparseDataLength <
  7846. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE)) ||
  7847. (ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset != 0) ||
  7848. (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset !=
  7849. (ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof( UNICODE_NULL ))) ||
  7850. (ReparseBuffer->ReparseDataLength !=
  7851. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE) +
  7852. ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength +
  7853. ReparseBuffer->MountPointReparseBuffer.PrintNameLength +
  7854. 2 * sizeof( UNICODE_NULL ))) {
  7855. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7856. } else {
  7857. //
  7858. // While we don't hold any of our resources open the target path to
  7859. // check what it points to. We only allow mount points to local
  7860. // disks and cdroms
  7861. //
  7862. Path.Length = Path.MaximumLength = ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength;
  7863. Path.Buffer = &ReparseBuffer->MountPointReparseBuffer.PathBuffer[0];
  7864. if (Path.Buffer[ (Path.Length / sizeof( WCHAR )) - 1] == L'\\') {
  7865. Path.Length -= sizeof( WCHAR );
  7866. }
  7867. //
  7868. // Set the call self flag so status can't wait is handled in the create and
  7869. // not returned back
  7870. //
  7871. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  7872. InitializeObjectAttributes( &Oa, &Path, OBJ_CASE_INSENSITIVE, NULL, NULL );
  7873. Status = ZwCreateFile( &TestHandle,
  7874. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  7875. &Oa,
  7876. &Iosb,
  7877. NULL,
  7878. FILE_ATTRIBUTE_NORMAL,
  7879. FILE_SHARE_READ | FILE_SHARE_WRITE,
  7880. FILE_OPEN,
  7881. FILE_SYNCHRONOUS_IO_NONALERT,
  7882. NULL,
  7883. 0 );
  7884. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  7885. if (NT_SUCCESS( Status )) {
  7886. PFILE_OBJECT TestFileObject;
  7887. Status = ObReferenceObjectByHandle( TestHandle,
  7888. FILE_READ_ATTRIBUTES,
  7889. *IoFileObjectType,
  7890. KernelMode,
  7891. (PVOID *) &TestFileObject,
  7892. NULL );
  7893. if (NT_SUCCESS( Status )) {
  7894. if ((TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_DISK) &&
  7895. (TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_CD_ROM) &&
  7896. (TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_TAPE)) {
  7897. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7898. }
  7899. ObDereferenceObject( TestFileObject );
  7900. }
  7901. ZwClose( TestHandle );
  7902. } else if (FlagOn( Ccb->AccessFlags, RESTORE_ACCESS)) {
  7903. //
  7904. // Allow restore operators to create a reparse point - even if the target doesn't
  7905. // exist
  7906. //
  7907. Status = STATUS_SUCCESS;
  7908. }
  7909. }
  7910. if (!NT_SUCCESS( Status )) {
  7911. //
  7912. // Return to caller.
  7913. //
  7914. NtfsCompleteRequest( IrpContext, Irp, STATUS_IO_REPARSE_DATA_INVALID );
  7915. DebugTrace( 0, Dbg, ("Name grafting data buffer is incorrect.\n") );
  7916. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7917. return STATUS_IO_REPARSE_DATA_INVALID;
  7918. }
  7919. }
  7920. //
  7921. // We set the IrpContext flag to indicate that we can wait, making this a synchronous
  7922. // call.
  7923. //
  7924. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  7925. //
  7926. // Capture the source information.
  7927. //
  7928. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  7929. //
  7930. // The parameters look good. We begin real work.
  7931. //
  7932. // Now it is time ot use a try-finally to facilitate cleanup.
  7933. //
  7934. try {
  7935. //
  7936. // If there is a paging io resource then acquire it exclusively. This is to
  7937. // protect us from a collided page wait if we go to convert another stream
  7938. // to non-resident at the same time a different thread is faulting into it.
  7939. //
  7940. if (Scb->Header.PagingIoResource != NULL) {
  7941. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  7942. PagingIoAcquired = TRUE;
  7943. }
  7944. //
  7945. // Acquire the Fcb exclusively. The volume could've gotten dismounted,
  7946. // so check that too.
  7947. //
  7948. NtfsAcquireExclusiveScb( IrpContext, Scb );
  7949. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  7950. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  7951. }
  7952. //
  7953. // If the file object is a directory, we want it to be empty and to remain
  7954. // empty. Thus our check after the Fcb has been acquired. As reparse points
  7955. // impede the normal flow down through the name hierarchy we want to make
  7956. // it difficult for a caller to inadvertently block a name subtree by
  7957. // establishing a reparse point.
  7958. //
  7959. if (TypeOfOpen == UserDirectoryOpen) {
  7960. BOOLEAN NonEmptyIndex;
  7961. //
  7962. // The directory is deleteable if all the $INDEX_ROOT attributes are empty.
  7963. // Just what we need to establish a reparse point.
  7964. //
  7965. if (!NtfsIsFileDeleteable( IrpContext, Fcb, &NonEmptyIndex )) {
  7966. //
  7967. // This directory is not empty. Do not establish a reparse point in it.
  7968. // Return to caller an invalid parameter error.
  7969. //
  7970. DebugTrace( 0, Dbg, ("Non-empty directory used by caller.\n") );
  7971. Status = STATUS_DIRECTORY_NOT_EMPTY;
  7972. //
  7973. // Return to caller.
  7974. //
  7975. try_return( Status );
  7976. }
  7977. }
  7978. //
  7979. // EA attributes and reparse points are not to exist simultaneously.
  7980. // If the non-reparse point file object has EA attributes, we do not set
  7981. // a reparse point.
  7982. // We verify this condition after the Fcb resource has been acquired to
  7983. // impede a change in this state till we complete.
  7984. //
  7985. if ((!FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) &&
  7986. (Fcb->Info.PackedEaSize > 0)) {
  7987. //
  7988. // This non-reparse point file object has EAs. Do not establish a
  7989. // reparse point in it.
  7990. // Return to caller STATUS_EAS_NOT_SUPPORTED.
  7991. //
  7992. DebugTrace( 0, Dbg, ("EAs present, cannot establish reparse point.\n") );
  7993. Status = STATUS_EAS_NOT_SUPPORTED;
  7994. //
  7995. // Return to caller.
  7996. //
  7997. try_return( Status );
  7998. }
  7999. //
  8000. // Remember the values of the file attribute flags and of the reparse tag
  8001. // for abnormal termination recovery.
  8002. //
  8003. IncomingFileAttributes = Fcb->Info.FileAttributes;
  8004. IncomingReparsePointTag = Fcb->Info.ReparsePointTag;
  8005. //
  8006. // Initialize the context structure to search for the attribute.
  8007. //
  8008. NtfsInitializeAttributeContext( &AttributeContext );
  8009. CleanupAttributeContext = TRUE;
  8010. //
  8011. // Establish whether the file has the $REPARSE_POINT attribute.
  8012. // If it exists, it will be updated with the new data.
  8013. //
  8014. if (NtfsLookupAttributeByCode( IrpContext,
  8015. Fcb,
  8016. &Fcb->FileReference,
  8017. $REPARSE_POINT,
  8018. &AttributeContext )) {
  8019. ULONG ValueLength = 0;
  8020. if (!FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8021. DebugTrace( 0, Dbg, ("The FILE_ATTRIBUTE_REPARSE_POINT flag is not set.\n") );
  8022. //
  8023. // Should not happen. Raise an exeption as we are in an inconsistent state.
  8024. // The presence of the $REPARSE_POINT attribute says that the flag has to
  8025. // be set.
  8026. //
  8027. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8028. }
  8029. //
  8030. // Verify that the incomming tag value matches the tag value present in
  8031. // the $REPARSE_POINT attribute.
  8032. //
  8033. {
  8034. PREPARSE_GUID_DATA_BUFFER ReparseBufferTwo = NULL;
  8035. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  8036. PVOID AttributeData = NULL;
  8037. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  8038. //
  8039. // Map the reparse point if the attribute is non-resident. Otherwise
  8040. // the attribute is already mapped and we have a Bcb in the attribute
  8041. // context.
  8042. //
  8043. if (NtfsIsAttributeResident( AttributeHeader )) {
  8044. //
  8045. // Point to the value of the arribute.
  8046. //
  8047. AttributeData = NtfsAttributeValue( AttributeHeader );
  8048. ValueLength = AttributeHeader->Form.Resident.ValueLength;
  8049. DebugTrace( 0, Dbg, ("Existing attribute is resident.\n") );
  8050. } else {
  8051. if (AttributeHeader->Form.Nonresident.FileSize > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  8052. NtfsRaiseStatus( IrpContext,STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8053. }
  8054. DebugTrace( 0, Dbg, ("Existing attribute is non-resident.\n") );
  8055. NtfsMapAttributeValue( IrpContext,
  8056. Fcb,
  8057. &AttributeData, // point to the value
  8058. &ValueLength,
  8059. &Bcb,
  8060. &AttributeContext );
  8061. }
  8062. //
  8063. // Verify that the two tag values match.
  8064. //
  8065. ReparseBufferTwo = (PREPARSE_GUID_DATA_BUFFER)AttributeData;
  8066. DebugTrace( 0, Dbg, ("Existing tag is [d]%03ld - New tag is [d]%03ld\n", ReparseTag, ReparseBufferTwo->ReparseTag) );
  8067. if (ReparseTag != ReparseBufferTwo->ReparseTag) {
  8068. //
  8069. // Return status STATUS_IO_REPARSE_TAG_MISMATCH
  8070. //
  8071. DebugTrace( 0, Dbg, ("Tag mismatch with the existing reparse point.\n") );
  8072. Status = STATUS_IO_REPARSE_TAG_MISMATCH;
  8073. try_return( Status );
  8074. }
  8075. //
  8076. // For non-Microsoft tags, verify that the GUIDs match.
  8077. //
  8078. if (!IsReparseTagMicrosoft( ReparseTag )) {
  8079. if (!((ReparseGuidBuffer->ReparseGuid.Data1 == ReparseBufferTwo->ReparseGuid.Data1) &&
  8080. (ReparseGuidBuffer->ReparseGuid.Data2 == ReparseBufferTwo->ReparseGuid.Data2) &&
  8081. (ReparseGuidBuffer->ReparseGuid.Data3 == ReparseBufferTwo->ReparseGuid.Data3) &&
  8082. (ReparseGuidBuffer->ReparseGuid.Data4[0] == ReparseBufferTwo->ReparseGuid.Data4[0]) &&
  8083. (ReparseGuidBuffer->ReparseGuid.Data4[1] == ReparseBufferTwo->ReparseGuid.Data4[1]) &&
  8084. (ReparseGuidBuffer->ReparseGuid.Data4[2] == ReparseBufferTwo->ReparseGuid.Data4[2]) &&
  8085. (ReparseGuidBuffer->ReparseGuid.Data4[3] == ReparseBufferTwo->ReparseGuid.Data4[3]) &&
  8086. (ReparseGuidBuffer->ReparseGuid.Data4[4] == ReparseBufferTwo->ReparseGuid.Data4[4]) &&
  8087. (ReparseGuidBuffer->ReparseGuid.Data4[5] == ReparseBufferTwo->ReparseGuid.Data4[5]) &&
  8088. (ReparseGuidBuffer->ReparseGuid.Data4[6] == ReparseBufferTwo->ReparseGuid.Data4[6]) &&
  8089. (ReparseGuidBuffer->ReparseGuid.Data4[7] == ReparseBufferTwo->ReparseGuid.Data4[7]))) {
  8090. //
  8091. // Return status STATUS_REPARSE_ATTRIBUTE_CONFLICT
  8092. //
  8093. DebugTrace( 0, Dbg, ("GUID mismatch with the existing reparse point.\n") );
  8094. Status = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
  8095. try_return( Status );
  8096. }
  8097. }
  8098. //
  8099. // Unpin the Bcb. The unpin routine checks for NULL.
  8100. //
  8101. NtfsUnpinBcb( IrpContext, &Bcb );
  8102. }
  8103. //
  8104. // If we're growing throttle ourselves through cc, we can't wait because we own resources
  8105. // here and this would deadlock
  8106. //
  8107. if (InputBufferLength > ValueLength) {
  8108. if (!CcCanIWrite(IrpSp->FileObject,
  8109. InputBufferLength - ValueLength,
  8110. FALSE,
  8111. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) {
  8112. BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE);
  8113. //
  8114. // PrePosting the irp will free the resources so fcb will not be acquired afterwards
  8115. //
  8116. NtfsPrePostIrp( IrpContext, Irp );
  8117. ASSERT( !NtfsIsExclusiveFcb( Fcb ) );
  8118. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE );
  8119. CcDeferWrite( IrpSp->FileObject,
  8120. (PCC_POST_DEFERRED_WRITE)NtfsAddToWorkque,
  8121. IrpContext,
  8122. Irp,
  8123. InputBufferLength - ValueLength,
  8124. Retrying );
  8125. try_return( Status = STATUS_PENDING );
  8126. }
  8127. }
  8128. //
  8129. // Update the value of the attribute.
  8130. //
  8131. NtfsChangeAttributeValue( IrpContext,
  8132. Fcb,
  8133. (ULONG) 0, // ValueOffset
  8134. (PVOID)(Irp->AssociatedIrp.SystemBuffer), // Value
  8135. InputBufferLength, // ValueLength
  8136. TRUE, // SetNewLength
  8137. TRUE, // LogNonresidentToo
  8138. FALSE, // CreateSectionUnderway
  8139. FALSE, // PreserveContext
  8140. &AttributeContext ); // Context
  8141. //
  8142. // Cleanup the attribute context state
  8143. //
  8144. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8145. CleanupAttributeContext = FALSE;
  8146. } else {
  8147. //
  8148. // The $REPARSE_POINT attribute is not present.
  8149. //
  8150. if (FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8151. DebugTrace( 0, Dbg, ("The FILE_ATTRIBUTE_REPARSE_POINT flag is set.\n") );
  8152. //
  8153. // Should not happen. Raise an exeption as we are in an inconsistent state.
  8154. // The absence of the $REPARSE_POINT attribute says that the flag has to
  8155. // not be set.
  8156. //
  8157. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8158. }
  8159. //
  8160. // throttle ourselves throuch cc
  8161. //
  8162. if (!CcCanIWrite(IrpSp->FileObject,
  8163. InputBufferLength,
  8164. FALSE,
  8165. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) {
  8166. BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE);
  8167. //
  8168. // PrePosting the irp will free the resources so fcb will not be acquired afterwards
  8169. //
  8170. NtfsPrePostIrp( IrpContext, Irp );
  8171. ASSERT( !NtfsIsExclusiveFcb( Fcb ) );
  8172. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE );
  8173. CcDeferWrite( IrpSp->FileObject,
  8174. (PCC_POST_DEFERRED_WRITE)NtfsAddToWorkque,
  8175. IrpContext,
  8176. Irp,
  8177. InputBufferLength,
  8178. Retrying );
  8179. try_return( Status = STATUS_PENDING );
  8180. }
  8181. //
  8182. // Insert the record into the reparse point index.
  8183. //
  8184. {
  8185. INDEX_KEY IndexKey;
  8186. INDEX_ROW IndexRow;
  8187. REPARSE_INDEX_KEY KeyValue;
  8188. //
  8189. // Acquire the ReparsePointIndex Scb. We still hold the target fcb resource,
  8190. // so the volume couldn't have gotten dismounted under us.
  8191. //
  8192. NtfsAcquireExclusiveScb( IrpContext, Vcb->ReparsePointTableScb );
  8193. ASSERT( NtfsIsExclusiveFcb( Fcb ));
  8194. ASSERT( !FlagOn( Vcb->ReparsePointTableScb->ScbState, SCB_STATE_VOLUME_DISMOUNTED ));
  8195. //
  8196. // Add the file Id to the reparse point index.
  8197. //
  8198. KeyValue.FileReparseTag = ReparseTag;
  8199. KeyValue.FileId = *(PLARGE_INTEGER)&Scb->Fcb->FileReference;
  8200. IndexKey.Key = (PVOID)&KeyValue;
  8201. IndexKey.KeyLength = sizeof(KeyValue);
  8202. IndexRow.KeyPart = IndexKey;
  8203. IndexRow.DataPart.DataLength = 0;
  8204. IndexRow.DataPart.Data = NULL;
  8205. //
  8206. // NtOfsAddRecords will raise if the file id already belongs in the index.
  8207. //
  8208. NtOfsAddRecords( IrpContext,
  8209. Vcb->ReparsePointTableScb,
  8210. 1, // adding one record to the index
  8211. &IndexRow,
  8212. FALSE ); // sequential insert
  8213. }
  8214. //
  8215. // Create the $REPARSE_POINT attribute with the data being sent in.
  8216. //
  8217. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8218. NtfsInitializeAttributeContext( &AttributeContext );
  8219. NtfsCreateAttributeWithValue( IrpContext,
  8220. Fcb,
  8221. $REPARSE_POINT,
  8222. NULL,
  8223. (PVOID) ( Irp->AssociatedIrp.SystemBuffer ),
  8224. InputBufferLength,
  8225. (USHORT) 0, // Attribute flags
  8226. NULL,
  8227. TRUE, // LogIt
  8228. &AttributeContext );
  8229. //
  8230. // Cleanup the attribute context state
  8231. //
  8232. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8233. CleanupAttributeContext = FALSE;
  8234. //
  8235. // Set the duplicate file attribute to Reparse Point.
  8236. //
  8237. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT );
  8238. //
  8239. // Set the ReparsePointTag field.
  8240. //
  8241. Fcb->Info.ReparsePointTag = ReparseTag;
  8242. //
  8243. // Set the change attribute flag.
  8244. //
  8245. ASSERTMSG( "conflict with flush",
  8246. NtfsIsSharedFcb( Fcb ) ||
  8247. (Fcb->PagingIoResource != NULL &&
  8248. NtfsIsSharedFcbPagingIo( Fcb )) );
  8249. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  8250. }
  8251. //
  8252. // Set the archive bit in the Ccb.
  8253. //
  8254. if (!IsDirectory( &Fcb->Info )) {
  8255. SetFlag( Ccb->Flags, CCB_FLAG_SET_ARCHIVE );
  8256. }
  8257. //
  8258. // Flag to set the change time in the Ccb.
  8259. //
  8260. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  8261. //
  8262. // Update the standard information in the file record to reflect its a reparse pt.
  8263. //
  8264. NtfsUpdateStandardInformation( IrpContext, Fcb );
  8265. //
  8266. // Post the change to the Usn Journal (on errors change is backed out)
  8267. //
  8268. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_REPARSE_POINT_CHANGE );
  8269. //
  8270. // Checkpoint the Txn to commit the changes.
  8271. //
  8272. NtfsCleanupTransactionAndCommit( IrpContext, STATUS_SUCCESS, TRUE );
  8273. try_exit: NOTHING;
  8274. } finally {
  8275. DebugUnwind( NtfsSetReparsePoint );
  8276. //
  8277. // Unpin the Bcb. The unpin routine checks for NULL.
  8278. //
  8279. NtfsUnpinBcb( IrpContext, &Bcb );
  8280. //
  8281. // Clean-up all the pertinent state.
  8282. //
  8283. if (CleanupAttributeContext) {
  8284. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8285. }
  8286. //
  8287. // Need to roll-back the value of the reparse point flag in case of
  8288. // problems. I leave the archive bit set anyway.
  8289. //
  8290. if (AbnormalTermination()) {
  8291. Fcb->Info.FileAttributes = IncomingFileAttributes;
  8292. Fcb->Info.ReparsePointTag = IncomingReparsePointTag;
  8293. }
  8294. //
  8295. // Release the paging io resource if held.
  8296. //
  8297. if (PagingIoAcquired) {
  8298. ExReleaseResourceLite( Fcb->PagingIoResource );
  8299. }
  8300. }
  8301. if (Status != STATUS_PENDING) {
  8302. NtfsCompleteRequest( IrpContext, Irp, Status );
  8303. }
  8304. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  8305. return Status;
  8306. }
  8307. //
  8308. // Local support routine
  8309. //
  8310. NTSTATUS
  8311. NtfsGetReparsePoint (
  8312. IN PIRP_CONTEXT IrpContext,
  8313. IN PIRP Irp
  8314. )
  8315. /*++
  8316. Routine Description:
  8317. This routine finds the specified reparse point returning the value
  8318. of the corresponding attribute.
  8319. The value of the reparse point attribute is the linearized version of
  8320. the buffer sent in the NtfsSetReparsePoint call including the header
  8321. fields ReparseTag and ReparseDataLength. We retrieve all fields, unmodified,
  8322. so that the caller can decode it using the same buffer template used in the
  8323. set operation.
  8324. Arguments:
  8325. IrpContext - Supplies the Irp context of the call
  8326. Irp - Supplies the Irp to process
  8327. Return Value:
  8328. NTSTATUS - The return status for the operation
  8329. --*/
  8330. {
  8331. NTSTATUS Status = STATUS_SUCCESS;
  8332. PIO_STACK_LOCATION IrpSp;
  8333. ULONG FsControlCode;
  8334. TYPE_OF_OPEN TypeOfOpen;
  8335. PVCB Vcb;
  8336. PFCB Fcb;
  8337. PSCB Scb;
  8338. PCCB Ccb;
  8339. PBCB Bcb = NULL; // does not get initialized below in NtfsDecodeFileObject
  8340. PCHAR OutputBuffer = NULL;
  8341. ULONG OutputBufferLength = 0; // invalid value as we need an output buffer
  8342. ULONG InputBufferLength = 0; // invalid value as we need an input buffer
  8343. BOOLEAN CleanupAttributeContext = FALSE;
  8344. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  8345. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  8346. PATTRIBUTE_LIST_ENTRY AttributeListEntry = NULL;
  8347. ULONG AttributeLengthInBytes = 0;
  8348. PVOID AttributeData = NULL;
  8349. BOOLEAN ScbAcquired = FALSE;
  8350. ASSERT_IRP_CONTEXT( IrpContext );
  8351. ASSERT_IRP( Irp );
  8352. PAGED_CODE();
  8353. //
  8354. // Get the current Irp stack location
  8355. //
  8356. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  8357. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  8358. DebugTrace( +1, Dbg, ("NtfsGetReparsePoint, FsControlCode = %08lx\n", FsControlCode) );
  8359. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  8360. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  8361. //
  8362. // Decode all the relevant File System data structures.
  8363. //
  8364. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  8365. IrpSp->FileObject,
  8366. &Vcb,
  8367. &Fcb,
  8368. &Scb,
  8369. &Ccb,
  8370. TRUE ); // Raise an exeption if error is encountered
  8371. //
  8372. // Check for the correct type of open.
  8373. //
  8374. //
  8375. // See that we have a file or a directory open.
  8376. //
  8377. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  8378. //
  8379. // Return an invalid parameter error
  8380. //
  8381. Status = STATUS_INVALID_PARAMETER;
  8382. //
  8383. // Return to caller.
  8384. //
  8385. NtfsCompleteRequest( IrpContext, Irp, Status );
  8386. DebugTrace( 0, Dbg, ("Invalid parameter passed by caller\n") );
  8387. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8388. return Status;
  8389. }
  8390. ASSERT_VCB( Vcb );
  8391. ASSERT_FCB( Fcb );
  8392. ASSERT_SCB( Scb );
  8393. ASSERT_CCB( Ccb );
  8394. if (!NtfsVolumeVersionCheck( Vcb, NTFS_REPARSE_POINT_VERSION )) {
  8395. //
  8396. // Return a volume not upgraded error.
  8397. //
  8398. Status = STATUS_VOLUME_NOT_UPGRADED;
  8399. //
  8400. // Return to caller.
  8401. //
  8402. NtfsCompleteRequest( IrpContext, Irp, Status );
  8403. DebugTrace( 0, Dbg, ("Non-upgraded volume passed by caller.\n") );
  8404. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8405. return Status;
  8406. }
  8407. //
  8408. // Get the length of the output buffer.
  8409. //
  8410. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  8411. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  8412. DebugTrace( 0, Dbg, ("InputBufferLength %08lx [d]%08d OutputBufferLength %08lx\n", InputBufferLength, InputBufferLength, OutputBufferLength) );
  8413. //
  8414. // Do not allow input buffer in the get command.
  8415. //
  8416. if (InputBufferLength > 0) {
  8417. //
  8418. // Return an invalid parameter error.
  8419. //
  8420. Status = STATUS_INVALID_PARAMETER;
  8421. //
  8422. // Return to caller.
  8423. //
  8424. NtfsCompleteRequest( IrpContext, Irp, Status );
  8425. DebugTrace( 0, Dbg, ("Non-null input buffer.\n") );
  8426. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8427. return Status;
  8428. }
  8429. //
  8430. // Get a pointer to the output buffer. First look at the system buffer field in
  8431. // the IRP. Then look in the IRP Mdl.
  8432. //
  8433. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  8434. OutputBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
  8435. } else if (Irp->MdlAddress != NULL) {
  8436. OutputBuffer = (PCHAR)MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  8437. if (OutputBuffer == NULL) {
  8438. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  8439. return STATUS_INSUFFICIENT_RESOURCES;
  8440. }
  8441. } else {
  8442. //
  8443. // Return an invalid user buffer error.
  8444. //
  8445. Status = STATUS_INVALID_USER_BUFFER;
  8446. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  8447. DebugTrace( 0, Dbg, ("User buffer is not good.\n") );
  8448. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8449. return Status;
  8450. }
  8451. //
  8452. // Zero the Information field in IoStatus.
  8453. //
  8454. Irp->IoStatus.Information = 0;
  8455. //
  8456. // We set the IrpContext flag to indicate that we can wait, making htis a synchronous
  8457. // call.
  8458. //
  8459. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  8460. //
  8461. // Now it is time ot use a try-finally to facilitate cleanup.
  8462. //
  8463. try {
  8464. //
  8465. // We acquire the Scb in shared mode so that the underlying Fcb remains stable.
  8466. //
  8467. NtfsAcquireSharedScb( IrpContext, Scb );
  8468. ScbAcquired = TRUE;
  8469. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  8470. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  8471. }
  8472. //
  8473. // The parameters and boundary conditions look good and we have a reparse point.
  8474. // We begin real work.
  8475. //
  8476. // Find the reparse point attribute.
  8477. //
  8478. NtfsInitializeAttributeContext( &AttributeContext );
  8479. CleanupAttributeContext = TRUE;
  8480. if (!NtfsLookupAttributeByCode( IrpContext,
  8481. Fcb,
  8482. &Fcb->FileReference,
  8483. $REPARSE_POINT,
  8484. &AttributeContext )) {
  8485. DebugTrace( 0, Dbg, ("Can't find the $REPARSE_POINT attribute.\n") );
  8486. //
  8487. // Verify that the information in FileAttributes is consistent.
  8488. //
  8489. if (FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8490. DebugTrace( 0, Dbg, ("The Fcb says this IS a reparse point.\n") );
  8491. //
  8492. // Should not happen. Raise an exeption as we are in an inconsistent state.
  8493. // The attribute flag says that $REPARSE_POINT has to be present.
  8494. //
  8495. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8496. }
  8497. //
  8498. // Return STATUS_NOT_A_REPARSE_POINT
  8499. //
  8500. Status = STATUS_NOT_A_REPARSE_POINT;
  8501. try_return( Status );
  8502. }
  8503. //
  8504. // Find the size of the attribute.
  8505. // Determine whether we have enough buffer to return it to the caller.
  8506. //
  8507. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  8508. if (NtfsIsAttributeResident( AttributeHeader )) {
  8509. AttributeLengthInBytes = AttributeHeader->Form.Resident.ValueLength;
  8510. DebugTrace( 0, Dbg, ("Resident attribute with length %05lx\n", AttributeLengthInBytes) );
  8511. if (AttributeLengthInBytes > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  8512. //
  8513. // Return STATUS_IO_REPARSE_DATA_INVALID
  8514. //
  8515. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8516. DebugTrace( 0, Dbg, ("AttributeLengthInBytes is [x]%08lx is too long.\n", AttributeLengthInBytes) );
  8517. try_return( Status );
  8518. }
  8519. //
  8520. // Point to the value of the arribute.
  8521. //
  8522. AttributeData = NtfsAttributeValue( AttributeHeader );
  8523. ASSERT( Bcb == NULL );
  8524. } else {
  8525. ULONG Length;
  8526. if (AttributeHeader->Form.Nonresident.FileSize > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  8527. //
  8528. // Return STATUS_IO_REPARSE_DATA_INVALID
  8529. //
  8530. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8531. DebugTrace( 0, Dbg, ("Nonresident.FileSize is too long.\n") );
  8532. try_return( Status );
  8533. }
  8534. //
  8535. // Note that we coerse different LENGTHs
  8536. //
  8537. AttributeLengthInBytes = (ULONG)AttributeHeader->Form.Nonresident.FileSize;
  8538. DebugTrace( 0, Dbg, ("Non-resident attribute with length %05lx\n", AttributeLengthInBytes) );
  8539. //
  8540. // Map the attribute list if the attribute is non-resident. Otherwise the
  8541. // attribute is already mapped and we have a Bcb in the attribute context.
  8542. //
  8543. NtfsMapAttributeValue( IrpContext,
  8544. Fcb,
  8545. &AttributeData, // point to the value
  8546. &Length,
  8547. &Bcb,
  8548. &AttributeContext );
  8549. if (AttributeLengthInBytes != Length) {
  8550. DebugTrace( 0, Dbg, ("AttributeLengthInBytes %05lx and Length %05lx differ.\n", AttributeLengthInBytes, Length) );
  8551. }
  8552. ASSERT( AttributeLengthInBytes == Length );
  8553. }
  8554. DebugTrace( 0, Dbg, ("AttributeLengthInBytes is [d]%06ld %05lx\n", AttributeLengthInBytes, AttributeLengthInBytes) );
  8555. if (AttributeLengthInBytes > OutputBufferLength) {
  8556. DebugTrace( 0, Dbg, ("Insufficient output buffer passed by caller.\n") );
  8557. //
  8558. // Check whether the fixed portion will fit.
  8559. //
  8560. if (OutputBufferLength < sizeof( REPARSE_GUID_DATA_BUFFER )) {
  8561. //
  8562. // This is the error path. Don't return anything.
  8563. //
  8564. try_return( Status = STATUS_BUFFER_TOO_SMALL );
  8565. } else {
  8566. Status = STATUS_BUFFER_OVERFLOW;
  8567. }
  8568. //
  8569. // Remember the smaller number of returned bytes.
  8570. //
  8571. AttributeLengthInBytes = OutputBufferLength;
  8572. }
  8573. //
  8574. // Copy the value of the reparse point attribute to the buffer.
  8575. // Return all the value including the system header fields (e.g., Tag and Length)
  8576. // stored at the beginning of the value of the reparse point attribute.
  8577. //
  8578. RtlCopyMemory( OutputBuffer,
  8579. AttributeData,
  8580. AttributeLengthInBytes );
  8581. //
  8582. // Set the information field to the length of the buffer returned.
  8583. // This tells the re-director to do the corresponding data transmission.
  8584. //
  8585. Irp->IoStatus.Information = AttributeLengthInBytes;
  8586. //
  8587. // Cleanup the attribute context state.
  8588. //
  8589. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8590. CleanupAttributeContext = FALSE;
  8591. try_exit: NOTHING;
  8592. } finally {
  8593. //
  8594. // Clean-up all the pertinent state.
  8595. //
  8596. DebugUnwind( NtfsGetReparsePoint );
  8597. if (CleanupAttributeContext) {
  8598. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8599. }
  8600. //
  8601. // Unpin the Bcb ... in case you needed to pin it above.
  8602. // The unpin routine checks for NULL.
  8603. //
  8604. NtfsUnpinBcb( IrpContext, &Bcb );
  8605. //
  8606. // Relase the Fcb.
  8607. //
  8608. if (ScbAcquired) {
  8609. NtfsReleaseScb( IrpContext, Scb );
  8610. } else {
  8611. //
  8612. // We must have raised an exception in NtfsAcquireSharedFcb.
  8613. // Because we check for the existence of the file this must mean
  8614. // that it has been deleted from under us.
  8615. //
  8616. // Nothing is to be done as exception processing sets the correct
  8617. // return code.
  8618. //
  8619. }
  8620. }
  8621. NtfsCompleteRequest( IrpContext, Irp, Status );
  8622. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8623. return Status;
  8624. }
  8625. //
  8626. // Local support routine
  8627. //
  8628. NTSTATUS
  8629. NtfsDeleteReparsePoint (
  8630. IN PIRP_CONTEXT IrpContext,
  8631. IN PIRP Irp
  8632. )
  8633. /*++
  8634. Routine Description:
  8635. This routine deletes a reparse point at the file object entry
  8636. specified in the IRP.
  8637. The IN buffer specified by the caller has the value of the Tag of the reparse point
  8638. being deleted, and no data, thus needing to have a value of zero for DataLength.
  8639. If the tags do not match the delete fails.
  8640. If the file object has the FILE_ATTRIBUTE_REPARSE_POINT bit set then the
  8641. $REPARSE_POINT attribute is expected to be in the file.
  8642. There is no OUT buffer sent by the caller.
  8643. This function deletes the corresponding entry from the reparse point table.
  8644. Arguments:
  8645. IrpContext - Supplies the Irp context of the call
  8646. Irp - Supplies the Irp to process
  8647. Return Value:
  8648. NTSTATUS - The return status for the operation
  8649. --*/
  8650. {
  8651. NTSTATUS Status = STATUS_SUCCESS;
  8652. PIO_STACK_LOCATION IrpSp;
  8653. ULONG FsControlCode;
  8654. TYPE_OF_OPEN TypeOfOpen;
  8655. PVCB Vcb;
  8656. PFCB Fcb;
  8657. PSCB Scb;
  8658. PSCB NonResidentScb = NULL;
  8659. PCCB Ccb;
  8660. PBCB Bcb = NULL; // does not get initialized below in NtfsDecodeFileObject
  8661. PREPARSE_DATA_BUFFER ReparseBuffer = NULL;
  8662. ULONG ReparseTag;
  8663. USHORT ReparseDataLength = 0; // only valid value
  8664. ULONG InputBufferLength = 0; // invalid value as the header is needed
  8665. ULONG OutputBufferLength = 2; // invalid value as no output buffer is used
  8666. ULONG IncomingFileAttributes = 0; // invalid value
  8667. ULONG IncomingReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; // invalid value
  8668. BOOLEAN CleanupAttributeContext = FALSE;
  8669. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  8670. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  8671. MAP_HANDLE MapHandle;
  8672. BOOLEAN NonResidentScbAcquired = FALSE;
  8673. BOOLEAN InitializedMapHandle = FALSE;
  8674. ASSERT_IRP_CONTEXT( IrpContext );
  8675. ASSERT_IRP( Irp );
  8676. PAGED_CODE();
  8677. //
  8678. // Get the current Irp stack location
  8679. //
  8680. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  8681. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  8682. DebugTrace( +1, Dbg, ("NtfsDeleteReparsePoint, FsControlCode = %08lx\n", FsControlCode) );
  8683. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  8684. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  8685. //
  8686. // Get the length of the input and output buffers.
  8687. //
  8688. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  8689. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  8690. DebugTrace( 0, Dbg, ("InputBufferLength = %08lx, OutputBufferLength = %08lx\n", InputBufferLength, OutputBufferLength) );
  8691. //
  8692. // Do not allow output buffer in the delete command.
  8693. //
  8694. if (OutputBufferLength > 0) {
  8695. //
  8696. // Return an invalid parameter error.
  8697. //
  8698. Status = STATUS_INVALID_PARAMETER;
  8699. //
  8700. // Return to caller.
  8701. //
  8702. NtfsCompleteRequest( IrpContext, Irp, Status );
  8703. DebugTrace( 0, Dbg, ("Non-null output buffer.\n") );
  8704. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8705. return Status;
  8706. }
  8707. //
  8708. // Decode all the relevant File System data structures.
  8709. //
  8710. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  8711. IrpSp->FileObject,
  8712. &Vcb,
  8713. &Fcb,
  8714. &Scb,
  8715. &Ccb,
  8716. TRUE ); // Raise an exeption if error is encountered
  8717. //
  8718. // Check for the correct type of open.
  8719. //
  8720. if (
  8721. //
  8722. // See that we have a file or a directory.
  8723. //
  8724. ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen))) {
  8725. //
  8726. // Return an invalid parameter error
  8727. //
  8728. Status = STATUS_INVALID_PARAMETER;
  8729. //
  8730. // Return to caller.
  8731. //
  8732. NtfsCompleteRequest( IrpContext, Irp, Status );
  8733. DebugTrace( 0, Dbg, ("Invalid TypeOfOpen\n") );
  8734. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8735. return Status;
  8736. }
  8737. //
  8738. // The caller has FILE_SPECIAL_ACCESS. The NTFS driver enforces access checks more stringent
  8739. // than FILE_ANY_ACCESS:
  8740. // (a) FILE_WRITE_DATA or FILE_WRITE_ATTRIBUTES_ACCESS
  8741. //
  8742. if (!FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS ) &&
  8743. //
  8744. // Temporary KLUDGE for DavePr.
  8745. // The Ccb->AccessFlags and the FileObject->WriteAccess may not coincide as a
  8746. // filter may change the "visible" file object after the open. The Ccb flags do
  8747. // not change after open.
  8748. //
  8749. !(IrpSp->FileObject->WriteAccess == TRUE)) {
  8750. //
  8751. // Return access denied.
  8752. //
  8753. Status = STATUS_ACCESS_DENIED;
  8754. //
  8755. // Return to caller.
  8756. //
  8757. NtfsCompleteRequest( IrpContext, Irp, Status );
  8758. DebugTrace( 0, Dbg, ("Ccb->AccessFlags %x\n", Ccb->AccessFlags) );
  8759. DebugTrace( 0, Dbg, ("Caller did not have the appropriate access rights.\n") );
  8760. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8761. return Status;
  8762. }
  8763. ASSERT_VCB( Vcb );
  8764. ASSERT_FCB( Fcb );
  8765. ASSERT_SCB( Scb );
  8766. ASSERT_CCB( Ccb );
  8767. //
  8768. // Read only volumes stay read only.
  8769. //
  8770. if (NtfsIsVolumeReadOnly( Vcb )) {
  8771. Status = STATUS_MEDIA_WRITE_PROTECTED;
  8772. NtfsCompleteRequest( IrpContext, Irp, Status );
  8773. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8774. return Status;
  8775. }
  8776. if (!NtfsVolumeVersionCheck( Vcb, NTFS_REPARSE_POINT_VERSION )) {
  8777. //
  8778. // Return a volume not upgraded error.
  8779. //
  8780. Status = STATUS_VOLUME_NOT_UPGRADED;
  8781. //
  8782. // Return to caller.
  8783. //
  8784. NtfsCompleteRequest( IrpContext, Irp, Status );
  8785. DebugTrace( 0, Dbg, ("Non-upgraded volume passed by caller.\n") );
  8786. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8787. return Status;
  8788. }
  8789. //
  8790. // Check for invalid conditions in the parameters.
  8791. //
  8792. if (
  8793. //
  8794. // Verify that we have the required system input buffer.
  8795. //
  8796. (Irp->AssociatedIrp.SystemBuffer == NULL)) {
  8797. //
  8798. // Return an invalid buffer error.
  8799. //
  8800. Status = STATUS_INVALID_BUFFER_SIZE;
  8801. //
  8802. // Return to caller.
  8803. //
  8804. NtfsCompleteRequest( IrpContext, Irp, Status );
  8805. DebugTrace( 0, Dbg, ("Null buffer passed by system.\n") );
  8806. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8807. return Status;
  8808. }
  8809. //
  8810. // See that the buffer sent in by the caller is the exact header.
  8811. //
  8812. if ((InputBufferLength != REPARSE_DATA_BUFFER_HEADER_SIZE) &&
  8813. (InputBufferLength != REPARSE_GUID_DATA_BUFFER_HEADER_SIZE)) {
  8814. //
  8815. // Return an invalid reparse data.
  8816. //
  8817. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8818. //
  8819. // Return to caller.
  8820. //
  8821. NtfsCompleteRequest( IrpContext, Irp, Status );
  8822. DebugTrace( 0, Dbg, ("Invalid parameter reparse data passed by caller\n") );
  8823. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8824. return Status;
  8825. }
  8826. //
  8827. // Get the header information brought in the input buffer.
  8828. // While the first two fields coincide in REPARSE_DATA_BUFFER and REPARSE_GUID_DATA_BUFFER,
  8829. // a common assignment can be used below.
  8830. //
  8831. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseTag) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseTag) );
  8832. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseDataLength) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseDataLength) );
  8833. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, Reserved) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, Reserved) );
  8834. ReparseBuffer = (PREPARSE_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  8835. ReparseTag = ReparseBuffer->ReparseTag;
  8836. ReparseDataLength = ReparseBuffer->ReparseDataLength;
  8837. DebugTrace( 0, Dbg, ("ReparseTag = %08lx, ReparseDataLength = %05lx [d]%d\n", ReparseTag, ReparseDataLength, ReparseDataLength) );
  8838. //
  8839. // We verify that ReparseDataLength is zero.
  8840. //
  8841. if (ReparseDataLength != 0) {
  8842. //
  8843. // Return an invalid reparse data.
  8844. //
  8845. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8846. //
  8847. // Return to caller.
  8848. //
  8849. NtfsCompleteRequest( IrpContext, Irp, Status );
  8850. DebugTrace( 0, Dbg, ("Invalid header value passed by caller\n") );
  8851. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8852. return Status;
  8853. }
  8854. //
  8855. // We verify that the caller uses one of the non-reserved tags.
  8856. //
  8857. if ((ReparseTag == IO_REPARSE_TAG_RESERVED_ZERO) ||
  8858. (ReparseTag == IO_REPARSE_TAG_RESERVED_ONE)) {
  8859. //
  8860. // Return an invalid reparse tag.
  8861. //
  8862. Status = STATUS_IO_REPARSE_TAG_INVALID;
  8863. //
  8864. // Return to caller.
  8865. //
  8866. NtfsCompleteRequest( IrpContext, Irp, Status );
  8867. DebugTrace( 0, Dbg, ("Caller passed in a reserved tag for the reparse data.\n") );
  8868. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8869. return Status;
  8870. }
  8871. //
  8872. // We verify that for non-Microsoft tags the caller has the GUID header.
  8873. //
  8874. if (!IsReparseTagMicrosoft( ReparseTag ) &&
  8875. (InputBufferLength != REPARSE_GUID_DATA_BUFFER_HEADER_SIZE)) {
  8876. //
  8877. // Return an invalid reparse data.
  8878. //
  8879. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8880. //
  8881. // Return to caller.
  8882. //
  8883. NtfsCompleteRequest( IrpContext, Irp, Status );
  8884. DebugTrace( 0, Dbg, ("Caller used non-Microsoft tag and did not use the GUID buffer.\n") );
  8885. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8886. return Status;
  8887. }
  8888. //
  8889. // We set the IrpContext flag to indicate that we can wait, making this a synchronous
  8890. // call.
  8891. //
  8892. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  8893. //
  8894. // Capture the source information.
  8895. //
  8896. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  8897. //
  8898. // Now it is time ot use a try-finally to facilitate cleanup.
  8899. //
  8900. try {
  8901. //
  8902. // Acquire exclusive the Fcb.
  8903. //
  8904. NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, 0 );
  8905. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  8906. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  8907. }
  8908. //
  8909. // Remember the value of the file attribute flags and of the reparse point.
  8910. //
  8911. IncomingFileAttributes = Fcb->Info.FileAttributes;
  8912. IncomingReparsePointTag = Fcb->Info.ReparsePointTag;
  8913. //
  8914. // All the parameters and boundary conditions look good. We begin real work.
  8915. //
  8916. // Delete the appropriate system defined reparse point attribute.
  8917. // First point to it and then nuke it.
  8918. //
  8919. NtfsInitializeAttributeContext( &AttributeContext );
  8920. CleanupAttributeContext = TRUE;
  8921. if (!(NtfsLookupAttributeByCode( IrpContext,
  8922. Fcb,
  8923. &Fcb->FileReference,
  8924. $REPARSE_POINT,
  8925. &AttributeContext ) ) ) {
  8926. DebugTrace( 0, Dbg, ("Can't find the $REPARSE_POINT attribute\n") );
  8927. //
  8928. // See if FileAttributes agrees that we do not have a reparse point.
  8929. //
  8930. if (FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8931. DebugTrace( 0, Dbg, ("The Fcb says this IS a reparse point.\n") );
  8932. //
  8933. // Should not happen. Raise an exeption as we are in an
  8934. // inconsistent state. The attribute flag says that
  8935. // $REPARSE_POINT has to be present.
  8936. //
  8937. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8938. }
  8939. //
  8940. // Return STATUS_NOT_A_REPARSE_POINT
  8941. //
  8942. Status = STATUS_NOT_A_REPARSE_POINT;
  8943. try_return( Status );
  8944. }
  8945. //
  8946. // Verify that the incomming tag value matches the tag value present in
  8947. // the $REPARSE_POINT attribute.
  8948. //
  8949. {
  8950. PREPARSE_GUID_DATA_BUFFER ReparseBufferTwo = NULL;
  8951. PVOID AttributeData = NULL;
  8952. ULONG Length = 0;
  8953. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  8954. if (NtfsIsAttributeResident( AttributeHeader )) {
  8955. //
  8956. // Point to the value of the arribute.
  8957. //
  8958. AttributeData = NtfsAttributeValue( AttributeHeader );
  8959. DebugTrace( 0, Dbg, ("Existing attribute is resident.\n") );
  8960. } else {
  8961. //
  8962. // Map the attribute list if the attribute is non-resident. Otherwise the
  8963. // attribute is already mapped and we have a Bcb in the attribute context.
  8964. //
  8965. DebugTrace( 0, Dbg, ("Existing attribute is non-resident.\n") );
  8966. NtfsMapAttributeValue( IrpContext,
  8967. Fcb,
  8968. &AttributeData, // point to the value
  8969. &Length,
  8970. &Bcb,
  8971. &AttributeContext );
  8972. }
  8973. //
  8974. // Verify that the two tag values match.
  8975. //
  8976. ReparseBufferTwo = (PREPARSE_GUID_DATA_BUFFER)AttributeData;
  8977. DebugTrace( 0, Dbg, ("Existing tag is [d]%03ld - New tag is [d]%03ld\n", ReparseBufferTwo->ReparseTag, ReparseBuffer->ReparseTag) );
  8978. if (ReparseBuffer->ReparseTag != ReparseBufferTwo->ReparseTag) {
  8979. //
  8980. // Return status STATUS_IO_REPARSE_TAG_MISMATCH
  8981. //
  8982. DebugTrace( 0, Dbg, ("Tag mismatch with the existing reparse point.\n") );
  8983. Status = STATUS_IO_REPARSE_TAG_MISMATCH;
  8984. try_return( Status );
  8985. }
  8986. //
  8987. // For non-Microsoft tags, verify that the GUIDs match.
  8988. //
  8989. if (!IsReparseTagMicrosoft( ReparseTag )) {
  8990. PREPARSE_GUID_DATA_BUFFER ReparseGuidBuffer = NULL;
  8991. ReparseGuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer;
  8992. if (!((ReparseGuidBuffer->ReparseGuid.Data1 == ReparseBufferTwo->ReparseGuid.Data1) &&
  8993. (ReparseGuidBuffer->ReparseGuid.Data2 == ReparseBufferTwo->ReparseGuid.Data2) &&
  8994. (ReparseGuidBuffer->ReparseGuid.Data3 == ReparseBufferTwo->ReparseGuid.Data3) &&
  8995. (ReparseGuidBuffer->ReparseGuid.Data4[0] == ReparseBufferTwo->ReparseGuid.Data4[0]) &&
  8996. (ReparseGuidBuffer->ReparseGuid.Data4[1] == ReparseBufferTwo->ReparseGuid.Data4[1]) &&
  8997. (ReparseGuidBuffer->ReparseGuid.Data4[2] == ReparseBufferTwo->ReparseGuid.Data4[2]) &&
  8998. (ReparseGuidBuffer->ReparseGuid.Data4[3] == ReparseBufferTwo->ReparseGuid.Data4[3]) &&
  8999. (ReparseGuidBuffer->ReparseGuid.Data4[4] == ReparseBufferTwo->ReparseGuid.Data4[4]) &&
  9000. (ReparseGuidBuffer->ReparseGuid.Data4[5] == ReparseBufferTwo->ReparseGuid.Data4[5]) &&
  9001. (ReparseGuidBuffer->ReparseGuid.Data4[6] == ReparseBufferTwo->ReparseGuid.Data4[6]) &&
  9002. (ReparseGuidBuffer->ReparseGuid.Data4[7] == ReparseBufferTwo->ReparseGuid.Data4[7]))) {
  9003. //
  9004. // Return status STATUS_REPARSE_ATTRIBUTE_CONFLICT
  9005. //
  9006. DebugTrace( 0, Dbg, ("GUID mismatch with the existing reparse point.\n") );
  9007. Status = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
  9008. try_return( Status );
  9009. }
  9010. }
  9011. //
  9012. // Unpin the Bcb. The unpin routine checks for NULL.
  9013. //
  9014. NtfsUnpinBcb( IrpContext, &Bcb );
  9015. }
  9016. //
  9017. // Delete the record from the reparse point index.
  9018. //
  9019. {
  9020. INDEX_KEY IndexKey;
  9021. INDEX_ROW IndexRow;
  9022. REPARSE_INDEX_KEY KeyValue;
  9023. //
  9024. // Acquire the mount table index so that the following two operations on it
  9025. // are atomic for this call.
  9026. //
  9027. NtfsAcquireExclusiveScb( IrpContext, Vcb->ReparsePointTableScb );
  9028. //
  9029. // Verify that this file is in the reparse point index and delete it.
  9030. //
  9031. KeyValue.FileReparseTag = ReparseTag;
  9032. KeyValue.FileId = *(PLARGE_INTEGER)&Scb->Fcb->FileReference;
  9033. IndexKey.Key = (PVOID)&KeyValue;
  9034. IndexKey.KeyLength = sizeof(KeyValue);
  9035. NtOfsInitializeMapHandle( &MapHandle );
  9036. InitializedMapHandle = TRUE;
  9037. //
  9038. // NtOfsFindRecord will return an error status if the key is not found.
  9039. //
  9040. Status = NtOfsFindRecord( IrpContext,
  9041. Vcb->ReparsePointTableScb,
  9042. &IndexKey,
  9043. &IndexRow,
  9044. &MapHandle,
  9045. NULL );
  9046. if (!NT_SUCCESS(Status)) {
  9047. //
  9048. // Should not happen. The reparse point should be in the index.
  9049. //
  9050. DebugTrace( 0, Dbg, ("Record not found in the reparse point index.\n") );
  9051. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  9052. }
  9053. //
  9054. // Remove the entry from the reparse point index.
  9055. //
  9056. NtOfsDeleteRecords( IrpContext,
  9057. Vcb->ReparsePointTableScb,
  9058. 1, // deleting one record from the index
  9059. &IndexKey );
  9060. }
  9061. //
  9062. // If the stream is non-resident, then get hold of an Scb for it.
  9063. //
  9064. if (!NtfsIsAttributeResident( AttributeHeader )) {
  9065. NonResidentScb = NtfsCreateScb( IrpContext,
  9066. Fcb,
  9067. $REPARSE_POINT,
  9068. &NtfsEmptyString,
  9069. FALSE,
  9070. NULL );
  9071. NtfsAcquireExclusiveScb( IrpContext, NonResidentScb );
  9072. NonResidentScbAcquired = TRUE;
  9073. }
  9074. //
  9075. // Nuke the attribute.
  9076. //
  9077. NtfsDeleteAttributeRecord( IrpContext,
  9078. Fcb,
  9079. DELETE_LOG_OPERATION |
  9080. DELETE_RELEASE_FILE_RECORD |
  9081. DELETE_RELEASE_ALLOCATION,
  9082. &AttributeContext );
  9083. //
  9084. // Cleanup the attribute context.
  9085. //
  9086. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  9087. CleanupAttributeContext = FALSE;
  9088. //
  9089. // Set the change attribute flag.
  9090. //
  9091. ASSERTMSG( "conflict with flush",
  9092. NtfsIsSharedFcb( Fcb ) ||
  9093. (Fcb->PagingIoResource != NULL &&
  9094. NtfsIsSharedFcbPagingIo( Fcb )) );
  9095. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  9096. //
  9097. // Clear the reparse point bit in the duplicate file attribute.
  9098. //
  9099. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT );
  9100. //
  9101. // Clear the ReparsePointTag field in the duplicate file attribute.
  9102. //
  9103. Fcb->Info.ReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO;
  9104. //
  9105. // Update the standard information in the file record.
  9106. //
  9107. NtfsUpdateStandardInformation( IrpContext, Fcb );
  9108. //
  9109. // Post the change to the Usn Journal (on errors change is backed out)
  9110. //
  9111. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_REPARSE_POINT_CHANGE );
  9112. //
  9113. // Checkpoint the Txn to commit the changes.
  9114. //
  9115. NtfsCleanupTransactionAndCommit( IrpContext, STATUS_SUCCESS, TRUE );
  9116. //
  9117. // Flag the change time change in the Ccb.
  9118. //
  9119. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  9120. //
  9121. // Don't set the archive bit on a directory. Otherwise we break existing
  9122. // apps that don't expect to see this flag.
  9123. //
  9124. if (!IsDirectory( &Fcb->Info )) {
  9125. SetFlag( Ccb->Flags, CCB_FLAG_SET_ARCHIVE );
  9126. }
  9127. //
  9128. // Reflect that the attribute is gone in the corresponding Scb.
  9129. //
  9130. if (NonResidentScbAcquired) {
  9131. NonResidentScb->AttributeTypeCode = $UNUSED;
  9132. //
  9133. // If we have acquired the Scb then set the sizes back to zero.
  9134. // Flag that the attribute has been deleted.
  9135. //
  9136. NonResidentScb->Header.FileSize =
  9137. NonResidentScb->Header.ValidDataLength =
  9138. NonResidentScb->Header.AllocationSize = Li0;
  9139. //
  9140. // Set the Scb flag to indicate that the attribute is gone.
  9141. //
  9142. SetFlag( NonResidentScb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  9143. //
  9144. // Go ahead and dereference any internal file object. No sense in keeping it around.
  9145. //
  9146. NtfsDeleteInternalAttributeStream( NonResidentScb, FALSE, 0 );
  9147. }
  9148. try_exit: NOTHING;
  9149. } finally {
  9150. DebugUnwind( NtfsDeleteReparsePoint );
  9151. //
  9152. // Unpin the Bcb. The unpin routine checks for NULL.
  9153. //
  9154. NtfsUnpinBcb( IrpContext, &Bcb );
  9155. if (CleanupAttributeContext) {
  9156. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  9157. }
  9158. //
  9159. // Need to roll-back the value of the reparse point flag in case of
  9160. // problems. I leave the archive bit set anyway.
  9161. //
  9162. if (AbnormalTermination()) {
  9163. Fcb->Info.FileAttributes = IncomingFileAttributes;
  9164. Fcb->Info.ReparsePointTag = IncomingReparsePointTag;
  9165. }
  9166. //
  9167. // Release the reparse point index Scb and the map handle.
  9168. //
  9169. if (InitializedMapHandle) {
  9170. NtOfsReleaseMap( IrpContext, &MapHandle );
  9171. }
  9172. }
  9173. NtfsCompleteRequest( IrpContext, Irp, Status );
  9174. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  9175. return Status;
  9176. }
  9177. NTSTATUS
  9178. NtfsGetTunneledData (
  9179. IN PIRP_CONTEXT IrpContext,
  9180. IN PFCB Fcb,
  9181. IN OUT PNTFS_TUNNELED_DATA TunneledData
  9182. )
  9183. /*++
  9184. Routine Description:
  9185. This routine will get the tunneled data for the
  9186. given Fcb. Currently, this means getting the Fcb's
  9187. creation time.
  9188. Arguments:
  9189. Fcb - Supplies the Fcb for which to get the data.
  9190. TunneledData - Where to store the tunneled data.
  9191. Return Value:
  9192. NTSTATUS - The return status for the operation
  9193. --*/
  9194. {
  9195. PAGED_CODE();
  9196. UNREFERENCED_PARAMETER( IrpContext );
  9197. TunneledData->CreationTime = Fcb->Info.CreationTime;
  9198. return STATUS_SUCCESS;
  9199. }
  9200. NTSTATUS
  9201. NtfsSetTunneledData (
  9202. IN PIRP_CONTEXT IrpContext,
  9203. IN PFCB Fcb,
  9204. IN PNTFS_TUNNELED_DATA TunneledData
  9205. )
  9206. /*++
  9207. Routine Description:
  9208. This routine will set the tunneled data for the
  9209. given Fcb. Currently, this means setting the Fcb's
  9210. creation time and setting its object id, if any.
  9211. Arguments:
  9212. Fcb - Supplies the Fcb whose tunneled data should be set.
  9213. TunneledData - Supplies the data to set for the Fcb.
  9214. Return Value:
  9215. NTSTATUS - The return status for the operation
  9216. --*/
  9217. {
  9218. NTSTATUS Status = STATUS_SUCCESS;
  9219. PAGED_CODE();
  9220. Fcb->Info.CreationTime = TunneledData->CreationTime;
  9221. if (TunneledData->HasObjectId) {
  9222. try {
  9223. Status = NtfsSetObjectIdInternal( IrpContext,
  9224. Fcb,
  9225. Fcb->Vcb,
  9226. &TunneledData->ObjectIdBuffer );
  9227. } except( EXCEPTION_EXECUTE_HANDLER ) {
  9228. Status = GetExceptionCode();
  9229. NtfsMinimumExceptionProcessing( IrpContext );
  9230. //
  9231. // If setting the object id failed just because the id is in use
  9232. // for another file, or if the file already has an object id,
  9233. // there's no point in failing the entire create operation.
  9234. // We'll just say that all went well in that case, and only raise
  9235. // if something unexpected happened.
  9236. //
  9237. if ((Status == STATUS_DUPLICATE_NAME) ||
  9238. (Status == STATUS_OBJECT_NAME_COLLISION)) {
  9239. //
  9240. // We notify anyone watching the object id index that this
  9241. // object id couldn't be tunnelled. This lets a link tracking
  9242. // service decide for itself how to handle this case.
  9243. //
  9244. if (Fcb->Vcb->ViewIndexNotifyCount != 0) {
  9245. FILE_OBJECTID_INFORMATION FileObjectIdInfo;
  9246. RtlCopyMemory( &FileObjectIdInfo.FileReference,
  9247. &Fcb->FileReference,
  9248. sizeof(FILE_REFERENCE) );
  9249. RtlCopyMemory( FileObjectIdInfo.ObjectId,
  9250. TunneledData->ObjectIdBuffer.ObjectId,
  9251. OBJECT_ID_KEY_LENGTH );
  9252. RtlCopyMemory( FileObjectIdInfo.ExtendedInfo,
  9253. TunneledData->ObjectIdBuffer.ExtendedInfo,
  9254. OBJECT_ID_EXT_INFO_LENGTH );
  9255. NtfsReportViewIndexNotify( Fcb->Vcb,
  9256. Fcb->Vcb->ObjectIdTableScb->Fcb,
  9257. FILE_NOTIFY_CHANGE_FILE_NAME,
  9258. (Status == STATUS_DUPLICATE_NAME ?
  9259. FILE_ACTION_ID_NOT_TUNNELLED :
  9260. FILE_ACTION_TUNNELLED_ID_COLLISION),
  9261. &FileObjectIdInfo,
  9262. sizeof(FILE_OBJECTID_INFORMATION) );
  9263. }
  9264. IrpContext->ExceptionStatus = Status = STATUS_SUCCESS;
  9265. } else {
  9266. NtfsRaiseStatus( IrpContext, Status, NULL, NULL);
  9267. }
  9268. }
  9269. }
  9270. return Status;
  9271. }
  9272. //
  9273. // Local Support Routine
  9274. //
  9275. NTSTATUS
  9276. NtfsCreateUsnJournal (
  9277. IN PIRP_CONTEXT IrpContext,
  9278. IN PIRP Irp
  9279. )
  9280. /*++
  9281. Routine Description:
  9282. This routine creates the Usn journal for the first time, and is a noop
  9283. if Usn journal already exists.
  9284. Arguments:
  9285. IrpContext - context of the call
  9286. Irp - request being serviced
  9287. Return Value:
  9288. NTSTATUS - The return status for the operation
  9289. --*/
  9290. {
  9291. PIO_STACK_LOCATION IrpSp;
  9292. NTSTATUS Status = STATUS_SUCCESS;
  9293. PFILE_OBJECT FileObject;
  9294. TYPE_OF_OPEN TypeOfOpen;
  9295. PVCB Vcb;
  9296. PFCB Fcb;
  9297. PSCB Scb;
  9298. PCCB Ccb;
  9299. CREATE_USN_JOURNAL_DATA CapturedData;
  9300. //
  9301. // Don't post this request, we can't lock the input buffer.
  9302. //
  9303. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9304. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9305. //
  9306. // Get the current Irp stack location and save some references.
  9307. //
  9308. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  9309. //
  9310. // Extract and decode the file object and check for type of open.
  9311. //
  9312. FileObject = IrpSp->FileObject;
  9313. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  9314. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  9315. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  9316. return STATUS_ACCESS_DENIED;
  9317. }
  9318. if (NtfsIsVolumeReadOnly( Vcb )) {
  9319. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  9320. return STATUS_MEDIA_WRITE_PROTECTED;
  9321. }
  9322. if (Vcb->ExtendDirectory == NULL) {
  9323. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  9324. return STATUS_VOLUME_NOT_UPGRADED;
  9325. }
  9326. //
  9327. // Check for a minimum length on the input buffer.
  9328. //
  9329. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( CREATE_USN_JOURNAL_DATA )) {
  9330. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  9331. return STATUS_INVALID_PARAMETER;
  9332. }
  9333. //
  9334. // Do the work, if needed. Acquire the VCB exclusive to lock out creates which
  9335. // have a locking order vis a vis the usn journal / extend directory / mft opposed
  9336. // to this path
  9337. //
  9338. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  9339. try {
  9340. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  9341. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  9342. }
  9343. //
  9344. // Also fail if the journal is currently being deleted.
  9345. //
  9346. if (FlagOn( Vcb->VcbState, VCB_STATE_USN_DELETE )) {
  9347. NtfsRaiseStatus( IrpContext, STATUS_JOURNAL_DELETE_IN_PROGRESS, NULL, NULL );
  9348. }
  9349. //
  9350. // Capture the JournalData from the unsafe user buffer.
  9351. //
  9352. try {
  9353. if (Irp->RequestorMode != KernelMode) {
  9354. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9355. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  9356. NTFS_TYPE_ALIGNMENT( CREATE_USN_JOURNAL_DATA ));
  9357. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9358. CREATE_USN_JOURNAL_DATA )){
  9359. Status = STATUS_INVALID_USER_BUFFER;
  9360. leave;
  9361. }
  9362. CapturedData = *(PCREATE_USN_JOURNAL_DATA)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  9363. } except(EXCEPTION_EXECUTE_HANDLER) {
  9364. NtfsRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER, NULL, NULL);
  9365. }
  9366. //
  9367. // Create or change the Usn Journal parameters.
  9368. //
  9369. NtfsInitializeUsnJournal( IrpContext, Vcb, TRUE, FALSE, &CapturedData );
  9370. } finally {
  9371. NtfsReleaseVcb( IrpContext, Vcb );
  9372. }
  9373. NtfsCompleteRequest( IrpContext, Irp, Status );
  9374. return Status;
  9375. }
  9376. //
  9377. // Local Support Routine
  9378. //
  9379. typedef struct _USN_DATA_CONTEXT {
  9380. USN_RECORD UNALIGNED *UsnRecord;
  9381. ULONG RoomLeft;
  9382. ULONG BytesUsed;
  9383. USN LowUsn;
  9384. USN HighUsn;
  9385. FILE_REFERENCE FileReference;
  9386. } USN_DATA_CONTEXT, *PUSN_DATA_CONTEXT;
  9387. NTSTATUS
  9388. NtfsReadUsnWorker (
  9389. IN PIRP_CONTEXT IrpContext,
  9390. IN PFCB Fcb,
  9391. IN PVOID Context
  9392. )
  9393. /*++
  9394. Routine Description:
  9395. This routine reads the USN data from the file record and returns
  9396. it in the user's buffer.
  9397. Arguments:
  9398. Fcb - Fcb for the file to be processed.
  9399. Context - Pointer to USN_DATA_CONTEXT.
  9400. Return Value:
  9401. STATUS_SUCCESS if a record was successfully stored
  9402. STATUS_BUFFER_OVERFLOW if buffer was not big enough for record
  9403. --*/
  9404. {
  9405. ATTRIBUTE_ENUMERATION_CONTEXT NameContext;
  9406. PUSN_DATA_CONTEXT UsnContext = (PUSN_DATA_CONTEXT) Context;
  9407. PFILE_NAME FileName;
  9408. ULONG RecordLength;
  9409. ULONG FileAttributes;
  9410. NTSTATUS Status = STATUS_SUCCESS;
  9411. BOOLEAN MoreToGo;
  9412. //
  9413. // Find name record; Initialize the context structure.
  9414. //
  9415. try {
  9416. NtfsInitializeAttributeContext( &NameContext );
  9417. //
  9418. // Locate a file name with the FILE_NAME_NTFS bit set
  9419. //
  9420. MoreToGo = NtfsLookupAttributeByCode( IrpContext,
  9421. Fcb,
  9422. &Fcb->FileReference,
  9423. $FILE_NAME,
  9424. &NameContext );
  9425. //
  9426. // While we've found an attribute
  9427. //
  9428. while (MoreToGo) {
  9429. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &NameContext ));
  9430. //
  9431. // See if the NTFS name is set for this name.
  9432. //
  9433. if (FlagOn( FileName->Flags, FILE_NAME_NTFS )) {
  9434. break;
  9435. }
  9436. //
  9437. // The last one wasn't it. Let's try again.
  9438. //
  9439. MoreToGo = NtfsLookupNextAttributeByCode( IrpContext,
  9440. Fcb,
  9441. $FILE_NAME,
  9442. &NameContext );
  9443. }
  9444. if (!MoreToGo) {
  9445. NtfsCleanupAttributeContext( IrpContext, &NameContext );
  9446. NtfsInitializeAttributeContext( &NameContext );
  9447. //
  9448. // Couldn't find an Ntfs name, check for any hard link.
  9449. //
  9450. MoreToGo = NtfsLookupAttributeByCode( IrpContext,
  9451. Fcb,
  9452. &Fcb->FileReference,
  9453. $FILE_NAME,
  9454. &NameContext );
  9455. //
  9456. // While we've found an attribute
  9457. //
  9458. while (MoreToGo) {
  9459. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &NameContext ));
  9460. //
  9461. // See if the DOS name is not set for this name.
  9462. //
  9463. if (!FlagOn( FileName->Flags, FILE_NAME_DOS )) {
  9464. break;
  9465. }
  9466. //
  9467. // The last one wasn't it. Let's try again.
  9468. //
  9469. MoreToGo = NtfsLookupNextAttributeByCode( IrpContext,
  9470. Fcb,
  9471. $FILE_NAME,
  9472. &NameContext );
  9473. }
  9474. if (!MoreToGo) {
  9475. ASSERTMSG( "Couldn't find a name string for file\n", FALSE );
  9476. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  9477. }
  9478. }
  9479. //
  9480. // Check there's enough room for a USN record.
  9481. //
  9482. // Record length is a function of the filename length and the structure the
  9483. // user expects.
  9484. //
  9485. RecordLength = FIELD_OFFSET( USN_RECORD, FileName ) + (FileName->FileNameLength * sizeof( WCHAR ));
  9486. RecordLength = QuadAlign( RecordLength );
  9487. if (RecordLength > UsnContext->RoomLeft) {
  9488. Status = STATUS_BUFFER_TOO_SMALL;
  9489. leave;
  9490. }
  9491. if (Fcb->Usn < UsnContext->LowUsn ||
  9492. Fcb->Usn > UsnContext->HighUsn ) {
  9493. leave;
  9494. }
  9495. //
  9496. // Set up fixed portion of USN record. The following fields are the
  9497. // same for either version.
  9498. //
  9499. UsnContext->UsnRecord->RecordLength = RecordLength;
  9500. UsnContext->UsnRecord->FileReferenceNumber = *(PULONGLONG)&Fcb->FileReference;
  9501. UsnContext->UsnRecord->ParentFileReferenceNumber = *(PULONGLONG)&FileName->ParentDirectory;
  9502. UsnContext->UsnRecord->Usn = Fcb->Usn;
  9503. //
  9504. // Presumably the caller is not interested in the TimeStamp while scanning the Mft,
  9505. // but if he is, then he may need to go read the Usn we are returning.
  9506. //
  9507. UsnContext->UsnRecord->TimeStamp.QuadPart = 0;
  9508. UsnContext->UsnRecord->Reason = 0;
  9509. //
  9510. // Build the FileAttributes from the Fcb.
  9511. //
  9512. FileAttributes = Fcb->Info.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
  9513. //
  9514. // We have to generate the DIRECTORY attribute.
  9515. //
  9516. if (IsDirectory( &Fcb->Info ) || IsViewIndex( &Fcb->Info )) {
  9517. SetFlag( FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
  9518. }
  9519. //
  9520. // If there are no flags set then explicitly set the NORMAL flag.
  9521. //
  9522. if (FileAttributes == 0) {
  9523. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  9524. }
  9525. //
  9526. // Now set the other fields.
  9527. //
  9528. UsnContext->UsnRecord->MajorVersion = 2;
  9529. UsnContext->UsnRecord->MinorVersion = 0;
  9530. UsnContext->UsnRecord->SourceInfo = 0;
  9531. UsnContext->UsnRecord->SecurityId = (ULONG) Fcb->SecurityId;
  9532. UsnContext->UsnRecord->FileAttributes = FileAttributes;
  9533. //
  9534. // Copy file name to Usn record
  9535. //
  9536. UsnContext->UsnRecord->FileNameLength = (USHORT)(FileName->FileNameLength * sizeof( WCHAR ));
  9537. UsnContext->UsnRecord->FileNameOffset = FIELD_OFFSET( USN_RECORD, FileName );
  9538. RtlCopyMemory( &UsnContext->UsnRecord->FileName[0],
  9539. &FileName->FileName[0],
  9540. FileName->FileNameLength * sizeof( WCHAR ));
  9541. //
  9542. // Adjust context for next record
  9543. //
  9544. UsnContext->UsnRecord = (PUSN_RECORD) Add2Ptr( UsnContext->UsnRecord, RecordLength );
  9545. UsnContext->RoomLeft -= RecordLength;
  9546. UsnContext->BytesUsed += RecordLength;
  9547. } finally {
  9548. NtfsCleanupAttributeContext( IrpContext, &NameContext );
  9549. }
  9550. return Status;
  9551. }
  9552. //
  9553. // Local Support Routine
  9554. //
  9555. NTSTATUS
  9556. NtfsReadFileRecordUsnData (
  9557. IN PIRP_CONTEXT IrpContext,
  9558. IN PIRP Irp
  9559. )
  9560. /*++
  9561. Routine Description:
  9562. This routine enumerates base file records beginning at a specified
  9563. one and returns USN data from the found records.
  9564. Arguments:
  9565. IrpContext - context of the call
  9566. Irp - request being serviced
  9567. Return Value:
  9568. NTSTATUS - The return status for the operation
  9569. --*/
  9570. {
  9571. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  9572. NTSTATUS Status = STATUS_SUCCESS;
  9573. USN_DATA_CONTEXT Context;
  9574. MFT_ENUM_DATA UNALIGNED *EnumData = (PMFT_ENUM_DATA) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  9575. BOOLEAN LockedMdl = FALSE;
  9576. PVCB Vcb;
  9577. PFCB Fcb;
  9578. PSCB Scb;
  9579. PCCB Ccb;
  9580. TYPE_OF_OPEN TypeOfOpen;
  9581. //
  9582. // Don't post this request.
  9583. //
  9584. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9585. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9586. //
  9587. // We'll catch dismounted volumes explicitly in iterate mft so don't raise on error
  9588. //
  9589. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  9590. IrpSp->FileObject,
  9591. &Vcb,
  9592. &Fcb,
  9593. &Scb,
  9594. &Ccb,
  9595. FALSE );
  9596. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  9597. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  9598. return STATUS_ACCESS_DENIED;
  9599. }
  9600. //
  9601. // Check for a minimum length on the input and output buffers.
  9602. //
  9603. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MFT_ENUM_DATA )) {
  9604. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  9605. return STATUS_INVALID_PARAMETER;
  9606. }
  9607. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof( FILE_REFERENCE )) {
  9608. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  9609. return STATUS_BUFFER_TOO_SMALL;
  9610. }
  9611. try {
  9612. //
  9613. // Probe the input and output buffers.
  9614. //
  9615. if (Irp->RequestorMode != KernelMode) {
  9616. ProbeForRead( EnumData,
  9617. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  9618. NTFS_TYPE_ALIGNMENT( MFT_ENUM_DATA ));
  9619. ProbeForWrite( Irp->UserBuffer,
  9620. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  9621. NTFS_TYPE_ALIGNMENT( FILE_REFERENCE ));
  9622. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9623. MFT_ENUM_DATA ) ||
  9624. !IsTypeAligned( Irp->UserBuffer, FILE_REFERENCE )) {
  9625. Status = STATUS_INVALID_USER_BUFFER;
  9626. leave;
  9627. }
  9628. //
  9629. // Capture the starting file reference
  9630. //
  9631. Context.FileReference = *(PFILE_REFERENCE) &EnumData->StartFileReferenceNumber;
  9632. if (NtfsFullSegmentNumber( &Context.FileReference ) < FIRST_USER_FILE_NUMBER) {
  9633. NtfsSetSegmentNumber( &Context.FileReference, 0, FIRST_USER_FILE_NUMBER );
  9634. }
  9635. //
  9636. // Set up for filling output records
  9637. //
  9638. Context.RoomLeft = IrpSp->Parameters.FileSystemControl.OutputBufferLength - sizeof( FILE_REFERENCE );
  9639. Context.UsnRecord = (PUSN_RECORD) Add2Ptr( Irp->UserBuffer, sizeof( FILE_REFERENCE ));
  9640. Context.BytesUsed = sizeof( FILE_REFERENCE );
  9641. Context.LowUsn = EnumData->LowUsn;
  9642. Context.HighUsn = EnumData->HighUsn;
  9643. //
  9644. // Iterate through the Mft beginning at the specified file reference
  9645. //
  9646. Status = NtfsIterateMft( IrpContext,
  9647. Vcb,
  9648. &Context.FileReference,
  9649. NtfsReadUsnWorker,
  9650. &Context );
  9651. if ((Status == STATUS_BUFFER_TOO_SMALL) ||
  9652. ((Status == STATUS_END_OF_FILE) && (Context.BytesUsed != sizeof( FILE_REFERENCE )))) {
  9653. Status = STATUS_SUCCESS;
  9654. }
  9655. if (NT_SUCCESS( Status )) {
  9656. //
  9657. // Set the returned file reference number and bytes used. Note: UserBuffer
  9658. // is a raw user mode ptr and must be in a try-except
  9659. //
  9660. Irp->IoStatus.Information = Context.BytesUsed;
  9661. *((PFILE_REFERENCE) Irp->UserBuffer) = Context.FileReference;
  9662. }
  9663. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  9664. NtfsRaiseStatus( IrpContext,
  9665. STATUS_INVALID_USER_BUFFER,
  9666. NULL,
  9667. NULL);
  9668. }
  9669. NtfsCompleteRequest( IrpContext, Irp, Status);
  9670. return Status;
  9671. }
  9672. //
  9673. // Local Support Routine
  9674. //
  9675. typedef struct _SID_MATCH_CONTEXT {
  9676. FILE_NAME_INFORMATION UNALIGNED *FileNames;
  9677. ULONG RoomLeft;
  9678. ULONG BytesUsed;
  9679. ULONG OwnerId;
  9680. FILE_REFERENCE Parent;
  9681. } SID_MATCH_CONTEXT, *PSID_MATCH_CONTEXT;
  9682. NTSTATUS
  9683. NtfsFindBySidWorker (
  9684. IN PIRP_CONTEXT IrpContext,
  9685. IN PFCB Fcb,
  9686. IN PVOID Context
  9687. )
  9688. /*++
  9689. Routine Description:
  9690. This routine finds files owned by a Sid in a given context.
  9691. Arguments:
  9692. Fcb - Fcb for the file to be processed.
  9693. Context - Pointer to SID_MATCH_CONTEXT.
  9694. Return Value:
  9695. STATUS_SUCCESS if file did not match SID or
  9696. matched sid but wasn't in scope or
  9697. matched sid and was in scope and was stored.
  9698. STATUS_BUFFER_OVERFLOW if buffer was not big enough for record
  9699. --*/
  9700. {
  9701. PSID_MATCH_CONTEXT SidContext = (PSID_MATCH_CONTEXT) Context;
  9702. SCOPE_CONTEXT ScopeContext;
  9703. NTSTATUS Status;
  9704. //
  9705. // See if the file is owned by the specified Sid
  9706. //
  9707. if (Fcb->OwnerId != SidContext->OwnerId) {
  9708. return STATUS_SUCCESS;
  9709. }
  9710. //
  9711. // Find name record; Initialize the context structure.
  9712. //
  9713. try {
  9714. //
  9715. // If we're at the root of the scope, then build the name directly
  9716. //
  9717. if (NtfsEqualMftRef( &SidContext->Parent, &Fcb->FileReference )) {
  9718. ScopeContext.Name.Buffer = NtfsAllocatePool(PagedPool, 2 );
  9719. ScopeContext.Name.MaximumLength = ScopeContext.Name.Length = 2;
  9720. ScopeContext.Name.Buffer[0] = '\\';
  9721. Status = STATUS_NO_MORE_FILES;
  9722. //
  9723. // Otherwise, walk up the tree
  9724. //
  9725. } else {
  9726. ScopeContext.IsRoot = NtfsEqualMftRef( &RootIndexFileReference, &SidContext->Parent );
  9727. ScopeContext.Name.Buffer = NULL;
  9728. ScopeContext.Name.Length = 0;
  9729. ScopeContext.Name.MaximumLength = 0;
  9730. ScopeContext.Scope = SidContext->Parent;
  9731. Status = NtfsWalkUpTree( IrpContext, Fcb, NtfsBuildRelativeName, &ScopeContext );
  9732. }
  9733. //
  9734. // If we either received SUCCESS (i.e., walked to root successfully)
  9735. // or NO_MORE_FILES (walked to scope successfully)
  9736. //
  9737. if (Status == STATUS_SUCCESS || Status == STATUS_NO_MORE_FILES) {
  9738. ULONG Length =
  9739. QuadAlign( ScopeContext.Name.Length - sizeof( WCHAR ) +
  9740. sizeof( FILE_NAME_INFORMATION ) - sizeof( WCHAR ));
  9741. //
  9742. // Verify that there is enough room for this file name
  9743. //
  9744. if (Length > SidContext->RoomLeft) {
  9745. Status = STATUS_BUFFER_TOO_SMALL;
  9746. leave;
  9747. }
  9748. //
  9749. // Emit the file name to the caller's buffer
  9750. //
  9751. SidContext->FileNames->FileNameLength = ScopeContext.Name.Length - sizeof( WCHAR );
  9752. RtlCopyMemory( SidContext->FileNames->FileName,
  9753. ScopeContext.Name.Buffer + 1,
  9754. ScopeContext.Name.Length - sizeof( WCHAR ));
  9755. //
  9756. // Adjust for next name
  9757. //
  9758. SidContext->BytesUsed += Length;
  9759. SidContext->RoomLeft -= Length;
  9760. SidContext->FileNames = (PFILE_NAME_INFORMATION) Add2Ptr( SidContext->FileNames, Length );
  9761. }
  9762. Status = STATUS_SUCCESS;
  9763. } finally {
  9764. if (ScopeContext.Name.Buffer != NULL) {
  9765. NtfsFreePool( ScopeContext.Name.Buffer );
  9766. }
  9767. }
  9768. return Status;
  9769. }
  9770. //
  9771. // Local Support Routine
  9772. //
  9773. NTSTATUS
  9774. NtfsFindFilesOwnedBySid (
  9775. IN PIRP_CONTEXT IrpContext,
  9776. IN PIRP Irp
  9777. )
  9778. /*++
  9779. Routine Description:
  9780. This routine enumerates file records, finds entries owned by a
  9781. specified Sid and returns the path relative to the called-on Fcb
  9782. of the found file.
  9783. We hide the details of this Mft-based scan by encapsulating this
  9784. a find-first/next structure.
  9785. Arguments:
  9786. IrpContext - context of the call. The input buffer contains a ULONG
  9787. followed by a SID:
  9788. 0 = continue enumeration
  9789. 1 = start enumeration
  9790. Irp - request being serviced
  9791. Return Value:
  9792. NTSTATUS - The return status for the operation
  9793. --*/
  9794. {
  9795. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  9796. FILE_REFERENCE FileReference;
  9797. NTSTATUS Status = STATUS_SUCCESS;
  9798. SID_MATCH_CONTEXT Context;
  9799. PFIND_BY_SID_DATA FindData =
  9800. (PFIND_BY_SID_DATA)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  9801. PFIND_BY_SID_DATA CapturedFindData = NULL;
  9802. TYPE_OF_OPEN TypeOfOpen;
  9803. PVCB Vcb;
  9804. PFCB Fcb;
  9805. PSCB Scb;
  9806. PCCB Ccb;
  9807. BOOLEAN ReleaseVcb = FALSE;
  9808. PAGED_CODE();
  9809. //
  9810. // Don't post this request, we can't lock both input and output buffers.
  9811. //
  9812. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9813. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9814. //
  9815. // Decode the file object, fail this request if not a user data stream.
  9816. //
  9817. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  9818. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  9819. &Vcb,
  9820. &Fcb,
  9821. &Scb,
  9822. &Ccb,
  9823. TRUE );
  9824. if (TypeOfOpen != UserDirectoryOpen || Ccb == NULL) {
  9825. Status = STATUS_INVALID_PARAMETER;
  9826. NtfsCompleteRequest( IrpContext, Irp, Status );
  9827. return Status;
  9828. }
  9829. try {
  9830. try {
  9831. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  9832. ReleaseVcb = TRUE;
  9833. if (Irp->RequestorMode != KernelMode) {
  9834. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9835. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  9836. NTFS_TYPE_ALIGNMENT( FIND_BY_SID_DATA ));
  9837. ProbeForWrite( Irp->UserBuffer,
  9838. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  9839. NTFS_TYPE_ALIGNMENT( FILE_NAME_INFORMATION ));
  9840. }
  9841. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  9842. Status = STATUS_VOLUME_DISMOUNTED;
  9843. leave;
  9844. }
  9845. if (Vcb->OwnerIdTableScb == NULL) {
  9846. Status = STATUS_VOLUME_NOT_UPGRADED;
  9847. leave;
  9848. }
  9849. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( ULONG )) {
  9850. Status = STATUS_INVALID_USER_BUFFER;
  9851. leave;
  9852. }
  9853. //
  9854. // Allocate a buffer to capture the input buffer.
  9855. //
  9856. CapturedFindData = NtfsAllocatePool( PagedPool,
  9857. IrpSp->Parameters.FileSystemControl.InputBufferLength );
  9858. RtlCopyMemory( CapturedFindData,
  9859. FindData,
  9860. IrpSp->Parameters.FileSystemControl.InputBufferLength );
  9861. //
  9862. // Do some final checks on the input and output buffers.
  9863. //
  9864. if (
  9865. //
  9866. // The input and output buffers must be aligned
  9867. //
  9868. !IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9869. FIND_BY_SID_DATA )
  9870. DebugDoit( && DebugPrint(( "Input buffer not long aligned" ))) ||
  9871. !IsTypeAligned( Irp->UserBuffer, FILE_NAME_INFORMATION )
  9872. DebugDoit( && DebugPrint(( "Output buffer not long aligned" ))) ||
  9873. //
  9874. // There must be enough room in the output buffer.
  9875. // (Input buffer is already verified).
  9876. //
  9877. IrpSp->Parameters.FileSystemControl.OutputBufferLength <
  9878. sizeof( FILE_NAME_INFORMATION )
  9879. DebugDoit( && DebugPrint(( "Output buffer shorter than FILE_NAME_INFORMATION" ))) ||
  9880. //
  9881. // The input flag must be 0 or 1
  9882. //
  9883. CapturedFindData->Restart > 1
  9884. DebugDoit( && DebugPrint(( "Restart not 0/1" ))) ||
  9885. //
  9886. // There must be enough room for a SID in the input
  9887. //
  9888. sizeof( ULONG ) + RtlLengthSid( &FindData->Sid ) >
  9889. IrpSp->Parameters.FileSystemControl.InputBufferLength
  9890. DebugDoit( && DebugPrint(( "Not enough room for input SID" ))) ||
  9891. //
  9892. // Also verify the captured data in case our caller is playing games.
  9893. //
  9894. sizeof( ULONG ) + RtlLengthSid( &CapturedFindData->Sid ) >
  9895. IrpSp->Parameters.FileSystemControl.InputBufferLength
  9896. DebugDoit( && DebugPrint(( "Not enough room for captured input SID" )))
  9897. ) {
  9898. Status = STATUS_INVALID_USER_BUFFER;
  9899. leave;
  9900. }
  9901. //
  9902. // Set up starting file reference either from where the user left off
  9903. // or from the next position
  9904. //
  9905. if (CapturedFindData->Restart) {
  9906. NtfsSetSegmentNumber( &FileReference, 0, ROOT_FILE_NAME_INDEX_NUMBER );
  9907. } else {
  9908. ASSERT( Ccb->NodeByteSize == sizeof( CCB ) );
  9909. FileReference = Ccb->MftScanFileReference;
  9910. if (NtfsSegmentNumber( &FileReference ) < ROOT_FILE_NAME_INDEX_NUMBER) {
  9911. NtfsSetSegmentNumber( &FileReference, 0, ROOT_FILE_NAME_INDEX_NUMBER );
  9912. }
  9913. }
  9914. //
  9915. // Set up for filling output records
  9916. //
  9917. Context.RoomLeft = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  9918. Context.FileNames = (PFILE_NAME_INFORMATION) Irp->UserBuffer;
  9919. Context.BytesUsed = 0;
  9920. //
  9921. // Convert input Sid into OWNER_ID. If we haven't seen this SID before
  9922. // then we are done! We use the copy of the Sid so we don't take an access
  9923. // violation in the user frees the memory. Some of our internal routines
  9924. // never expect a failure touching this buffer.
  9925. //
  9926. Context.OwnerId = NtfsGetOwnerId( IrpContext, &CapturedFindData->Sid, FALSE, NULL );
  9927. if (Context.OwnerId == QUOTA_INVALID_ID) {
  9928. Status = STATUS_SUCCESS;
  9929. leave;
  9930. }
  9931. Context.Parent = Fcb->FileReference;
  9932. //
  9933. // Iterate through the Mft beginning at the specified file reference.
  9934. // Release the Vcb now because the worker routine will acquire and
  9935. // drop as necessary. We don't want to block out critical operations
  9936. // like clean checkpoints during a full Mft scan.
  9937. //
  9938. NtfsReleaseVcb( IrpContext, Vcb );
  9939. ReleaseVcb = FALSE;
  9940. Status = NtfsIterateMft( IrpContext,
  9941. Vcb,
  9942. &FileReference,
  9943. NtfsFindBySidWorker,
  9944. &Context );
  9945. //
  9946. // If we failed due to running out of space and we stored something or
  9947. // if we ran off the end of the MFT, then this is really a successful
  9948. // return.
  9949. //
  9950. Irp->IoStatus.Information = Context.BytesUsed;
  9951. if (!NT_SUCCESS( Status )) {
  9952. if ((Status == STATUS_BUFFER_TOO_SMALL && Context.BytesUsed != 0)
  9953. || Status == STATUS_END_OF_FILE) {
  9954. Status = STATUS_SUCCESS;
  9955. } else {
  9956. leave;
  9957. }
  9958. }
  9959. Ccb->MftScanFileReference = FileReference;
  9960. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  9961. NtfsRaiseStatus( IrpContext,
  9962. STATUS_INVALID_USER_BUFFER,
  9963. NULL,
  9964. NULL);
  9965. }
  9966. } finally {
  9967. //
  9968. // Free the Vcb if still held.
  9969. //
  9970. if (ReleaseVcb) {
  9971. NtfsReleaseVcb( IrpContext, Vcb );
  9972. }
  9973. //
  9974. // Free the captured input buffer if allocated.
  9975. //
  9976. if (CapturedFindData != NULL) {
  9977. NtfsFreePool( CapturedFindData );
  9978. }
  9979. }
  9980. //
  9981. // If nothing raised then complete the irp.
  9982. //
  9983. NtfsCompleteRequest( IrpContext, Irp, Status );
  9984. return Status;
  9985. }
  9986. //
  9987. // Local Support Routine
  9988. //
  9989. NTSTATUS
  9990. NtfsReadFileUsnData (
  9991. IN PIRP_CONTEXT IrpContext,
  9992. IN PIRP Irp
  9993. )
  9994. /*++
  9995. Routine Description:
  9996. This routine enumerates base file records beginning at a specified
  9997. one and returns USN data from the found records.
  9998. Arguments:
  9999. IrpContext - context of the call
  10000. Irp - request being serviced
  10001. RecordVersion - format for the usn record to return
  10002. Return Value:
  10003. NTSTATUS - The return status for the operation
  10004. --*/
  10005. {
  10006. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10007. NTSTATUS Status = STATUS_SUCCESS;
  10008. USN_DATA_CONTEXT Context;
  10009. PFILE_OBJECT FileObject;
  10010. TYPE_OF_OPEN TypeOfOpen;
  10011. PVCB Vcb;
  10012. PFCB Fcb;
  10013. PSCB Scb;
  10014. PCCB Ccb;
  10015. //
  10016. // Don't post this request.
  10017. //
  10018. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10019. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10020. //
  10021. // Get the current Irp stack location and save some references.
  10022. //
  10023. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  10024. //
  10025. // Extract and decode the file object and check for type of open.
  10026. // We don't want to raise on dismounts here because we check for that further down
  10027. // anyway. So send FALSE.
  10028. //
  10029. FileObject = IrpSp->FileObject;
  10030. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  10031. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  10032. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10033. return STATUS_INVALID_PARAMETER;
  10034. }
  10035. //
  10036. // Check that the user's buffer is large enough.
  10037. //
  10038. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof( USN_RECORD )) {
  10039. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  10040. return STATUS_BUFFER_TOO_SMALL;
  10041. }
  10042. //
  10043. // Set up for filling output records
  10044. //
  10045. Context.RoomLeft = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  10046. Context.UsnRecord = Irp->UserBuffer;
  10047. Context.BytesUsed = 0;
  10048. Context.LowUsn = 0;
  10049. Context.HighUsn = MAXLONGLONG;
  10050. NtfsAcquireSharedScb( IrpContext, Scb );
  10051. try {
  10052. //
  10053. // Verify the volume is mounted.
  10054. //
  10055. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10056. Status = STATUS_VOLUME_DISMOUNTED;
  10057. leave;
  10058. }
  10059. //
  10060. // Careful access to the user's buffer.
  10061. //
  10062. try {
  10063. //
  10064. // Probe the output buffer.
  10065. //
  10066. if (Irp->RequestorMode != KernelMode) {
  10067. ProbeForWrite( Irp->UserBuffer,
  10068. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  10069. NTFS_TYPE_ALIGNMENT( USN_DATA_CONTEXT ));
  10070. } else if (!IsTypeAligned( Irp->UserBuffer, USN_DATA_CONTEXT )) {
  10071. Status = STATUS_INVALID_USER_BUFFER;
  10072. leave;
  10073. }
  10074. //
  10075. // Now read the Usn data.
  10076. //
  10077. Status = NtfsReadUsnWorker( IrpContext, Fcb, &Context );
  10078. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  10079. NtfsRaiseStatus( IrpContext,
  10080. STATUS_INVALID_USER_BUFFER,
  10081. NULL,
  10082. NULL );
  10083. }
  10084. } finally {
  10085. NtfsReleaseScb( IrpContext, Scb );
  10086. }
  10087. //
  10088. // On success return bytes in Usn Record.
  10089. //
  10090. if (NT_SUCCESS(Status)) {
  10091. Irp->IoStatus.Information = Context.BytesUsed;
  10092. }
  10093. NtfsCompleteRequest( IrpContext, Irp, Status);
  10094. return Status;
  10095. }
  10096. //
  10097. // Local Support Routine
  10098. //
  10099. NTSTATUS
  10100. NtfsWriteUsnCloseRecord (
  10101. IN PIRP_CONTEXT IrpContext,
  10102. IN PIRP Irp
  10103. )
  10104. /*++
  10105. Routine Description:
  10106. This routine writes a close Usn record for the current file, and returns
  10107. its Usn.
  10108. Arguments:
  10109. IrpContext - context of the call
  10110. Irp - request being serviced
  10111. Return Value:
  10112. NTSTATUS - The return status for the operation
  10113. --*/
  10114. {
  10115. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10116. NTSTATUS Status = STATUS_SUCCESS;
  10117. PFILE_OBJECT FileObject;
  10118. TYPE_OF_OPEN TypeOfOpen;
  10119. PVCB Vcb;
  10120. PFCB Fcb;
  10121. PSCB Scb;
  10122. PCCB Ccb;
  10123. PVOID UserBuffer;
  10124. BOOLEAN AccessingUserBuffer = FALSE;
  10125. //
  10126. // Go ahead and make this operation synchronous.
  10127. //
  10128. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10129. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10130. //
  10131. // Get the current Irp stack location and save some references.
  10132. //
  10133. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  10134. //
  10135. // Extract and decode the file object and check for type of open.
  10136. // We check for dismount further below, so send FALSE to not raise here.
  10137. //
  10138. FileObject = IrpSp->FileObject;
  10139. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  10140. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  10141. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10142. return STATUS_INVALID_PARAMETER;
  10143. }
  10144. if (NtfsIsVolumeReadOnly( Vcb )) {
  10145. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  10146. return STATUS_MEDIA_WRITE_PROTECTED;
  10147. }
  10148. //
  10149. // There must be room in the output buffer.
  10150. //
  10151. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(USN)) {
  10152. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10153. return STATUS_INVALID_PARAMETER;
  10154. }
  10155. UserBuffer = NtfsMapUserBuffer( Irp );
  10156. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10157. try {
  10158. //
  10159. // Verify the volume is mounted.
  10160. //
  10161. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10162. Status = STATUS_VOLUME_DISMOUNTED;
  10163. leave;
  10164. }
  10165. //
  10166. // Fail this request if the journal is being deleted or is not running.
  10167. //
  10168. if (FlagOn( Vcb->VcbState, VCB_STATE_USN_DELETE )) {
  10169. Status = STATUS_JOURNAL_DELETE_IN_PROGRESS;
  10170. leave;
  10171. }
  10172. if (!FlagOn( Vcb->VcbState, VCB_STATE_USN_JOURNAL_ACTIVE )) {
  10173. Status = STATUS_JOURNAL_NOT_ACTIVE;
  10174. leave;
  10175. }
  10176. //
  10177. // Use a try-except to check our access to the user buffer.
  10178. //
  10179. try {
  10180. //
  10181. // Probe the output buffer.
  10182. //
  10183. if (Irp->RequestorMode != KernelMode) {
  10184. AccessingUserBuffer = TRUE;
  10185. ProbeForWrite( Irp->UserBuffer,
  10186. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  10187. NTFS_TYPE_ALIGNMENT( USN ));
  10188. AccessingUserBuffer = FALSE;
  10189. } else if (!IsTypeAligned( Irp->UserBuffer, USN )) {
  10190. Status = STATUS_INVALID_USER_BUFFER;
  10191. leave;
  10192. }
  10193. //
  10194. // Now write the close record.
  10195. //
  10196. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_CLOSE );
  10197. //
  10198. // Now, if anything at all is posted to the Usn Journal, we must write it now
  10199. // so that we do not get a log file full later.
  10200. //
  10201. ASSERT( IrpContext->Usn.NextUsnFcb == NULL );
  10202. if (IrpContext->Usn.CurrentUsnFcb != NULL) {
  10203. //
  10204. // Now write the journal, checkpoint the transaction, and free the UsnJournal to
  10205. // reduce contention.
  10206. //
  10207. NtfsWriteUsnJournalChanges( IrpContext );
  10208. NtfsCheckpointCurrentTransaction( IrpContext );
  10209. }
  10210. //
  10211. // Set the returned Usn.
  10212. //
  10213. AccessingUserBuffer = TRUE;
  10214. *(USN *)UserBuffer = Fcb->Usn;
  10215. AccessingUserBuffer = FALSE;
  10216. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  10217. NtfsRaiseStatus( IrpContext,
  10218. STATUS_INVALID_USER_BUFFER,
  10219. NULL,
  10220. NULL );
  10221. }
  10222. } finally {
  10223. NtfsReleaseScb( IrpContext, Scb );
  10224. }
  10225. //
  10226. // On success return bytes in Usn Record.
  10227. //
  10228. if (NT_SUCCESS(Status)) {
  10229. Irp->IoStatus.Information = sizeof(USN);
  10230. }
  10231. NtfsCompleteRequest( IrpContext, Irp, Status );
  10232. return Status;
  10233. }
  10234. //
  10235. // Local Support Routine
  10236. //
  10237. NTSTATUS
  10238. NtfsBulkSecurityIdCheck (
  10239. IN PIRP_CONTEXT IrpContext,
  10240. IN PIRP Irp
  10241. )
  10242. /*++
  10243. Routine Description:
  10244. This routine performs a check to see if the current subject is granted access by
  10245. the security descriptors identified by the security Ids.
  10246. Arguments:
  10247. IrpContext - context of the call
  10248. Irp - request being serviced
  10249. Return Value:
  10250. NTSTATUS - The return status for the operation
  10251. --*/
  10252. {
  10253. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10254. NTSTATUS Status = STATUS_SUCCESS;
  10255. PBULK_SECURITY_TEST_DATA SecurityData =
  10256. (PBULK_SECURITY_TEST_DATA) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  10257. PNTSTATUS OutputStatus = (PNTSTATUS) Irp->UserBuffer;
  10258. ACCESS_MASK DesiredAccess;
  10259. BOOLEAN AccessGranted;
  10260. ACCESS_MASK GrantedAccess;
  10261. ULONG i, SecurityIdCount;
  10262. SECURITY_SUBJECT_CONTEXT SecurityContext;
  10263. TYPE_OF_OPEN TypeOfOpen;
  10264. PVCB Vcb;
  10265. PFCB Fcb;
  10266. PSCB Scb;
  10267. PCCB Ccb;
  10268. ASSERT_IRP_CONTEXT( IrpContext );
  10269. ASSERT_IRP( Irp );
  10270. PAGED_CODE();
  10271. DebugTrace( +1, Dbg, ("NtfsBulkSecurityIdCheck...\n") );
  10272. //
  10273. // Don't post this request, we can't lock both input and output buffers.
  10274. //
  10275. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10276. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10277. //
  10278. // Verify this is a valid type of open.
  10279. //
  10280. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  10281. IrpSp->FileObject,
  10282. &Vcb,
  10283. &Fcb,
  10284. &Scb,
  10285. &Ccb,
  10286. TRUE );
  10287. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  10288. Status = STATUS_ACCESS_DENIED;
  10289. DebugTrace( -1, Dbg, ("NtfsBulkSecurityIdCheck -> %08lx\n", Status) );
  10290. NtfsCompleteRequest( IrpContext, Irp, Status );
  10291. return Status;
  10292. }
  10293. try {
  10294. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  10295. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  10296. Status = STATUS_VOLUME_DISMOUNTED;
  10297. leave;
  10298. }
  10299. try {
  10300. if (Irp->RequestorMode != KernelMode) {
  10301. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10302. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  10303. NTFS_TYPE_ALIGNMENT( BULK_SECURITY_TEST_DATA ));
  10304. ProbeForWrite( Irp->UserBuffer,
  10305. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  10306. sizeof(ULONG));
  10307. }
  10308. SecurityIdCount =
  10309. (IrpSp->Parameters.FileSystemControl.InputBufferLength
  10310. - FIELD_OFFSET( BULK_SECURITY_TEST_DATA, SecurityIds )) / sizeof( SECURITY_ID );
  10311. if (
  10312. //
  10313. // The input and output buffers must be aligned
  10314. //
  10315. !IsTypeAligned( SecurityData, BULK_SECURITY_TEST_DATA )
  10316. || !IsLongAligned( OutputStatus )
  10317. //
  10318. // The output buffer must contain the same number of NTSTATUS
  10319. // as SECURITY_IDs
  10320. //
  10321. || SecurityIdCount * sizeof( NTSTATUS ) !=
  10322. IrpSp->Parameters.FileSystemControl.OutputBufferLength
  10323. ) {
  10324. NtfsRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER, NULL, NULL );
  10325. }
  10326. //
  10327. // Capture the desired access so we can modify it
  10328. //
  10329. DesiredAccess = SecurityData->DesiredAccess;
  10330. RtlMapGenericMask( &DesiredAccess, IoGetFileObjectGenericMapping() );
  10331. SeCaptureSubjectContext( &SecurityContext );
  10332. SeLockSubjectContext( &SecurityContext );
  10333. try {
  10334. for (i = 0; i < SecurityIdCount; i++) {
  10335. PSHARED_SECURITY SharedSecurity;
  10336. SharedSecurity = NtfsCacheSharedSecurityBySecurityId( IrpContext,
  10337. Vcb,
  10338. SecurityData->SecurityIds[i] );
  10339. //
  10340. // Do the access check
  10341. //
  10342. AccessGranted = SeAccessCheck( SharedSecurity->SecurityDescriptor,
  10343. &SecurityContext,
  10344. TRUE, // Tokens are locked
  10345. DesiredAccess,
  10346. 0,
  10347. NULL,
  10348. IoGetFileObjectGenericMapping(),
  10349. (KPROCESSOR_MODE)(FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ?
  10350. UserMode :
  10351. Irp->RequestorMode),
  10352. &GrantedAccess,
  10353. &OutputStatus[i] );
  10354. NtfsAcquireFcbSecurity( Vcb );
  10355. RemoveReferenceSharedSecurityUnsafe( &SharedSecurity );
  10356. NtfsReleaseFcbSecurity( Vcb );
  10357. }
  10358. } finally {
  10359. SeUnlockSubjectContext( &SecurityContext );
  10360. SeReleaseSubjectContext( &SecurityContext );
  10361. }
  10362. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  10363. NtfsRaiseStatus( IrpContext,
  10364. STATUS_INVALID_USER_BUFFER,
  10365. NULL,
  10366. NULL );
  10367. }
  10368. } finally {
  10369. NtfsReleaseVcb( IrpContext, Vcb );
  10370. }
  10371. NtfsCompleteRequest( IrpContext, Irp, Status);
  10372. return Status;
  10373. }
  10374. //
  10375. // Local support routine.
  10376. //
  10377. NTSTATUS
  10378. NtfsQueryAllocatedRanges (
  10379. IN PIRP_CONTEXT IrpContext,
  10380. IN PIRP Irp
  10381. )
  10382. /*++
  10383. Routine Description:
  10384. This routines scans the allocation of the file looking for allocated ranges
  10385. starting from some offset given by our caller. An allocated range is one
  10386. which either has any allocation within the defined sparse block size (64K) or
  10387. has any clusters reserved within this same block. Sparse file support is meant
  10388. to optimize the case where the user has a large unallocated range. We will
  10389. force him to read zeroes from the file where the deallocated ranges are
  10390. smaller than 64K.
  10391. If the file is not marked as sparse then we will return the entire file as
  10392. allocated even for the compressed stream case where large blocks of
  10393. zeroes are represented by holes.
  10394. The Irp contains the input and output buffers for this request. This fsctrl
  10395. specifies METHOD_NEITHER so we must carefully access these buffers.
  10396. Arguments:
  10397. Irp - Request being serviced
  10398. Return Value:
  10399. NTSTATUS - The return status for the operation
  10400. --*/
  10401. {
  10402. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10403. NTSTATUS Status = STATUS_SUCCESS;
  10404. BOOLEAN AcquiredScb = FALSE;
  10405. PVCB Vcb;
  10406. PFCB Fcb;
  10407. PSCB Scb;
  10408. PCCB Ccb;
  10409. BOOLEAN AccessingUserBuffer = FALSE;
  10410. BOOLEAN Allocated;
  10411. ULONG RemainingBytes;
  10412. LONGLONG StartingOffset;
  10413. LONGLONG Length;
  10414. PFILE_ALLOCATED_RANGE_BUFFER OutputBuffer;
  10415. PFILE_ALLOCATED_RANGE_BUFFER CurrentBuffer;
  10416. VCN NextVcn;
  10417. VCN CurrentVcn;
  10418. LONGLONG RemainingClusters;
  10419. LONGLONG ThisClusterCount;
  10420. LONGLONG TwoGigInClusters;
  10421. BOOLEAN UserMappedView;
  10422. ASSERT_IRP_CONTEXT( IrpContext );
  10423. ASSERT_IRP( Irp );
  10424. PAGED_CODE();
  10425. Irp->IoStatus.Information = 0;
  10426. //
  10427. // Don't post this request, we can't lock both input and output buffers.
  10428. //
  10429. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10430. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10431. //
  10432. // Extract and decode the file object.
  10433. // We only allow this operation on user data files.
  10434. // We check for dismount further below, so send FALSE to not raise here.
  10435. //
  10436. if (NtfsDecodeFileObject( IrpContext,
  10437. IrpSp->FileObject,
  10438. &Vcb,
  10439. &Fcb,
  10440. &Scb,
  10441. &Ccb,
  10442. FALSE ) != UserFileOpen) {
  10443. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10444. return STATUS_INVALID_PARAMETER;
  10445. }
  10446. //
  10447. // Acquired exclusive access to the paging Io resource because we might
  10448. // need to extend the file when flushing the cache
  10449. //
  10450. NtfsAcquireExclusivePagingIo( IrpContext, Scb->Fcb );
  10451. //
  10452. // Use a try-finally to facilitate cleanup.
  10453. //
  10454. try {
  10455. //
  10456. // If the volume isn't mounted then fail immediately.
  10457. //
  10458. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10459. Status = STATUS_VOLUME_DISMOUNTED;
  10460. leave;
  10461. }
  10462. //
  10463. // Check the length of the input buffer.
  10464. //
  10465. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  10466. Status = STATUS_INVALID_PARAMETER;
  10467. leave;
  10468. }
  10469. //
  10470. // Use a try-except to catch any errors accessing the user's buffers.
  10471. // We will maintain a boolean which indicates if we are accessing
  10472. // the user's buffer.
  10473. //
  10474. AccessingUserBuffer = TRUE;
  10475. try {
  10476. //
  10477. // If our caller is not kernel mode then probe the input and
  10478. // output buffers.
  10479. //
  10480. RemainingBytes = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  10481. OutputBuffer = (PFILE_ALLOCATED_RANGE_BUFFER) NtfsMapUserBuffer( Irp );
  10482. CurrentBuffer = OutputBuffer - 1;
  10483. if (Irp->RequestorMode != KernelMode) {
  10484. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10485. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  10486. NTFS_TYPE_ALIGNMENT( FILE_ALLOCATED_RANGE_BUFFER ));
  10487. ProbeForWrite( OutputBuffer,
  10488. RemainingBytes,
  10489. NTFS_TYPE_ALIGNMENT( FILE_ALLOCATED_RANGE_BUFFER ));
  10490. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10491. FILE_ALLOCATED_RANGE_BUFFER ) ||
  10492. !IsTypeAligned( OutputBuffer, FILE_ALLOCATED_RANGE_BUFFER )) {
  10493. Status = STATUS_INVALID_USER_BUFFER;
  10494. leave;
  10495. }
  10496. //
  10497. // Carefully extract the starting offset and length from
  10498. // the input buffer. If we are beyond the end of the file
  10499. // or the length is zero then return immediately. Otherwise
  10500. // trim the length to file size.
  10501. //
  10502. StartingOffset = ((PFILE_ALLOCATED_RANGE_BUFFER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->FileOffset.QuadPart;
  10503. Length = ((PFILE_ALLOCATED_RANGE_BUFFER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->Length.QuadPart;
  10504. AccessingUserBuffer = FALSE;
  10505. //
  10506. // Check that the input parameters are valid.
  10507. //
  10508. if ((Length < 0) ||
  10509. (StartingOffset < 0) ||
  10510. (Length > MAXLONGLONG - StartingOffset)) {
  10511. Status = STATUS_INVALID_PARAMETER;
  10512. leave;
  10513. }
  10514. //
  10515. // Check that the requested range is within file size
  10516. // and has a non-zero length.
  10517. //
  10518. if (Length == 0) {
  10519. leave;
  10520. }
  10521. //
  10522. // Lets acquire the Scb for the file as well.
  10523. //
  10524. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10525. AcquiredScb = TRUE;
  10526. NtfsAcquireFsrtlHeader( Scb );
  10527. if (StartingOffset >= Scb->Header.FileSize.QuadPart) {
  10528. NtfsReleaseFsrtlHeader( Scb );
  10529. leave;
  10530. }
  10531. if (Scb->Header.FileSize.QuadPart - StartingOffset < Length) {
  10532. Length = Scb->Header.FileSize.QuadPart - StartingOffset;
  10533. }
  10534. NtfsReleaseFsrtlHeader( Scb );
  10535. //
  10536. // If the file is not sparse or is resident then show that
  10537. // the entire requested range is allocated.
  10538. //
  10539. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE ) ||
  10540. FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  10541. if (RemainingBytes < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  10542. Status = STATUS_BUFFER_TOO_SMALL;
  10543. } else {
  10544. CurrentBuffer += 1;
  10545. AccessingUserBuffer = TRUE;
  10546. CurrentBuffer->FileOffset.QuadPart = StartingOffset;
  10547. CurrentBuffer->Length.QuadPart = Length;
  10548. Irp->IoStatus.Information = sizeof( FILE_ALLOCATED_RANGE_BUFFER );
  10549. }
  10550. leave;
  10551. }
  10552. //
  10553. // Convert the range to check to Vcns so we can use the
  10554. // allocation routines.
  10555. //
  10556. NextVcn = -1;
  10557. CurrentVcn = LlClustersFromBytesTruncate( Vcb, StartingOffset );
  10558. ((PLARGE_INTEGER) &CurrentVcn)->LowPart &= ~(Vcb->SparseFileClusters - 1);
  10559. RemainingClusters = LlClustersFromBytesTruncate( Vcb,
  10560. StartingOffset + Length + Vcb->SparseFileUnit - 1 );
  10561. ((PLARGE_INTEGER) &RemainingClusters)->LowPart &= ~(Vcb->SparseFileClusters - 1);
  10562. RemainingClusters -= CurrentVcn;
  10563. TwoGigInClusters = LlClustersFromBytesTruncate( Vcb, (LONGLONG) 0x80000000 );
  10564. //
  10565. // We will walk through the file in two gigabyte chunks.
  10566. //
  10567. do {
  10568. //
  10569. // We will try to swallow two gig at a time.
  10570. //
  10571. ThisClusterCount = TwoGigInClusters;
  10572. if (ThisClusterCount > RemainingClusters) {
  10573. ThisClusterCount = RemainingClusters;
  10574. }
  10575. RemainingClusters -= ThisClusterCount;
  10576. //
  10577. // Preload two gigabytes of allocation information at our Current Vcn.
  10578. //
  10579. NtfsPreloadAllocation( IrpContext,
  10580. Scb,
  10581. CurrentVcn,
  10582. CurrentVcn + ThisClusterCount );
  10583. //
  10584. // If the file is mapped then flush the data so we can simply
  10585. // trust the Mcb. There is a performance cost here but otherwise
  10586. // we would be returning the entire file as allocated.
  10587. //
  10588. if (FlagOn( Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE ) &&
  10589. FlagOn( Scb->ScbState, SCB_STATE_WRITE_ACCESS_SEEN ) &&
  10590. (Scb->NonpagedScb->SegmentObject.DataSectionObject != NULL)) {
  10591. LONGLONG CheckClusterCount;
  10592. LONGLONG RemainingCheckClusterCount = ThisClusterCount;
  10593. LONGLONG FlushOffset;
  10594. VCN CheckVcn = CurrentVcn;
  10595. BOOLEAN ReloadAllocation = FALSE;
  10596. PRESERVED_BITMAP_RANGE BitMap = Scb->ScbType.Data.ReservedBitMap;
  10597. ASSERT( Scb->Header.NodeTypeCode == NTFS_NTC_SCB_DATA );
  10598. while (TRUE) {
  10599. //
  10600. // Check to see if this range is allocated.
  10601. //
  10602. Allocated = NtfsIsRangeAllocated( Scb,
  10603. CheckVcn,
  10604. CheckVcn + RemainingCheckClusterCount,
  10605. TRUE,
  10606. &CheckClusterCount );
  10607. if (!Allocated) {
  10608. if (Scb->FileObject == NULL) {
  10609. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  10610. }
  10611. NtfsReleaseScb( IrpContext, Scb );
  10612. AcquiredScb = FALSE;
  10613. FlushOffset = LlBytesFromClusters( Vcb, CheckVcn );
  10614. CcFlushCache( &Scb->NonpagedScb->SegmentObject,
  10615. (PLARGE_INTEGER) &FlushOffset,
  10616. (ULONG) LlBytesFromClusters( Vcb, CheckClusterCount ),
  10617. &Irp->IoStatus );
  10618. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10619. AcquiredScb = TRUE;
  10620. //
  10621. // On error get out.
  10622. //
  10623. NtfsNormalizeAndCleanupTransaction( IrpContext,
  10624. &Irp->IoStatus.Status,
  10625. TRUE,
  10626. STATUS_UNEXPECTED_IO_ERROR );
  10627. ReloadAllocation = TRUE;
  10628. }
  10629. if (RemainingCheckClusterCount <= CheckClusterCount) {
  10630. break;
  10631. }
  10632. RemainingCheckClusterCount -= CheckClusterCount;
  10633. CheckVcn += CheckClusterCount;
  10634. }
  10635. //
  10636. // Reload two gigabytes of allocation information at our Current Vcn.
  10637. //
  10638. if (ReloadAllocation) {
  10639. NtfsPreloadAllocation( IrpContext,
  10640. Scb,
  10641. CurrentVcn,
  10642. CurrentVcn + ThisClusterCount );
  10643. }
  10644. }
  10645. //
  10646. // Loop while we have more clusters to look for. We will load
  10647. // two gigabytes of allocation at a time into the Mcb.
  10648. //
  10649. UserMappedView = !(MmCanFileBeTruncated( &(Scb->NonpagedScb->SegmentObject), NULL ));
  10650. do {
  10651. LONGLONG CurrentClusterCount;
  10652. //
  10653. // Check to see if this range is allocated.
  10654. //
  10655. Allocated = NtfsIsRangeAllocated( Scb,
  10656. CurrentVcn,
  10657. CurrentVcn + ThisClusterCount,
  10658. TRUE,
  10659. &CurrentClusterCount );
  10660. //
  10661. // If we have an unallocated range then we need to trim it by any
  10662. // sparse units which have reservation. This is possible if it we haven't flushed because
  10663. // its never been mapped or its still being user mapped so our flush is unreliable.
  10664. // If the first unit has reservation then change the state of the range to 'Allocated'.
  10665. //
  10666. if ((UserMappedView || !FlagOn( Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE )) &&
  10667. !Allocated &&
  10668. NtfsCheckForReservedClusters( Scb, CurrentVcn, &CurrentClusterCount ) &&
  10669. (CurrentClusterCount < Vcb->SparseFileClusters)) {
  10670. Allocated = TRUE;
  10671. CurrentClusterCount = Vcb->SparseFileClusters;
  10672. }
  10673. //
  10674. // If allocated check and see whether to extend a previous
  10675. // run or start a new run.
  10676. //
  10677. if (Allocated) {
  10678. //
  10679. // Extend the previous run if contiguous.
  10680. //
  10681. AccessingUserBuffer = TRUE;
  10682. if (NextVcn == CurrentVcn) {
  10683. CurrentBuffer->Length.QuadPart += LlBytesFromClusters( Vcb, CurrentClusterCount );
  10684. //
  10685. // Otherwise use the next buffer location.
  10686. //
  10687. } else {
  10688. //
  10689. // Check that there is space.
  10690. //
  10691. if (RemainingBytes < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  10692. //
  10693. // We may already have some entries in the buffer. Return
  10694. // a different code if we were able to store at least one
  10695. // entry in the output buffer.
  10696. //
  10697. if (CurrentBuffer + 1 == OutputBuffer) {
  10698. Status = STATUS_BUFFER_TOO_SMALL;
  10699. } else {
  10700. Status = STATUS_BUFFER_OVERFLOW;
  10701. }
  10702. RemainingClusters = 0;
  10703. break;
  10704. }
  10705. RemainingBytes -= sizeof( FILE_ALLOCATED_RANGE_BUFFER );
  10706. //
  10707. // Move to the next position in the buffer and
  10708. // fill in the current position.
  10709. //
  10710. CurrentBuffer += 1;
  10711. CurrentBuffer->FileOffset.QuadPart = LlBytesFromClusters( Vcb, CurrentVcn );
  10712. CurrentBuffer->Length.QuadPart = LlBytesFromClusters( Vcb, CurrentClusterCount );
  10713. }
  10714. AccessingUserBuffer = FALSE;
  10715. CurrentVcn += CurrentClusterCount;
  10716. NextVcn = CurrentVcn;
  10717. //
  10718. // Otherwise move forward to the next range.
  10719. //
  10720. } else {
  10721. CurrentVcn += CurrentClusterCount;
  10722. }
  10723. //
  10724. // Break out of the loop if we have processed all of the user's
  10725. // clusters.
  10726. //
  10727. //
  10728. // Grab the FsRtl header lock to check if we are beyond
  10729. // file size. If so then trim the last entry in the
  10730. // output buffer to file size if necessary and break out.
  10731. //
  10732. NtfsAcquireFsrtlHeader( Scb );
  10733. if (((LONGLONG) LlBytesFromClusters( Vcb, CurrentVcn )) >= Scb->Header.FileSize.QuadPart) {
  10734. NtfsReleaseFsrtlHeader( Scb );
  10735. RemainingClusters = 0;
  10736. break;
  10737. }
  10738. NtfsReleaseFsrtlHeader( Scb );
  10739. ThisClusterCount -= CurrentClusterCount;
  10740. } while (ThisClusterCount > 0);
  10741. } while (RemainingClusters != 0);
  10742. //
  10743. // If we have at least one entry then check and see if we
  10744. // need to bias either the starting value or final
  10745. // length based on the user's input values.
  10746. //
  10747. if (CurrentBuffer != OutputBuffer - 1) {
  10748. AccessingUserBuffer = TRUE;
  10749. if (OutputBuffer->FileOffset.QuadPart < StartingOffset) {
  10750. OutputBuffer->Length.QuadPart -= (StartingOffset - OutputBuffer->FileOffset.QuadPart);
  10751. OutputBuffer->FileOffset.QuadPart = StartingOffset;
  10752. }
  10753. if ((CurrentBuffer->FileOffset.QuadPart + CurrentBuffer->Length.QuadPart) >
  10754. (StartingOffset + Length)) {
  10755. CurrentBuffer->Length.QuadPart = StartingOffset + Length - CurrentBuffer->FileOffset.QuadPart;
  10756. }
  10757. AccessingUserBuffer = FALSE;
  10758. }
  10759. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  10760. //
  10761. // Convert any unexpected error to INVALID_USER_BUFFER if we
  10762. // are writing in the user's buffer.
  10763. //
  10764. NtfsRaiseStatus( IrpContext,
  10765. STATUS_INVALID_USER_BUFFER,
  10766. NULL,
  10767. NULL );
  10768. }
  10769. //
  10770. // If we were successful then update the output information.
  10771. //
  10772. Irp->IoStatus.Information = PtrOffset( OutputBuffer, (CurrentBuffer + 1) );
  10773. } finally {
  10774. DebugUnwind( NtfsQueryAllocatedRanges );
  10775. //
  10776. // Release resources.
  10777. //
  10778. NtfsReleasePagingIo( IrpContext, Scb->Fcb );
  10779. if (AcquiredScb) {
  10780. NtfsReleaseScb( IrpContext, Scb );
  10781. }
  10782. //
  10783. // If nothing raised then complete the irp.
  10784. //
  10785. if (!AbnormalTermination()) {
  10786. NtfsCompleteRequest( IrpContext, Irp, Status );
  10787. }
  10788. }
  10789. return Status;
  10790. }
  10791. //
  10792. // Local support routine.
  10793. //
  10794. NTSTATUS
  10795. NtfsSetSparse (
  10796. IN PIRP_CONTEXT IrpContext,
  10797. IN PIRP Irp
  10798. )
  10799. /*++
  10800. Routine Description:
  10801. This routine is called to set the state of a stream to sparse. We only allow
  10802. this on user data streams. There is no input or output buffer needed for this call.
  10803. Arguments:
  10804. Irp - Request being serviced
  10805. Return Value:
  10806. NTSTATUS - The return status for the operation
  10807. --*/
  10808. {
  10809. NTSTATUS Status = STATUS_SUCCESS;
  10810. PVCB Vcb;
  10811. PFCB Fcb;
  10812. PSCB Scb;
  10813. PCCB Ccb;
  10814. PIO_STACK_LOCATION IrpSp;
  10815. BOOLEAN SetSparse = TRUE;
  10816. PAGED_CODE();
  10817. //
  10818. // Decode the file object, fail this request if not a user data stream.
  10819. // We check for dismount further below, so send FALSE to not raise here.
  10820. //
  10821. if (NtfsDecodeFileObject( IrpContext,
  10822. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10823. &Vcb,
  10824. &Fcb,
  10825. &Scb,
  10826. &Ccb,
  10827. FALSE ) != UserFileOpen) {
  10828. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10829. return STATUS_INVALID_PARAMETER;
  10830. }
  10831. //
  10832. // For now accept a zero length input buffer meaning set sparse
  10833. // remove this before shipping nt5
  10834. //
  10835. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10836. if (IrpSp->Parameters.FileSystemControl.InputBufferLength != 0 &&
  10837. IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( FILE_SET_SPARSE_BUFFER )) {
  10838. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10839. return STATUS_INVALID_PARAMETER;
  10840. }
  10841. //
  10842. // Fsctrl is buffered so we don't need to probe etc. the input
  10843. //
  10844. if ((Irp->RequestorMode != KernelMode) && (IrpSp->Parameters.FileSystemControl.InputBufferLength != 0) ) {
  10845. SetSparse = ((PFILE_SET_SPARSE_BUFFER)Irp->AssociatedIrp.SystemBuffer)->SetSparse;
  10846. }
  10847. //
  10848. // For this release we don't support unsparsifying files
  10849. //
  10850. if (SetSparse == FALSE) {
  10851. NtfsCompleteRequest( IrpContext, Irp, STATUS_NOT_IMPLEMENTED );
  10852. return STATUS_NOT_IMPLEMENTED;
  10853. }
  10854. //
  10855. // Only upgraded volumes can have sparse files.
  10856. //
  10857. if (!NtfsVolumeVersionCheck( Vcb, NTFS_SPARSE_FILE_VERSION )) {
  10858. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  10859. return STATUS_VOLUME_NOT_UPGRADED;
  10860. }
  10861. //
  10862. // Readonly mount should be just that: read only.
  10863. //
  10864. if (NtfsIsVolumeReadOnly( Vcb )) {
  10865. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  10866. return STATUS_MEDIA_WRITE_PROTECTED;
  10867. }
  10868. //
  10869. // Remember the source info flags in the Ccb.
  10870. //
  10871. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  10872. //
  10873. // Acquire the paging Io resource. User data streams should always have
  10874. // a paging io resource.
  10875. //
  10876. ASSERT( Scb->Header.PagingIoResource != NULL );
  10877. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  10878. //
  10879. // Acquire the main resource as well.
  10880. //
  10881. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10882. //
  10883. // Check that the volume is still mounted.
  10884. //
  10885. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10886. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  10887. return STATUS_VOLUME_DISMOUNTED;
  10888. }
  10889. //
  10890. // Make sure the caller has the appropriate access to this stream.
  10891. //
  10892. if (!(FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS )) &&
  10893. !IrpSp->FileObject->WriteAccess) {
  10894. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  10895. return STATUS_ACCESS_DENIED;
  10896. }
  10897. //
  10898. // Change the sparse state of the file.
  10899. //
  10900. NtfsSetSparseStream( IrpContext, NULL, Scb );
  10901. //
  10902. // There is no data returned in an output buffer for this.
  10903. //
  10904. Irp->IoStatus.Information = 0;
  10905. //
  10906. // Go ahead and complete the request.
  10907. //
  10908. NtfsCompleteRequest( IrpContext, Irp, Status );
  10909. return Status;
  10910. }
  10911. //
  10912. // Local support routine.
  10913. //
  10914. NTSTATUS
  10915. NtfsZeroRange (
  10916. IN PIRP_CONTEXT IrpContext,
  10917. IN PIRP Irp
  10918. )
  10919. /*++
  10920. Routine Description:
  10921. This routine is called to zero a range of a file. We will also deallocate any convenient
  10922. allocation on a sparse file.
  10923. Arguments:
  10924. Irp - Request being serviced
  10925. Return Value:
  10926. NTSTATUS - The return status for the operation
  10927. --*/
  10928. {
  10929. NTSTATUS Status = STATUS_SUCCESS;
  10930. PFILE_ZERO_DATA_INFORMATION ZeroRange;
  10931. PVCB Vcb;
  10932. PFCB Fcb;
  10933. PSCB Scb;
  10934. PCCB Ccb;
  10935. PAGED_CODE();
  10936. //
  10937. // Make sure the input buffer is large enough for the ZeroRange request.
  10938. //
  10939. if (IoGetCurrentIrpStackLocation( Irp )->Parameters.FileSystemControl.InputBufferLength < sizeof( FILE_ZERO_DATA_INFORMATION )) {
  10940. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10941. return STATUS_INVALID_PARAMETER;
  10942. }
  10943. //
  10944. // Verify the ZeroRange request is properly formed.
  10945. //
  10946. ZeroRange = (PFILE_ZERO_DATA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  10947. if ((ZeroRange->FileOffset.QuadPart < 0) ||
  10948. (ZeroRange->BeyondFinalZero.QuadPart < 0) ||
  10949. (ZeroRange->FileOffset.QuadPart > ZeroRange->BeyondFinalZero.QuadPart)) {
  10950. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10951. return STATUS_INVALID_PARAMETER;
  10952. }
  10953. //
  10954. // Decode the file object, fail this request if not a user data stream.
  10955. //
  10956. if (NtfsDecodeFileObject( IrpContext,
  10957. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10958. &Vcb,
  10959. &Fcb,
  10960. &Scb,
  10961. &Ccb,
  10962. TRUE ) != UserFileOpen) {
  10963. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10964. return STATUS_INVALID_PARAMETER;
  10965. }
  10966. if (NtfsIsVolumeReadOnly( Vcb )) {
  10967. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  10968. return STATUS_MEDIA_WRITE_PROTECTED;
  10969. }
  10970. //
  10971. // Capture the source information.
  10972. //
  10973. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  10974. //
  10975. // Zero this range of the stream.
  10976. //
  10977. Status = NtfsZeroRangeInStream( IrpContext,
  10978. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10979. Scb,
  10980. &ZeroRange->FileOffset.QuadPart,
  10981. ZeroRange->BeyondFinalZero.QuadPart );
  10982. if (Status != STATUS_PENDING) {
  10983. //
  10984. // There is no data returned in an output buffer for this.
  10985. //
  10986. Irp->IoStatus.Information = 0;
  10987. //
  10988. // Go ahead and complete the request. Raise any error
  10989. // status to make sure to unwind any Usn reasons.
  10990. //
  10991. if (NT_SUCCESS( Status )) {
  10992. NtfsCompleteRequest( IrpContext, Irp, Status );
  10993. } else {
  10994. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  10995. }
  10996. }
  10997. return Status;
  10998. }
  10999. //
  11000. // Local support routine
  11001. //
  11002. NTSTATUS
  11003. NtfsEncryptionFsctl (
  11004. IN PIRP_CONTEXT IrpContext,
  11005. IN PIRP Irp
  11006. )
  11007. /*++
  11008. Routine Description:
  11009. This routine is called to pass the request through to the installed encryption
  11010. driver if present.
  11011. Arguments:
  11012. Irp - Request being serviced
  11013. Return Value:
  11014. NTSTATUS - The return status for the operation
  11015. --*/
  11016. {
  11017. NTSTATUS Status = STATUS_SUCCESS;
  11018. PVCB Vcb;
  11019. PFCB Fcb;
  11020. PSCB Scb;
  11021. PCCB Ccb;
  11022. TYPE_OF_OPEN TypeOfOpen;
  11023. PVOID InputBuffer;
  11024. ULONG InputBufferLength = 0;
  11025. PVOID OutputBuffer;
  11026. ULONG OutputBufferLength = 0;
  11027. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  11028. BOOLEAN ReleasePagingIo = FALSE;
  11029. BOOLEAN ReleaseScb = FALSE;
  11030. BOOLEAN ReleaseVcb = FALSE;
  11031. PAGED_CODE();
  11032. //
  11033. // This call should always be synchronous.
  11034. //
  11035. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  11036. //
  11037. // Decode the file object, fail this request if not a user data stream or directory.
  11038. // We check for dismount further below, so send FALSE to not raise here.
  11039. //
  11040. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  11041. IrpSp->FileObject,
  11042. &Vcb,
  11043. &Fcb,
  11044. &Scb,
  11045. &Ccb,
  11046. FALSE );
  11047. //
  11048. // This is only legal for files and directories, and not for anything
  11049. // that's compressed.
  11050. //
  11051. if (((TypeOfOpen != UserFileOpen) &&
  11052. (TypeOfOpen != UserDirectoryOpen)) ||
  11053. (FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ))) {
  11054. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11055. return STATUS_INVALID_PARAMETER;
  11056. }
  11057. //
  11058. // This is also only supported on upgraded volumes.
  11059. //
  11060. if (!NtfsVolumeVersionCheck( Vcb, NTFS_ENCRYPTION_VERSION )) {
  11061. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  11062. return STATUS_VOLUME_NOT_UPGRADED;
  11063. }
  11064. OutputBuffer = NtfsMapUserBuffer( Irp );
  11065. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  11066. InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  11067. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  11068. //
  11069. // Probe the user's buffers if necessary.
  11070. //
  11071. if (Irp->RequestorMode != KernelMode) {
  11072. try {
  11073. ProbeForRead( InputBuffer,
  11074. InputBufferLength,
  11075. sizeof(UCHAR) );
  11076. ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
  11077. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  11078. NtfsRaiseStatus( IrpContext,
  11079. STATUS_INVALID_USER_BUFFER,
  11080. NULL,
  11081. NULL );
  11082. }
  11083. }
  11084. //
  11085. // Use a try-finally to free the resource.
  11086. //
  11087. try {
  11088. //
  11089. // Acquire both resources if present on the file.
  11090. //
  11091. if (Fcb->PagingIoResource != NULL) {
  11092. ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, TRUE );
  11093. ReleasePagingIo = TRUE;
  11094. }
  11095. NtfsAcquireExclusiveScb( IrpContext, Scb );
  11096. ReleaseScb = TRUE;
  11097. //
  11098. // Check that the volume is still mounted.
  11099. //
  11100. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  11101. Status = STATUS_VOLUME_DISMOUNTED;
  11102. leave;
  11103. }
  11104. //
  11105. // Call the EFS routine if specified.
  11106. //
  11107. if (NtfsData.EncryptionCallBackTable.FileSystemControl_2 != NULL) {
  11108. ULONG EncryptionFlag = 0;
  11109. if (IsEncrypted( &Fcb->Info )) {
  11110. SetFlag( EncryptionFlag, FILE_ENCRYPTED );
  11111. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11112. SetFlag( EncryptionFlag, STREAM_ENCRYPTED );
  11113. }
  11114. }
  11115. Status = NtfsData.EncryptionCallBackTable.FileSystemControl_2(
  11116. InputBuffer,
  11117. InputBufferLength,
  11118. OutputBuffer,
  11119. &OutputBufferLength,
  11120. EncryptionFlag,
  11121. Ccb->AccessFlags,
  11122. (NtfsIsVolumeReadOnly( Vcb )) ? READ_ONLY_VOLUME : 0,
  11123. IrpSp->Parameters.FileSystemControl.FsControlCode,
  11124. Fcb,
  11125. IrpContext,
  11126. (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ),
  11127. Scb,
  11128. &Scb->EncryptionContext,
  11129. &Scb->EncryptionContextLength);
  11130. Irp->IoStatus.Information = OutputBufferLength;
  11131. //
  11132. // There is no encryption driver present.
  11133. //
  11134. } else {
  11135. Status = STATUS_INVALID_DEVICE_REQUEST;
  11136. Irp->IoStatus.Information = 0;
  11137. }
  11138. NtfsCleanupTransaction( IrpContext, Status, TRUE );
  11139. } finally {
  11140. DebugUnwind( NtfsEncryptionPassThrough );
  11141. //
  11142. // Acquire both resources if present on the file.
  11143. //
  11144. if (ReleasePagingIo) {
  11145. ExReleaseResourceLite( Fcb->PagingIoResource );
  11146. }
  11147. if (ReleaseScb) {
  11148. NtfsReleaseScb( IrpContext, Scb );
  11149. }
  11150. if (ReleaseVcb) {
  11151. NtfsReleaseVcb( IrpContext, Vcb );
  11152. }
  11153. }
  11154. //
  11155. // Go ahead and complete the request.
  11156. //
  11157. NtfsCompleteRequest( IrpContext, Irp, Status );
  11158. return Status;
  11159. }
  11160. //
  11161. // Local support routine
  11162. //
  11163. VOID
  11164. NtfsEncryptStream (
  11165. IN PIRP_CONTEXT IrpContext,
  11166. IN PFCB Fcb,
  11167. IN PSCB Scb OPTIONAL,
  11168. IN PATTRIBUTE_ENUMERATION_CONTEXT AttrContext
  11169. )
  11170. /*++
  11171. Routine Description:
  11172. This routine is called to mark a user data stream as encrypted. It sets
  11173. the encryption bit in the filerecord (handling logging, etc.) and in the
  11174. Scb if one is provided..
  11175. Arguments:
  11176. Fcb - The Fcb containing the stream to mark as encrypted.
  11177. Scb - The Scb (if one exists) to mark as ancrypted.
  11178. AttrContext - The attribute context that indicates where the stream is
  11179. within the file record.
  11180. Return Value:
  11181. None
  11182. --*/
  11183. {
  11184. ATTRIBUTE_RECORD_HEADER NewAttribute;
  11185. PATTRIBUTE_RECORD_HEADER Attribute;
  11186. NtfsPinMappedAttribute( IrpContext, Fcb->Vcb, AttrContext );
  11187. Attribute = NtfsFoundAttribute( AttrContext );
  11188. //
  11189. // We only need enough of the attribute to modify the bit.
  11190. //
  11191. RtlCopyMemory( &NewAttribute, Attribute, SIZEOF_RESIDENT_ATTRIBUTE_HEADER );
  11192. SetFlag( NewAttribute.Flags, ATTRIBUTE_FLAG_ENCRYPTED );
  11193. //
  11194. // Now, log the changed attribute.
  11195. //
  11196. (VOID)NtfsWriteLog( IrpContext,
  11197. Fcb->Vcb->MftScb,
  11198. NtfsFoundBcb( AttrContext ),
  11199. UpdateResidentValue,
  11200. &NewAttribute,
  11201. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11202. UpdateResidentValue,
  11203. Attribute,
  11204. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11205. NtfsMftOffset( AttrContext ),
  11206. PtrOffset(NtfsContainingFileRecord( AttrContext ), Attribute),
  11207. 0,
  11208. Fcb->Vcb->BytesPerFileRecordSegment );
  11209. //
  11210. // Change the attribute by calling the same routine called at restart.
  11211. //
  11212. NtfsRestartChangeValue( IrpContext,
  11213. NtfsContainingFileRecord( AttrContext ),
  11214. PtrOffset( NtfsContainingFileRecord( AttrContext ), Attribute ),
  11215. 0,
  11216. &NewAttribute,
  11217. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11218. FALSE );
  11219. if (ARGUMENT_PRESENT( Scb )) {
  11220. SetFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11221. }
  11222. //
  11223. // Now update the Fcb if this is the first of the streams.
  11224. //
  11225. if (!IsEncrypted( &Fcb->Info )) {
  11226. //
  11227. // Set the flag in the Fcb info field and let ourselves know to
  11228. // update the standard information.
  11229. //
  11230. ASSERTMSG( "conflict with flush",
  11231. NtfsIsSharedFcb( Fcb ) ||
  11232. (Fcb->PagingIoResource != NULL &&
  11233. NtfsIsSharedFcbPagingIo( Fcb )) );
  11234. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11235. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11236. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  11237. //
  11238. // If this is a directory, remember to set the appropriate bit in its Fcb.
  11239. //
  11240. if (IsDirectory( &Fcb->Info )) {
  11241. SetFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11242. }
  11243. }
  11244. }
  11245. //
  11246. // Local support routine
  11247. //
  11248. NTSTATUS
  11249. NtfsSetEncryption (
  11250. IN PIRP_CONTEXT IrpContext,
  11251. IN PIRP Irp
  11252. )
  11253. /*++
  11254. Routine Description:
  11255. This routine is called to initiate a set encryption operation. The input buffer specifies
  11256. whether we are accessing a file or a directory.
  11257. Arguments:
  11258. Irp - Request being serviced
  11259. Return Value:
  11260. NTSTATUS - The return status for the operation
  11261. --*/
  11262. {
  11263. NTSTATUS Status = STATUS_SUCCESS;
  11264. PVCB Vcb;
  11265. PFCB Fcb;
  11266. PSCB Scb;
  11267. PCCB Ccb;
  11268. PLCB Lcb;
  11269. PSCB ParentScb = NULL;
  11270. TYPE_OF_OPEN TypeOfOpen;
  11271. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  11272. BOOLEAN ReleasePagingIo = FALSE;
  11273. BOOLEAN ReleaseVcb = FALSE;
  11274. ULONG EncryptionFlag = 0;
  11275. ULONG EncryptionOperation;
  11276. ULONG InputBufferLength;
  11277. ULONG OutputBufferLength;
  11278. ULONG FilterMatch;
  11279. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  11280. BOOLEAN CleanupAttrContext = FALSE;
  11281. BOOLEAN FoundAttribute;
  11282. ATTRIBUTE_RECORD_HEADER NewAttribute;
  11283. PATTRIBUTE_RECORD_HEADER Attribute;
  11284. BOOLEAN UpdateCcbFlags = FALSE;
  11285. BOOLEAN ClearFcbUpdateFlag = FALSE;
  11286. BOOLEAN ClearFcbInfoFlags = FALSE;
  11287. BOOLEAN RestoreEncryptionFlag = FALSE;
  11288. BOOLEAN DirectoryFileEncrypted = FALSE;
  11289. PENCRYPTION_BUFFER EncryptionBuffer;
  11290. PDECRYPTION_STATUS_BUFFER DecryptionStatusBuffer;
  11291. PAGED_CODE();
  11292. //
  11293. // This call should always be synchronous.
  11294. //
  11295. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  11296. //
  11297. // Decode the file object, fail this request if not a user data stream or directory.
  11298. //
  11299. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  11300. IrpSp->FileObject,
  11301. &Vcb,
  11302. &Fcb,
  11303. &Scb,
  11304. &Ccb,
  11305. TRUE );
  11306. //
  11307. // This is only legal for files and directories.
  11308. //
  11309. if ((TypeOfOpen != UserFileOpen) &&
  11310. (TypeOfOpen != UserDirectoryOpen)) {
  11311. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11312. return STATUS_INVALID_PARAMETER;
  11313. }
  11314. //
  11315. // Readonly mount should be just that: read only.
  11316. //
  11317. if (NtfsIsVolumeReadOnly( Vcb )) {
  11318. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  11319. return STATUS_MEDIA_WRITE_PROTECTED;
  11320. }
  11321. //
  11322. // Get the input and output buffer lengths and pointers. Remember that the output
  11323. // buffer is optional.
  11324. //
  11325. EncryptionBuffer = (PENCRYPTION_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  11326. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  11327. DecryptionStatusBuffer = (PDECRYPTION_STATUS_BUFFER)NtfsMapUserBuffer( Irp );
  11328. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  11329. //
  11330. // Check for a minimum length on the input and ouput buffers. The output buffer
  11331. // only needs to be a certain length if one was specified.
  11332. //
  11333. if ((InputBufferLength < sizeof(ENCRYPTION_BUFFER)) ||
  11334. ((DecryptionStatusBuffer != NULL) && (OutputBufferLength < sizeof(DECRYPTION_STATUS_BUFFER)))) {
  11335. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  11336. DebugTrace( -1, Dbg, ("NtfsSetEncryption -> %08lx\n", STATUS_BUFFER_TOO_SMALL) );
  11337. return STATUS_BUFFER_TOO_SMALL;
  11338. }
  11339. //
  11340. // Probe the user's buffers.
  11341. //
  11342. try {
  11343. if (Irp->RequestorMode != KernelMode) {
  11344. ProbeForRead( EncryptionBuffer, InputBufferLength, sizeof(UCHAR) );
  11345. if (DecryptionStatusBuffer != NULL) ProbeForWrite( DecryptionStatusBuffer, OutputBufferLength, sizeof(UCHAR) );
  11346. }
  11347. EncryptionOperation = EncryptionBuffer->EncryptionOperation;
  11348. Irp->IoStatus.Information = 0;
  11349. if (DecryptionStatusBuffer != NULL) {
  11350. DecryptionStatusBuffer->NoEncryptedStreams = FALSE;
  11351. }
  11352. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  11353. DebugTrace( -1, Dbg, ("NtfsSetEncryption -> %08lx\n", FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER) );
  11354. NtfsRaiseStatus( IrpContext,
  11355. STATUS_INVALID_USER_BUFFER,
  11356. NULL,
  11357. NULL );
  11358. }
  11359. //
  11360. // Verify that the user didn't specify any illegal flags.
  11361. //
  11362. if (EncryptionOperation > MAXIMUM_ENCRYPTION_VALUE) {
  11363. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11364. return STATUS_INVALID_PARAMETER;
  11365. }
  11366. //
  11367. // Capture the source information.
  11368. //
  11369. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  11370. //
  11371. // It's okay to mark the file encryption bit if this stream is compressed,
  11372. // but we do want to prevent setting the stream encrypted bit for a
  11373. // compressed stream. In some future release when we have a chance to
  11374. // test compression & encryption together (perhaps with some third-party
  11375. // encryption engine) we can relax/remove this restriction.
  11376. //
  11377. if ((EncryptionOperation == STREAM_SET_ENCRYPTION) &&
  11378. (FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ))) {
  11379. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11380. return STATUS_INVALID_PARAMETER;
  11381. }
  11382. //
  11383. // This is also only supported on upgraded volumes.
  11384. //
  11385. if (!NtfsVolumeVersionCheck( Vcb, NTFS_ENCRYPTION_VERSION )) {
  11386. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  11387. return STATUS_VOLUME_NOT_UPGRADED;
  11388. }
  11389. //
  11390. // Use a try-finally to free the resource.
  11391. //
  11392. try {
  11393. //
  11394. // Acquire the Vcb shared in case we need to update the parent directory entry.
  11395. //
  11396. ReleaseVcb = NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  11397. //
  11398. // Acquire both resources if present on the file.
  11399. //
  11400. if (Fcb->PagingIoResource != NULL) {
  11401. ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, TRUE );
  11402. ReleasePagingIo = TRUE;
  11403. }
  11404. NtfsAcquireExclusiveScb( IrpContext, Scb );
  11405. //
  11406. // Check that the volume is still mounted.
  11407. //
  11408. if ( !FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  11409. Status = STATUS_VOLUME_DISMOUNTED;
  11410. leave;
  11411. }
  11412. //
  11413. // We can't go on if there isn't an encryption driver loaded. We did our best
  11414. // to get it loaded above. If that didn't work, we need to leave now.
  11415. //
  11416. if (!FlagOn( NtfsData.Flags, NTFS_FLAGS_ENCRYPTION_DRIVER )) {
  11417. Status = STATUS_INVALID_DEVICE_REQUEST;
  11418. leave;
  11419. }
  11420. //
  11421. // Update the Scb from disk if necessary.
  11422. //
  11423. if (Scb->AttributeTypeCode == $INDEX_ALLOCATION) {
  11424. if (Scb->ScbType.Index.BytesPerIndexBuffer == 0) {
  11425. NtfsInitializeAttributeContext( &AttrContext );
  11426. CleanupAttrContext = TRUE;
  11427. if (!NtfsLookupAttributeByName( IrpContext,
  11428. Scb->Fcb,
  11429. &Scb->Fcb->FileReference,
  11430. $INDEX_ROOT,
  11431. &Scb->AttributeName,
  11432. NULL,
  11433. FALSE,
  11434. &AttrContext )) {
  11435. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  11436. }
  11437. NtfsUpdateIndexScbFromAttribute( IrpContext,
  11438. Scb,
  11439. NtfsFoundAttribute( &AttrContext ),
  11440. FALSE );
  11441. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11442. }
  11443. } else if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  11444. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  11445. }
  11446. //
  11447. // Remember the starting encryption state for this operation.
  11448. //
  11449. if (IsEncrypted( &Fcb->Info )) {
  11450. SetFlag( EncryptionFlag, FILE_ENCRYPTED );
  11451. if (FlagOn( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED )) {
  11452. DirectoryFileEncrypted = TRUE;
  11453. }
  11454. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11455. SetFlag( EncryptionFlag, STREAM_ENCRYPTED );
  11456. }
  11457. }
  11458. RestoreEncryptionFlag = TRUE;
  11459. //
  11460. // If the caller wants to clear the encryption bit on the file then there should
  11461. // be no encrypted streams on the file.
  11462. //
  11463. if ((EncryptionOperation == FILE_CLEAR_ENCRYPTION) && IsEncrypted( &Fcb->Info )) {
  11464. NtfsInitializeAttributeContext( &AttrContext );
  11465. CleanupAttrContext = TRUE;
  11466. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  11467. Fcb,
  11468. &Fcb->FileReference,
  11469. $DATA,
  11470. &AttrContext );
  11471. while (FoundAttribute) {
  11472. //
  11473. // We only want to look at this attribute if it is resident or the
  11474. // first attribute header for a non-resident attribute.
  11475. //
  11476. Attribute = NtfsFoundAttribute( &AttrContext );
  11477. if (NtfsIsAttributeResident( Attribute ) ||
  11478. (Attribute->Form.Nonresident.LowestVcn == 0)) {
  11479. if (FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11480. break;
  11481. }
  11482. }
  11483. FoundAttribute = NtfsLookupNextAttributeByCode( IrpContext,
  11484. Fcb,
  11485. $DATA,
  11486. &AttrContext );
  11487. }
  11488. if (FoundAttribute) {
  11489. Status = STATUS_INVALID_DEVICE_REQUEST;
  11490. leave;
  11491. }
  11492. //
  11493. // If this is a directory then we need to check the index root as well.
  11494. //
  11495. if (IsDirectory( &Fcb->Info )) {
  11496. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11497. NtfsInitializeAttributeContext( &AttrContext );
  11498. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11499. Fcb,
  11500. &Fcb->FileReference,
  11501. $INDEX_ROOT,
  11502. &NtfsFileNameIndex,
  11503. NULL,
  11504. FALSE,
  11505. &AttrContext );
  11506. //
  11507. // We should always find this attribute in this case.
  11508. //
  11509. if (!FoundAttribute) {
  11510. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11511. }
  11512. Attribute = NtfsFoundAttribute( &AttrContext );
  11513. if (FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11514. Status = STATUS_INVALID_DEVICE_REQUEST;
  11515. leave;
  11516. }
  11517. }
  11518. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11519. CleanupAttrContext = FALSE;
  11520. }
  11521. //
  11522. // It's a pretty rare case that we'll decide we don't need to update
  11523. // the duplicate info below, so let's go ahead and prepare now. We
  11524. // can't wait until after the convert to nonresident, as that will
  11525. // acquire the quota resources before we've acquired the parent scb,
  11526. // resulting in a potential deadlock.
  11527. //
  11528. Lcb = Ccb->Lcb;
  11529. NtfsPrepareForUpdateDuplicate( IrpContext, Fcb, &Lcb, &ParentScb, TRUE );
  11530. //
  11531. // Now let's go ahead and modify the bit on the file/stream.
  11532. //
  11533. if (EncryptionOperation == FILE_SET_ENCRYPTION) {
  11534. if (!IsEncrypted( &Fcb->Info )) {
  11535. //
  11536. // Set the flag in the Fcb info field and let ourselves know to
  11537. // update the standard information.
  11538. //
  11539. ASSERTMSG( "conflict with flush",
  11540. NtfsIsSharedFcb( Fcb ) ||
  11541. (Fcb->PagingIoResource != NULL &&
  11542. NtfsIsSharedFcbPagingIo( Fcb )) );
  11543. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11544. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11545. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  11546. UpdateCcbFlags = TRUE;
  11547. }
  11548. } else if (EncryptionOperation == FILE_CLEAR_ENCRYPTION) {
  11549. if (IsEncrypted( &Fcb->Info )) {
  11550. //
  11551. // Clear the flag in the Fcb info field and let ourselves know to
  11552. // update the standard information. Also clear the directory
  11553. // encrypted bit, even though it may not even be set.
  11554. //
  11555. ASSERTMSG( "conflict with flush",
  11556. NtfsIsSharedFcb( Fcb ) ||
  11557. (Fcb->PagingIoResource != NULL &&
  11558. NtfsIsSharedFcbPagingIo( Fcb )) );
  11559. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11560. ClearFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11561. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11562. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  11563. UpdateCcbFlags = TRUE;
  11564. }
  11565. } else if (EncryptionOperation == STREAM_SET_ENCRYPTION) {
  11566. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11567. NtfsInitializeAttributeContext( &AttrContext );
  11568. CleanupAttrContext = TRUE;
  11569. //
  11570. // If we're being called to set the encyrption bit on a new named stream
  11571. // and we created the unnamed stream silently without calling out to the
  11572. // encryption engine, this is the best time to set the encryption bit on
  11573. // the unnamed stream and convert it to nonresident, too. Some encryption
  11574. // engines may not want this behavior, so we check the ImplementationFlags.
  11575. //
  11576. if (!FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
  11577. FlagOn( Fcb->FcbState, FCB_STATE_ENCRYPTION_PENDING) &&
  11578. FlagOn( NtfsData.EncryptionCallBackTable.ImplementationFlags, ENCRYPTION_ALL_STREAMS ) &&
  11579. NtfsIsTypeCodeUserData( Scb->AttributeTypeCode )) {
  11580. if (NtfsLookupAttributeByCode( IrpContext,
  11581. Fcb,
  11582. &Fcb->FileReference,
  11583. $DATA,
  11584. &AttrContext )) {
  11585. //
  11586. // If there is an the unnamed data attribute, it will be the
  11587. // first data attribute we find. There may be no unnamed data
  11588. // attribute in the case where we've been asked to encrypt a
  11589. // named data stream on a directory.
  11590. //
  11591. Attribute = NtfsFoundAttribute( &AttrContext );
  11592. if (Attribute->NameLength == 0) {
  11593. PSCB DefaultStreamScb = NULL;
  11594. ASSERT( NtfsIsAttributeResident( Attribute ) &&
  11595. Attribute->Form.Resident.ValueLength == 0 );
  11596. NtfsConvertToNonresident( IrpContext,
  11597. Fcb,
  11598. Attribute,
  11599. TRUE,
  11600. &AttrContext );
  11601. while (TRUE) {
  11602. DefaultStreamScb = NtfsGetNextChildScb( Fcb, DefaultStreamScb );
  11603. //
  11604. // If we've reached the end of the list of Scbs, or else
  11605. // found the unnamed data stream's Scb, we're done.
  11606. //
  11607. if ((DefaultStreamScb == NULL) ||
  11608. FlagOn( DefaultStreamScb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  11609. break;
  11610. }
  11611. }
  11612. NtfsEncryptStream( IrpContext, Fcb, DefaultStreamScb, &AttrContext );
  11613. }
  11614. }
  11615. //
  11616. // Get the AttrContext ready for reuse.
  11617. //
  11618. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11619. NtfsInitializeAttributeContext( &AttrContext );
  11620. }
  11621. //
  11622. // If the stream is a data stream we can look up the attribute
  11623. // from the Scb.
  11624. //
  11625. if (TypeOfOpen == UserFileOpen) {
  11626. NtfsLookupAttributeForScb( IrpContext,
  11627. Scb,
  11628. NULL,
  11629. &AttrContext );
  11630. //
  11631. // Convert to non-resident if necessary. It's entirely possible
  11632. // that our caller will not have read or write access to this
  11633. // file and won't have a key. Therefore we don't want to create
  11634. // a cache section for this stream during the convert, as we
  11635. // may not have a key with which to do flushes later.
  11636. //
  11637. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  11638. NtfsConvertToNonresident( IrpContext,
  11639. Fcb,
  11640. NtfsFoundAttribute( &AttrContext ),
  11641. TRUE,
  11642. &AttrContext );
  11643. }
  11644. } else {
  11645. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11646. Fcb,
  11647. &Fcb->FileReference,
  11648. $INDEX_ROOT,
  11649. &NtfsFileNameIndex,
  11650. NULL,
  11651. FALSE,
  11652. &AttrContext );
  11653. //
  11654. // We should always find this attribute in this case.
  11655. //
  11656. if (!FoundAttribute) {
  11657. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11658. }
  11659. }
  11660. NtfsEncryptStream( IrpContext, Fcb, Scb, &AttrContext );
  11661. UpdateCcbFlags = TRUE;
  11662. }
  11663. } else { // EncryptionOperation == STREAM_CLEAR_ENCRYPTION
  11664. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11665. NtfsInitializeAttributeContext( &AttrContext );
  11666. CleanupAttrContext = TRUE;
  11667. //
  11668. // If the stream is a data stream we can look up the attribute
  11669. // from the Scb.
  11670. //
  11671. if (TypeOfOpen == UserFileOpen) {
  11672. NtfsLookupAttributeForScb( IrpContext,
  11673. Scb,
  11674. NULL,
  11675. &AttrContext );
  11676. } else {
  11677. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11678. Fcb,
  11679. &Fcb->FileReference,
  11680. $INDEX_ROOT,
  11681. &NtfsFileNameIndex,
  11682. NULL,
  11683. FALSE,
  11684. &AttrContext );
  11685. //
  11686. // We should always find this attribute in this case.
  11687. //
  11688. if (!FoundAttribute) {
  11689. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11690. }
  11691. }
  11692. NtfsPinMappedAttribute( IrpContext, Vcb, &AttrContext );
  11693. Attribute = NtfsFoundAttribute( &AttrContext );
  11694. //
  11695. // We only need enough of the attribute to modify the bit.
  11696. //
  11697. RtlCopyMemory( &NewAttribute, Attribute, SIZEOF_RESIDENT_ATTRIBUTE_HEADER );
  11698. ClearFlag( NewAttribute.Flags, ATTRIBUTE_FLAG_ENCRYPTED );
  11699. //
  11700. // Now, log the changed attribute.
  11701. //
  11702. (VOID)NtfsWriteLog( IrpContext,
  11703. Vcb->MftScb,
  11704. NtfsFoundBcb( &AttrContext ),
  11705. UpdateResidentValue,
  11706. &NewAttribute,
  11707. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11708. UpdateResidentValue,
  11709. Attribute,
  11710. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11711. NtfsMftOffset( &AttrContext ),
  11712. PtrOffset(NtfsContainingFileRecord( &AttrContext ), Attribute),
  11713. 0,
  11714. Vcb->BytesPerFileRecordSegment );
  11715. //
  11716. // Change the attribute by calling the same routine called at restart.
  11717. //
  11718. NtfsRestartChangeValue( IrpContext,
  11719. NtfsContainingFileRecord( &AttrContext ),
  11720. PtrOffset( NtfsContainingFileRecord( &AttrContext ), Attribute ),
  11721. 0,
  11722. &NewAttribute,
  11723. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11724. FALSE );
  11725. ClearFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11726. //
  11727. // Now check if this is the last stream on the file with the encryption
  11728. // bit set.
  11729. //
  11730. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11731. NtfsInitializeAttributeContext( &AttrContext );
  11732. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  11733. Fcb,
  11734. &Fcb->FileReference,
  11735. $DATA,
  11736. &AttrContext );
  11737. while (FoundAttribute) {
  11738. //
  11739. // We only want to look at this attribute if it is resident or the
  11740. // first attribute header for a non-resident attribute.
  11741. //
  11742. Attribute = NtfsFoundAttribute( &AttrContext );
  11743. if (NtfsIsAttributeResident( Attribute ) ||
  11744. (Attribute->Form.Nonresident.LowestVcn == 0)) {
  11745. if (FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11746. break;
  11747. }
  11748. }
  11749. FoundAttribute = NtfsLookupNextAttributeByCode( IrpContext,
  11750. Fcb,
  11751. $DATA,
  11752. &AttrContext );
  11753. }
  11754. //
  11755. // If this is a directory then we need to check the index root as well.
  11756. //
  11757. if (!FoundAttribute && IsDirectory( &Fcb->Info )) {
  11758. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11759. NtfsInitializeAttributeContext( &AttrContext );
  11760. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11761. Fcb,
  11762. &Fcb->FileReference,
  11763. $INDEX_ROOT,
  11764. &NtfsFileNameIndex,
  11765. NULL,
  11766. FALSE,
  11767. &AttrContext );
  11768. //
  11769. // We should always find this attribute in this case.
  11770. //
  11771. if (!FoundAttribute) {
  11772. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11773. }
  11774. Attribute = NtfsFoundAttribute( &AttrContext );
  11775. if (!FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11776. FoundAttribute = FALSE;
  11777. }
  11778. }
  11779. //
  11780. // If our caller is interested, let it know if we have decrypted the
  11781. // last encrypted stream. Since this is the only place we touch this
  11782. // buffer, we'll just wrap a little try/except around it here.
  11783. //
  11784. if (DecryptionStatusBuffer != NULL) {
  11785. try {
  11786. DecryptionStatusBuffer->NoEncryptedStreams = TRUE;
  11787. Irp->IoStatus.Information = sizeof(DECRYPTION_STATUS_BUFFER);
  11788. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  11789. DebugTrace( -1, Dbg, ("NtfsSetEncryption -> %08lx\n", FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER) );
  11790. NtfsRaiseStatus( IrpContext,
  11791. STATUS_INVALID_USER_BUFFER,
  11792. NULL,
  11793. NULL );
  11794. }
  11795. }
  11796. UpdateCcbFlags = TRUE;
  11797. }
  11798. }
  11799. //
  11800. // Now let's update the on-disk structures.
  11801. //
  11802. if (FlagOn( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  11803. NtfsUpdateStandardInformation( IrpContext, Fcb );
  11804. ClearFcbUpdateFlag = TRUE;
  11805. NtfsUpdateDuplicateInfo( IrpContext, Fcb, Lcb, ParentScb );
  11806. //
  11807. // Now perform the dir notify call if this is not an
  11808. // open by FileId.
  11809. //
  11810. if ((Vcb->NotifyCount != 0) &&
  11811. (ParentScb != NULL) &&
  11812. !FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_FILE_ID )) {
  11813. FilterMatch = NtfsBuildDirNotifyFilter( IrpContext,
  11814. Fcb->InfoFlags | Lcb->InfoFlags );
  11815. if (FilterMatch != 0) {
  11816. NtfsReportDirNotify( IrpContext,
  11817. Fcb->Vcb,
  11818. &Ccb->FullFileName,
  11819. Ccb->LastFileNameOffset,
  11820. NULL,
  11821. ((FlagOn( Ccb->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  11822. (Ccb->Lcb != NULL) &&
  11823. (Ccb->Lcb->Scb->ScbType.Index.NormalizedName.Length != 0)) ?
  11824. &Ccb->Lcb->Scb->ScbType.Index.NormalizedName :
  11825. NULL),
  11826. FilterMatch,
  11827. FILE_ACTION_MODIFIED,
  11828. ParentScb->Fcb );
  11829. }
  11830. }
  11831. NtfsUpdateLcbDuplicateInfo( Fcb, Lcb );
  11832. ClearFcbInfoFlags = TRUE;
  11833. }
  11834. //
  11835. // Call the EFS routine if specified.
  11836. //
  11837. if (NtfsData.EncryptionCallBackTable.FileSystemControl_1 != NULL) {
  11838. Status = NtfsData.EncryptionCallBackTable.FileSystemControl_1(
  11839. EncryptionBuffer,
  11840. InputBufferLength,
  11841. NULL,
  11842. NULL,
  11843. EncryptionFlag,
  11844. Ccb->AccessFlags,
  11845. (NtfsIsVolumeReadOnly( Vcb )) ? READ_ONLY_VOLUME : 0,
  11846. IrpSp->Parameters.FileSystemControl.FsControlCode,
  11847. Fcb,
  11848. IrpContext,
  11849. (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ),
  11850. Scb,
  11851. &Scb->EncryptionContext,
  11852. &Scb->EncryptionContextLength);
  11853. }
  11854. //
  11855. // Post the change to the Usn Journal (on errors change is backed out)
  11856. //
  11857. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_ENCRYPTION_CHANGE );
  11858. NtfsCleanupTransaction( IrpContext, Status, TRUE );
  11859. ASSERT( NT_SUCCESS( Status ));
  11860. //
  11861. // Clear the flags in the Fcb if the update is complete.
  11862. //
  11863. if (ClearFcbUpdateFlag) {
  11864. ClearFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11865. }
  11866. if (ClearFcbInfoFlags) {
  11867. Fcb->InfoFlags = 0;
  11868. }
  11869. if (UpdateCcbFlags) {
  11870. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE | CCB_FLAG_SET_ARCHIVE );
  11871. }
  11872. RestoreEncryptionFlag = FALSE;
  11873. } finally {
  11874. DebugUnwind( NtfsSetEncryption );
  11875. //
  11876. // In the error path we need to restore the correct encryption bit in
  11877. // the Fcb and Scb.
  11878. //
  11879. if (RestoreEncryptionFlag) {
  11880. DebugTrace( 0, Dbg, ("Error in NtfsSetEncryption, restoring encryption flags\n") );
  11881. if (FlagOn( EncryptionFlag, FILE_ENCRYPTED )) {
  11882. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11883. if (DirectoryFileEncrypted) {
  11884. SetFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11885. }
  11886. } else {
  11887. ClearFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11888. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11889. }
  11890. if (FlagOn( EncryptionFlag, STREAM_ENCRYPTED )) {
  11891. SetFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11892. } else {
  11893. ClearFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11894. }
  11895. }
  11896. //
  11897. // Acquire both resources if present on the file.
  11898. //
  11899. if (ReleasePagingIo) {
  11900. ExReleaseResourceLite( Fcb->PagingIoResource );
  11901. }
  11902. if (ReleaseVcb) {
  11903. NtfsReleaseVcb( IrpContext, Vcb );
  11904. }
  11905. if (CleanupAttrContext) {
  11906. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11907. }
  11908. }
  11909. //
  11910. // Go ahead and complete the request.
  11911. //
  11912. NtfsCompleteRequest( IrpContext, Irp, Status );
  11913. return Status;
  11914. }
  11915. //
  11916. // Local Support Routine
  11917. //
  11918. NTSTATUS
  11919. NtfsReadRawEncrypted (
  11920. IN PIRP_CONTEXT IrpContext,
  11921. IN PIRP Irp
  11922. )
  11923. /*++
  11924. Routine Description:
  11925. This routine performs a 'raw' read of encrypted data. By 'raw', we
  11926. mean without attempting to unencrypt. This is useful for backup
  11927. operations, and also for data recovery in the event the key stream
  11928. is somehow lost. Since this fsctrl works with any access, we have
  11929. to fail the request for unencrypted files. This routine is
  11930. responsible for either completing or enqueuing the input Irp.
  11931. Notes: DataUnit is the size of each peice written out in the buffer
  11932. ChunkUnit is the size of a compression chunk (not used yet)
  11933. For Sparse files DataUnit == CompressionUnit
  11934. Arguments:
  11935. Irp - Supplies the Irp to process
  11936. Return Value:
  11937. NTSTATUS - The return status for the operation
  11938. --*/
  11939. {
  11940. LONGLONG StartingVbo;
  11941. LONGLONG RequestedOffset;
  11942. LONGLONG RoundedFileSize;
  11943. ULONG TotalByteCount;
  11944. ULONG ByteCount;
  11945. ULONG BytesRead;
  11946. PIRP ReadIrp = NULL;
  11947. PDEVICE_OBJECT DeviceObject;
  11948. PFILE_OBJECT FileObject;
  11949. PVCB Vcb;
  11950. PFCB Fcb;
  11951. PSCB Scb;
  11952. PCCB Ccb;
  11953. PIO_STACK_LOCATION IrpSp;
  11954. PIO_STACK_LOCATION ReadIrpSp;
  11955. TYPE_OF_OPEN TypeOfOpen;
  11956. ULONG InputBufferLength;
  11957. ULONG OutputBufferLength;
  11958. ULONG ReadLength;
  11959. PREQUEST_RAW_ENCRYPTED_DATA RequestRawEncryptedData;
  11960. PENCRYPTED_DATA_INFO EncryptedDataInfo;
  11961. USHORT BlockIndex;
  11962. USHORT BlockCount = 0;
  11963. PUCHAR RawDataDestination;
  11964. NTFS_IO_CONTEXT LocalContext;
  11965. BOOLEAN PagingAcquired = FALSE;
  11966. BOOLEAN LockedReadIrpPages = FALSE;
  11967. BOOLEAN SparseFile = FALSE;
  11968. BOOLEAN RangeAllocated = TRUE;
  11969. BOOLEAN AccessingUserBuffer = FALSE;
  11970. ULONG OutputBufferOffset;
  11971. ULONG BytesWithinValidDataLength = 0;
  11972. ULONG BytesWithinFileSize = 0;
  11973. ULONG i;
  11974. LONG BytesPerSectorMask;
  11975. NTSTATUS Status = STATUS_SUCCESS;
  11976. UCHAR TotalShift;
  11977. UCHAR DataUnitShift;
  11978. PAGED_CODE();
  11979. //
  11980. // Don't post this request, we can't lock both input and output buffers.
  11981. //
  11982. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  11983. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  11984. DebugTrace( +1, Dbg, ("NtfsReadRawEncrypted:\n") );
  11985. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  11986. FileObject = IrpSp->FileObject;
  11987. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  11988. FileObject,
  11989. &Vcb,
  11990. &Fcb,
  11991. &Scb,
  11992. &Ccb,
  11993. TRUE );
  11994. //
  11995. // This operation only applies to files, not indexes,
  11996. // or volumes.
  11997. //
  11998. if (TypeOfOpen != UserFileOpen) {
  11999. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12000. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12001. return STATUS_INVALID_PARAMETER;
  12002. }
  12003. //
  12004. // We can't allow reads of unencrypted data, as that would let any
  12005. // user read any file's contents..
  12006. //
  12007. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED ) ||
  12008. //
  12009. // Even for an encrypted file, we should only allow this if the
  12010. // user is a backup operator or has read access.
  12011. //
  12012. !FlagOn( Ccb->AccessFlags, BACKUP_ACCESS | READ_DATA_ACCESS )) {
  12013. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  12014. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", STATUS_ACCESS_DENIED) );
  12015. return STATUS_ACCESS_DENIED;
  12016. }
  12017. //
  12018. // Get the input and output buffer lengths and pointers.
  12019. // Initialize some variables.
  12020. //
  12021. RequestRawEncryptedData = (PREQUEST_RAW_ENCRYPTED_DATA)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  12022. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  12023. EncryptedDataInfo = (PENCRYPTED_DATA_INFO)NtfsMapUserBuffer( Irp );
  12024. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  12025. //
  12026. // Check for a minimum length on the input and ouput buffers.
  12027. //
  12028. if ((InputBufferLength < sizeof(REQUEST_RAW_ENCRYPTED_DATA)) ||
  12029. (OutputBufferLength < sizeof(ENCRYPTED_DATA_INFO))) {
  12030. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  12031. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", STATUS_BUFFER_TOO_SMALL) );
  12032. return STATUS_BUFFER_TOO_SMALL;
  12033. }
  12034. //
  12035. // Probe the user's buffers.
  12036. //
  12037. try {
  12038. if (Irp->RequestorMode != KernelMode) {
  12039. ProbeForRead( RequestRawEncryptedData, InputBufferLength, sizeof(UCHAR) );
  12040. ProbeForWrite( EncryptedDataInfo, OutputBufferLength, sizeof(UCHAR) );
  12041. }
  12042. RequestedOffset = RequestRawEncryptedData->FileOffset;
  12043. ReadLength = RequestRawEncryptedData->Length;
  12044. //
  12045. // Zero the buffer.
  12046. //
  12047. RtlZeroMemory( EncryptedDataInfo, OutputBufferLength );
  12048. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  12049. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER) );
  12050. NtfsRaiseStatus( IrpContext,
  12051. STATUS_INVALID_USER_BUFFER,
  12052. NULL,
  12053. NULL );
  12054. }
  12055. try {
  12056. //
  12057. // Make sure we aren't starting past the end of the file, in which case
  12058. // we would have nothing to return.
  12059. //
  12060. if ((RequestedOffset > Scb->Header.FileSize.QuadPart) || (RequestedOffset >= Scb->Header.AllocationSize.QuadPart)) {
  12061. try_return( Status = STATUS_END_OF_FILE );
  12062. }
  12063. //
  12064. // Sanity check the read length.
  12065. //
  12066. if (0 == ReadLength) {
  12067. try_return( Status = STATUS_INVALID_PARAMETER );
  12068. }
  12069. RoundedFileSize = (Scb->Header.FileSize.QuadPart + Vcb->BytesPerSector) & ~((LONGLONG)Vcb->BytesPerSector);
  12070. if (RequestedOffset + ReadLength > RoundedFileSize) {
  12071. ReadLength = (ULONG)(RoundedFileSize - RequestedOffset);
  12072. }
  12073. try {
  12074. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  12075. //
  12076. // File is not compressed or sparse.
  12077. //
  12078. AccessingUserBuffer = TRUE;
  12079. EncryptedDataInfo->CompressionFormat = COMPRESSION_FORMAT_NONE;
  12080. AccessingUserBuffer = FALSE;
  12081. //
  12082. // For a simple uncompressed, nonsparse file, we can start on any
  12083. // cluster boundary. We like to start on a cluster boundary
  12084. // since the cluster size is always >= the size of a cipher block,
  12085. // and a recovery agent will always need to work with whole cipher
  12086. // blocks. Notice that the StartingVbo is rounded _down_ to the
  12087. // previous cluster boundary, while TotalByteCount is rounded _up_ to
  12088. // the next larger cluster multiple.
  12089. //
  12090. StartingVbo = RequestedOffset & Vcb->InverseClusterMask;
  12091. TotalByteCount = ClusterAlign( Vcb, ReadLength );
  12092. //
  12093. // We will do the transfer in one block for this simple case.
  12094. //
  12095. BlockCount = 1;
  12096. ByteCount = TotalByteCount;
  12097. //
  12098. // For an uncompressed file, we'll pick a data unit size so
  12099. // that it's some convenient power of two.
  12100. //
  12101. for (DataUnitShift = 0, i = TotalByteCount - 1;
  12102. i > 0;
  12103. i = i / 2) {
  12104. DataUnitShift += 1;
  12105. }
  12106. AccessingUserBuffer = TRUE;
  12107. EncryptedDataInfo->DataUnitShift = DataUnitShift;
  12108. EncryptedDataInfo->ChunkShift = DataUnitShift;
  12109. AccessingUserBuffer = FALSE;
  12110. } else if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  12111. //
  12112. // File is sparse and not compressed.
  12113. //
  12114. SparseFile = TRUE;
  12115. ASSERT( Vcb->ClusterShift + Scb->CompressionUnitShift <= MAXUCHAR );
  12116. TotalShift = (UCHAR)(Scb->CompressionUnitShift + Vcb->ClusterShift);
  12117. AccessingUserBuffer = TRUE;
  12118. EncryptedDataInfo->CompressionFormat = COMPRESSION_FORMAT_NONE;
  12119. EncryptedDataInfo->ChunkShift = TotalShift;
  12120. AccessingUserBuffer = FALSE;
  12121. //
  12122. // For a sparse file, we can start on any compression unit
  12123. // boundary. Notice that the StartingVbo is rounded _down_ to the
  12124. // previous compression unit boundary, while TotalByteCount is rounded
  12125. // _up_ to the next larger compression unit multiple.
  12126. //
  12127. StartingVbo = RequestedOffset & ~(ULONG_PTR)(Scb->CompressionUnit - 1);
  12128. TotalByteCount = (ReadLength + (Scb->CompressionUnit - 1)) & ~(Scb->CompressionUnit - 1);
  12129. //
  12130. // BlockCount is the number of blocks needed to describe this range
  12131. // of the file. It is simply the number of bytes we're reading on
  12132. // this request divided by the size of a compression unit.
  12133. // (Literally, we're shifting, but semantically, we're dividing).
  12134. //
  12135. BlockCount = (USHORT) (TotalByteCount >> TotalShift);
  12136. //
  12137. // Since BlockCount is derived from a user-supplied value, we need
  12138. // to make sure we aren't about to divide by zero.
  12139. //
  12140. if (BlockCount == 0) {
  12141. Status = STATUS_INVALID_PARAMETER;
  12142. leave;
  12143. }
  12144. //
  12145. // ByteCount is the number of bytes to read per Irp, while TotalByteCount
  12146. // is how many bytes to try to read during this call into NtfsReadRawEncrypted.
  12147. //
  12148. ByteCount = TotalByteCount / BlockCount;
  12149. AccessingUserBuffer = TRUE;
  12150. EncryptedDataInfo->DataUnitShift = TotalShift;
  12151. AccessingUserBuffer = FALSE;
  12152. } else {
  12153. //
  12154. // We do not support compressed encrypted files yet.
  12155. //
  12156. Status = STATUS_NOT_IMPLEMENTED;
  12157. leave;
  12158. }
  12159. //
  12160. // The actual file contents will start after the fixed length part
  12161. // of the encrypted data info struct plus one ulong per block that
  12162. // specifies the length of that block. We also need to round
  12163. // OutputBufferOffset up so that the buffer we pass to the underlying
  12164. // driver(s) is sector aligned, since that is required for all
  12165. // unbuffered I/O.
  12166. //
  12167. BytesPerSectorMask = Vcb->BytesPerSector - 1;
  12168. OutputBufferOffset = sizeof(ENCRYPTED_DATA_INFO) + (BlockCount * sizeof(ULONG));
  12169. OutputBufferOffset = PtrOffset(EncryptedDataInfo,
  12170. (((UINT_PTR) EncryptedDataInfo + OutputBufferOffset + BytesPerSectorMask) & ~BytesPerSectorMask));
  12171. AccessingUserBuffer = TRUE;
  12172. EncryptedDataInfo->OutputBufferOffset = OutputBufferOffset;
  12173. EncryptedDataInfo->NumberOfDataBlocks = BlockCount;
  12174. AccessingUserBuffer = FALSE;
  12175. //
  12176. // Now that we know how much data we're going to try to read, and the
  12177. // offset into the user's buffer where we will start putting it, we
  12178. // can test one last time that the buffer is big enough.
  12179. //
  12180. if ((OutputBufferOffset + TotalByteCount) > OutputBufferLength) {
  12181. Status = STATUS_BUFFER_TOO_SMALL;
  12182. leave;
  12183. }
  12184. //
  12185. // Acquire paging io before we do the flush.
  12186. //
  12187. ExAcquireResourceSharedLite( Scb->Header.PagingIoResource, TRUE );
  12188. PagingAcquired = TRUE;
  12189. //
  12190. // While we have something acquired, let's take this opportunity to make sure
  12191. // that the volume hasn't been dismounted.
  12192. //
  12193. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  12194. Status = STATUS_VOLUME_DISMOUNTED;
  12195. leave;
  12196. }
  12197. #ifdef COMPRESS_ON_WIRE
  12198. if (Scb->Header.FileObjectC != NULL) {
  12199. PCOMPRESSION_SYNC CompressionSync = NULL;
  12200. //
  12201. // Use a try-finally to clean up the compression sync.
  12202. //
  12203. try {
  12204. NtfsSynchronizeUncompressedIo( Scb,
  12205. NULL,
  12206. 0,
  12207. TRUE,
  12208. &CompressionSync );
  12209. } finally {
  12210. NtfsReleaseCompressionSync( CompressionSync );
  12211. }
  12212. }
  12213. #endif
  12214. //
  12215. // Get any cached changes flushed to disk.
  12216. //
  12217. CcFlushCache( FileObject->SectionObjectPointer,
  12218. (PLARGE_INTEGER)&StartingVbo,
  12219. TotalByteCount,
  12220. &Irp->IoStatus );
  12221. //
  12222. // Make sure the data got out to disk. The above call is asynchronous,
  12223. // but Cc will hold the paging shared while it does the flush. When
  12224. // we are able to acquire paging exclusively, we know the flush
  12225. // has completed.
  12226. //
  12227. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  12228. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  12229. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  12230. PagingAcquired = FALSE;
  12231. //
  12232. // Check for errors in the flush.
  12233. //
  12234. NtfsNormalizeAndCleanupTransaction( IrpContext,
  12235. &Irp->IoStatus.Status,
  12236. TRUE,
  12237. STATUS_UNEXPECTED_IO_ERROR );
  12238. //
  12239. // Now get paging & main exclusively again to keep eof from changing
  12240. // beneath us, and so we can safely query the mapping info below.
  12241. //
  12242. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  12243. NtfsAcquireFcbWithPaging( IrpContext, Scb->Fcb, 0 );
  12244. //
  12245. // Store where we really started in the file.
  12246. //
  12247. AccessingUserBuffer = TRUE;
  12248. EncryptedDataInfo->StartingFileOffset = StartingVbo;
  12249. EncryptedDataInfo->ClusterShift = (UCHAR) Vcb->ClusterShift;
  12250. EncryptedDataInfo->EncryptionFormat = ENCRYPTION_FORMAT_DEFAULT;
  12251. AccessingUserBuffer = FALSE;
  12252. //
  12253. // Begin by getting a pointer to the device object that the file resides
  12254. // on.
  12255. //
  12256. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  12257. //
  12258. // This IrpContext probably isn't ready to do noncached I/O yet,
  12259. // so let's set up its NtfsIoContext. We know we will be doing
  12260. // this operation synchronously, so it is safe to use the
  12261. // local context.
  12262. //
  12263. if (IrpContext->Union.NtfsIoContext == NULL) {
  12264. IrpContext->Union.NtfsIoContext = &LocalContext;
  12265. RtlZeroMemory( IrpContext->Union.NtfsIoContext, sizeof( NTFS_IO_CONTEXT ));
  12266. //
  12267. // Store the fact that we did _not_ allocate this context structure
  12268. // in the structure itself.
  12269. //
  12270. IrpContext->Union.NtfsIoContext->AllocatedContext = FALSE;
  12271. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_IO_CONTEXT );
  12272. //
  12273. // And make sure the world knows we want this done synchronously.
  12274. //
  12275. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) );
  12276. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  12277. //
  12278. // Create an event so we can do synchronous I/O.
  12279. //
  12280. KeInitializeEvent( &IrpContext->Union.NtfsIoContext->Wait.SyncEvent,
  12281. NotificationEvent,
  12282. FALSE );
  12283. }
  12284. //
  12285. // Now we just loop through for each block and do the actual read(s).
  12286. //
  12287. DebugTrace( 0, Dbg, ("BlockCount %08lx\n", BlockCount) );
  12288. DebugTrace( 0, Dbg, ("TotalByteCount %08lx\n", TotalByteCount) );
  12289. DebugTrace( 0, Dbg, ("ByteCount %08lx\n", ByteCount) );
  12290. for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
  12291. //
  12292. // Compute the address to which we will start copying raw data.
  12293. //
  12294. RawDataDestination = Add2Ptr( EncryptedDataInfo, OutputBufferOffset );
  12295. DebugTrace( 0, Dbg, ("RawDataDestination %p\n", (ULONG_PTR)RawDataDestination) );
  12296. //
  12297. // If this is a sparse file, we need to determine whether this compression
  12298. // unit is allocated.
  12299. //
  12300. if (SparseFile) {
  12301. VCN StartVcn = LlClustersFromBytes( Vcb, StartingVbo );
  12302. VCN FinalCluster = LlClustersFromBytes( Vcb, (StartingVbo + ByteCount) ) - 1;
  12303. LONGLONG ClusterCount;
  12304. DebugTrace( 0, Dbg, ("SparseFile block %08lx\n", BlockIndex) );
  12305. DebugTrace( 0, Dbg, (" StartingVbo %016I64x\n", StartingVbo) );
  12306. DebugTrace( 0, Dbg, (" StartVcn %016I64x\n", StartVcn) );
  12307. DebugTrace( 0, Dbg, (" FinalCluster %016I64x\n", FinalCluster) );
  12308. //
  12309. // We need to call NtfsPreloadAllocation to make sure all the
  12310. // ranges in this NtfsMcb are loaded.
  12311. //
  12312. NtfsPreloadAllocation( IrpContext,
  12313. Scb,
  12314. StartVcn,
  12315. FinalCluster );
  12316. RangeAllocated = NtfsIsRangeAllocated( Scb,
  12317. StartVcn,
  12318. FinalCluster,
  12319. FALSE,
  12320. &ClusterCount );
  12321. if (!RangeAllocated) { DebugTrace( 0, Dbg, ("Deallocated range at Vcn %016I64x\n", StartVcn) ); }
  12322. } else {
  12323. //
  12324. // If this isn't a sparse file, we can skip the potentially expensive
  12325. // mapping lookup.
  12326. //
  12327. ASSERT( BlockCount == 1 );
  12328. ASSERT( RangeAllocated );
  12329. }
  12330. if (RangeAllocated) {
  12331. //
  12332. // Allocate an I/O Request Packet (IRP) for this raw read operation.
  12333. //
  12334. AccessingUserBuffer = TRUE;
  12335. ReadIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ,
  12336. Vcb->Vpb->DeviceObject,
  12337. RawDataDestination,
  12338. ByteCount,
  12339. (PLARGE_INTEGER)&StartingVbo,
  12340. NULL );
  12341. AccessingUserBuffer = FALSE;
  12342. if (ReadIrp == NULL) {
  12343. Status = STATUS_INSUFFICIENT_RESOURCES;
  12344. leave;
  12345. }
  12346. //
  12347. // We now have an Irp, we want to make it look as though it is part of
  12348. // the current call. We need to adjust the Irp stack to update this.
  12349. //
  12350. ReadIrp->CurrentLocation--;
  12351. ReadIrpSp = IoGetNextIrpStackLocation( ReadIrp );
  12352. ReadIrp->Tail.Overlay.CurrentStackLocation = ReadIrpSp;
  12353. ReadIrpSp->DeviceObject = DeviceObject;
  12354. //
  12355. // Put our buffer in the Irp and lock it as well.
  12356. //
  12357. ReadIrp->UserBuffer = RawDataDestination;
  12358. AccessingUserBuffer = TRUE;
  12359. NtfsLockUserBuffer( IrpContext,
  12360. ReadIrp,
  12361. IoWriteAccess,
  12362. ByteCount );
  12363. LockedReadIrpPages = TRUE;
  12364. //
  12365. // Put the read code into the IrpContext.
  12366. //
  12367. IrpContext->MajorFunction = IRP_MJ_READ;
  12368. //
  12369. // Actually read the raw data from the disk.
  12370. //
  12371. // N.B. -- If the file is compressed, also pass the COMPRESSED_STREAM flag.
  12372. //
  12373. NtfsNonCachedIo( IrpContext,
  12374. ReadIrp,
  12375. Scb,
  12376. StartingVbo,
  12377. ByteCount,
  12378. ENCRYPTED_STREAM );
  12379. //
  12380. // Fill in how many bytes we actually read.
  12381. //
  12382. BytesRead = (ULONG) ReadIrp->IoStatus.Information;
  12383. ASSERT( OutputBufferLength >
  12384. ((BlockIndex * sizeof(ULONG)) + FIELD_OFFSET(ENCRYPTED_DATA_INFO, DataBlockSize)));
  12385. EncryptedDataInfo->DataBlockSize[BlockIndex] = BytesRead;
  12386. AccessingUserBuffer = FALSE;
  12387. OutputBufferOffset += BytesRead;
  12388. } else {
  12389. //
  12390. // We didn't really read anything, so we want to set the
  12391. // size of this block to 0, but we want to pretend we
  12392. // read a whole compression unit so that BytesWithinXXX
  12393. // get updated correctly.
  12394. //
  12395. ASSERT( ReadIrp == NULL );
  12396. AccessingUserBuffer = TRUE;
  12397. EncryptedDataInfo->DataBlockSize[BlockIndex] = 0;
  12398. AccessingUserBuffer = FALSE;
  12399. BytesRead = Scb->CompressionUnit;
  12400. }
  12401. //
  12402. // Fill in the fields that let our caller know whether any of
  12403. // the file size or valid data length boundaries occured in
  12404. // the range of this transfer.
  12405. //
  12406. if ((StartingVbo + BytesRead) > Scb->Header.FileSize.QuadPart) {
  12407. //
  12408. // Only increment if we start before filesize
  12409. //
  12410. if (StartingVbo < Scb->Header.FileSize.QuadPart) {
  12411. BytesWithinFileSize += (ULONG)(Scb->Header.FileSize.QuadPart -
  12412. StartingVbo);
  12413. }
  12414. //
  12415. // If we're at the end of the file, and it isn't compressed, we can save
  12416. // the user a ton of space on the tape if we truncate to the first 512 byte
  12417. // boundary beyond the end of the data.
  12418. // 512 is the maximum cipher block size an encryption engine can rely on the
  12419. // file system to allow..
  12420. //
  12421. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  12422. ASSERT( OutputBufferLength >
  12423. ((BlockIndex * sizeof(ULONG)) + FIELD_OFFSET(ENCRYPTED_DATA_INFO, DataBlockSize)));
  12424. AccessingUserBuffer = TRUE;
  12425. EncryptedDataInfo->DataBlockSize[BlockIndex] = ((BytesWithinFileSize + (ULONG)0x200) & (ULONG)(~0x1ff));
  12426. AccessingUserBuffer = FALSE;
  12427. }
  12428. } else {
  12429. BytesWithinFileSize += BytesRead;
  12430. }
  12431. if ((StartingVbo + BytesRead) > Scb->Header.ValidDataLength.QuadPart) {
  12432. //
  12433. // Make sure BytesWithinValidDataLength can't go negative.
  12434. //
  12435. if (Scb->Header.ValidDataLength.QuadPart > StartingVbo) {
  12436. BytesWithinValidDataLength += (ULONG)(Scb->Header.ValidDataLength.QuadPart -
  12437. StartingVbo);
  12438. }
  12439. } else {
  12440. BytesWithinValidDataLength += BytesRead;
  12441. }
  12442. StartingVbo += ByteCount;
  12443. //
  12444. // We need to clean up the irp before we go around again.
  12445. //
  12446. if (ReadIrp != NULL) {
  12447. //
  12448. // If there is an Mdl we free that first.
  12449. //
  12450. if (ReadIrp->MdlAddress != NULL) {
  12451. if (LockedReadIrpPages) {
  12452. MmUnlockPages( ReadIrp->MdlAddress );
  12453. LockedReadIrpPages = FALSE;
  12454. }
  12455. IoFreeMdl( ReadIrp->MdlAddress );
  12456. ReadIrp->MdlAddress = NULL;
  12457. }
  12458. IoFreeIrp( ReadIrp );
  12459. ReadIrp = NULL;
  12460. }
  12461. } // endfor
  12462. AccessingUserBuffer = TRUE;
  12463. EncryptedDataInfo->BytesWithinFileSize = BytesWithinFileSize;
  12464. EncryptedDataInfo->BytesWithinValidDataLength = BytesWithinValidDataLength;
  12465. AccessingUserBuffer = FALSE;
  12466. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  12467. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted raising %08lx\n", Status) );
  12468. NtfsRaiseStatus( IrpContext,
  12469. STATUS_INVALID_USER_BUFFER,
  12470. NULL,
  12471. NULL );
  12472. }
  12473. try_exit: NOTHING;
  12474. } finally {
  12475. if (PagingAcquired) {
  12476. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  12477. }
  12478. if (ReadIrp != NULL) {
  12479. //
  12480. // If there is an Mdl we free that first.
  12481. //
  12482. if (ReadIrp->MdlAddress != NULL) {
  12483. if (LockedReadIrpPages) {
  12484. MmUnlockPages( ReadIrp->MdlAddress );
  12485. }
  12486. IoFreeMdl( ReadIrp->MdlAddress );
  12487. }
  12488. IoFreeIrp( ReadIrp );
  12489. }
  12490. }
  12491. NtfsCompleteRequest( IrpContext, Irp, Status );
  12492. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", Status) );
  12493. return Status;
  12494. }
  12495. LONG
  12496. NtfsWriteRawExceptionFilter (
  12497. IN PIRP_CONTEXT IrpContext,
  12498. IN PEXCEPTION_POINTERS ExceptionPointer
  12499. )
  12500. /*++
  12501. Routine Description:
  12502. Exception filter for errors during cleanup. We want to raise if this is
  12503. a retryable condition or fatal error, plow on as best we can if not.
  12504. Arguments:
  12505. IrpContext - IrpContext
  12506. ExceptionPointer - Pointer to the exception context.
  12507. Status - Address to store the error status.
  12508. Return Value:
  12509. Exception status - EXCEPTION_CONTINUE_SEARCH if we want to raise to another handler,
  12510. EXCEPTION_EXECUTE_HANDLER if we plan to proceed on.
  12511. --*/
  12512. {
  12513. UNREFERENCED_PARAMETER( IrpContext );
  12514. UNREFERENCED_PARAMETER( ExceptionPointer );
  12515. ASSERT( FsRtlIsNtstatusExpected( ExceptionPointer->ExceptionRecord->ExceptionCode ) );
  12516. return EXCEPTION_EXECUTE_HANDLER;
  12517. }
  12518. NTSTATUS
  12519. NtfsWriteRawEncrypted (
  12520. IN PIRP_CONTEXT IrpContext,
  12521. IN PIRP Irp
  12522. )
  12523. /*++
  12524. Routine Description:
  12525. This routine performs a 'raw' write of encrypted data. By 'raw', we
  12526. mean without attempting to encrypt. This is useful for restore
  12527. operations, where the restore operator does not have a key with which
  12528. to read the plaintext. This routine is responsible for either
  12529. completing or enqueuing the input Irp.
  12530. NOTE: there is a strong assumption that the encrypted data info blocks
  12531. are ordered monotonically from the beginning to end of the file
  12532. Arguments:
  12533. Irp - Supplies the Irp to process
  12534. Return Value:
  12535. NTSTATUS - The return status for the operation
  12536. --*/
  12537. {
  12538. LONGLONG StartingVbo;
  12539. LONGLONG EndingVbo;
  12540. LONGLONG TotalBytesWritten = 0;
  12541. LONGLONG FirstZero;
  12542. LONGLONG OriginalStartingVbo;
  12543. ULONG ByteCount;
  12544. ULONG BytesWithinValidDataLength;
  12545. ULONG BytesWithinFileSize;
  12546. USHORT CompressionFormat;
  12547. PIRP WriteIrp = NULL;
  12548. PDEVICE_OBJECT DeviceObject;
  12549. PFILE_OBJECT FileObject;
  12550. PVCB Vcb;
  12551. PFCB Fcb;
  12552. PSCB Scb;
  12553. PCCB Ccb;
  12554. PIO_STACK_LOCATION IrpSp;
  12555. PIO_STACK_LOCATION WriteIrpSp;
  12556. TYPE_OF_OPEN TypeOfOpen;
  12557. ULONG InputBufferLength;
  12558. PENCRYPTED_DATA_INFO EncryptedDataInfo;
  12559. ULONG InputBufferOffset;
  12560. USHORT BlockIndex;
  12561. USHORT BlockCount;
  12562. PUCHAR RawDataSource;
  12563. BOOLEAN AccessingUserBuffer = FALSE;
  12564. UCHAR EncryptionFormat;
  12565. UCHAR ChunkShift;
  12566. KEVENT Event;
  12567. IO_STATUS_BLOCK Iosb;
  12568. NTSTATUS Status = STATUS_SUCCESS;
  12569. PAGED_CODE();
  12570. //
  12571. // Don't post this request, we can't lock both input and output buffers.
  12572. //
  12573. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  12574. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  12575. DebugTrace( +1, Dbg, ("NtfsWriteRawEncrypted:\n") );
  12576. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  12577. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  12578. FileObject = IrpSp->FileObject;
  12579. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  12580. FileObject,
  12581. &Vcb,
  12582. &Fcb,
  12583. &Scb,
  12584. &Ccb,
  12585. TRUE );
  12586. //
  12587. // This operation only applies to files, not indexes,
  12588. // or volumes.
  12589. //
  12590. if (TypeOfOpen != UserFileOpen) {
  12591. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12592. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted not a UserFileOpen -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12593. return STATUS_INVALID_PARAMETER;
  12594. }
  12595. //
  12596. // Readonly mount should be just that: read only.
  12597. //
  12598. if (NtfsIsVolumeReadOnly( Vcb )) {
  12599. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  12600. DebugTrace( -1, Dbg, ("SetCompression returning WRITE_PROTECTED\n") );
  12601. return STATUS_MEDIA_WRITE_PROTECTED;
  12602. }
  12603. //
  12604. // Remember the source info flags in the Ccb.
  12605. //
  12606. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  12607. //
  12608. // We can't allow writes to unencrypted files, as that could let any
  12609. // user write to any file..
  12610. //
  12611. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED ) ||
  12612. //
  12613. // Even for an encrypted file, we should only allow this if the
  12614. // user has write access.
  12615. //
  12616. (!(FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS )))) {
  12617. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  12618. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted -> %08lx\n", STATUS_ACCESS_DENIED) );
  12619. return STATUS_ACCESS_DENIED;
  12620. }
  12621. //
  12622. // Get the input buffer length and pointer.
  12623. //
  12624. EncryptedDataInfo = (PENCRYPTED_DATA_INFO)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  12625. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  12626. //
  12627. // Check for a minimum length on the input buffer.
  12628. //
  12629. if (InputBufferLength < sizeof(ENCRYPTED_DATA_INFO)) {
  12630. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  12631. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted -> %08lx\n", STATUS_BUFFER_TOO_SMALL) );
  12632. return STATUS_BUFFER_TOO_SMALL;
  12633. }
  12634. //
  12635. // Probe the user's buffer.
  12636. //
  12637. try {
  12638. ProbeForRead( EncryptedDataInfo, InputBufferLength, sizeof(UCHAR) );
  12639. InputBufferOffset = EncryptedDataInfo->OutputBufferOffset;
  12640. BytesWithinValidDataLength = EncryptedDataInfo->BytesWithinValidDataLength;
  12641. BytesWithinFileSize = EncryptedDataInfo->BytesWithinFileSize;
  12642. BlockCount = EncryptedDataInfo->NumberOfDataBlocks;
  12643. EncryptionFormat = EncryptedDataInfo->EncryptionFormat;
  12644. OriginalStartingVbo = StartingVbo = EncryptedDataInfo->StartingFileOffset;
  12645. ChunkShift = EncryptedDataInfo->ChunkShift;
  12646. CompressionFormat = EncryptedDataInfo->CompressionFormat;
  12647. } except( NtfsWriteRawExceptionFilter( IrpContext, GetExceptionInformation() ) ) {
  12648. Status = GetExceptionCode();
  12649. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted raising %08lx\n", Status) );
  12650. NtfsRaiseStatus( IrpContext,
  12651. FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER,
  12652. NULL,
  12653. NULL );
  12654. }
  12655. //
  12656. // See whether the data we're being given is valid.
  12657. //
  12658. if ((EncryptionFormat != ENCRYPTION_FORMAT_DEFAULT) ||
  12659. (BytesWithinValidDataLength > BytesWithinFileSize) ||
  12660. (CompressionFormat != COMPRESSION_FORMAT_NONE) ||
  12661. (BlockCount == 0) ||
  12662. (InputBufferOffset > InputBufferLength)) {
  12663. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12664. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted bad input data -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12665. return STATUS_INVALID_PARAMETER;
  12666. }
  12667. try {
  12668. //
  12669. // Serialize with anyone who might be changing file sizes. Acquire main directly
  12670. // because we call CommonWrite mult times and want to hold the resource across the calls
  12671. //
  12672. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  12673. NtfsAcquireExclusiveScb( IrpContext, Scb );
  12674. #ifdef COMPRESS_ON_WIRE
  12675. //
  12676. // Before we proceed, let's make sure this file is not cached.
  12677. //
  12678. if (Scb->Header.FileObjectC != NULL) {
  12679. PCOMPRESSION_SYNC CompressionSync = NULL;
  12680. //
  12681. // Use a try-finally to clean up the compression sync.
  12682. //
  12683. try {
  12684. NtfsSynchronizeUncompressedIo( Scb,
  12685. NULL,
  12686. 0,
  12687. TRUE,
  12688. &CompressionSync );
  12689. } finally {
  12690. NtfsReleaseCompressionSync( CompressionSync );
  12691. }
  12692. }
  12693. #endif
  12694. CcFlushCache( &Scb->NonpagedScb->SegmentObject, NULL, 0, &Irp->IoStatus );
  12695. NtfsNormalizeAndCleanupTransaction( IrpContext, &Irp->IoStatus.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  12696. if (!CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject, NULL, 0, FALSE )) {
  12697. DebugTrace( 0, Dbg, ("Can't purge cache section in write raw...aborting\n") );
  12698. Status = STATUS_UNABLE_TO_DELETE_SECTION;
  12699. leave;
  12700. }
  12701. // **** TIGHTEN THIS ASSERT ****
  12702. // ASSERT( Scb->NonpagedScb->SegmentObject.SharedCacheMap == NULL );
  12703. //
  12704. // Since we can't add zeroes in the middle of the file (since we may not
  12705. // have a key with which to encrypt them) it's illegal to try to write
  12706. // at some arbitrary offset beyond the current eof.
  12707. //
  12708. if (StartingVbo != Scb->Header.FileSize.QuadPart) {
  12709. DebugTrace( 0, Dbg, ("Attempting to begin a write raw beyond EOF...aborting\n") );
  12710. Status = STATUS_INVALID_PARAMETER;
  12711. leave;
  12712. }
  12713. //
  12714. // Add any allocation necc. to reach the new filesize
  12715. //
  12716. if (OriginalStartingVbo + BytesWithinFileSize > Scb->Header.AllocationSize.QuadPart) {
  12717. LONGLONG EndingVbo;
  12718. EndingVbo = OriginalStartingVbo + BytesWithinFileSize;
  12719. //
  12720. // Always add in compression units for sparse files
  12721. //
  12722. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  12723. EndingVbo += Scb->CompressionUnit - 1;
  12724. EndingVbo &= ~(LONGLONG)(Scb->CompressionUnit - 1);
  12725. }
  12726. NtfsAddAllocation( IrpContext,
  12727. NULL,
  12728. Scb,
  12729. LlClustersFromBytes( Vcb,
  12730. Scb->Header.AllocationSize.QuadPart ),
  12731. LlClustersFromBytes( Vcb, EndingVbo - Scb->Header.AllocationSize.QuadPart ),
  12732. FALSE,
  12733. NULL );
  12734. }
  12735. //
  12736. // Now we just loop through for each block and do the actual write(s).
  12737. //
  12738. DebugTrace( 0, Dbg, ("BlockCount %08lx\n", BlockCount) );
  12739. for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
  12740. AccessingUserBuffer = TRUE;
  12741. ByteCount = EncryptedDataInfo->DataBlockSize[BlockIndex];
  12742. AccessingUserBuffer = FALSE;
  12743. EndingVbo = StartingVbo + ByteCount;
  12744. DebugTrace( 0, Dbg, ("BlockIndex %08lx\n", BlockIndex) );
  12745. DebugTrace( 0, Dbg, ("ByteCount %08lx\n", ByteCount) );
  12746. if (ByteCount != 0 && BytesWithinValidDataLength > 0) {
  12747. //
  12748. // Compute the address from which we will start copying raw data.
  12749. //
  12750. RawDataSource = Add2Ptr( EncryptedDataInfo, InputBufferOffset );
  12751. //
  12752. // Make sure we aren't about to touch memory beyond that part of the
  12753. // user's buffer that we probed above.
  12754. //
  12755. if ((InputBufferOffset + ByteCount) > InputBufferLength) {
  12756. DebugTrace( 0, Dbg, ("Going beyond InputBufferLength...aborting\n") );
  12757. Status = STATUS_INVALID_PARAMETER;
  12758. leave;
  12759. }
  12760. InputBufferOffset += ByteCount;
  12761. //
  12762. // Begin by getting a pointer to the device object that the file resides
  12763. // on.
  12764. //
  12765. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  12766. //
  12767. // Allocate an I/O Request Packet (IRP) for this raw write operation.
  12768. // It has to be synchronous so that it completes before we adjust
  12769. // filesize and valid data length.
  12770. //
  12771. AccessingUserBuffer = TRUE;
  12772. WriteIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE,
  12773. Vcb->Vpb->DeviceObject,
  12774. RawDataSource,
  12775. ByteCount,
  12776. (PLARGE_INTEGER)&StartingVbo,
  12777. &Event,
  12778. &Iosb );
  12779. AccessingUserBuffer = FALSE;
  12780. if (WriteIrp == NULL) {
  12781. Status = STATUS_INSUFFICIENT_RESOURCES;
  12782. leave;
  12783. }
  12784. //
  12785. // Put our buffer in the Irp and set some other irp fields.
  12786. //
  12787. WriteIrp->UserBuffer = RawDataSource;
  12788. SetFlag( WriteIrp->Flags, IRP_NOCACHE );
  12789. //
  12790. // We now have an Irp, we want to make it look as though it came from
  12791. // IoCallDriver and need to adjust the Irp stack to update this.
  12792. //
  12793. WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
  12794. WriteIrpSp->DeviceObject = DeviceObject;
  12795. WriteIrpSp->Parameters.Write.ByteOffset.QuadPart = StartingVbo;
  12796. WriteIrpSp->Parameters.Write.Length = ByteCount;
  12797. WriteIrpSp->FileObject = FileObject;
  12798. ASSERT( NtfsIsExclusiveScb( Scb ) );
  12799. //
  12800. // Callback directly into ourselfs - don't confuse filters with
  12801. // an extra write
  12802. //
  12803. Status = IoCallDriver( Vcb->Vpb->DeviceObject, WriteIrp );
  12804. if (Status == STATUS_PENDING) {
  12805. Status = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  12806. if (Status == STATUS_SUCCESS) {
  12807. Status = Iosb.Status;
  12808. }
  12809. }
  12810. //
  12811. // The write should always be done synchronously, we should still own
  12812. // the resource and all our cleanup structures and snapshots should be good
  12813. //
  12814. ASSERT(Status != STATUS_PENDING && Status != STATUS_CANT_WAIT);
  12815. ASSERT( NtfsIsExclusiveScb( Scb ) );
  12816. ASSERT( (IrpContext->CleanupStructure == Fcb) && (Scb->ScbSnapshot != NULL) );
  12817. NtfsNormalizeAndCleanupTransaction( IrpContext, &Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  12818. TotalBytesWritten += ByteCount;
  12819. } else if (ByteCount == 0) {
  12820. //
  12821. // This is a sparse hole, so there's nothing to actually write.
  12822. // We just need to make sure this stream is sparse, and zero this
  12823. // range. We can't ask our caller to mark the file as sparse,
  12824. // since they just opened the handle and don't have write
  12825. // access to this file.
  12826. //
  12827. DebugTrace( 0, Dbg, ("Deallocated range for block %x\n", BlockIndex) );
  12828. //
  12829. // Make sure our test of the attribute flag is safe.
  12830. //
  12831. ASSERT_SHARED_RESOURCE( Scb->Header.PagingIoResource );
  12832. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  12833. DebugTrace( 0, Dbg, ("Marking stream as sparse\n") );
  12834. NtfsSetSparseStream( IrpContext, NULL, Scb );
  12835. }
  12836. ByteCount = (1 << ChunkShift);
  12837. EndingVbo = StartingVbo + ByteCount;
  12838. //
  12839. // Add any allocation necc. to back this. Ie we have a sparse region
  12840. // beyond filesize
  12841. //
  12842. if (Scb->Header.AllocationSize.QuadPart < EndingVbo) {
  12843. //
  12844. // Round up to a compression unit
  12845. //
  12846. EndingVbo += Scb->CompressionUnit - 1;
  12847. EndingVbo &= ~(LONGLONG)(Scb->CompressionUnit - 1);
  12848. NtfsAddAllocation( IrpContext,
  12849. NULL,
  12850. Scb,
  12851. LlClustersFromBytes( Vcb,
  12852. Scb->Header.AllocationSize.QuadPart ),
  12853. LlClustersFromBytes( Vcb,
  12854. EndingVbo - Scb->Header.AllocationSize.QuadPart ),
  12855. FALSE,
  12856. NULL );
  12857. }
  12858. DebugTrace( 0, Dbg, ("Zeroing range from %I64x\n", StartingVbo) );
  12859. DebugTrace( 0, Dbg, ("to %I64x\n", (StartingVbo + ByteCount - 1)) );
  12860. //
  12861. // We can't synthesize partial sparse holes, since our caller may
  12862. // not have a key with which to encrypt a buffer full of zeroes.
  12863. // Therefore, we can't do this restore if the volume we're restoring
  12864. // to requires sparse holes to be bigger than the hole we're
  12865. // trying to restore now.
  12866. //
  12867. if (ByteCount < Scb->CompressionUnit) {
  12868. DebugTrace( 0, Dbg, ("Can't synthesize partial sparse hole\n") );
  12869. Status = STATUS_INVALID_PARAMETER;
  12870. leave;
  12871. }
  12872. //
  12873. // Copy StartingVbo in case ZeroRangeInStream modifies it.
  12874. // NtfsZeroRangeInStream uses the cleanupstructure so always
  12875. // return it back to its original value afterwards
  12876. //
  12877. FirstZero = StartingVbo;
  12878. Status = NtfsZeroRangeInStream( IrpContext,
  12879. FileObject,
  12880. Scb,
  12881. &FirstZero,
  12882. (StartingVbo + ByteCount - 1) );
  12883. ASSERT( (PFCB)IrpContext->CleanupStructure == Fcb );
  12884. if (!NT_SUCCESS( Status )) {
  12885. leave;
  12886. }
  12887. //
  12888. // Let's move the filesize up now, just like NtfsCommonWrite does in
  12889. // the other half of this if statement.
  12890. //
  12891. {
  12892. LONGLONG NewFileSize = StartingVbo + ByteCount;
  12893. DebugTrace( 0, Dbg, ("Adjusting sparse file size to %I64x\n", NewFileSize) );
  12894. Scb->Header.FileSize.QuadPart = NewFileSize;
  12895. NtfsWriteFileSizes( IrpContext, Scb, &NewFileSize, FALSE, TRUE, TRUE );
  12896. if (Scb->FileObject != NULL) {
  12897. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  12898. }
  12899. }
  12900. TotalBytesWritten += ByteCount;
  12901. }
  12902. StartingVbo += ByteCount;
  12903. }
  12904. DebugTrace( 0, Dbg, ("TotalBytesWritten %I64x\n", TotalBytesWritten) );
  12905. //
  12906. // Only adjust the filesizes if the write succeeded. If the write failed
  12907. // the IrpContext has been freed already. Note: startyingvbo must be <= original eof
  12908. //
  12909. if (NT_SUCCESS( Status ) &&
  12910. ((LONGLONG)BytesWithinFileSize != TotalBytesWritten ||
  12911. (LONGLONG)BytesWithinValidDataLength < TotalBytesWritten)) {
  12912. LONGLONG NewValidDataLength = OriginalStartingVbo + BytesWithinValidDataLength;
  12913. Scb->Header.FileSize.QuadPart = OriginalStartingVbo + BytesWithinFileSize;
  12914. if (NewValidDataLength < Scb->Header.ValidDataLength.QuadPart) {
  12915. Scb->Header.ValidDataLength.QuadPart = NewValidDataLength;
  12916. }
  12917. //
  12918. // WriteFileSizes will only move the VDL back since we set AdvanceOnly to False
  12919. //
  12920. ASSERT( IrpContext->CleanupStructure != NULL );
  12921. NtfsWriteFileSizes( IrpContext, Scb, &NewValidDataLength, FALSE, TRUE, TRUE );
  12922. //
  12923. // Readjust VDD - for non compressed files this is a noop since vdd is not updated for them
  12924. //
  12925. if (Scb->ValidDataToDisk > Scb->Header.ValidDataLength.QuadPart) {
  12926. Scb->ValidDataToDisk = Scb->Header.ValidDataLength.QuadPart;
  12927. }
  12928. if (Scb->FileObject != NULL) {
  12929. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  12930. }
  12931. }
  12932. } except( NtfsWriteRawExceptionFilter( IrpContext, GetExceptionInformation() ) ) {
  12933. Status = GetExceptionCode();
  12934. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted raising %08lx\n", Status) );
  12935. NtfsRaiseStatus( IrpContext,
  12936. ((FsRtlIsNtstatusExpected(Status) || !AccessingUserBuffer) ? Status : STATUS_INVALID_USER_BUFFER),
  12937. NULL,
  12938. NULL );
  12939. }
  12940. NtfsCompleteRequest( IrpContext, Irp, Status );
  12941. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted -> %08lx\n", Status) );
  12942. return Status;
  12943. }
  12944. //
  12945. // Local Support Routine
  12946. //
  12947. NTSTATUS
  12948. NtfsExtendVolume (
  12949. IN PIRP_CONTEXT IrpContext,
  12950. IN PIRP Irp
  12951. )
  12952. /*++
  12953. Routine Description:
  12954. This routine extends an Ntfs volume. We will take the number of sectors
  12955. passed to this routine and extend the volume provided that this will grow
  12956. the volume by at least one cluster.
  12957. Arguments:
  12958. Irp - Supplies the Irp to process
  12959. Return Value:
  12960. NTSTATUS - The return status for the operation
  12961. --*/
  12962. {
  12963. NTSTATUS Status = STATUS_SUCCESS;
  12964. PIO_STACK_LOCATION IrpSp;
  12965. TYPE_OF_OPEN TypeOfOpen;
  12966. PVCB Vcb;
  12967. PFCB Fcb;
  12968. PSCB Scb;
  12969. PCCB Ccb;
  12970. FILE_REFERENCE FileReference = { BOOT_FILE_NUMBER, 0, BOOT_FILE_NUMBER };
  12971. PSCB BootFileScb = NULL;
  12972. BOOLEAN RemovedBootFileFcb = FALSE;
  12973. BOOLEAN UnloadMcb = FALSE;
  12974. LONGLONG NewVolumeSize;
  12975. LONGLONG NewTotalClusters;
  12976. PVOID ZeroBuffer = NULL;
  12977. LONGLONG NewBitmapSize;
  12978. LONGLONG NewBitmapAllocation;
  12979. LONGLONG AddBytes;
  12980. LONGLONG AddClusters = 0;
  12981. LONGLONG PreviousBitmapAllocation;
  12982. LCN NewLcn;
  12983. LCN Lcn;
  12984. LONGLONG ClusterCount;
  12985. LONGLONG FileOffset;
  12986. LONGLONG BeyondBitsToModify;
  12987. LONGLONG NewSectors;
  12988. IO_STATUS_BLOCK Iosb;
  12989. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  12990. DISK_GEOMETRY DiskGeometry;
  12991. LONGLONG DiskBytes;
  12992. PBCB PrimaryBootBcb = NULL;
  12993. PBCB BackupBootBcb = NULL;
  12994. PPACKED_BOOT_SECTOR PrimaryBootSector;
  12995. PPACKED_BOOT_SECTOR BackupBootSector;
  12996. ASSERT_IRP_CONTEXT( IrpContext );
  12997. ASSERT_IRP( Irp );
  12998. PAGED_CODE();
  12999. DebugTrace( +1, Dbg, ("NtfsExtendVolume...\n") );
  13000. //
  13001. // Make sure the input parameters are valid.
  13002. //
  13003. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  13004. //
  13005. // The input buffer is a LONGLONG and it should not be zero.
  13006. //
  13007. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( LONGLONG )) {
  13008. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13009. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_INVALID_PARAMETER) );
  13010. return STATUS_INVALID_PARAMETER;
  13011. }
  13012. RtlCopyMemory( &NewSectors, Irp->AssociatedIrp.SystemBuffer, sizeof( LONGLONG ));
  13013. if (NewSectors <= 0) {
  13014. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13015. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_INVALID_PARAMETER) );
  13016. return STATUS_INVALID_PARAMETER;
  13017. }
  13018. //
  13019. // Extract and decode the file object, and only permit user volume opens
  13020. //
  13021. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  13022. IrpSp->FileObject,
  13023. &Vcb,
  13024. &Fcb,
  13025. &Scb,
  13026. &Ccb,
  13027. TRUE );
  13028. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13029. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13030. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  13031. return STATUS_ACCESS_DENIED;
  13032. }
  13033. //
  13034. // Readonly mount should be just that: read only.
  13035. //
  13036. if (NtfsIsVolumeReadOnly( Vcb )) {
  13037. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  13038. DebugTrace( -1, Dbg, ("SetCompression returning WRITE_PROTECTED\n") );
  13039. return STATUS_MEDIA_WRITE_PROTECTED;
  13040. }
  13041. //
  13042. // We don't want to rewind back to a different value than what we currently have
  13043. //
  13044. ASSERT( Vcb->PreviousTotalClusters == Vcb->TotalClusters );
  13045. //
  13046. // Lets set the Scb to the volume bitmap scb at this point. We no longer care about
  13047. // the volume Dasd Scb from here on.
  13048. //
  13049. Scb = NULL;
  13050. //
  13051. // Compute the new volume size. Don't forget to allow one sector for the backup
  13052. // boot sector.
  13053. //
  13054. NewVolumeSize = (NewSectors - 1) * Vcb->BytesPerSector;
  13055. NewTotalClusters = LlClustersFromBytesTruncate( Vcb, NewVolumeSize );
  13056. //
  13057. // Make sure the volume size didn't wrap and that we don't have more than 2^32 - 2 clusters.
  13058. // We make this 2^32 - 2 so that we can generate a cluster for the backup boot sector in
  13059. // order to write it.
  13060. //
  13061. if ((NewVolumeSize < NewSectors) ||
  13062. (NewTotalClusters > (0x100000000 - 2))) {
  13063. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13064. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_INVALID_PARAMETER) );
  13065. return STATUS_INVALID_PARAMETER;
  13066. }
  13067. //
  13068. // We hold the Vcb exclusively for this operation. Make sure the wait flag is
  13069. // set in the IrpContext.
  13070. //
  13071. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  13072. NtfsInitializeAttributeContext( &AttrContext );
  13073. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  13074. //
  13075. // Use a try-finally to facilitate cleanup.
  13076. //
  13077. try {
  13078. //
  13079. // Make sure the volume is mounted.
  13080. //
  13081. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  13082. Status = STATUS_VOLUME_DISMOUNTED;
  13083. leave;
  13084. }
  13085. //
  13086. // We only need the Mft and volume bitmap for this operation.
  13087. // Lets set the Scb to the volume bitmap scb at this point. We no longer care about
  13088. // the volume Dasd Scb from here on. We acquire it here solely to be able to
  13089. // update the size when we are done.
  13090. //
  13091. Scb = Vcb->BitmapScb;
  13092. NtfsAcquireExclusiveFcb( IrpContext, Vcb->VolumeDasdScb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  13093. NtfsAcquireExclusiveFcb( IrpContext, Vcb->MftScb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  13094. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  13095. NtfsAcquireExclusiveFcb( IrpContext, Scb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK | ACQUIRE_HOLD_BITMAP );
  13096. ASSERT( Scb->Fcb->ExclusiveFcbLinks.Flink != NULL );
  13097. //
  13098. // Make sure we are adding at least one cluster.
  13099. //
  13100. if ((Vcb->TotalClusters >= NewTotalClusters) &&
  13101. (NewTotalClusters >= 0)) {
  13102. Status = STATUS_INVALID_PARAMETER;
  13103. leave;
  13104. }
  13105. //
  13106. // Also check that the driver supports a drive of this size.
  13107. // Total size in use == NewVolumeSize + the last copy of the boot sector
  13108. // NewVolumeSize is already biased for the boot sector copy
  13109. //
  13110. NtfsGetDiskGeometry( IrpContext, Vcb->TargetDeviceObject, &DiskGeometry, &DiskBytes );
  13111. if ((Vcb->BytesPerSector != DiskGeometry.BytesPerSector) ||
  13112. (NewVolumeSize + Vcb->BytesPerSector > DiskBytes)) {
  13113. Status = STATUS_INVALID_PARAMETER;
  13114. leave;
  13115. }
  13116. //
  13117. // Go ahead and create an Fcb and Scb for the BootFile.
  13118. //
  13119. BootFileScb = NtfsCreatePrerestartScb( IrpContext, Vcb, &FileReference, $DATA, NULL, 0 );
  13120. //
  13121. // Acquire this Fcb exclusively but don't put it our exclusive lists or snapshot it.
  13122. //
  13123. NtfsAcquireResourceExclusive( IrpContext, BootFileScb, TRUE );
  13124. if (!FlagOn( BootFileScb->ScbState, SCB_STATE_FILE_SIZE_LOADED )) {
  13125. NtfsUpdateScbFromAttribute( IrpContext, BootFileScb, NULL );
  13126. }
  13127. //
  13128. // Lets flush and purge the volume bitmap. We want to make sure there are no
  13129. // partial pages at the end of the bitmap.
  13130. //
  13131. CcFlushCache( &Scb->NonpagedScb->SegmentObject,
  13132. NULL,
  13133. 0,
  13134. &Iosb );
  13135. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  13136. if (!CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject,
  13137. NULL,
  13138. 0,
  13139. FALSE )) {
  13140. NtfsRaiseStatus( IrpContext, STATUS_UNABLE_TO_DELETE_SECTION, NULL, NULL );
  13141. }
  13142. //
  13143. // We want to snapshot the volume bitmap.
  13144. //
  13145. NtfsSnapshotScb( IrpContext, Scb );
  13146. //
  13147. // Unload the Mcb in case of errors.
  13148. //
  13149. ASSERT( Scb->ScbSnapshot != NULL );
  13150. Scb->ScbSnapshot->LowestModifiedVcn = 0;
  13151. Scb->ScbSnapshot->HighestModifiedVcn = MAXLONGLONG;
  13152. //
  13153. // Round the bitmap size up to an 8 byte boundary.
  13154. //
  13155. NewBitmapSize = Int64ShraMod32( NewTotalClusters + 7, 3 ) + 7;
  13156. NewBitmapSize &= ~(7);
  13157. NewBitmapAllocation = LlBytesFromClusters( Vcb, LlClustersFromBytes( Vcb, NewBitmapSize ));
  13158. PreviousBitmapAllocation = Scb->Header.AllocationSize.QuadPart;
  13159. //
  13160. // Store the new total clusters in the Vcb now. Several of our routines
  13161. // check that a cluster being used lies within the volume. We will temporarily round
  13162. // this up to an 8 byte boundary so we can set any unused bits in the tail of
  13163. // the bitmap.
  13164. //
  13165. Vcb->TotalClusters = Int64ShllMod32( NewBitmapSize, 3 );
  13166. //
  13167. // If we are growing the allocation for the volume bitmap then
  13168. // we want to make sure the entire new clusters are zeroed and
  13169. // then added to the volume bitmap.
  13170. //
  13171. if (NewBitmapAllocation > PreviousBitmapAllocation) {
  13172. AddBytes = NewBitmapAllocation - PreviousBitmapAllocation;
  13173. AddClusters = LlClustersFromBytesTruncate( Vcb, AddBytes );
  13174. ZeroBuffer = NtfsAllocatePool( NonPagedPoolCacheAligned,
  13175. (ULONG) ROUND_TO_PAGES( (ULONG) AddBytes ));
  13176. RtlZeroMemory( ZeroBuffer, (ULONG) AddBytes );
  13177. //
  13178. // Add the entry to Mcb. We would prefer not to overwrite the existing
  13179. // backup boot sector if possible.
  13180. //
  13181. NewLcn = Vcb->PreviousTotalClusters + 1;
  13182. if (NewLcn + AddClusters > NewTotalClusters) {
  13183. NewLcn -= 1;
  13184. }
  13185. NtfsAddNtfsMcbEntry( &Scb->Mcb,
  13186. LlClustersFromBytesTruncate( Vcb, PreviousBitmapAllocation ),
  13187. NewLcn,
  13188. AddClusters,
  13189. FALSE );
  13190. //
  13191. // We may need to unload the Mcb by hand if we get a failure before the first log record.
  13192. //
  13193. UnloadMcb = TRUE;
  13194. //
  13195. // Now write zeroes into these clusters.
  13196. //
  13197. NtfsWriteClusters( IrpContext,
  13198. Vcb,
  13199. Scb,
  13200. PreviousBitmapAllocation,
  13201. ZeroBuffer,
  13202. (ULONG) AddClusters );
  13203. //
  13204. // Go ahead and write the new mapping pairs for the larger allocation.
  13205. //
  13206. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &AttrContext );
  13207. NtfsAddAttributeAllocation( IrpContext, Scb, &AttrContext, NULL, NULL );
  13208. //
  13209. // Our transaction handling will deal with the Mcb now.
  13210. //
  13211. UnloadMcb = FALSE;
  13212. //
  13213. // Now tell the cache manager about the larger section.
  13214. //
  13215. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  13216. }
  13217. //
  13218. // We now have allocated enough space for the new clusters. The next step is to mark them
  13219. // allocated in the new volume bitmap. Start by updating the file size in the Scb and
  13220. // on disk for the new size. We can make the whole new range valid. We will explicitly
  13221. // update any bytes that may still be incorrect on disk.
  13222. //
  13223. Scb->Header.ValidDataLength.QuadPart =
  13224. Scb->Header.FileSize.QuadPart = NewBitmapSize;
  13225. Scb->TotalAllocated = Scb->Header.AllocationSize.QuadPart;
  13226. NtfsWriteFileSizes( IrpContext, Scb, &NewBitmapSize, TRUE, TRUE, TRUE );
  13227. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  13228. //
  13229. // The file size is now correct in the Scb and on disk. The next thing to do is
  13230. // to zero out any bits between the previous end of the bitmap and the end of the previous
  13231. // allocation (or the current total clusters, whichever is smaller).
  13232. //
  13233. BeyondBitsToModify = Int64ShllMod32( PreviousBitmapAllocation, 3 );
  13234. if (Vcb->TotalClusters < BeyondBitsToModify) {
  13235. BeyondBitsToModify = Vcb->TotalClusters;
  13236. }
  13237. if (BeyondBitsToModify != Vcb->PreviousTotalClusters) {
  13238. NtfsModifyBitsInBitmap( IrpContext,
  13239. Vcb,
  13240. Vcb->PreviousTotalClusters,
  13241. BeyondBitsToModify,
  13242. ClearBitsInNonresidentBitMap,
  13243. SetBitsInNonresidentBitMap );
  13244. }
  13245. //
  13246. // Now we need to set bits for all of the new clusters which are part of
  13247. // the extension of the volume bitmap.
  13248. //
  13249. if (AddClusters != 0) {
  13250. NtfsModifyBitsInBitmap( IrpContext,
  13251. Vcb,
  13252. NewLcn,
  13253. NewLcn + AddClusters,
  13254. SetBitsInNonresidentBitMap,
  13255. ClearBitsInNonresidentBitMap );
  13256. }
  13257. //
  13258. // Finally we need to set all of the bits in the new bitmap which lie beyond
  13259. // the end of the actual on-disk clusters.
  13260. //
  13261. BeyondBitsToModify = Int64ShllMod32( NewBitmapSize, 3 );
  13262. if (BeyondBitsToModify != NewTotalClusters) {
  13263. NtfsModifyBitsInBitmap( IrpContext,
  13264. Vcb,
  13265. NewTotalClusters,
  13266. BeyondBitsToModify,
  13267. SetBitsInNonresidentBitMap,
  13268. Noop );
  13269. }
  13270. //
  13271. // Now set to the exact clusters on the disk.
  13272. //
  13273. Vcb->TotalClusters = NewTotalClusters;
  13274. //
  13275. // Now it is time to modify the boot sectors for the volume. We want to:
  13276. //
  13277. // o Remove the allocation for the n/2 boot sector if present (3.51 format)
  13278. // o Copy the current boot sector to the end of the volume (with the new sector count)
  13279. // o Update the primary boot sector at the beginning of the volume.
  13280. //
  13281. // Start by purging the stream.
  13282. //
  13283. NtfsCreateInternalAttributeStream( IrpContext, BootFileScb, TRUE, NULL );
  13284. //
  13285. // Don't let the lazy writer touch this stream.
  13286. //
  13287. CcSetAdditionalCacheAttributes( BootFileScb->FileObject, TRUE, TRUE );
  13288. //
  13289. // Now look to see if the file has more than one run. If so we want to truncate
  13290. // it to the end of the first run.
  13291. //
  13292. if (NtfsLookupAllocation( IrpContext, BootFileScb, 0, &Lcn, &ClusterCount, NULL, NULL )) {
  13293. NtfsDeleteAllocation( IrpContext,
  13294. BootFileScb->FileObject,
  13295. BootFileScb,
  13296. ClusterCount,
  13297. MAXLONGLONG,
  13298. TRUE,
  13299. FALSE );
  13300. }
  13301. //
  13302. // Now create mapping for this stream where the first page (or cluster) will be used for the
  13303. // primary boot sector and we will have the additional sectors to be able to write to the
  13304. // last sector.
  13305. //
  13306. BootFileScb->Header.FileSize.QuadPart = PAGE_SIZE;
  13307. if (PAGE_SIZE < Vcb->BytesPerCluster) {
  13308. BootFileScb->Header.FileSize.QuadPart = Vcb->BytesPerCluster;
  13309. }
  13310. BootFileScb->Header.FileSize.QuadPart += (NewVolumeSize + Vcb->BytesPerSector) - LlBytesFromClusters( Vcb, NewTotalClusters );
  13311. BootFileScb->Header.ValidDataLength.QuadPart = BootFileScb->Header.FileSize.QuadPart;
  13312. BootFileScb->Header.AllocationSize.QuadPart = LlBytesFromClusters( Vcb, LlClustersFromBytes( Vcb, BootFileScb->Header.FileSize.QuadPart ));
  13313. CcSetFileSizes( BootFileScb->FileObject, (PCC_FILE_SIZES) &BootFileScb->Header.AllocationSize );
  13314. //
  13315. // Go ahead purge any existing data and empty the Mcb.
  13316. //
  13317. CcPurgeCacheSection( &BootFileScb->NonpagedScb->SegmentObject,
  13318. NULL,
  13319. 0,
  13320. FALSE );
  13321. NtfsUnloadNtfsMcbRange( &BootFileScb->Mcb,
  13322. 0,
  13323. MAXLONGLONG,
  13324. FALSE,
  13325. FALSE );
  13326. //
  13327. // Lets create the Mcb by hand for this.
  13328. //
  13329. NtfsAddNtfsMcbEntry( &BootFileScb->Mcb,
  13330. 0,
  13331. 0,
  13332. LlClustersFromBytes( Vcb, PAGE_SIZE ),
  13333. FALSE );
  13334. NtfsAddNtfsMcbEntry( &BootFileScb->Mcb,
  13335. LlClustersFromBytes( Vcb, PAGE_SIZE ),
  13336. NewTotalClusters,
  13337. 1,
  13338. FALSE );
  13339. //
  13340. // Now lets pin the two boot sectors.
  13341. //
  13342. FileOffset = 0;
  13343. NtfsPinStream( IrpContext,
  13344. BootFileScb,
  13345. 0,
  13346. Vcb->BytesPerSector,
  13347. &PrimaryBootBcb,
  13348. &PrimaryBootSector );
  13349. FileOffset = BootFileScb->Header.FileSize.QuadPart - Vcb->BytesPerSector;
  13350. NtfsPinStream( IrpContext,
  13351. BootFileScb,
  13352. FileOffset,
  13353. Vcb->BytesPerSector,
  13354. &BackupBootBcb,
  13355. &BackupBootSector );
  13356. //
  13357. // Remember thge new sector count is 1 less than what we were given
  13358. //
  13359. NewSectors -= 1;
  13360. //
  13361. // Copy the primary boot sector to the backup location.
  13362. //
  13363. RtlCopyMemory( BackupBootSector, PrimaryBootSector, Vcb->BytesPerSector );
  13364. //
  13365. // Now copy the sector count into the boot sectors and flush to disk.
  13366. // Use RtlCopy to avoid alignment faults.
  13367. //
  13368. RtlCopyMemory( &BackupBootSector->NumberSectors, &NewSectors, sizeof( LONGLONG ));
  13369. CcSetDirtyPinnedData( BackupBootBcb, NULL );
  13370. CcFlushCache( &BootFileScb->NonpagedScb->SegmentObject,
  13371. (PLARGE_INTEGER) &FileOffset,
  13372. Vcb->BytesPerSector,
  13373. &Iosb );
  13374. //
  13375. // Make sure the flush worked.
  13376. //
  13377. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  13378. //
  13379. // Now do the primary.
  13380. //
  13381. FileOffset = 0;
  13382. RtlCopyMemory( &PrimaryBootSector->NumberSectors, &NewSectors, sizeof( LONGLONG ));
  13383. CcSetDirtyPinnedData( PrimaryBootBcb, NULL );
  13384. CcFlushCache( &BootFileScb->NonpagedScb->SegmentObject,
  13385. (PLARGE_INTEGER) &FileOffset,
  13386. Vcb->BytesPerSector,
  13387. &Iosb );
  13388. //
  13389. // Make sure the flush worked.
  13390. //
  13391. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  13392. //
  13393. // Let's get rid of the pages for this stream now.
  13394. //
  13395. NtfsUnpinBcb( IrpContext, &PrimaryBootBcb );
  13396. NtfsUnpinBcb( IrpContext, &BackupBootBcb );
  13397. CcPurgeCacheSection( &BootFileScb->NonpagedScb->SegmentObject,
  13398. NULL,
  13399. 0,
  13400. FALSE );
  13401. NtfsCleanupTransaction( IrpContext, Status, TRUE );
  13402. //
  13403. // Commit the transaction now so we can update some of the in-memory structures.
  13404. //
  13405. NtfsCheckpointCurrentTransaction( IrpContext );
  13406. LfsFlushToLsn( Vcb->LogHandle, LiMax );
  13407. //
  13408. // We know this request has succeeded. Go ahead and remember the new total cluster count
  13409. // and sector count.
  13410. //
  13411. Vcb->PreviousTotalClusters = Vcb->TotalClusters;
  13412. Vcb->NumberSectors = NewSectors;
  13413. //
  13414. // Also update the volume dasd size.
  13415. //
  13416. Vcb->VolumeDasdScb->Header.ValidDataLength.QuadPart =
  13417. Vcb->VolumeDasdScb->Header.FileSize.QuadPart =
  13418. Vcb->VolumeDasdScb->Header.AllocationSize.QuadPart = LlBytesFromClusters( Vcb, Vcb->TotalClusters );
  13419. //
  13420. // Set the flag in the Vcb to cause a rescan of the bitmap for free clusters. This will also
  13421. // let the bitmap package use the larger blocks of available disk space.
  13422. //
  13423. SetFlag( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS );
  13424. } finally {
  13425. DebugUnwind( NtfsExtendVolume );
  13426. NtfsUnpinBcb( IrpContext, &PrimaryBootBcb );
  13427. NtfsUnpinBcb( IrpContext, &BackupBootBcb );
  13428. //
  13429. // Remove the boot file Fcb if we created it.
  13430. //
  13431. if (BootFileScb != NULL) {
  13432. //
  13433. // Let's know the sizes to zero and get rid of the pages.
  13434. //
  13435. BootFileScb->Header.AllocationSize.QuadPart =
  13436. BootFileScb->Header.FileSize.QuadPart =
  13437. BootFileScb->Header.ValidDataLength.QuadPart = 0;
  13438. ClearFlag( BootFileScb->ScbState, SCB_STATE_FILE_SIZE_LOADED );
  13439. NtfsUnloadNtfsMcbRange( &BootFileScb->Mcb,
  13440. 0,
  13441. MAXLONGLONG,
  13442. FALSE,
  13443. FALSE );
  13444. if (BootFileScb->FileObject != NULL) {
  13445. //
  13446. // Deleting the internal attribute stream should automatically
  13447. // trigger teardown since its the last ref count
  13448. //
  13449. CcSetFileSizes( BootFileScb->FileObject, (PCC_FILE_SIZES) &BootFileScb->Header.AllocationSize );
  13450. NtfsIncrementCloseCounts( BootFileScb, TRUE, FALSE );
  13451. NtfsDeleteInternalAttributeStream( BootFileScb, TRUE, FALSE );
  13452. NtfsDecrementCloseCounts( IrpContext, BootFileScb, NULL, TRUE, FALSE, TRUE );
  13453. }
  13454. NtfsTeardownStructures( IrpContext,
  13455. BootFileScb->Fcb,
  13456. NULL,
  13457. FALSE,
  13458. 0,
  13459. &RemovedBootFileFcb );
  13460. if (!RemovedBootFileFcb) {
  13461. NtfsReleaseResource( IrpContext, BootFileScb );
  13462. }
  13463. }
  13464. if (UnloadMcb) {
  13465. NtfsUnloadNtfsMcbRange( &Scb->Mcb,
  13466. 0,
  13467. MAXLONGLONG,
  13468. FALSE,
  13469. FALSE );
  13470. }
  13471. //
  13472. // Release the file resources if we hold them.
  13473. //
  13474. if (Scb != NULL) {
  13475. NtfsReleaseFcb( IrpContext, Scb->Fcb );
  13476. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  13477. NtfsReleaseFcb( IrpContext, Vcb->MftScb->Fcb );
  13478. NtfsReleaseFcb( IrpContext, Vcb->VolumeDasdScb->Fcb );
  13479. }
  13480. NtfsReleaseVcb( IrpContext, Vcb );
  13481. if (ZeroBuffer) { NtfsFreePool( ZeroBuffer ); }
  13482. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  13483. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", Status) );
  13484. }
  13485. NtfsCompleteRequest( IrpContext, Irp, Status );
  13486. return Status;
  13487. }
  13488. //
  13489. // Local support routine
  13490. //
  13491. NTSTATUS
  13492. NtfsMarkHandle (
  13493. IN PIRP_CONTEXT IrpContext,
  13494. IN PIRP Irp
  13495. )
  13496. /*++
  13497. Routine Description:
  13498. This routine is used to attach special properties to a user handle.
  13499. Arguments:
  13500. Irp - Supplies the Irp to process
  13501. Return Value:
  13502. NTSTATUS - The return status for the operation
  13503. --*/
  13504. {
  13505. NTSTATUS Status = STATUS_SUCCESS;
  13506. PIO_STACK_LOCATION IrpSp;
  13507. PMARK_HANDLE_INFO HandleInfo;
  13508. TYPE_OF_OPEN TypeOfOpen;
  13509. PVCB Vcb;
  13510. PFILE_OBJECT DasdFileObject;
  13511. PFCB DasdFcb, Fcb;
  13512. PSCB DasdScb, Scb;
  13513. PCCB DasdCcb, Ccb;
  13514. BOOLEAN ReleaseScb = FALSE;
  13515. #if defined(_WIN64)
  13516. MARK_HANDLE_INFO LocalMarkHandleInfo;
  13517. #endif
  13518. extern POBJECT_TYPE *IoFileObjectType;
  13519. PAGED_CODE();
  13520. //
  13521. // Always make this synchronous.
  13522. //
  13523. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  13524. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  13525. //
  13526. // Get the current Irp stack location and save some references.
  13527. //
  13528. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  13529. //
  13530. // Extract and decode the file object and check for type of open.
  13531. //
  13532. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  13533. //
  13534. // We currently support this call for files and directories only.
  13535. //
  13536. if ((TypeOfOpen != UserFileOpen) &&
  13537. (TypeOfOpen != UserDirectoryOpen) &&
  13538. (TypeOfOpen != UserViewIndexOpen)) {
  13539. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13540. return STATUS_INVALID_PARAMETER;
  13541. }
  13542. #if defined(_WIN64)
  13543. //
  13544. // Win32/64 thunking code
  13545. //
  13546. if (IoIs32bitProcess( Irp )) {
  13547. PMARK_HANDLE_INFO32 MarkHandle32;
  13548. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO32 )) {
  13549. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13550. return STATUS_BUFFER_TOO_SMALL;
  13551. }
  13552. MarkHandle32 = (PMARK_HANDLE_INFO32) Irp->AssociatedIrp.SystemBuffer;
  13553. LocalMarkHandleInfo.HandleInfo = MarkHandle32->HandleInfo;
  13554. LocalMarkHandleInfo.UsnSourceInfo = MarkHandle32->UsnSourceInfo;
  13555. LocalMarkHandleInfo.VolumeHandle = (HANDLE)(ULONG_PTR)(LONG) MarkHandle32->VolumeHandle;
  13556. HandleInfo = &LocalMarkHandleInfo;
  13557. } else {
  13558. #endif
  13559. //
  13560. // Get the input buffer pointer and check its length.
  13561. //
  13562. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO )) {
  13563. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13564. return STATUS_BUFFER_TOO_SMALL;
  13565. }
  13566. HandleInfo = (PMARK_HANDLE_INFO) Irp->AssociatedIrp.SystemBuffer;
  13567. #if defined(_WIN64)
  13568. }
  13569. #endif
  13570. //
  13571. // Check that only legal bits are being set. We currently only support certain bits in the
  13572. // UsnSource reasons.
  13573. //
  13574. if (FlagOn( HandleInfo->HandleInfo, ~(MARK_HANDLE_PROTECT_CLUSTERS)) ||
  13575. FlagOn( HandleInfo->UsnSourceInfo,
  13576. ~(USN_SOURCE_DATA_MANAGEMENT |
  13577. USN_SOURCE_AUXILIARY_DATA |
  13578. USN_SOURCE_REPLICATION_MANAGEMENT) )) {
  13579. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13580. return STATUS_INVALID_PARAMETER;
  13581. }
  13582. //
  13583. // Check that the user has a valid volume handle or the manage volume
  13584. // privilege or is a kerbel mode caller
  13585. //
  13586. if ((Irp->RequestorMode != KernelMode) && !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13587. if (HandleInfo->VolumeHandle == 0) {
  13588. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13589. return STATUS_ACCESS_DENIED;
  13590. }
  13591. Status = ObReferenceObjectByHandle( HandleInfo->VolumeHandle,
  13592. 0,
  13593. *IoFileObjectType,
  13594. Irp->RequestorMode,
  13595. &DasdFileObject,
  13596. NULL );
  13597. if (!NT_SUCCESS(Status)) {
  13598. NtfsCompleteRequest( IrpContext, Irp, Status );
  13599. return Status;
  13600. }
  13601. // Check that this file object is opened on the same volume as the
  13602. // handle used to call this routine.
  13603. //
  13604. if (DasdFileObject->Vpb != Vcb->Vpb) {
  13605. ObDereferenceObject( DasdFileObject );
  13606. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13607. return STATUS_INVALID_PARAMETER;
  13608. }
  13609. //
  13610. // Now decode this FileObject and verify it is a volume handle.
  13611. // We don't care to raise on dismounts here because
  13612. // we check for that further down anyway. So send FALSE.
  13613. //
  13614. TypeOfOpen = NtfsDecodeFileObject( IrpContext, DasdFileObject, &Vcb, &DasdFcb, &DasdScb, &DasdCcb, FALSE );
  13615. ObDereferenceObject( DasdFileObject );
  13616. if ((DasdCcb == NULL) || !FlagOn( DasdCcb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13617. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13618. return STATUS_ACCESS_DENIED;
  13619. }
  13620. }
  13621. //
  13622. // Acquire the paging io resource exclusively if present.
  13623. //
  13624. if (Scb->Header.PagingIoResource != NULL) {
  13625. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  13626. }
  13627. try {
  13628. //
  13629. // Acquire the file exclusively to serialize changes to the Ccb.
  13630. //
  13631. NtfsAcquireExclusiveScb( IrpContext, Scb );
  13632. ReleaseScb = TRUE;
  13633. //
  13634. // Verify the volume is still mounted.
  13635. //
  13636. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  13637. Status = STATUS_VOLUME_DISMOUNTED;
  13638. leave;
  13639. }
  13640. //
  13641. // Set these new bits in the Ccb.
  13642. //
  13643. if (FlagOn( HandleInfo->HandleInfo, MARK_HANDLE_PROTECT_CLUSTERS )) {
  13644. //
  13645. // We can't deny defrag if anyone else already has
  13646. //
  13647. if (FlagOn( Scb->ScbPersist, SCB_PERSIST_DENY_DEFRAG )) {
  13648. Status = STATUS_ACCESS_DENIED;
  13649. leave;
  13650. }
  13651. SetFlag( Ccb->Flags, CCB_FLAG_DENY_DEFRAG );
  13652. SetFlag( Scb->ScbPersist, SCB_PERSIST_DENY_DEFRAG );
  13653. }
  13654. SetFlag( Ccb->UsnSourceInfo, HandleInfo->UsnSourceInfo );
  13655. } finally {
  13656. DebugUnwind( NtfsMarkHandle );
  13657. //
  13658. // Release the Scb.
  13659. //
  13660. if (ReleaseScb) {
  13661. NtfsReleaseScb( IrpContext, Scb );
  13662. }
  13663. if (Scb->Header.PagingIoResource != NULL) {
  13664. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  13665. }
  13666. }
  13667. NtfsCompleteRequest( IrpContext, Irp, Status );
  13668. return Status;
  13669. }
  13670. //
  13671. // Local Support routine
  13672. //
  13673. NTSTATUS
  13674. NtfsPrefetchFile (
  13675. IN PIRP_CONTEXT IrpContext,
  13676. IN PIRP Irp
  13677. )
  13678. /*++
  13679. Routine Description:
  13680. This routine is called to perform the requested prefetch on a system file.
  13681. Arguments:
  13682. Irp - Supplies the Irp to process
  13683. Return Value:
  13684. NTSTATUS - The return status for the operation
  13685. --*/
  13686. {
  13687. NTSTATUS Status = STATUS_SUCCESS;
  13688. NTSTATUS MmStatus = STATUS_SUCCESS;
  13689. PIO_STACK_LOCATION IrpSp;
  13690. PFILE_PREFETCH FilePrefetch;
  13691. PREAD_LIST ReadList = NULL;
  13692. PULONGLONG NextFileId;
  13693. ULONG Count;
  13694. ULONGLONG FileOffset;
  13695. TYPE_OF_OPEN TypeOfOpen;
  13696. PVCB Vcb;
  13697. PFCB Fcb;
  13698. PSCB Scb;
  13699. PCCB Ccb;
  13700. BOOLEAN ReleaseMft = FALSE;
  13701. PAGED_CODE();
  13702. //
  13703. // Always make this synchronous. There isn't much advantage to posting this work to a
  13704. // worker thread.
  13705. //
  13706. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  13707. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  13708. //
  13709. // Get the current Irp stack location and save some references.
  13710. //
  13711. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  13712. //
  13713. // Extract and decode the file object and check for type of open.
  13714. //
  13715. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  13716. //
  13717. // We currently support this call only for the Mft (accessed through a volume handle).
  13718. //
  13719. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13720. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13721. return STATUS_ACCESS_DENIED;
  13722. }
  13723. //
  13724. // Get the input buffer pointer and check its length. It needs to be sufficient to
  13725. // contain the fixed portion of structure plus whatever optional fields passed in.
  13726. //
  13727. FilePrefetch = (PFILE_PREFETCH) Irp->AssociatedIrp.SystemBuffer;
  13728. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < FIELD_OFFSET( FILE_PREFETCH, Prefetch )) {
  13729. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13730. return STATUS_BUFFER_TOO_SMALL;
  13731. }
  13732. //
  13733. // Make sure the type and cound fields are valid.
  13734. //
  13735. if ((FilePrefetch->Type != FILE_PREFETCH_TYPE_FOR_CREATE) ||
  13736. (FilePrefetch->Count > 0x300)) {
  13737. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13738. return STATUS_INVALID_PARAMETER;
  13739. }
  13740. //
  13741. // Finally verify that the variable length data is of valid length.
  13742. //
  13743. if (IrpSp->Parameters.FileSystemControl.InputBufferLength <
  13744. (FIELD_OFFSET( FILE_PREFETCH, Prefetch ) + (sizeof( ULONGLONG ) * FilePrefetch->Count))) {
  13745. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13746. return STATUS_BUFFER_TOO_SMALL;
  13747. }
  13748. //
  13749. // If the user didn't specify any entries we are done.
  13750. //
  13751. if (FilePrefetch->Count == 0) {
  13752. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  13753. return STATUS_SUCCESS;
  13754. }
  13755. //
  13756. // Acquire the volume dasd file shared to do this.
  13757. //
  13758. NtfsAcquireSharedScb( IrpContext, Scb );
  13759. try {
  13760. //
  13761. // Verify the volume is still mounted.
  13762. //
  13763. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  13764. Status = STATUS_VOLUME_DISMOUNTED;
  13765. leave;
  13766. }
  13767. //
  13768. // Allocate the necessary pool to pass to MM.
  13769. //
  13770. ReadList = NtfsAllocatePool( PagedPool,
  13771. FIELD_OFFSET( READ_LIST, List ) + (FilePrefetch->Count * sizeof( FILE_SEGMENT_ELEMENT )));
  13772. //
  13773. // Initialize the read list.
  13774. //
  13775. ReadList->FileObject = Vcb->MftScb->FileObject;
  13776. ASSERT( Vcb->MftScb->FileObject != NULL );
  13777. ReadList->NumberOfEntries = 0;
  13778. ReadList->IsImage = FALSE;
  13779. //
  13780. // Walk through and load the list. We won't bother to check sequence numbers
  13781. // as they don't really change the correctness of this call. We do check for the
  13782. // valid length of the Mft though.
  13783. //
  13784. NtfsAcquireSharedScb( IrpContext, Vcb->MftScb );
  13785. ReleaseMft = TRUE;
  13786. NextFileId = &FilePrefetch->Prefetch[0];
  13787. Count = FilePrefetch->Count;
  13788. while (Count > 0) {
  13789. FileOffset = NtfsFullSegmentNumber( NextFileId );
  13790. FileOffset = LlBytesFromFileRecords( Vcb, FileOffset );
  13791. //
  13792. // Round down to page boundary. This will reduce the number of entries
  13793. // passed to MM.
  13794. //
  13795. ((PLARGE_INTEGER) &FileOffset)->LowPart &= ~(PAGE_SIZE - 1);
  13796. //
  13797. // Check if we are beyond the end of the Mft. Treat this as a ULONGLONG
  13798. // so we can catch the case where the ID generates a negative number.
  13799. //
  13800. if (FileOffset >= (ULONGLONG) Vcb->MftScb->Header.ValidDataLength.QuadPart) {
  13801. Status = STATUS_END_OF_FILE;
  13802. //
  13803. // If not then add to the buffer to pass to mm.
  13804. //
  13805. } else {
  13806. ULONG Index;
  13807. //
  13808. // Position ourselves in the output array. Look in reverse
  13809. // order in case our caller has already sorted this.
  13810. //
  13811. Index = ReadList->NumberOfEntries;
  13812. while (Index != 0) {
  13813. //
  13814. // If the prior entry is less than the current entry we are done.
  13815. //
  13816. if (ReadList->List[Index - 1].Alignment < FileOffset) {
  13817. break;
  13818. }
  13819. //
  13820. // If the prior entry equals the current entry then skip it.
  13821. //
  13822. if (ReadList->List[Index - 1].Alignment == FileOffset) {
  13823. Index = MAXULONG;
  13824. break;
  13825. }
  13826. //
  13827. // Move backwards to the previous entry.
  13828. //
  13829. Index -= 1;
  13830. }
  13831. //
  13832. // Index now points to the insert point, except if MAXULONG. Insert the entry
  13833. // and shift any existing entries necessary if we are doing the insert.
  13834. //
  13835. if (Index != MAXULONG) {
  13836. if (Index != ReadList->NumberOfEntries) {
  13837. RtlMoveMemory( &ReadList->List[Index + 1],
  13838. &ReadList->List[Index],
  13839. sizeof( LONGLONG ) * (ReadList->NumberOfEntries - Index) );
  13840. }
  13841. ReadList->NumberOfEntries += 1;
  13842. ReadList->List[Index].Alignment = FileOffset;
  13843. }
  13844. }
  13845. //
  13846. // Move to the next entry.
  13847. //
  13848. Count -= 1;
  13849. NextFileId += 1;
  13850. }
  13851. //
  13852. // We're done with the Mft. If we ever support shrinking the Mft we will have to close
  13853. // the hole here.
  13854. //
  13855. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  13856. ReleaseMft = FALSE;
  13857. //
  13858. // Now call mm to do the IO.
  13859. //
  13860. if (ReadList->NumberOfEntries != 0) {
  13861. MmStatus = MmPrefetchPages( 1, &ReadList );
  13862. //
  13863. // Use the Mm status if we don't already have one.
  13864. //
  13865. if (Status == STATUS_SUCCESS) {
  13866. Status = MmStatus;
  13867. }
  13868. }
  13869. } finally {
  13870. DebugUnwind( NtfsPrefetchFile );
  13871. //
  13872. // Free the read list if allocated.
  13873. //
  13874. if (ReadList != NULL) {
  13875. NtfsFreePool( ReadList );
  13876. }
  13877. //
  13878. // Release any Scb acquired.
  13879. //
  13880. if (ReleaseMft) {
  13881. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  13882. }
  13883. NtfsReleaseScb( IrpContext, Scb );
  13884. }
  13885. NtfsCompleteRequest( IrpContext, Irp, Status );
  13886. return Status;
  13887. }
  13888. //
  13889. // Local Support routine
  13890. //
  13891. LONG
  13892. NtfsFsctrlExceptionFilter (
  13893. IN PIRP_CONTEXT IrpContext,
  13894. IN PEXCEPTION_POINTERS ExceptionPointer,
  13895. IN BOOLEAN AccessingUserData,
  13896. OUT PNTSTATUS Status
  13897. )
  13898. /*++
  13899. Routine Description:
  13900. Generic Exception filter for errors during fsctrl processing. Raise invalid user buffer
  13901. directly or let it filter on to the top level try-except
  13902. Arguments:
  13903. IrpContext - IrpContext
  13904. ExceptionPointer - Pointer to the exception context.
  13905. AccessingUserData - if false always let the exception filter up
  13906. Status - Address to store the error status.
  13907. Return Value:
  13908. Exception status - EXCEPTION_CONTINUE_SEARCH if we want to raise to another handler,
  13909. EXCEPTION_EXECUTE_HANDLER if we plan to proceed on.
  13910. --*/
  13911. {
  13912. *Status = ExceptionPointer->ExceptionRecord->ExceptionCode;
  13913. if (!FsRtlIsNtstatusExpected( *Status ) && AccessingUserData) {
  13914. NtfsMinimumExceptionProcessing( IrpContext );
  13915. return EXCEPTION_EXECUTE_HANDLER;
  13916. } else {
  13917. return EXCEPTION_CONTINUE_SEARCH;
  13918. }
  13919. }
  13920. #ifdef SYSCACHE_DEBUG
  13921. //
  13922. // Local support routine
  13923. //
  13924. VOID
  13925. NtfsInitializeSyscacheLogFile (
  13926. IN PIRP_CONTEXT IrpContext,
  13927. IN PVCB Vcb
  13928. )
  13929. /*++
  13930. Routine Description:
  13931. This routine creates the syscache logfile in the root directory.
  13932. Arguments:
  13933. Vcb - Pointer to the Vcb for the volume
  13934. Return Value:
  13935. None.
  13936. --*/
  13937. {
  13938. UNICODE_STRING AttrName;
  13939. struct {
  13940. FILE_NAME FileName;
  13941. WCHAR FileNameChars[10];
  13942. } FileNameAttr;
  13943. FILE_REFERENCE FileReference;
  13944. LONGLONG FileRecordOffset;
  13945. PINDEX_ENTRY IndexEntry;
  13946. PBCB FileRecordBcb = NULL;
  13947. PBCB IndexEntryBcb = NULL;
  13948. PBCB ParentSecurityBcb = NULL;
  13949. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  13950. UCHAR FileNameFlags;
  13951. BOOLEAN FoundEntry;
  13952. PFCB Fcb = NULL;
  13953. BOOLEAN AcquiredFcbTable = FALSE;
  13954. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  13955. ULONG DesiredAccess = GENERIC_READ | GENERIC_WRITE;
  13956. NTSTATUS Status = STATUS_SUCCESS;
  13957. NtfsAcquireExclusiveScb( IrpContext, Vcb->RootIndexScb );
  13958. //
  13959. // Initialize the FileName.
  13960. //
  13961. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  13962. FileNameAttr.FileName.ParentDirectory = Vcb->RootIndexScb->Fcb->FileReference;
  13963. FileNameAttr.FileName.FileNameLength = (UCHAR)(9); // 9 unicode characters long
  13964. RtlCopyMemory( FileNameAttr.FileName.FileName, L"$ntfs.log", 9 * sizeof( WCHAR ) );
  13965. NtfsInitializeAttributeContext( &Context );
  13966. try {
  13967. //
  13968. // Does the file already exist?
  13969. //
  13970. FoundEntry = NtfsFindIndexEntry( IrpContext,
  13971. Vcb->RootIndexScb,
  13972. &FileNameAttr,
  13973. FALSE,
  13974. NULL,
  13975. &IndexEntryBcb,
  13976. &IndexEntry,
  13977. NULL );
  13978. //
  13979. // If we did not find it, then start creating the file.
  13980. //
  13981. if (!FoundEntry) {
  13982. //
  13983. // We will now try to do all of the on-disk operations. This means first
  13984. // allocating and initializing an Mft record. After that we create
  13985. // an Fcb to use to access this record.
  13986. //
  13987. FileReference = NtfsAllocateMftRecord( IrpContext, Vcb, FALSE );
  13988. //
  13989. // Pin the file record we need.
  13990. //
  13991. NtfsPinMftRecord( IrpContext,
  13992. Vcb,
  13993. &FileReference,
  13994. TRUE,
  13995. &FileRecordBcb,
  13996. &FileRecord,
  13997. &FileRecordOffset );
  13998. //
  13999. // Initialize the file record header.
  14000. //
  14001. NtfsInitializeMftRecord( IrpContext,
  14002. Vcb,
  14003. &FileReference,
  14004. FileRecord,
  14005. FileRecordBcb,
  14006. FALSE );
  14007. //
  14008. // If we found the file, then just get its FileReference out of the
  14009. // IndexEntry.
  14010. //
  14011. } else {
  14012. FileReference = IndexEntry->FileReference;
  14013. }
  14014. //
  14015. // Now that we know the FileReference, we can create the Fcb.
  14016. //
  14017. NtfsAcquireFcbTable( IrpContext, Vcb );
  14018. AcquiredFcbTable = TRUE;
  14019. Fcb = NtfsCreateFcb( IrpContext,
  14020. Vcb,
  14021. FileReference,
  14022. FALSE,
  14023. FALSE,
  14024. NULL );
  14025. //
  14026. // Reference the Fcb so it doesn't go away.
  14027. //
  14028. Fcb->ReferenceCount += 1;
  14029. NtfsReleaseFcbTable( IrpContext, Vcb );
  14030. AcquiredFcbTable = FALSE;
  14031. //
  14032. // Acquire the main resource
  14033. //
  14034. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  14035. NtfsAcquireFcbTable( IrpContext, Vcb );
  14036. Fcb->ReferenceCount -= 1;
  14037. NtfsReleaseFcbTable( IrpContext, Vcb );
  14038. //
  14039. // If we are creating this file, then carry on.
  14040. //
  14041. if (!FoundEntry) {
  14042. BOOLEAN LogIt = FALSE;
  14043. //
  14044. // Just copy the Security Id from the parent. (Load it first if necc.)
  14045. //
  14046. if (Vcb->RootIndexScb->Fcb->SharedSecurity == NULL) {
  14047. NtfsLoadSecurityDescriptor( IrpContext, Vcb->RootIndexScb->Fcb );
  14048. }
  14049. NtfsAcquireFcbSecurity( Fcb->Vcb );
  14050. Fcb->SecurityId = Vcb->RootIndexScb->Fcb->SecurityId;
  14051. ASSERT( Fcb->SharedSecurity == NULL );
  14052. Fcb->SharedSecurity = Vcb->RootIndexScb->Fcb->SharedSecurity;
  14053. Fcb->SharedSecurity->ReferenceCount++;
  14054. NtfsReleaseFcbSecurity( Fcb->Vcb );
  14055. //
  14056. // The changes to make on disk are first to create a standard information
  14057. // attribute. We start by filling the Fcb with the information we
  14058. // know and creating the attribute on disk.
  14059. //
  14060. NtfsInitializeFcbAndStdInfo( IrpContext,
  14061. Fcb,
  14062. FALSE,
  14063. FALSE,
  14064. FALSE,
  14065. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  14066. NULL );
  14067. //
  14068. // Now link the file into the $Extend directory.
  14069. //
  14070. NtfsAddLink( IrpContext,
  14071. TRUE,
  14072. Vcb->RootIndexScb,
  14073. Fcb,
  14074. (PFILE_NAME)&FileNameAttr,
  14075. &LogIt,
  14076. &FileNameFlags,
  14077. NULL,
  14078. NULL,
  14079. NULL );
  14080. /*
  14081. //
  14082. // Set this flag to indicate that the file is to be locked via the Scb
  14083. // pointers in the Vcb.
  14084. //
  14085. SetFlag( FileRecord->Flags, FILE_SYSTEM_FILE );
  14086. */
  14087. //
  14088. // Log the file record.
  14089. //
  14090. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  14091. Vcb->MftScb,
  14092. FileRecordBcb,
  14093. InitializeFileRecordSegment,
  14094. FileRecord,
  14095. FileRecord->FirstFreeByte,
  14096. Noop,
  14097. NULL,
  14098. 0,
  14099. FileRecordOffset,
  14100. 0,
  14101. 0,
  14102. Vcb->BytesPerFileRecordSegment );
  14103. //
  14104. // Verify that the file record for this file is valid.
  14105. //
  14106. } else {
  14107. ULONG CorruptHint;
  14108. if (!NtfsLookupAttributeByCode( IrpContext,
  14109. Fcb,
  14110. &Fcb->FileReference,
  14111. $STANDARD_INFORMATION,
  14112. &Context ) ||
  14113. !NtfsCheckFileRecord( Vcb, NtfsContainingFileRecord( &Context ), &Fcb->FileReference, &CorruptHint )) {
  14114. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, &Fcb->FileReference, NULL );
  14115. }
  14116. }
  14117. //
  14118. // Update Fcb fields from disk.
  14119. //
  14120. SetFlag( Fcb->FcbState, FCB_STATE_SYSTEM_FILE );
  14121. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, Fcb, NULL );
  14122. //
  14123. // Open/Create the data stream
  14124. //
  14125. memset( &AttrName, 0, sizeof( AttrName ) );
  14126. NtOfsCreateAttribute( IrpContext,
  14127. Fcb,
  14128. AttrName,
  14129. CREATE_OR_OPEN,
  14130. FALSE,
  14131. &Vcb->SyscacheScb );
  14132. RtlMapGenericMask( &DesiredAccess, IoGetFileObjectGenericMapping() );
  14133. IoSetShareAccess( DesiredAccess, FILE_SHARE_READ, Vcb->SyscacheScb->FileObject, &Vcb->SyscacheScb->ShareAccess );
  14134. do {
  14135. if (STATUS_LOG_FILE_FULL == Status) {
  14136. NtfsCleanCheckpoint( IrpContext->Vcb );
  14137. Status = STATUS_SUCCESS;
  14138. }
  14139. try {
  14140. LONGLONG Length = PAGE_SIZE * 0x1d00; // approx 30mb
  14141. NtOfsSetLength( IrpContext, Vcb->SyscacheScb, Length );
  14142. //
  14143. // Make this look like it came from a write so ioateof is not done
  14144. // we must do a writefilesizes to update VDL by hand
  14145. //
  14146. SetFlag(IrpContext->TopLevelIrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_SEEN);
  14147. NtfsZeroData( IrpContext, Vcb->SyscacheScb, Vcb->SyscacheScb->FileObject, 0, Length, NULL );
  14148. NtfsWriteFileSizes( IrpContext, Vcb->SyscacheScb, &Vcb->SyscacheScb->Header.ValidDataLength.QuadPart, TRUE, TRUE, TRUE );
  14149. } except( EXCEPTION_EXECUTE_HANDLER ) {
  14150. Status = GetExceptionCode();
  14151. ASSERT( Status == STATUS_DISK_FULL || Status == STATUS_LOG_FILE_FULL );
  14152. NtfsMinimumExceptionProcessing( IrpContext );
  14153. IrpContext->ExceptionStatus = 0;
  14154. }
  14155. ClearFlag(IrpContext->TopLevelIrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_SEEN);
  14156. NtfsReleaseScb( IrpContext, Vcb->SyscacheScb );
  14157. } while ( STATUS_LOG_FILE_FULL == Status );
  14158. //
  14159. // Increment cleanup counts to enforce the sharing we set up
  14160. //
  14161. NtfsIncrementCleanupCounts( Vcb->SyscacheScb, NULL, FALSE );
  14162. } finally {
  14163. NtfsCleanupAttributeContext( IrpContext, &Context );
  14164. NtfsUnpinBcb( IrpContext, &FileRecordBcb );
  14165. NtfsUnpinBcb( IrpContext, &IndexEntryBcb );
  14166. NtfsUnpinBcb( IrpContext, &ParentSecurityBcb );
  14167. //
  14168. // On any kind of error, nuke the Fcb.
  14169. //
  14170. if (AbnormalTermination()) {
  14171. //
  14172. // If some error caused us to abort, then delete
  14173. // the Fcb, because we are the only ones who will.
  14174. //
  14175. if (Fcb) {
  14176. if (!AcquiredFcbTable) {
  14177. NtfsAcquireFcbTable( IrpContext, Vcb );
  14178. AcquiredFcbTable = TRUE;
  14179. }
  14180. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  14181. ASSERT(!AcquiredFcbTable);
  14182. }
  14183. if (AcquiredFcbTable) {
  14184. NtfsReleaseFcbTable( IrpContext, Vcb );
  14185. }
  14186. }
  14187. }
  14188. }
  14189. #endif