Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

19802 lines
596 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 = TRUE;
  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. NtfsInitializeDevice (
  66. IN PIRP_CONTEXT IrpContext,
  67. IN PVPB Vpb,
  68. IN PDEVICE_OBJECT DiskDevice,
  69. OUT PBOOLEAN VcbAcquired,
  70. OUT PVOLUME_DEVICE_OBJECT * VolDo
  71. );
  72. NTSTATUS
  73. NtfsMountVolume (
  74. IN PIRP_CONTEXT IrpContext,
  75. IN PIRP Irp
  76. );
  77. NTSTATUS
  78. NtfsUpdateAttributeTable (
  79. IN PIRP_CONTEXT IrpContext,
  80. IN PVCB Vcb
  81. );
  82. NTSTATUS
  83. NtfsVerifyVolume (
  84. IN PIRP_CONTEXT IrpContext,
  85. IN PIRP Irp
  86. );
  87. NTSTATUS
  88. NtfsUserFsRequest (
  89. IN PIRP_CONTEXT IrpContext,
  90. IN PIRP Irp
  91. );
  92. NTSTATUS
  93. NtfsOplockRequest (
  94. IN PIRP_CONTEXT IrpContext,
  95. IN PIRP Irp
  96. );
  97. NTSTATUS
  98. NtfsLockVolume (
  99. IN PIRP_CONTEXT IrpContext,
  100. IN PIRP Irp
  101. );
  102. NTSTATUS
  103. NtfsUnlockVolume (
  104. IN PIRP_CONTEXT IrpContext,
  105. IN PIRP Irp
  106. );
  107. NTSTATUS
  108. NtfsDismountVolume (
  109. IN PIRP_CONTEXT IrpContext,
  110. IN PIRP Irp
  111. );
  112. NTSTATUS
  113. NtfsIsVolumeMounted (
  114. IN PIRP_CONTEXT IrpContext,
  115. IN PIRP Irp
  116. );
  117. NTSTATUS
  118. NtfsDirtyVolume (
  119. IN PIRP_CONTEXT IrpContext,
  120. IN PIRP Irp
  121. );
  122. BOOLEAN
  123. NtfsGetDiskGeometry (
  124. IN PIRP_CONTEXT IrpContext,
  125. IN PDEVICE_OBJECT DeviceObjectWeTalkTo,
  126. IN PDISK_GEOMETRY DiskGeometry,
  127. IN PLONGLONG PartitionSize
  128. );
  129. VOID
  130. NtfsReadBootSector (
  131. IN PIRP_CONTEXT IrpContext,
  132. IN PVCB Vcb,
  133. OUT PSCB *BootScb,
  134. OUT PBCB *BootBcb,
  135. OUT PVOID *BootSector
  136. );
  137. BOOLEAN
  138. NtfsIsBootSectorNtfs (
  139. IN PPACKED_BOOT_SECTOR BootSector,
  140. IN PVCB Vcb
  141. );
  142. VOID
  143. NtfsGetVolumeInformation (
  144. IN PIRP_CONTEXT IrpContext,
  145. IN PVPB Vpb OPTIONAL,
  146. IN PVCB Vcb,
  147. OUT PUSHORT VolumeFlags
  148. );
  149. VOID
  150. NtfsSetAndGetVolumeTimes (
  151. IN PIRP_CONTEXT IrpContext,
  152. IN PVCB Vcb,
  153. IN BOOLEAN MarkDirty
  154. );
  155. VOID
  156. NtfsOpenSystemFile (
  157. IN PIRP_CONTEXT IrpContext,
  158. IN OUT PSCB *Scb,
  159. IN PVCB Vcb,
  160. IN ULONG FileNumber,
  161. IN LONGLONG Size,
  162. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  163. IN BOOLEAN ModifiedNoWrite
  164. );
  165. VOID
  166. NtfsOpenRootDirectory (
  167. IN PIRP_CONTEXT IrpContext,
  168. IN PVCB Vcb
  169. );
  170. NTSTATUS
  171. NtfsQueryRetrievalPointers (
  172. IN PIRP_CONTEXT IrpContext,
  173. IN PIRP Irp
  174. );
  175. NTSTATUS
  176. NtfsGetCompression (
  177. IN PIRP_CONTEXT IrpContext,
  178. IN PIRP Irp
  179. );
  180. VOID
  181. NtfsChangeAttributeCompression (
  182. IN PIRP_CONTEXT IrpContext,
  183. IN PSCB Scb,
  184. IN PVCB Vcb,
  185. IN PCCB Ccb,
  186. IN USHORT CompressionState
  187. );
  188. NTSTATUS
  189. NtfsSetCompression (
  190. IN PIRP_CONTEXT IrpContext,
  191. IN PIRP Irp
  192. );
  193. NTSTATUS
  194. NtfsMarkAsSystemHive (
  195. IN PIRP_CONTEXT IrpContext,
  196. IN PIRP Irp
  197. );
  198. NTSTATUS
  199. NtfsGetStatistics (
  200. IN PIRP_CONTEXT IrpContext,
  201. IN PIRP Irp
  202. );
  203. LONG
  204. NtfsWriteRawExceptionFilter (
  205. IN PIRP_CONTEXT IrpContext,
  206. IN PEXCEPTION_POINTERS ExceptionPointer
  207. );
  208. #define NtfsMapPageInBitmap(A,B,C,D,E,F) NtfsMapOrPinPageInBitmap(A,B,C,D,E,F,FALSE)
  209. #define NtfsPinPageInBitmap(A,B,C,D,E,F) NtfsMapOrPinPageInBitmap(A,B,C,D,E,F,TRUE)
  210. VOID
  211. NtfsMapOrPinPageInBitmap (
  212. IN PIRP_CONTEXT IrpContext,
  213. IN PVCB Vcb,
  214. IN LCN Lcn,
  215. OUT PLCN StartingLcn,
  216. IN OUT PRTL_BITMAP Bitmap,
  217. OUT PBCB *BitmapBcb,
  218. IN BOOLEAN AlsoPinData
  219. );
  220. #define BYTES_PER_PAGE (PAGE_SIZE)
  221. #define BITS_PER_PAGE (BYTES_PER_PAGE * 8)
  222. NTSTATUS
  223. NtfsGetVolumeData (
  224. IN PIRP_CONTEXT IrpContext,
  225. IN PIRP Irp
  226. );
  227. NTSTATUS
  228. NtfsGetVolumeBitmap (
  229. IN PIRP_CONTEXT IrpContext,
  230. IN PIRP Irp
  231. );
  232. NTSTATUS
  233. NtfsGetRetrievalPointers (
  234. IN PIRP_CONTEXT IrpContext,
  235. IN PIRP Irp
  236. );
  237. NTSTATUS
  238. NtfsGetMftRecord (
  239. IN PIRP_CONTEXT IrpContext,
  240. IN PIRP Irp
  241. );
  242. NTSTATUS
  243. NtfsIsVolumeDirty (
  244. IN PIRP_CONTEXT IrpContext,
  245. IN PIRP Irp
  246. );
  247. NTSTATUS
  248. NtfsSetExtendedDasdIo (
  249. IN PIRP_CONTEXT IrpContext,
  250. IN PIRP Irp
  251. );
  252. NTSTATUS
  253. NtfsCreateUsnJournal (
  254. IN PIRP_CONTEXT IrpContext,
  255. IN PIRP Irp
  256. );
  257. NTSTATUS
  258. NtfsReadFileRecordUsnData (
  259. IN PIRP_CONTEXT IrpContext,
  260. IN PIRP Irp
  261. );
  262. NTSTATUS
  263. NtfsReadFileUsnData (
  264. IN PIRP_CONTEXT IrpContext,
  265. IN PIRP Irp
  266. );
  267. NTSTATUS
  268. NtfsWriteUsnCloseRecord (
  269. IN PIRP_CONTEXT IrpContext,
  270. IN PIRP Irp
  271. );
  272. NTSTATUS
  273. NtfsReadUsnWorker (
  274. IN PIRP_CONTEXT IrpContext,
  275. IN PFCB Fcb,
  276. IN PVOID Context
  277. );
  278. NTSTATUS
  279. NtfsBulkSecurityIdCheck (
  280. IN PIRP_CONTEXT IrpContext,
  281. IN PIRP Irp
  282. );
  283. VOID
  284. NtfsInitializeSecurityFile (
  285. IN PIRP_CONTEXT IrpContext,
  286. IN PVCB Vcb
  287. );
  288. VOID
  289. NtfsUpgradeSecurity (
  290. IN PIRP_CONTEXT IrpContext,
  291. IN PVCB Vcb
  292. );
  293. VOID
  294. NtfsInitializeQuotaFile (
  295. IN PIRP_CONTEXT IrpContext,
  296. IN PVCB Vcb
  297. );
  298. VOID
  299. NtfsInitializeObjectIdFile (
  300. IN PIRP_CONTEXT IrpContext,
  301. IN PVCB Vcb
  302. );
  303. VOID
  304. NtfsInitializeReparseFile (
  305. IN PIRP_CONTEXT IrpContext,
  306. IN PVCB Vcb
  307. );
  308. VOID
  309. NtfsInitializeUsnJournal (
  310. IN PIRP_CONTEXT IrpContext,
  311. IN PVCB Vcb,
  312. IN ULONG CreateIfNotExist,
  313. IN ULONG Restamp,
  314. IN PCREATE_USN_JOURNAL_DATA NewJournalData
  315. );
  316. VOID
  317. NtfsInitializeExtendDirectory (
  318. IN PIRP_CONTEXT IrpContext,
  319. IN PVCB Vcb
  320. );
  321. NTSTATUS
  322. NtfsQueryAllocatedRanges (
  323. IN PIRP_CONTEXT IrpContext,
  324. IN PIRP Irp
  325. );
  326. NTSTATUS
  327. NtfsSetSparse (
  328. IN PIRP_CONTEXT IrpContext,
  329. IN PIRP Irp
  330. );
  331. NTSTATUS
  332. NtfsZeroRange (
  333. IN PIRP_CONTEXT IrpContext,
  334. IN PIRP Irp
  335. );
  336. NTSTATUS
  337. NtfsSetReparsePoint (
  338. IN PIRP_CONTEXT IrpContext,
  339. IN PIRP Irp );
  340. NTSTATUS
  341. NtfsGetReparsePoint (
  342. IN PIRP_CONTEXT IrpContext,
  343. IN PIRP Irp );
  344. NTSTATUS
  345. NtfsDeleteReparsePoint (
  346. IN PIRP_CONTEXT IrpContext,
  347. IN PIRP Irp );
  348. NTSTATUS
  349. NtfsEncryptionFsctl (
  350. IN PIRP_CONTEXT IrpContext,
  351. IN PIRP Irp
  352. );
  353. NTSTATUS
  354. NtfsSetEncryption (
  355. IN PIRP_CONTEXT IrpContext,
  356. IN PIRP Irp
  357. );
  358. NTSTATUS
  359. NtfsReadRawEncrypted (
  360. IN PIRP_CONTEXT IrpContext,
  361. IN PIRP Irp
  362. );
  363. NTSTATUS
  364. NtfsWriteRawEncrypted (
  365. IN PIRP_CONTEXT IrpContext,
  366. IN PIRP Irp
  367. );
  368. NTSTATUS
  369. NtfsFindFilesOwnedBySid (
  370. IN PIRP_CONTEXT IrpContext,
  371. IN PIRP Irp
  372. );
  373. NTSTATUS
  374. NtfsFindBySidWorker (
  375. IN PIRP_CONTEXT IrpContext,
  376. IN PFCB Fcb,
  377. IN PVOID Context
  378. );
  379. NTSTATUS
  380. NtfsExtendVolume (
  381. IN PIRP_CONTEXT IrpContext,
  382. IN PIRP Irp
  383. );
  384. NTSTATUS
  385. NtfsMarkHandle (
  386. IN PIRP_CONTEXT IrpContext,
  387. IN PIRP Irp
  388. );
  389. NTSTATUS
  390. NtfsPrefetchFile (
  391. IN PIRP_CONTEXT IrpContext,
  392. IN PIRP Irp
  393. );
  394. LONG
  395. NtfsFsctrlExceptionFilter (
  396. IN PIRP_CONTEXT IrpContext,
  397. IN PEXCEPTION_POINTERS ExceptionPointer,
  398. IN BOOLEAN AccessingUserData,
  399. IN OUT PNTSTATUS Status
  400. );
  401. #ifdef BRIANDBG
  402. LONG
  403. NtfsDismountExceptionFilter (
  404. IN PEXCEPTION_POINTERS ExceptionPointer
  405. );
  406. #endif
  407. #ifdef SYSCACHE_DEBUG
  408. VOID
  409. NtfsInitializeSyscacheLogFile (
  410. IN PIRP_CONTEXT IrpContext,
  411. IN PVCB Vcb
  412. );
  413. #endif
  414. #ifdef ALLOC_PRAGMA
  415. #pragma alloc_text(PAGE, NtfsBulkSecurityIdCheck)
  416. #pragma alloc_text(PAGE, NtfsChangeAttributeCompression)
  417. #pragma alloc_text(PAGE, NtfsCommonFileSystemControl)
  418. #pragma alloc_text(PAGE, NtfsCreateUsnJournal)
  419. #pragma alloc_text(PAGE, NtfsDeleteReparsePoint)
  420. #pragma alloc_text(PAGE, NtfsDirtyVolume)
  421. #pragma alloc_text(PAGE, NtfsDismountVolume)
  422. #pragma alloc_text(PAGE, NtfsEncryptionFsctl)
  423. #pragma alloc_text(PAGE, NtfsExtendVolume)
  424. #pragma alloc_text(PAGE, NtfsFindBySidWorker)
  425. #pragma alloc_text(PAGE, NtfsFindFilesOwnedBySid)
  426. #pragma alloc_text(PAGE, NtfsFsdFileSystemControl)
  427. #pragma alloc_text(PAGE, NtfsGetCompression)
  428. #pragma alloc_text(PAGE, NtfsGetDiskGeometry)
  429. #pragma alloc_text(PAGE, NtfsGetMftRecord)
  430. #pragma alloc_text(PAGE, NtfsGetReparsePoint)
  431. #pragma alloc_text(PAGE, NtfsGetRetrievalPointers)
  432. #pragma alloc_text(PAGE, NtfsGetStatistics)
  433. #pragma alloc_text(PAGE, NtfsGetTunneledData)
  434. #pragma alloc_text(PAGE, NtfsGetVolumeBitmap)
  435. #pragma alloc_text(PAGE, NtfsGetVolumeData)
  436. #pragma alloc_text(PAGE, NtfsGetVolumeInformation)
  437. #pragma alloc_text(PAGE, NtfsInitializeDevice)
  438. #pragma alloc_text(PAGE, NtfsInitializeExtendDirectory)
  439. #pragma alloc_text(PAGE, NtfsInitializeObjectIdFile)
  440. #pragma alloc_text(PAGE, NtfsInitializeReparseFile)
  441. #pragma alloc_text(PAGE, NtfsInitializeQuotaFile)
  442. #pragma alloc_text(PAGE, NtfsInitializeSecurityFile)
  443. #pragma alloc_text(PAGE, NtfsInitializeUsnJournal)
  444. #pragma alloc_text(PAGE, NtfsIsBootSectorNtfs)
  445. #pragma alloc_text(PAGE, NtfsIsVolumeDirty)
  446. #pragma alloc_text(PAGE, NtfsIsVolumeMounted)
  447. #pragma alloc_text(PAGE, NtfsLockVolume)
  448. #pragma alloc_text(PAGE, NtfsMarkAsSystemHive)
  449. #pragma alloc_text(PAGE, NtfsMarkHandle)
  450. #pragma alloc_text(PAGE, NtfsMountVolume)
  451. #pragma alloc_text(PAGE, NtfsOpenRootDirectory)
  452. #pragma alloc_text(PAGE, NtfsOpenSystemFile)
  453. #pragma alloc_text(PAGE, NtfsOplockRequest)
  454. #pragma alloc_text(PAGE, NtfsPrefetchFile)
  455. #pragma alloc_text(PAGE, NtfsQueryAllocatedRanges)
  456. #pragma alloc_text(PAGE, NtfsQueryRetrievalPointers)
  457. #pragma alloc_text(PAGE, NtfsReadBootSector)
  458. #pragma alloc_text(PAGE, NtfsReadFileRecordUsnData)
  459. #pragma alloc_text(PAGE, NtfsReadFileUsnData)
  460. #pragma alloc_text(PAGE, NtfsReadRawEncrypted)
  461. #pragma alloc_text(PAGE, NtfsReadUsnWorker)
  462. #pragma alloc_text(PAGE, NtfsSetAndGetVolumeTimes)
  463. #pragma alloc_text(PAGE, NtfsSetCompression)
  464. #pragma alloc_text(PAGE, NtfsSetEncryption)
  465. #pragma alloc_text(PAGE, NtfsSetExtendedDasdIo)
  466. #pragma alloc_text(PAGE, NtfsSetReparsePoint)
  467. #pragma alloc_text(PAGE, NtfsSetSparse)
  468. #pragma alloc_text(PAGE, NtfsSetTunneledData)
  469. #pragma alloc_text(PAGE, NtfsUnlockVolume)
  470. #pragma alloc_text(PAGE, NtfsUpdateAttributeTable)
  471. #pragma alloc_text(PAGE, NtfsUpgradeSecurity)
  472. #pragma alloc_text(PAGE, NtfsUserFsRequest)
  473. #pragma alloc_text(PAGE, NtfsVerifyVolume)
  474. #pragma alloc_text(PAGE, NtfsWriteRawEncrypted)
  475. #pragma alloc_text(PAGE, NtfsWriteUsnCloseRecord)
  476. #pragma alloc_text(PAGE, NtfsZeroRange)
  477. #endif
  478. #ifdef BRIANDBG
  479. LONG
  480. NtfsDismountExceptionFilter (
  481. IN PEXCEPTION_POINTERS ExceptionPointer
  482. )
  483. {
  484. UNREFERENCED_PARAMETER( ExceptionPointer );
  485. ASSERT( ExceptionPointer->ExceptionRecord->ExceptionCode == STATUS_SUCCESS );
  486. return EXCEPTION_CONTINUE_SEARCH;
  487. }
  488. #endif
  489. NTSTATUS
  490. NtfsFsdFileSystemControl (
  491. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  492. IN PIRP Irp
  493. )
  494. /*++
  495. Routine Description:
  496. This routine implements the FSD part of File System Control.
  497. Arguments:
  498. VolumeDeviceObject - Supplies the volume device object where the
  499. file exists
  500. Irp - Supplies the Irp being processed
  501. Return Value:
  502. NTSTATUS - The FSD status for the IRP
  503. --*/
  504. {
  505. TOP_LEVEL_CONTEXT TopLevelContext;
  506. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  507. PIRP_CONTEXT IrpContext = NULL;
  508. PIO_STACK_LOCATION IrpSp;
  509. NTSTATUS Status = STATUS_SUCCESS;
  510. BOOLEAN Wait;
  511. BOOLEAN Retry = FALSE;
  512. ASSERT_IRP( Irp );
  513. PAGED_CODE();
  514. DebugTrace( +1, Dbg, ("NtfsFsdFileSystemControl\n") );
  515. //
  516. // Call the common File System Control routine, with blocking allowed if
  517. // synchronous. This opeation needs to special case the mount
  518. // and verify suboperations because we know they are allowed to block.
  519. // We identify these suboperations by looking at the file object field
  520. // and seeing if its null.
  521. //
  522. if (IoGetCurrentIrpStackLocation( Irp )->FileObject == NULL) {
  523. Wait = TRUE;
  524. } else {
  525. Wait = CanFsdWait( Irp );
  526. }
  527. //
  528. // Make the callback if this is not our filesystem device object (i.e., !mount)
  529. // and thus a regular fsctrl. Mounts are handled later via a seperate callback.
  530. //
  531. if ((VolumeDeviceObject->DeviceObject.Size != sizeof( DEVICE_OBJECT )) &&
  532. (NtfsData.EncryptionCallBackTable.PreFileSystemControl != NULL)) {
  533. Status = NtfsData.EncryptionCallBackTable.PreFileSystemControl( (PDEVICE_OBJECT) VolumeDeviceObject,
  534. Irp,
  535. IoGetCurrentIrpStackLocation( Irp )->FileObject );
  536. //
  537. // Raise the status if a failure.
  538. //
  539. if (Status != STATUS_SUCCESS) {
  540. //
  541. // EFS should never return anything but STATUS_SUCCESS or an error or warning.
  542. //
  543. ASSERT( !NT_SUCCESS( Status ));
  544. NtfsCompleteRequest( NULL, Irp, Status );
  545. return Status;
  546. }
  547. }
  548. FsRtlEnterFileSystem();
  549. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  550. do {
  551. try {
  552. //
  553. // We are either initiating this request or retrying it.
  554. //
  555. if (IrpContext == NULL) {
  556. //
  557. // Allocate and initialize the Irp.
  558. //
  559. NtfsInitializeIrpContext( Irp, Wait, &IrpContext );
  560. //
  561. // Initialize the thread top level structure, if needed.
  562. //
  563. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  564. } else if (Status == STATUS_LOG_FILE_FULL) {
  565. Retry = TRUE;
  566. NtfsCheckpointForLogFileFull( IrpContext );
  567. } else if (Status == STATUS_CANT_WAIT) {
  568. Retry = TRUE;
  569. }
  570. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  571. if (IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME) {
  572. Status = NtfsPostRequest( IrpContext, Irp );
  573. } else {
  574. //
  575. // The SetCompression control is a long-winded function that has
  576. // to rewrite the entire stream, and has to tolerate log file full
  577. // conditions. If this is the first pass through we initialize some
  578. // fields in the NextIrpSp to allow us to resume the set compression
  579. // operation.
  580. //
  581. // David Goebel 1/3/96: Changed to next stack location so that we
  582. // don't wipe out buffer length values. These Irps are never
  583. // dispatched, so the next stack location will not be disturbed.
  584. //
  585. if ((IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
  586. (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_SET_COMPRESSION)) {
  587. if (!Retry) {
  588. PIO_STACK_LOCATION NextIrpSp;
  589. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  590. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = MAXULONG;
  591. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = MAXULONG;
  592. }
  593. }
  594. Status = NtfsCommonFileSystemControl( IrpContext, Irp );
  595. }
  596. break;
  597. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  598. //
  599. // We had some trouble trying to perform the requested
  600. // operation, so we'll abort the I/O request with
  601. // the error status that we get back from the
  602. // execption code
  603. //
  604. Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
  605. }
  606. } while (Status == STATUS_CANT_WAIT ||
  607. Status == STATUS_LOG_FILE_FULL);
  608. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  609. FsRtlExitFileSystem();
  610. //
  611. // And return to our caller
  612. //
  613. DebugTrace( -1, Dbg, ("NtfsFsdFileSystemControl -> %08lx\n", Status) );
  614. return Status;
  615. }
  616. NTSTATUS
  617. NtfsCommonFileSystemControl (
  618. IN PIRP_CONTEXT IrpContext,
  619. IN PIRP Irp
  620. )
  621. /*++
  622. Routine Description:
  623. This is the common routine for File System Control called by both the
  624. fsd and fsp threads.
  625. Arguments:
  626. Irp - Supplies the Irp to process
  627. Return Value:
  628. NTSTATUS - The return status for the operation
  629. --*/
  630. {
  631. NTSTATUS Status;
  632. PIO_STACK_LOCATION IrpSp;
  633. ASSERT_IRP_CONTEXT( IrpContext );
  634. ASSERT_IRP( Irp );
  635. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  636. PAGED_CODE();
  637. //
  638. // Get the current Irp stack location
  639. //
  640. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  641. DebugTrace( +1, Dbg, ("NtfsCommonFileSystemControl\n") );
  642. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  643. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  644. //
  645. // We know this is a file system control so we'll case on the
  646. // minor function, and call a internal worker routine to complete
  647. // the irp.
  648. //
  649. switch (IrpSp->MinorFunction) {
  650. case IRP_MN_MOUNT_VOLUME:
  651. Status = NtfsMountVolume( IrpContext, Irp );
  652. break;
  653. case IRP_MN_USER_FS_REQUEST:
  654. case IRP_MN_KERNEL_CALL:
  655. Status = NtfsUserFsRequest( IrpContext, Irp );
  656. break;
  657. default:
  658. DebugTrace( -1, Dbg, ("Invalid Minor Function %08lx\n", IrpSp->MinorFunction) );
  659. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST );
  660. break;
  661. }
  662. //
  663. // And return to our caller
  664. //
  665. DebugTrace( -1, Dbg, ("NtfsCommonFileSystemControl -> %08lx\n", Status) );
  666. return Status;
  667. }
  668. //
  669. // Local Support Routine
  670. //
  671. NTSTATUS
  672. NtfsInitializeDevice (
  673. IN PIRP_CONTEXT IrpContext,
  674. IN PVPB Vpb,
  675. IN PDEVICE_OBJECT DiskDevice,
  676. OUT PBOOLEAN VcbAcquired,
  677. OUT PVOLUME_DEVICE_OBJECT * VolDo
  678. )
  679. /*++
  680. Routine Description:
  681. This subroutine creates an initializes a device object for a new volume. It
  682. is called during mount. All the work necc. to init the device object fields is done here.
  683. After completion the volume still may not be ntfs and even it is will still have to be
  684. run through the main mount process. We get the actual disk geometry to fill in some
  685. fields and also init the vcb fields dependent on this.
  686. NOTE: in the long run it might be more efficient to read the boot sector before
  687. creating the device object
  688. Arguments:
  689. Vpb - The vpb for the volume being mounted
  690. DiskDevice - Storage device we mount on - Note: the vpb usually points to the middle of the
  691. storage stack - this device will be the top of the stack
  692. VcbAcquired - On return if true the vcb for the volume is acquired exclusive
  693. VolDo - The newly created volume device object
  694. Return Value:
  695. NTSTATUS - The return status for the operation
  696. --*/
  697. {
  698. NTSTATUS Status;
  699. DISK_GEOMETRY DiskGeometry;
  700. LONGLONG Length;
  701. ULONG BytesPerSector;
  702. ULONG Index;
  703. BOOLEAN WriteProtected;
  704. PAGED_CODE();
  705. *VcbAcquired = FALSE;
  706. Status = IoCreateDevice( NtfsData.DriverObject,
  707. sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
  708. NULL,
  709. FILE_DEVICE_DISK_FILE_SYSTEM,
  710. 0,
  711. FALSE,
  712. (PDEVICE_OBJECT *)VolDo );
  713. if (!NT_SUCCESS( Status )) {
  714. return Status;
  715. }
  716. //
  717. // Our alignment requirement is the larger of the processor alignment requirement
  718. // already in the volume device object and that in the DeviceObjectWeTalkTo
  719. //
  720. if (DiskDevice->AlignmentRequirement > (*VolDo)->DeviceObject.AlignmentRequirement) {
  721. (*VolDo)->DeviceObject.AlignmentRequirement = DiskDevice->AlignmentRequirement;
  722. }
  723. //
  724. // Add one more to the stack size requirements for our device
  725. //
  726. (*VolDo)->DeviceObject.StackSize = DiskDevice->StackSize + 1;
  727. //
  728. // Initialize the overflow queue for the volume
  729. //
  730. (*VolDo)->OverflowQueueCount = 0;
  731. InitializeListHead( &((*VolDo)->OverflowQueue) );
  732. KeInitializeEvent( &((*VolDo)->OverflowQueueEvent), SynchronizationEvent, FALSE );
  733. //
  734. // Get a reference to the Vcb hanging off the end of the volume device object
  735. // we just created
  736. //
  737. IrpContext->Vcb = &((*VolDo)->Vcb);
  738. //
  739. // Set the device object field in the vpb to point to our new volume device
  740. // object
  741. //
  742. Vpb->DeviceObject = (PDEVICE_OBJECT)(*VolDo);
  743. //
  744. // Initialize the Vcb. Set checkpoint
  745. // in progress (to prevent a real checkpoint from occuring until we
  746. // are done).
  747. //
  748. NtfsInitializeVcb( IrpContext, IrpContext->Vcb, DiskDevice, Vpb );
  749. NtfsAcquireExclusiveVcb( IrpContext, IrpContext->Vcb, TRUE );
  750. *VcbAcquired= TRUE;
  751. //
  752. // Query the device we talk to for this geometry and setup enough of the
  753. // vcb to read in the boot sectors. This is a temporary setup until
  754. // we've read in the actual boot sector and got the real cluster factor.
  755. //
  756. WriteProtected = NtfsGetDiskGeometry( IrpContext,
  757. DiskDevice,
  758. &DiskGeometry,
  759. &Length );
  760. if (WriteProtected) {
  761. SetFlag( IrpContext->Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY );
  762. }
  763. //
  764. // If the sector size is greater than the page size, it is probably
  765. // a bogus return, but we cannot use the device. We also verify that
  766. // the sector size is a power of two.
  767. //
  768. BytesPerSector = DiskGeometry.BytesPerSector;
  769. if ((BytesPerSector > PAGE_SIZE) ||
  770. (BytesPerSector == 0)) {
  771. NtfsRaiseStatus( IrpContext, STATUS_BAD_DEVICE_TYPE, NULL, NULL );
  772. }
  773. while (TRUE) {
  774. if (FlagOn( BytesPerSector, 1 )) {
  775. if (BytesPerSector != 1) {
  776. NtfsRaiseStatus( IrpContext, STATUS_BAD_DEVICE_TYPE, NULL, NULL );
  777. }
  778. break;
  779. }
  780. BytesPerSector >>= 1;
  781. }
  782. IrpContext->Vcb->BytesPerSector = DiskGeometry.BytesPerSector;
  783. IrpContext->Vcb->BytesPerCluster = IrpContext->Vcb->BytesPerSector;
  784. IrpContext->Vcb->NumberSectors = Length / DiskGeometry.BytesPerSector;
  785. //
  786. // Fail the mount if the number of sectors is less than 16. Oth
  787. // won't work.
  788. //
  789. if (IrpContext->Vcb->NumberSectors <= 0x10) {
  790. Status = STATUS_UNRECOGNIZED_VOLUME;
  791. }
  792. IrpContext->Vcb->ClusterMask = IrpContext->Vcb->BytesPerCluster - 1;
  793. IrpContext->Vcb->InverseClusterMask = ~IrpContext->Vcb->ClusterMask;
  794. for (IrpContext->Vcb->ClusterShift = 0, Index = IrpContext->Vcb->BytesPerCluster; Index > 1; Index = Index / 2) {
  795. IrpContext->Vcb->ClusterShift += 1;
  796. }
  797. IrpContext->Vcb->ClustersPerPage = PAGE_SIZE >> IrpContext->Vcb->ClusterShift;
  798. //
  799. // Set the sector size in our device object.
  800. //
  801. (*VolDo)->DeviceObject.SectorSize = (USHORT) IrpContext->Vcb->BytesPerSector;
  802. //
  803. // Now that all the DeviceObject fields are set clear the initializing flag
  804. //
  805. ClearFlag( (*VolDo)->DeviceObject.Flags, DO_DEVICE_INITIALIZING );
  806. return Status;
  807. }
  808. //
  809. // Local Support Routine
  810. //
  811. NTSTATUS
  812. NtfsMountVolume (
  813. IN PIRP_CONTEXT IrpContext,
  814. IN PIRP Irp
  815. )
  816. /*++
  817. Routine Description:
  818. This routine performs the mount volume operation. It is responsible for
  819. either completing of enqueuing the input Irp.
  820. Its job is to verify that the volume denoted in the IRP is an NTFS volume,
  821. and create the VCB and root SCB/FCB structures. The algorithm it uses is
  822. essentially as follows:
  823. 1. Create a new Vcb Structure, and initialize it enough to do cached
  824. volume file I/O.
  825. 2. Read the disk and check if it is an NTFS volume.
  826. 3. If it is not an NTFS volume then free the cached volume file, delete
  827. the VCB, and complete the IRP with STATUS_UNRECOGNIZED_VOLUME
  828. 4. Check if the volume was previously mounted and if it was then do a
  829. remount operation. This involves freeing the cached volume file,
  830. delete the VCB, hook in the old VCB, and complete the IRP.
  831. 5. Otherwise create a root SCB, recover the volume, create Fsp threads
  832. as necessary, and complete the IRP.
  833. Arguments:
  834. Irp - Supplies the Irp to process
  835. Return Value:
  836. NTSTATUS - The return status for the operation
  837. --*/
  838. {
  839. NTSTATUS Status;
  840. PIO_STACK_LOCATION IrpSp;
  841. PATTRIBUTE_RECORD_HEADER Attribute;
  842. PDEVICE_OBJECT DeviceObjectWeTalkTo;
  843. PVPB Vpb;
  844. PVOLUME_DEVICE_OBJECT VolDo = NULL;
  845. PVCB Vcb;
  846. PFILE_OBJECT RootDirFileObject = NULL;
  847. PBCB BootBcb = NULL;
  848. PPACKED_BOOT_SECTOR BootSector;
  849. PSCB BootScb = NULL;
  850. PSCB QuotaDataScb = NULL;
  851. POBJECT_NAME_INFORMATION DeviceObjectName = NULL;
  852. ULONG DeviceObjectNameLength;
  853. PBCB Bcbs[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  854. PMDL Mdls[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  855. ULONG FirstNonMirroredCluster;
  856. ULONG MirroredMftRange;
  857. PLIST_ENTRY MftLinks;
  858. PSCB AttributeListScb;
  859. ULONG i;
  860. IO_STATUS_BLOCK IoStatus;
  861. BOOLEAN UpdatesApplied;
  862. BOOLEAN VcbAcquired = FALSE;
  863. BOOLEAN MountFailed = TRUE;
  864. BOOLEAN CloseAttributes = FALSE;
  865. BOOLEAN UpgradeVolume = FALSE;
  866. BOOLEAN CurrentVersion = FALSE;
  867. BOOLEAN UnrecognizedRestart;
  868. ULONG RetryRestart;
  869. USHORT VolumeFlags = 0;
  870. LONGLONG LlTemp1;
  871. ASSERT_IRP_CONTEXT( IrpContext );
  872. ASSERT_IRP( Irp );
  873. PAGED_CODE();
  874. //
  875. //**** The following code is only temporary and is used to disable NTFS
  876. //**** from mounting any volumes
  877. //
  878. if (NtfsDisable) {
  879. NtfsCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  880. return STATUS_UNRECOGNIZED_VOLUME;
  881. }
  882. //
  883. // Reject floppies
  884. //
  885. if (FlagOn( IoGetCurrentIrpStackLocation(Irp)->
  886. Parameters.MountVolume.Vpb->
  887. RealDevice->Characteristics, FILE_FLOPPY_DISKETTE ) ) {
  888. Irp->IoStatus.Information = 0;
  889. NtfsCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  890. return STATUS_UNRECOGNIZED_VOLUME;
  891. }
  892. //
  893. // Get the current Irp stack location
  894. //
  895. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  896. DebugTrace( +1, Dbg, ("NtfsMountVolume\n") );
  897. //
  898. // Save some references to make our life a little easier
  899. //
  900. DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
  901. Vpb = IrpSp->Parameters.MountVolume.Vpb;
  902. ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  903. //
  904. // TEMPCODE Perform the following test for chkdsk testing.
  905. //
  906. if (NtfsDisableDevice == IrpSp->Parameters.MountVolume.DeviceObject) {
  907. NtfsCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
  908. return STATUS_UNRECOGNIZED_VOLUME;
  909. }
  910. //
  911. // Acquire exclusive global access
  912. //
  913. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  914. //
  915. // Now is a convenient time to look through the queue of Vcb's to see if there
  916. // are any which can be deleted.
  917. //
  918. try {
  919. PLIST_ENTRY Links;
  920. for (Links = NtfsData.VcbQueue.Flink;
  921. Links != &NtfsData.VcbQueue;
  922. Links = Links->Flink) {
  923. Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
  924. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  925. (Vcb->CloseCount == 0) &&
  926. FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT )) {
  927. //
  928. // Now we can check to see if we should perform the teardown
  929. // on this Vcb. The release Vcb routine below can do all of
  930. // the checks correctly. Make this appear to from a close
  931. // call since there is no special biasing for this case.
  932. //
  933. IrpContext->Vcb = Vcb;
  934. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  935. if (!FlagOn( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY )) {
  936. NtfsReleaseGlobal( IrpContext );
  937. NtfsReleaseVcbCheckDelete( IrpContext,
  938. Vcb,
  939. IRP_MJ_CLOSE,
  940. NULL );
  941. //
  942. // Only do one since we have lost our place in the Vcb list.
  943. //
  944. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  945. break;
  946. } else {
  947. NtfsReleaseVcb( IrpContext, Vcb );
  948. }
  949. }
  950. }
  951. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  952. //
  953. // Make sure we own the global resource for mount. We can only raise above
  954. // in the DeleteVcb path when we don't hold the resource.
  955. //
  956. NtfsAcquireExclusiveGlobal( IrpContext, TRUE );
  957. }
  958. Vcb = NULL;
  959. try {
  960. PFILE_RECORD_SEGMENT_HEADER MftBuffer;
  961. PVOID Mft2Buffer;
  962. LONGLONG MftMirrorOverlap;
  963. //
  964. // Create and init a new volume device object.
  965. //
  966. Status = NtfsInitializeDevice( IrpContext, Vpb, DeviceObjectWeTalkTo, &VcbAcquired, &VolDo );
  967. if (!NT_SUCCESS( Status )) {
  968. leave;
  969. }
  970. Vcb = IrpContext->Vcb;
  971. //
  972. // Read in the Boot sector, or spare boot sector, on exit of this try
  973. // body we will have set bootbcb and bootsector.
  974. //
  975. NtfsReadBootSector( IrpContext, Vcb, &BootScb, &BootBcb, (PVOID *)&BootSector );
  976. //
  977. // Check if this is an NTFS volume
  978. //
  979. if (!NtfsIsBootSectorNtfs( BootSector, Vcb )) {
  980. DebugTrace( 0, Dbg, ("Not an NTFS volume\n") );
  981. Status = STATUS_UNRECOGNIZED_VOLUME;
  982. leave;
  983. }
  984. //
  985. // Now that we have a real boot sector on a real NTFS volume we can
  986. // really set the proper Vcb fields.
  987. //
  988. {
  989. BIOS_PARAMETER_BLOCK Bpb;
  990. NtfsUnpackBios( &Bpb, &BootSector->PackedBpb );
  991. Vcb->BytesPerSector = Bpb.BytesPerSector;
  992. Vcb->BytesPerCluster = Bpb.BytesPerSector * Bpb.SectorsPerCluster;
  993. Vcb->NumberSectors = BootSector->NumberSectors;
  994. Vcb->MftStartLcn = BootSector->MftStartLcn;
  995. Vcb->Mft2StartLcn = BootSector->Mft2StartLcn;
  996. Vcb->ClusterMask = Vcb->BytesPerCluster - 1;
  997. Vcb->InverseClusterMask = ~Vcb->ClusterMask;
  998. for (Vcb->ClusterShift = 0, i = Vcb->BytesPerCluster; i > 1; i = i / 2) {
  999. Vcb->ClusterShift += 1;
  1000. }
  1001. //
  1002. // If the cluster size is greater than the page size then set this value to 1.
  1003. //
  1004. Vcb->ClustersPerPage = PAGE_SIZE >> Vcb->ClusterShift;
  1005. if (Vcb->ClustersPerPage == 0) {
  1006. Vcb->ClustersPerPage = 1;
  1007. }
  1008. //
  1009. // File records can be smaller, equal or larger than the cluster size. Initialize
  1010. // both ClustersPerFileRecordSegment and FileRecordsPerCluster.
  1011. //
  1012. // If the value in the boot sector is positive then it signifies the
  1013. // clusters/structure. If negative then it signifies the shift value
  1014. // to obtain the structure size.
  1015. //
  1016. if (BootSector->ClustersPerFileRecordSegment < 0) {
  1017. Vcb->BytesPerFileRecordSegment = 1 << (-1 * BootSector->ClustersPerFileRecordSegment);
  1018. //
  1019. // Initialize the other Mft/Cluster relationship numbers in the Vcb
  1020. // based on whether the clusters are larger or smaller than file
  1021. // records.
  1022. //
  1023. if (Vcb->BytesPerFileRecordSegment < Vcb->BytesPerCluster) {
  1024. Vcb->FileRecordsPerCluster = Vcb->BytesPerCluster / Vcb->BytesPerFileRecordSegment;
  1025. } else {
  1026. Vcb->ClustersPerFileRecordSegment = Vcb->BytesPerFileRecordSegment / Vcb->BytesPerCluster;
  1027. }
  1028. } else {
  1029. Vcb->BytesPerFileRecordSegment = BytesFromClusters( Vcb, BootSector->ClustersPerFileRecordSegment );
  1030. Vcb->ClustersPerFileRecordSegment = BootSector->ClustersPerFileRecordSegment;
  1031. }
  1032. for (Vcb->MftShift = 0, i = Vcb->BytesPerFileRecordSegment; i > 1; i = i / 2) {
  1033. Vcb->MftShift += 1;
  1034. }
  1035. //
  1036. // We want to shift between file records and clusters regardless of which is larger.
  1037. // Compute the shift value here. Anyone using this value will have to know which
  1038. // way to shift.
  1039. //
  1040. Vcb->MftToClusterShift = Vcb->MftShift - Vcb->ClusterShift;
  1041. if (Vcb->ClustersPerFileRecordSegment == 0) {
  1042. Vcb->MftToClusterShift = Vcb->ClusterShift - Vcb->MftShift;
  1043. }
  1044. //
  1045. // Remember the clusters per view section and 4 gig.
  1046. //
  1047. Vcb->ClustersPer4Gig = (ULONG) LlClustersFromBytesTruncate( Vcb, 0x100000000 );
  1048. //
  1049. // Compute the default index allocation buffer size.
  1050. //
  1051. if (BootSector->DefaultClustersPerIndexAllocationBuffer < 0) {
  1052. Vcb->DefaultBytesPerIndexAllocationBuffer = 1 << (-1 * BootSector->DefaultClustersPerIndexAllocationBuffer);
  1053. //
  1054. // Determine whether the index allocation buffer is larger/smaller
  1055. // than the cluster size to determine the block size.
  1056. //
  1057. if (Vcb->DefaultBytesPerIndexAllocationBuffer < Vcb->BytesPerCluster) {
  1058. Vcb->DefaultBlocksPerIndexAllocationBuffer = Vcb->DefaultBytesPerIndexAllocationBuffer / DEFAULT_INDEX_BLOCK_SIZE;
  1059. } else {
  1060. Vcb->DefaultBlocksPerIndexAllocationBuffer = Vcb->DefaultBytesPerIndexAllocationBuffer / Vcb->BytesPerCluster;
  1061. }
  1062. } else {
  1063. Vcb->DefaultBlocksPerIndexAllocationBuffer = BootSector->DefaultClustersPerIndexAllocationBuffer;
  1064. Vcb->DefaultBytesPerIndexAllocationBuffer = BytesFromClusters( Vcb, Vcb->DefaultBlocksPerIndexAllocationBuffer );
  1065. }
  1066. //
  1067. // Now compute our volume specific constants that are stored in
  1068. // the Vcb. The total number of clusters is:
  1069. //
  1070. // (NumberSectors * BytesPerSector) / BytesPerCluster
  1071. //
  1072. Vcb->PreviousTotalClusters =
  1073. Vcb->TotalClusters = LlClustersFromBytesTruncate( Vcb,
  1074. Vcb->NumberSectors * Vcb->BytesPerSector );
  1075. //
  1076. // Compute the maximum clusters for a file.
  1077. //
  1078. Vcb->MaxClusterCount = LlClustersFromBytesTruncate( Vcb, MAXFILESIZE );
  1079. //
  1080. // Compute the attribute flags mask for this volume for this volume.
  1081. //
  1082. Vcb->AttributeFlagsMask = 0xffff;
  1083. if (Vcb->BytesPerCluster > 0x1000) {
  1084. ClearFlag( Vcb->AttributeFlagsMask, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  1085. }
  1086. //
  1087. // For now, an attribute is considered "moveable" if it is at
  1088. // least 5/16 of the file record. This constant should only
  1089. // be changed i conjunction with the MAX_MOVEABLE_ATTRIBUTES
  1090. // constant. (The product of the two should be a little less
  1091. // than or equal to 1.)
  1092. //
  1093. Vcb->BigEnoughToMove = Vcb->BytesPerFileRecordSegment * 5 / 16;
  1094. //
  1095. // Set the serial number in the Vcb
  1096. //
  1097. Vcb->VolumeSerialNumber = BootSector->SerialNumber;
  1098. Vpb->SerialNumber = ((ULONG)BootSector->SerialNumber);
  1099. //
  1100. // Compute the sparse file values.
  1101. //
  1102. Vcb->SparseFileUnit = NTFS_SPARSE_FILE_UNIT;
  1103. Vcb->SparseFileClusters = ClustersFromBytes( Vcb, Vcb->SparseFileUnit );
  1104. //
  1105. // If this is the system boot partition, we need to remember to
  1106. // not allow this volume to be dismounted.
  1107. //
  1108. if (FlagOn( Vpb->RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION )) {
  1109. SetFlag( Vcb->VcbState, VCB_STATE_DISALLOW_DISMOUNT );
  1110. }
  1111. //
  1112. // We should never see the BOOT flag in the device we talk to unless it
  1113. // is in the real device.
  1114. //
  1115. ASSERT( !FlagOn( DeviceObjectWeTalkTo->Flags, DO_SYSTEM_BOOT_PARTITION ) ||
  1116. FlagOn( Vpb->RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION ));
  1117. }
  1118. //
  1119. // Initialize recovery state.
  1120. //
  1121. NtfsInitializeRestartTable( sizeof( OPEN_ATTRIBUTE_ENTRY ),
  1122. INITIAL_NUMBER_ATTRIBUTES,
  1123. &Vcb->OpenAttributeTable );
  1124. NtfsUpdateOatVersion( Vcb, NtfsDefaultRestartVersion );
  1125. NtfsInitializeRestartTable( sizeof( TRANSACTION_ENTRY ),
  1126. INITIAL_NUMBER_TRANSACTIONS,
  1127. &Vcb->TransactionTable );
  1128. //
  1129. // Now start preparing to restart the volume.
  1130. //
  1131. //
  1132. // Create the Mft and Log File Scbs and prepare to read them.
  1133. // The Mft and mirror length will be the first 4 file records or
  1134. // the first cluster.
  1135. //
  1136. FirstNonMirroredCluster = ClustersFromBytes( Vcb, 4 * Vcb->BytesPerFileRecordSegment );
  1137. MirroredMftRange = 4 * Vcb->BytesPerFileRecordSegment;
  1138. if (MirroredMftRange < Vcb->BytesPerCluster) {
  1139. MirroredMftRange = Vcb->BytesPerCluster;
  1140. }
  1141. //
  1142. // Check the case where the boot sector has an invalid value for either the
  1143. // beginning of the Mft or the beginning of the Mft mirror. Specifically
  1144. // check the they don't overlap. Otherwise we can corrupt the valid one
  1145. // as we read and possibly try to correct the invalid one.
  1146. //
  1147. if (Vcb->MftStartLcn > Vcb->Mft2StartLcn) {
  1148. MftMirrorOverlap = Vcb->MftStartLcn - Vcb->Mft2StartLcn;
  1149. } else {
  1150. MftMirrorOverlap = Vcb->Mft2StartLcn - Vcb->MftStartLcn;
  1151. }
  1152. MftMirrorOverlap = LlBytesFromClusters( Vcb, MftMirrorOverlap );
  1153. //
  1154. // Don't raise corrupt since we don't want to attempt to write the
  1155. // disk in this state. Someone who knows how will need to
  1156. // restore the correct boot sector.
  1157. //
  1158. if (MftMirrorOverlap < (LONGLONG) MirroredMftRange) {
  1159. DebugTrace( 0, Dbg, ("Not an NTFS volume\n") );
  1160. Status = STATUS_UNRECOGNIZED_VOLUME;
  1161. leave;
  1162. }
  1163. NtfsOpenSystemFile( IrpContext,
  1164. &Vcb->MftScb,
  1165. Vcb,
  1166. MASTER_FILE_TABLE_NUMBER,
  1167. MirroredMftRange,
  1168. $DATA,
  1169. TRUE );
  1170. CcSetAdditionalCacheAttributes( Vcb->MftScb->FileObject, TRUE, TRUE );
  1171. LlTemp1 = FirstNonMirroredCluster;
  1172. (VOID)NtfsAddNtfsMcbEntry( &Vcb->MftScb->Mcb,
  1173. (LONGLONG)0,
  1174. Vcb->MftStartLcn,
  1175. (LONGLONG)FirstNonMirroredCluster,
  1176. FALSE );
  1177. //
  1178. // Now the same for Mft2
  1179. //
  1180. NtfsOpenSystemFile( IrpContext,
  1181. &Vcb->Mft2Scb,
  1182. Vcb,
  1183. MASTER_FILE_TABLE2_NUMBER,
  1184. MirroredMftRange,
  1185. $DATA,
  1186. TRUE );
  1187. CcSetAdditionalCacheAttributes( Vcb->Mft2Scb->FileObject, TRUE, TRUE );
  1188. (VOID)NtfsAddNtfsMcbEntry( &Vcb->Mft2Scb->Mcb,
  1189. (LONGLONG)0,
  1190. Vcb->Mft2StartLcn,
  1191. (LONGLONG)FirstNonMirroredCluster,
  1192. FALSE );
  1193. //
  1194. // Create the dasd system file, we do it here because we need to dummy
  1195. // up the mcb for it, and that way everything else in NTFS won't need
  1196. // to know that it is a special file. We need to do this after
  1197. // cluster allocation initialization because that computes the total
  1198. // clusters on the volume. Also for verification purposes we will
  1199. // set and get the times off of the volume.
  1200. //
  1201. // Open it now before the Log File, because that is the first time
  1202. // anyone may want to mark the volume corrupt.
  1203. //
  1204. NtfsOpenSystemFile( IrpContext,
  1205. &Vcb->VolumeDasdScb,
  1206. Vcb,
  1207. VOLUME_DASD_NUMBER,
  1208. LlBytesFromClusters( Vcb, Vcb->TotalClusters ),
  1209. $DATA,
  1210. FALSE );
  1211. (VOID)NtfsAddNtfsMcbEntry( &Vcb->VolumeDasdScb->Mcb,
  1212. (LONGLONG)0,
  1213. (LONGLONG)0,
  1214. Vcb->TotalClusters,
  1215. FALSE );
  1216. SetFlag( Vcb->VolumeDasdScb->Fcb->FcbState, FCB_STATE_DUP_INITIALIZED );
  1217. Vcb->VolumeDasdScb->Fcb->LinkCount =
  1218. Vcb->VolumeDasdScb->Fcb->TotalLinks = 1;
  1219. //
  1220. // We want to read the first four record segments of each of these
  1221. // files. We do this so that we don't have a cache miss when we
  1222. // look up the real allocation below.
  1223. //
  1224. for (i = 0; i < 4; i++) {
  1225. FILE_REFERENCE FileReference;
  1226. BOOLEAN ValidRecord;
  1227. ULONG CorruptHint;
  1228. NtfsSetSegmentNumber( &FileReference, 0, i );
  1229. if (i > 0) {
  1230. FileReference.SequenceNumber = (USHORT)i;
  1231. } else {
  1232. FileReference.SequenceNumber = 1;
  1233. }
  1234. NtfsReadMftRecord( IrpContext,
  1235. Vcb,
  1236. &FileReference,
  1237. FALSE,
  1238. &Bcbs[i*2],
  1239. &MftBuffer,
  1240. NULL );
  1241. NtfsMapStream( IrpContext,
  1242. Vcb->Mft2Scb,
  1243. (LONGLONG)(i * Vcb->BytesPerFileRecordSegment),
  1244. Vcb->BytesPerFileRecordSegment,
  1245. &Bcbs[i*2 + 1],
  1246. &Mft2Buffer );
  1247. //
  1248. // First validate the record and if its valid and record 0
  1249. // do an extra check for whether its the mft.
  1250. //
  1251. ValidRecord = NtfsCheckFileRecord( Vcb, MftBuffer, &FileReference, &CorruptHint );
  1252. if (ValidRecord && (i == 0)) {
  1253. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  1254. NtfsInitializeAttributeContext( &Context );
  1255. try {
  1256. if (!NtfsLookupAttributeByCode( IrpContext, Vcb->MftScb->Fcb, &Vcb->MftScb->Fcb->FileReference, $ATTRIBUTE_LIST, &Context )) {
  1257. if (NtfsLookupAttributeByCode( IrpContext, Vcb->MftScb->Fcb, &Vcb->MftScb->Fcb->FileReference, $FILE_NAME, &Context )) {
  1258. PFILE_NAME FileName;
  1259. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &Context ) );
  1260. if ((FileName->FileNameLength != wcslen( L"MFT" )) ||
  1261. (!RtlEqualMemory( FileName->FileName, L"$MFT", FileName->FileNameLength * sizeof( WCHAR )))) {
  1262. ValidRecord = FALSE;
  1263. }
  1264. }
  1265. }
  1266. } finally {
  1267. NtfsCleanupAttributeContext( IrpContext, &Context );
  1268. }
  1269. }
  1270. //
  1271. // If any of these file records are bad then try the mirror
  1272. // (unless we are already looking at the mirror). If we
  1273. // can't find a valid record then fail the mount.
  1274. //
  1275. if (!ValidRecord) {
  1276. if ((MftBuffer != Mft2Buffer) &&
  1277. NtfsCheckFileRecord( Vcb, Mft2Buffer, &FileReference, &CorruptHint ) &&
  1278. !NtfsIsVolumeReadOnly( Vcb )) {
  1279. LlTemp1 = MAXLONGLONG;
  1280. //
  1281. // Put a BaadSignature in this file record,
  1282. // mark it dirty and then read it again.
  1283. // The baad signature should force us to bring
  1284. // in the mirror and we can correct the problem.
  1285. //
  1286. NtfsPinMappedData( IrpContext,
  1287. Vcb->MftScb,
  1288. i * Vcb->BytesPerFileRecordSegment,
  1289. Vcb->BytesPerFileRecordSegment,
  1290. &Bcbs[i*2] );
  1291. RtlCopyMemory( MftBuffer, Mft2Buffer, Vcb->BytesPerFileRecordSegment );
  1292. CcSetDirtyPinnedData( Bcbs[i*2], (PLARGE_INTEGER) &LlTemp1 );
  1293. } else {
  1294. NtfsMarkVolumeDirty( IrpContext, Vcb );
  1295. Status = STATUS_DISK_CORRUPT_ERROR;
  1296. leave;
  1297. }
  1298. }
  1299. }
  1300. //
  1301. // The last file record was the Volume Dasd, so check the version number.
  1302. //
  1303. Attribute = NtfsFirstAttribute(MftBuffer);
  1304. while (TRUE) {
  1305. Attribute = NtfsGetNextRecord(Attribute);
  1306. if (Attribute->TypeCode == $VOLUME_INFORMATION) {
  1307. PVOLUME_INFORMATION VolumeInformation;
  1308. VolumeInformation = (PVOLUME_INFORMATION)NtfsAttributeValue(Attribute);
  1309. VolumeFlags = VolumeInformation->VolumeFlags;
  1310. //
  1311. // Upgrading the disk on NT 5.0 will use version number 3.0. Version
  1312. // number 2.0 was used temporarily when the upgrade was automatic.
  1313. //
  1314. // NOTE - We use the presence of the version number to indicate
  1315. // that the first four file records have been validated. We won't
  1316. // flush the MftMirror if we can't verify these records. Otherwise
  1317. // we might corrupt a valid mirror.
  1318. //
  1319. Vcb->MajorVersion = VolumeInformation->MajorVersion;
  1320. Vcb->MinorVersion = VolumeInformation->MinorVersion;
  1321. if ((Vcb->MajorVersion < 1) || (Vcb->MajorVersion > 3)) {
  1322. NtfsRaiseStatus( IrpContext, STATUS_WRONG_VOLUME, NULL, NULL );
  1323. }
  1324. if (Vcb->MajorVersion > 1) {
  1325. CurrentVersion = TRUE;
  1326. ASSERT( (VolumeInformation->MajorVersion != 2) ||
  1327. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED ) );
  1328. if (NtfsDefragMftEnabled) {
  1329. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_PERMITTED );
  1330. }
  1331. }
  1332. break;
  1333. }
  1334. if (Attribute->TypeCode == $END) {
  1335. NtfsRaiseStatus( IrpContext, STATUS_WRONG_VOLUME, NULL, NULL );
  1336. }
  1337. }
  1338. //
  1339. // Create the log file Scb and really look up its size.
  1340. //
  1341. NtfsOpenSystemFile( IrpContext,
  1342. &Vcb->LogFileScb,
  1343. Vcb,
  1344. LOG_FILE_NUMBER,
  1345. 0,
  1346. $DATA,
  1347. TRUE );
  1348. Vcb->LogFileObject = Vcb->LogFileScb->FileObject;
  1349. CcSetAdditionalCacheAttributes( Vcb->LogFileScb->FileObject, TRUE, TRUE );
  1350. //
  1351. // Lookup the log file mapping now, since we will not go to the
  1352. // disk for allocation information any more once we set restart
  1353. // in progress.
  1354. //
  1355. (VOID)NtfsPreloadAllocation( IrpContext, Vcb->LogFileScb, 0, MAXLONGLONG );
  1356. //
  1357. // Now we have to unpin everything before restart, because it generally
  1358. // has to uninitialize everything.
  1359. //
  1360. NtfsUnpinBcb( IrpContext, &BootBcb );
  1361. for (i = 0; i < 8; i++) {
  1362. NtfsUnpinBcb( IrpContext, &Bcbs[i] );
  1363. }
  1364. NtfsPurgeFileRecordCache( IrpContext );
  1365. //
  1366. // Purge the Mft, since we only read the first four file
  1367. // records, not necessarily an entire page!
  1368. //
  1369. CcPurgeCacheSection( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, FALSE );
  1370. //
  1371. // Now start up the log file and perform Restart. This calls will
  1372. // unpin and remap the Mft Bcb's. The MftBuffer variables above
  1373. // may no longer point to the correct range of bytes. This is OK
  1374. // if they are never referenced.
  1375. //
  1376. // Put a try-except around this to catch any restart failures.
  1377. // This is important in order to allow us to limp along until
  1378. // autochk gets a chance to run.
  1379. //
  1380. // We set restart in progress first, to prevent us from looking up any
  1381. // more run information (now that we know where the log file is!)
  1382. //
  1383. SetFlag( Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS );
  1384. //
  1385. // See if we are in the retry process due to an earlier failure
  1386. // in processing the restart area
  1387. //
  1388. RetryRestart = FlagOn( IrpContext->State, IRP_CONTEXT_STATE_BAD_RESTART );
  1389. if (RetryRestart) {
  1390. //
  1391. // Pass the bad restart info further down the chain
  1392. // and mark the volume dirty.
  1393. // We mark the volume dirty on retry because the
  1394. // dirty bit will not get flush to the disk thru
  1395. // NtfsRaiseStatus. Also LFS calls ExRaiseStatus
  1396. // directly.
  1397. //
  1398. SetFlag( Vcb->VcbState, VCB_STATE_BAD_RESTART );
  1399. NtfsMarkVolumeDirty( IrpContext, Vcb );
  1400. }
  1401. try {
  1402. Status = STATUS_SUCCESS;
  1403. UnrecognizedRestart = FALSE;
  1404. NtfsStartLogFile( Vcb->LogFileScb,
  1405. Vcb );
  1406. //
  1407. // We call the cache manager again with the stream files for the Mft and
  1408. // Mft mirror as we didn't have a log handle for the first call.
  1409. //
  1410. CcSetLogHandleForFile( Vcb->MftScb->FileObject,
  1411. Vcb->LogHandle,
  1412. &LfsFlushToLsn );
  1413. CcSetLogHandleForFile( Vcb->Mft2Scb->FileObject,
  1414. Vcb->LogHandle,
  1415. &LfsFlushToLsn );
  1416. CloseAttributes = TRUE;
  1417. if (!NtfsIsVolumeReadOnly( Vcb )) {
  1418. UpdatesApplied = NtfsRestartVolume( IrpContext, Vcb, &UnrecognizedRestart );
  1419. }
  1420. //
  1421. // For right now, we will charge ahead with a dirty volume, no
  1422. // matter what the exception was. Later we will have to be
  1423. // defensive and use a filter.
  1424. //
  1425. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1426. Status = GetExceptionCode();
  1427. if ((Status == STATUS_DISK_CORRUPT_ERROR) ||
  1428. (Status == STATUS_FILE_CORRUPT_ERROR)) {
  1429. //
  1430. // If this is the first time we hit this error during restart,
  1431. // we will remember it in the irp context so that we can retry
  1432. // from the top by raising STATUS_CANT_WAIT.
  1433. //
  1434. if (!RetryRestart) {
  1435. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_BAD_RESTART );
  1436. NtfsFailedLfsRestart++;
  1437. }
  1438. }
  1439. //
  1440. // If the error is STATUS_LOG_FILE_FULL then it means that
  1441. // we couldn't complete the restart. Mark the volume dirty in
  1442. // this case. Don't return this error code.
  1443. //
  1444. if (Status == STATUS_LOG_FILE_FULL) {
  1445. Status = STATUS_DISK_CORRUPT_ERROR;
  1446. IrpContext->ExceptionStatus = STATUS_DISK_CORRUPT_ERROR;
  1447. }
  1448. }
  1449. //
  1450. // If we hit a corruption exception while processing the
  1451. // logfile, we need to retry and avoid those errors.
  1452. //
  1453. if (!RetryRestart &&
  1454. FlagOn( IrpContext->State, IRP_CONTEXT_STATE_BAD_RESTART )) {
  1455. IrpContext->ExceptionStatus = STATUS_CANT_WAIT;
  1456. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  1457. }
  1458. //
  1459. // If we hit an error trying to mount this as a readonly volume,
  1460. // fail the mount. We don't want to do any writes.
  1461. //
  1462. if (Status == STATUS_MEDIA_WRITE_PROTECTED) {
  1463. ASSERT( FlagOn( Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY ) );
  1464. ClearFlag( Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY );
  1465. leave;
  1466. }
  1467. //
  1468. // Mark the volume dirty if we hit an error during restart or if we didn't
  1469. // recognize the restart area. In that case also mark the volume dirty but
  1470. // continue to run.
  1471. //
  1472. if (!NT_SUCCESS( Status ) || UnrecognizedRestart) {
  1473. LONGLONG VolumeDasdOffset;
  1474. NtfsSetAndGetVolumeTimes( IrpContext, Vcb, TRUE );
  1475. //
  1476. // Now flush it out, so chkdsk can see it with Dasd.
  1477. // Clear the error in the IrpContext so that this
  1478. // flush will succeed. Otherwise CommonWrite will
  1479. // return FILE_LOCK_CONFLICT.
  1480. //
  1481. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  1482. VolumeDasdOffset = VOLUME_DASD_NUMBER << Vcb->MftShift;
  1483. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject,
  1484. (PLARGE_INTEGER)&VolumeDasdOffset,
  1485. Vcb->BytesPerFileRecordSegment,
  1486. NULL );
  1487. if (!NT_SUCCESS( Status )) {
  1488. leave;
  1489. }
  1490. }
  1491. //
  1492. // Now flush the Mft copies, because we are going to shut the real
  1493. // one down and reopen it for real.
  1494. //
  1495. CcFlushCache( &Vcb->Mft2Scb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1496. if (NT_SUCCESS( IoStatus.Status )) {
  1497. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1498. }
  1499. NtfsCleanupTransaction( IrpContext, IoStatus.Status, TRUE );
  1500. //
  1501. // Show that the restart is complete, and it is safe to go to
  1502. // the disk for the Mft allocation.
  1503. //
  1504. ClearFlag( Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS );
  1505. //
  1506. // Set the Mft sizes back down to the part which is guaranteed to
  1507. // be contiguous for now. Important on large page size systems!
  1508. //
  1509. Vcb->MftScb->Header.AllocationSize.QuadPart =
  1510. Vcb->MftScb->Header.FileSize.QuadPart =
  1511. Vcb->MftScb->Header.ValidDataLength.QuadPart = FirstNonMirroredCluster << Vcb->ClusterShift;
  1512. //
  1513. // Pin the first four file records. We need to lock the pages to
  1514. // absolutely guarantee they stay in memory, otherwise we may
  1515. // generate a recursive page fault, forcing MM to block.
  1516. //
  1517. for (i = 0; i < 4; i++) {
  1518. FILE_REFERENCE FileReference;
  1519. ULONG CorruptHint;
  1520. NtfsSetSegmentNumber( &FileReference, 0, i );
  1521. if (i > 0) {
  1522. FileReference.SequenceNumber = (USHORT)i;
  1523. } else {
  1524. FileReference.SequenceNumber = 1;
  1525. }
  1526. NtfsPinStream( IrpContext,
  1527. Vcb->MftScb,
  1528. (LONGLONG)(i << Vcb->MftShift),
  1529. Vcb->BytesPerFileRecordSegment,
  1530. &Bcbs[i*2],
  1531. (PVOID *)&MftBuffer );
  1532. Mdls[i*2] = IoAllocateMdl( MftBuffer,
  1533. Vcb->BytesPerFileRecordSegment,
  1534. FALSE,
  1535. FALSE,
  1536. NULL );
  1537. //
  1538. // Verify that we got an Mdl.
  1539. //
  1540. if (Mdls[i*2] == NULL) {
  1541. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  1542. }
  1543. MmProbeAndLockPages( Mdls[i*2], KernelMode, IoReadAccess );
  1544. NtfsPinStream( IrpContext,
  1545. Vcb->Mft2Scb,
  1546. (LONGLONG)(i << Vcb->MftShift),
  1547. Vcb->BytesPerFileRecordSegment,
  1548. &Bcbs[i*2 + 1],
  1549. &Mft2Buffer );
  1550. Mdls[i*2 + 1] = IoAllocateMdl( Mft2Buffer,
  1551. Vcb->BytesPerFileRecordSegment,
  1552. FALSE,
  1553. FALSE,
  1554. NULL );
  1555. //
  1556. // Verify that we got an Mdl.
  1557. //
  1558. if (Mdls[i*2 + 1] == NULL) {
  1559. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  1560. }
  1561. MmProbeAndLockPages( Mdls[i*2 + 1], KernelMode, IoReadAccess );
  1562. //
  1563. // If any of these file records are bad then try the mirror
  1564. // (unless we are already looking at the mirror). If we
  1565. // can't find a valid record then fail the mount.
  1566. //
  1567. if (!NtfsCheckFileRecord( Vcb, MftBuffer, &FileReference, &CorruptHint )) {
  1568. if ((MftBuffer != Mft2Buffer) &&
  1569. NtfsCheckFileRecord( Vcb, Mft2Buffer, &FileReference, &CorruptHint )) {
  1570. LlTemp1 = MAXLONGLONG;
  1571. //
  1572. // Put a BaadSignature in this file record,
  1573. // mark it dirty and then read it again.
  1574. // The baad signature should force us to bring
  1575. // in the mirror and we can correct the problem.
  1576. //
  1577. RtlCopyMemory( MftBuffer, Mft2Buffer, Vcb->BytesPerFileRecordSegment );
  1578. CcSetDirtyPinnedData( Bcbs[i*2], (PLARGE_INTEGER) &LlTemp1 );
  1579. } else {
  1580. NtfsMarkVolumeDirty( IrpContext, Vcb );
  1581. Status = STATUS_DISK_CORRUPT_ERROR;
  1582. leave;
  1583. }
  1584. }
  1585. }
  1586. //
  1587. // Now we need to uninitialize and purge the Mft and Mft2. This is
  1588. // because we could have only a partially filled page at the end, and
  1589. // we need to do real reads of whole pages now.
  1590. //
  1591. //
  1592. // Uninitialize and reinitialize the large mcbs so that we can reload
  1593. // it from the File Record.
  1594. //
  1595. NtfsUnloadNtfsMcbRange( &Vcb->MftScb->Mcb, (LONGLONG) 0, MAXLONGLONG, TRUE, FALSE );
  1596. NtfsUnloadNtfsMcbRange( &Vcb->Mft2Scb->Mcb, (LONGLONG) 0, MAXLONGLONG, TRUE, FALSE );
  1597. //
  1598. // Mark both of them as uninitialized.
  1599. //
  1600. ClearFlag( Vcb->MftScb->ScbState, SCB_STATE_FILE_SIZE_LOADED );
  1601. ClearFlag( Vcb->Mft2Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED );
  1602. //
  1603. // We need to deal with a rare case where the Scb for a non-resident attribute
  1604. // list for the Mft has been created but the size is not correct. This could
  1605. // happen if we logged part of the stream but not the whole stream. In that
  1606. // case we really want to load the correct numbers into the Scb. We will need the
  1607. // full attribute list if we are to look up the allocation for the Mft
  1608. // immediately after this.
  1609. //
  1610. MftLinks = Vcb->MftScb->Fcb->ScbQueue.Flink;
  1611. while (MftLinks != &Vcb->MftScb->Fcb->ScbQueue) {
  1612. AttributeListScb = CONTAINING_RECORD( MftLinks,
  1613. SCB,
  1614. FcbLinks );
  1615. if (AttributeListScb->AttributeTypeCode == $ATTRIBUTE_LIST) {
  1616. //
  1617. // Clear the flags so we can reload the information from disk.
  1618. // Also unload the allocation. If we have a log record for a
  1619. // change to the attribute list for the Mft then the allocation
  1620. // may only be partially loaded. Looking up the allocation for the
  1621. // Mft below could easily hit one of the holes. This way we will
  1622. // reload all of the allocation.
  1623. //
  1624. NtfsUnloadNtfsMcbRange( &AttributeListScb->Mcb, 0, MAXLONGLONG, TRUE, FALSE );
  1625. ClearFlag( AttributeListScb->ScbState, SCB_STATE_FILE_SIZE_LOADED | SCB_STATE_HEADER_INITIALIZED );
  1626. NtfsUpdateScbFromAttribute( IrpContext, AttributeListScb, NULL );
  1627. //
  1628. // Let the cache manager know the sizes if this is cached.
  1629. //
  1630. if (AttributeListScb->FileObject != NULL) {
  1631. CcSetFileSizes( AttributeListScb->FileObject,
  1632. (PCC_FILE_SIZES) &AttributeListScb->Header.AllocationSize );
  1633. }
  1634. break;
  1635. }
  1636. MftLinks = MftLinks->Flink;
  1637. }
  1638. //
  1639. // Now load up the real allocation from just the first file record.
  1640. //
  1641. if (Vcb->FileRecordsPerCluster == 0) {
  1642. NtfsPreloadAllocation( IrpContext,
  1643. Vcb->MftScb,
  1644. 0,
  1645. (FIRST_USER_FILE_NUMBER - 1) << Vcb->MftToClusterShift );
  1646. } else {
  1647. NtfsPreloadAllocation( IrpContext,
  1648. Vcb->MftScb,
  1649. 0,
  1650. (FIRST_USER_FILE_NUMBER - 1) >> Vcb->MftToClusterShift );
  1651. }
  1652. NtfsPreloadAllocation( IrpContext, Vcb->Mft2Scb, 0, MAXLONGLONG );
  1653. //
  1654. // We update the Mft and the Mft mirror before we delete the current
  1655. // stream file for the Mft. We know we can read the true attributes
  1656. // for the Mft and the Mirror because we initialized their sizes
  1657. // above through the first few records in the Mft.
  1658. //
  1659. NtfsUpdateScbFromAttribute( IrpContext, Vcb->MftScb, NULL );
  1660. //
  1661. // We will attempt to upgrade the version only if this isn't already
  1662. // a version 2 or 3 volume, the upgrade bit is set, and we aren't
  1663. // retrying the mount because the upgrade failed last time.
  1664. // We will always upgrade a new volume
  1665. //
  1666. if ((Vcb->MajorVersion == 1) &&
  1667. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED ) &&
  1668. (NtfsForceUpgrade ?
  1669. (!FlagOn( NtfsData.Flags, NTFS_FLAGS_DISABLE_UPGRADE ) ||
  1670. (Vcb->MftScb->Header.FileSize.QuadPart <= FIRST_USER_FILE_NUMBER * Vcb->BytesPerFileRecordSegment))
  1671. :
  1672. FlagOn( VolumeFlags, VOLUME_UPGRADE_ON_MOUNT ))) {
  1673. //
  1674. // We can't upgrade R/O volumes, so we can't proceed either.
  1675. //
  1676. if (NtfsIsVolumeReadOnly( Vcb )) {
  1677. Status = STATUS_MEDIA_WRITE_PROTECTED;
  1678. leave;
  1679. }
  1680. UpgradeVolume = TRUE;
  1681. }
  1682. ClearFlag( Vcb->MftScb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  1683. ClearFlag( Vcb->MftScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  1684. if (!FlagOn( Vcb->MftScb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  1685. Vcb->MftScb->CompressionUnit = 0;
  1686. Vcb->MftScb->CompressionUnitShift = 0;
  1687. }
  1688. NtfsUpdateScbFromAttribute( IrpContext, Vcb->Mft2Scb, NULL );
  1689. ClearFlag( Vcb->Mft2Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  1690. ClearFlag( Vcb->Mft2Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  1691. if (!FlagOn( Vcb->Mft2Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  1692. Vcb->Mft2Scb->CompressionUnit = 0;
  1693. Vcb->Mft2Scb->CompressionUnitShift = 0;
  1694. }
  1695. //
  1696. // Unpin the Bcb's for the Mft files before uninitializing.
  1697. //
  1698. for (i = 0; i < 8; i++) {
  1699. NtfsUnpinBcb( IrpContext, &Bcbs[i] );
  1700. //
  1701. // Now we can get rid of these Mdls.
  1702. //
  1703. MmUnlockPages( Mdls[i] );
  1704. IoFreeMdl( Mdls[i] );
  1705. Mdls[i] = NULL;
  1706. }
  1707. //
  1708. // Before we call CcSetAdditionalCacheAttributes to disable write behind,
  1709. // we need to flush what we can now.
  1710. //
  1711. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1712. //
  1713. // Now close and purge the Mft, and recreate its stream so that
  1714. // the Mft is in a normal state, and we can close the rest of
  1715. // the attributes from restart. We need to bump the close count
  1716. // to keep the scb around while we do this little bit of trickery
  1717. //
  1718. {
  1719. Vcb->MftScb->CloseCount += 1;
  1720. NtfsPurgeFileRecordCache( IrpContext );
  1721. NtfsDeleteInternalAttributeStream( Vcb->MftScb, TRUE, FALSE );
  1722. NtfsCreateInternalAttributeStream( IrpContext,
  1723. Vcb->MftScb,
  1724. FALSE,
  1725. &NtfsSystemFiles[MASTER_FILE_TABLE_NUMBER] );
  1726. //
  1727. // Tell the cache manager the file sizes for the MFT. It is possible
  1728. // that the shared cache map did not go away on the DeleteInternalAttributeStream
  1729. // call above. In that case the Cache Manager has the file sizes from
  1730. // restart.
  1731. //
  1732. CcSetFileSizes( Vcb->MftScb->FileObject,
  1733. (PCC_FILE_SIZES) &Vcb->MftScb->Header.AllocationSize );
  1734. CcSetAdditionalCacheAttributes( Vcb->MftScb->FileObject, TRUE, FALSE );
  1735. Vcb->MftScb->CloseCount -= 1;
  1736. }
  1737. //
  1738. // We want to read all of the file records for the Mft to put
  1739. // its complete mapping into the Mcb.
  1740. //
  1741. SetFlag( Vcb->VcbState, VCB_STATE_PRELOAD_MFT );
  1742. NtfsPreloadAllocation( IrpContext, Vcb->MftScb, 0, MAXLONGLONG );
  1743. ClearFlag( Vcb->VcbState, VCB_STATE_PRELOAD_MFT );
  1744. //
  1745. // Close the boot file (get rid of it because we do not know its proper
  1746. // size, and the Scb may be inconsistent).
  1747. //
  1748. NtfsDeleteInternalAttributeStream( BootScb, TRUE, FALSE );
  1749. BootScb = NULL;
  1750. //
  1751. // Closing the attributes from restart has to occur here after
  1752. // the Mft is clean, because flushing these files will cause
  1753. // file size updates to occur, etc.
  1754. //
  1755. Status = NtfsCloseAttributesFromRestart( IrpContext, Vcb );
  1756. CloseAttributes = FALSE;
  1757. if (!NT_SUCCESS( Status )) {
  1758. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  1759. }
  1760. //
  1761. // The CHECKPOINT flags function the same way whether the volume is mounted
  1762. // read-only or not. We just ignore the actual checkpointing process.
  1763. //
  1764. NtfsAcquireCheckpoint( IrpContext, Vcb );
  1765. //
  1766. // Show that it is ok to checkpoint now.
  1767. //
  1768. ClearFlag( Vcb->CheckpointFlags,
  1769. VCB_CHECKPOINT_SYNC_FLAGS |
  1770. VCB_LAST_CHECKPOINT_CLEAN |
  1771. VCB_LAST_CHECKPOINT_PSEUDO_CLEAN );
  1772. //
  1773. // Clear the flag indicating that we won't defrag the volume.
  1774. //
  1775. ClearFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_ENABLED );
  1776. NtfsSetCheckpointNotify( IrpContext, Vcb );
  1777. NtfsReleaseCheckpoint( IrpContext, Vcb );
  1778. //
  1779. // We always need to write a checkpoint record so that we have
  1780. // a checkpoint on the disk before we modify any files.
  1781. //
  1782. #ifdef PERF_STATS
  1783. IrpContext->LogFullReason = LF_MOUNT;
  1784. #endif
  1785. NtfsCheckpointVolume( IrpContext,
  1786. Vcb,
  1787. FALSE,
  1788. UpdatesApplied,
  1789. UpdatesApplied,
  1790. 0,
  1791. Vcb->LastRestartArea );
  1792. //
  1793. // Now set the defrag enabled flag.
  1794. //
  1795. NtfsAcquireCheckpoint( IrpContext, Vcb );
  1796. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_ENABLED );
  1797. NtfsReleaseCheckpoint( IrpContext, Vcb );
  1798. /* Format is using wrong attribute definitions
  1799. //
  1800. // At this point we are ready to use the volume normally. We could
  1801. // open the remaining system files by name, but for now we will go
  1802. // ahead and open them by file number.
  1803. //
  1804. NtfsOpenSystemFile( IrpContext,
  1805. &Vcb->AttributeDefTableScb,
  1806. Vcb,
  1807. ATTRIBUTE_DEF_TABLE_NUMBER,
  1808. 0,
  1809. $DATA,
  1810. FALSE );
  1811. //
  1812. // Read in the attribute definitions.
  1813. //
  1814. {
  1815. PSCB Scb = Vcb->AttributeDefTableScb;
  1816. if ((Scb->Header.FileSize.HighPart != 0) || (Scb->Header.FileSize.LowPart == 0)) {
  1817. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1818. }
  1819. Vcb->AttributeDefinitions = NtfsAllocatePool(PagedPool, Scb->Header.FileSize.LowPart );
  1820. CcCopyRead( Scb->FileObject,
  1821. &Li0,
  1822. Scb->Header.FileSize.LowPart,
  1823. TRUE,
  1824. Vcb->AttributeDefinitions,
  1825. &IoStatus );
  1826. if (!NT_SUCCESS(IoStatus.Status)) {
  1827. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1828. }
  1829. }
  1830. */
  1831. //
  1832. // Just point to our own attribute definitions for now.
  1833. //
  1834. Vcb->AttributeDefinitions = NtfsAttributeDefinitions;
  1835. //
  1836. // Open the upcase table.
  1837. //
  1838. NtfsOpenSystemFile( IrpContext,
  1839. &Vcb->UpcaseTableScb,
  1840. Vcb,
  1841. UPCASE_TABLE_NUMBER,
  1842. 0,
  1843. $DATA,
  1844. FALSE );
  1845. //
  1846. // Read in the upcase table.
  1847. //
  1848. {
  1849. PSCB Scb = Vcb->UpcaseTableScb;
  1850. if ((Scb->Header.FileSize.HighPart != 0) || (Scb->Header.FileSize.LowPart < 512)) {
  1851. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1852. }
  1853. Vcb->UpcaseTable = NtfsAllocatePool(PagedPool, Scb->Header.FileSize.LowPart );
  1854. Vcb->UpcaseTableSize = Scb->Header.FileSize.LowPart / sizeof( WCHAR );
  1855. CcCopyRead( Scb->FileObject,
  1856. &Li0,
  1857. Scb->Header.FileSize.LowPart,
  1858. TRUE,
  1859. Vcb->UpcaseTable,
  1860. &IoStatus );
  1861. if (!NT_SUCCESS( IoStatus.Status )) {
  1862. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1863. }
  1864. //
  1865. // If we do not have a global upcase table yet then make this one the global one
  1866. //
  1867. if (NtfsData.UpcaseTable == NULL) {
  1868. NtfsData.UpcaseTable = Vcb->UpcaseTable;
  1869. NtfsData.UpcaseTableSize = Vcb->UpcaseTableSize;
  1870. //
  1871. // Otherwise if this one perfectly matches the global upcase table then throw
  1872. // this one back and use the global one
  1873. //
  1874. } else if ((NtfsData.UpcaseTableSize == Vcb->UpcaseTableSize)
  1875. &&
  1876. (RtlCompareMemory( NtfsData.UpcaseTable,
  1877. Vcb->UpcaseTable,
  1878. Vcb->UpcaseTableSize) == Vcb->UpcaseTableSize)) {
  1879. NtfsFreePool( Vcb->UpcaseTable );
  1880. Vcb->UpcaseTable = NtfsData.UpcaseTable;
  1881. }
  1882. }
  1883. NtfsOpenSystemFile( IrpContext,
  1884. &Vcb->BitmapScb,
  1885. Vcb,
  1886. BIT_MAP_FILE_NUMBER,
  1887. 0,
  1888. $DATA,
  1889. TRUE );
  1890. NtfsOpenSystemFile( IrpContext,
  1891. &Vcb->BadClusterFileScb,
  1892. Vcb,
  1893. BAD_CLUSTER_FILE_NUMBER,
  1894. 0,
  1895. $DATA,
  1896. TRUE );
  1897. NtfsOpenSystemFile( IrpContext,
  1898. &Vcb->MftBitmapScb,
  1899. Vcb,
  1900. MASTER_FILE_TABLE_NUMBER,
  1901. 0,
  1902. $BITMAP,
  1903. TRUE );
  1904. //
  1905. // Initialize the bitmap support
  1906. //
  1907. NtfsInitializeClusterAllocation( IrpContext, Vcb );
  1908. NtfsSetAndGetVolumeTimes( IrpContext, Vcb, FALSE );
  1909. //
  1910. // Initialize the Mft record allocation
  1911. //
  1912. {
  1913. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  1914. BOOLEAN FoundAttribute;
  1915. ULONG ExtendGranularity;
  1916. //
  1917. // Lookup the bitmap allocation for the Mft file.
  1918. //
  1919. NtfsInitializeAttributeContext( &AttrContext );
  1920. //
  1921. // Use a try finally to cleanup the attribute context.
  1922. //
  1923. try {
  1924. //
  1925. // CODENOTE Is the Mft Fcb fully initialized at this point??
  1926. //
  1927. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  1928. Vcb->MftScb->Fcb,
  1929. &Vcb->MftScb->Fcb->FileReference,
  1930. $BITMAP,
  1931. &AttrContext );
  1932. //
  1933. // Error if we don't find the bitmap
  1934. //
  1935. if (!FoundAttribute) {
  1936. DebugTrace( 0, 0, ("Couldn't find bitmap attribute for Mft\n") );
  1937. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  1938. }
  1939. //
  1940. // If there is no file object for the Mft Scb, we create it now.
  1941. //
  1942. if (Vcb->MftScb->FileObject == NULL) {
  1943. NtfsCreateInternalAttributeStream( IrpContext, Vcb->MftScb, TRUE, NULL );
  1944. }
  1945. //
  1946. // TEMPCODE We need a better way to determine the optimal
  1947. // truncate and extend granularity.
  1948. //
  1949. ExtendGranularity = MFT_EXTEND_GRANULARITY;
  1950. if ((ExtendGranularity * Vcb->BytesPerFileRecordSegment) < Vcb->BytesPerCluster) {
  1951. ExtendGranularity = Vcb->FileRecordsPerCluster;
  1952. }
  1953. NtfsInitializeRecordAllocation( IrpContext,
  1954. Vcb->MftScb,
  1955. &AttrContext,
  1956. Vcb->BytesPerFileRecordSegment,
  1957. ExtendGranularity,
  1958. ExtendGranularity,
  1959. &Vcb->MftScb->ScbType.Index.RecordAllocationContext );
  1960. } finally {
  1961. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  1962. }
  1963. }
  1964. //
  1965. // Get the serial number and volume label for the volume
  1966. //
  1967. NtfsGetVolumeInformation( IrpContext, Vpb, Vcb, &VolumeFlags );
  1968. //
  1969. // Get the Device Name for this volume.
  1970. //
  1971. Status = ObQueryNameString( Vpb->RealDevice,
  1972. NULL,
  1973. 0,
  1974. &DeviceObjectNameLength );
  1975. ASSERT( Status != STATUS_SUCCESS );
  1976. //
  1977. // Unlike the rest of the system, ObQueryNameString returns
  1978. // STATUS_INFO_LENGTH_MISMATCH instead of STATUS_BUFFER_TOO_SMALL when
  1979. // passed too small a buffer.
  1980. //
  1981. // We expect to get this error here. Anything else we can't handle.
  1982. //
  1983. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  1984. DeviceObjectName = NtfsAllocatePool( PagedPool, DeviceObjectNameLength );
  1985. Status = ObQueryNameString( Vpb->RealDevice,
  1986. DeviceObjectName,
  1987. DeviceObjectNameLength,
  1988. &DeviceObjectNameLength );
  1989. }
  1990. if (!NT_SUCCESS( Status )) {
  1991. leave;
  1992. }
  1993. //
  1994. // Now that we are successfully mounting, let us see if we should
  1995. // enable balanced reads.
  1996. //
  1997. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY )) {
  1998. FsRtlBalanceReads( DeviceObjectWeTalkTo );
  1999. }
  2000. ASSERT( DeviceObjectName->Name.Length != 0 );
  2001. Vcb->DeviceName.MaximumLength =
  2002. Vcb->DeviceName.Length = DeviceObjectName->Name.Length;
  2003. Vcb->DeviceName.Buffer = NtfsAllocatePool( PagedPool, DeviceObjectName->Name.Length );
  2004. RtlCopyMemory( Vcb->DeviceName.Buffer,
  2005. DeviceObjectName->Name.Buffer,
  2006. DeviceObjectName->Name.Length );
  2007. //
  2008. // Now we want to initialize the remaining defrag status values.
  2009. //
  2010. Vcb->MftHoleGranularity = MFT_HOLE_GRANULARITY;
  2011. Vcb->MftClustersPerHole = Vcb->MftHoleGranularity << Vcb->MftToClusterShift;
  2012. if (MFT_HOLE_GRANULARITY < Vcb->FileRecordsPerCluster) {
  2013. Vcb->MftHoleGranularity = Vcb->FileRecordsPerCluster;
  2014. Vcb->MftClustersPerHole = 1;
  2015. }
  2016. Vcb->MftHoleMask = Vcb->MftHoleGranularity - 1;
  2017. Vcb->MftHoleInverseMask = ~(Vcb->MftHoleMask);
  2018. Vcb->MftHoleClusterMask = Vcb->MftClustersPerHole - 1;
  2019. Vcb->MftHoleClusterInverseMask = ~(Vcb->MftHoleClusterMask);
  2020. //
  2021. // Our maximum reserved Mft space is 0x140, we will try to
  2022. // get an extra 40 bytes if possible.
  2023. //
  2024. Vcb->MftReserved = Vcb->BytesPerFileRecordSegment / 8;
  2025. if (Vcb->MftReserved > 0x140) {
  2026. Vcb->MftReserved = 0x140;
  2027. }
  2028. Vcb->MftCushion = Vcb->MftReserved - 0x20;
  2029. NtfsScanMftBitmap( IrpContext, Vcb );
  2030. #ifdef NTFS_CHECK_BITMAP
  2031. {
  2032. ULONG BitmapSize;
  2033. ULONG Count;
  2034. BitmapSize = Vcb->BitmapScb->Header.FileSize.LowPart;
  2035. //
  2036. // Allocate a buffer for the bitmap copy and each individual bitmap.
  2037. //
  2038. Vcb->BitmapPages = (BitmapSize + PAGE_SIZE - 1) / PAGE_SIZE;
  2039. Vcb->BitmapCopy = NtfsAllocatePool(PagedPool, Vcb->BitmapPages * sizeof( RTL_BITMAP ));
  2040. RtlZeroMemory( Vcb->BitmapCopy, Vcb->BitmapPages * sizeof( RTL_BITMAP ));
  2041. //
  2042. // Now get a buffer for each page.
  2043. //
  2044. for (Count = 0; Count < Vcb->BitmapPages; Count += 1) {
  2045. (Vcb->BitmapCopy + Count)->Buffer = NtfsAllocatePool(PagedPool, PAGE_SIZE );
  2046. RtlInitializeBitMap( Vcb->BitmapCopy + Count, (Vcb->BitmapCopy + Count)->Buffer, PAGE_SIZE * 8 );
  2047. }
  2048. if (NtfsCopyBitmap) {
  2049. PUCHAR NextPage;
  2050. PBCB BitmapBcb = NULL;
  2051. ULONG BytesToCopy;
  2052. LONGLONG FileOffset = 0;
  2053. Count = 0;
  2054. while (BitmapSize) {
  2055. BytesToCopy = PAGE_SIZE;
  2056. if (BytesToCopy > BitmapSize) {
  2057. BytesToCopy = BitmapSize;
  2058. }
  2059. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  2060. NtfsMapStream( IrpContext, Vcb->BitmapScb, FileOffset, BytesToCopy, &BitmapBcb, &NextPage );
  2061. RtlCopyMemory( (Vcb->BitmapCopy + Count)->Buffer,
  2062. NextPage,
  2063. BytesToCopy );
  2064. BitmapSize -= BytesToCopy;
  2065. FileOffset += BytesToCopy;
  2066. Count += 1;
  2067. }
  2068. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  2069. //
  2070. // Otherwise we will want to scan the entire Mft and compare the mapping pairs
  2071. // with the current volume bitmap.
  2072. //
  2073. }
  2074. }
  2075. #endif
  2076. //
  2077. // Whether this was already an upgraded volume or we want it to
  2078. // be one now, we need to open all the new indices.
  2079. //
  2080. if ((CurrentVersion || UpgradeVolume) &&
  2081. !SkipNtOfs) {
  2082. BOOLEAN UpdatedVolumeVersion = FALSE;
  2083. try {
  2084. //
  2085. // Open the Root Directory.
  2086. //
  2087. NtfsOpenRootDirectory( IrpContext, Vcb );
  2088. //
  2089. // Create/open the security file and initialize security on the volume.
  2090. //
  2091. NtfsInitializeSecurityFile( IrpContext, Vcb );
  2092. //
  2093. // Create/open the $Extend directory.
  2094. //
  2095. NtfsInitializeExtendDirectory( IrpContext, Vcb );
  2096. //
  2097. // Create/open the Quota File and initialize quotas.
  2098. //
  2099. NtfsInitializeQuotaFile( IrpContext, Vcb );
  2100. //
  2101. // Create/open the Object Id File and initialize object ids.
  2102. //
  2103. NtfsInitializeObjectIdFile( IrpContext, Vcb );
  2104. //
  2105. // Create/open the Mount Points File and initialize it.
  2106. //
  2107. NtfsInitializeReparseFile( IrpContext, Vcb );
  2108. //
  2109. // Open the Usn Journal only if it is there. If the volume was mounted
  2110. // on a 4.0 system then we want to restamp the journal. Skip the
  2111. // initialization if the volume flags indicate that the journal
  2112. // delete has started.
  2113. // No USN journal if we're mounting Read Only.
  2114. //
  2115. if (FlagOn( VolumeFlags, VOLUME_DELETE_USN_UNDERWAY )) {
  2116. SetFlag( Vcb->VcbState, VCB_STATE_USN_DELETE );
  2117. } else if (!NtfsIsVolumeReadOnly( Vcb )) {
  2118. NtfsInitializeUsnJournal( IrpContext,
  2119. Vcb,
  2120. FALSE,
  2121. FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 ),
  2122. (PCREATE_USN_JOURNAL_DATA) &Vcb->UsnJournalInstance.MaximumSize );
  2123. if (FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 )) {
  2124. NtfsSetVolumeInfoFlagState( IrpContext,
  2125. Vcb,
  2126. VOLUME_MOUNTED_ON_40,
  2127. FALSE,
  2128. TRUE );
  2129. }
  2130. }
  2131. //
  2132. // Upgrade all security information
  2133. //
  2134. NtfsUpgradeSecurity( IrpContext, Vcb );
  2135. ASSERT( Vcb->RootIndexScb != NULL );
  2136. NtfsCleanupTransaction( IrpContext, STATUS_SUCCESS, FALSE );
  2137. //
  2138. // Update version numbers in volinfo
  2139. //
  2140. if (!NtfsIsVolumeReadOnly( Vcb )) {
  2141. UpdatedVolumeVersion = NtfsUpdateVolumeInfo( IrpContext, Vcb, NTFS_MAJOR_VERSION, NTFS_MINOR_VERSION );
  2142. }
  2143. //
  2144. // If we've gotten this far during the mount, it's safe to
  2145. // update the version number on disk if necessary.
  2146. //
  2147. if (UpgradeVolume) {
  2148. //
  2149. // Now enable defragging.
  2150. //
  2151. if (NtfsDefragMftEnabled) {
  2152. NtfsAcquireCheckpoint( IrpContext, Vcb );
  2153. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_PERMITTED );
  2154. NtfsReleaseCheckpoint( IrpContext, Vcb );
  2155. }
  2156. //
  2157. // Update the on-disk attribute definition table to include the
  2158. // new attributes for an upgraded volume.
  2159. //
  2160. NtfsUpdateAttributeTable( IrpContext, Vcb );
  2161. }
  2162. } finally {
  2163. if (!NT_SUCCESS( IrpContext->ExceptionStatus ) && UpgradeVolume) {
  2164. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED );
  2165. }
  2166. }
  2167. if (UpdatedVolumeVersion) {
  2168. //
  2169. // If we've upgraded successfully, we should clear the upgrade
  2170. // bit now so we can use it again in the future.
  2171. //
  2172. NtfsSetVolumeInfoFlagState( IrpContext,
  2173. Vcb,
  2174. VOLUME_UPGRADE_ON_MOUNT,
  2175. FALSE,
  2176. TRUE );
  2177. }
  2178. } else {
  2179. //
  2180. // If we haven't opened the root directory, do so
  2181. //
  2182. ASSERT( Vcb->RootIndexScb == NULL );
  2183. if (Vcb->RootIndexScb == NULL) {
  2184. NtfsOpenRootDirectory( IrpContext, Vcb );
  2185. }
  2186. NtfsCleanupTransaction( IrpContext, STATUS_SUCCESS, FALSE );
  2187. }
  2188. //
  2189. // Start the usn journal delete operation if the vcb flag is specified.
  2190. //
  2191. if (FlagOn( Vcb->VcbState, VCB_STATE_USN_DELETE )) {
  2192. NtfsPostSpecial( IrpContext, Vcb, NtfsDeleteUsnSpecial, &Vcb->DeleteUsnData );
  2193. }
  2194. //
  2195. // If the last mount was on a 4.0 volume then we need to clean up the quota
  2196. // and object id indices.
  2197. //
  2198. if ((Vcb->MajorVersion >= 3) &&
  2199. FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 )) {
  2200. NtfsSetVolumeInfoFlagState( IrpContext,
  2201. Vcb,
  2202. VOLUME_REPAIR_OBJECT_ID,
  2203. TRUE,
  2204. TRUE );
  2205. SetFlag( VolumeFlags, VOLUME_REPAIR_OBJECT_ID );
  2206. //
  2207. // Fire off the quota cleanup if quotas are enabled.
  2208. //
  2209. if (FlagOn( Vcb->QuotaFlags, (QUOTA_FLAG_TRACKING_REQUESTED |
  2210. QUOTA_FLAG_TRACKING_ENABLED |
  2211. QUOTA_FLAG_ENFORCEMENT_ENABLED ))) {
  2212. NtfsMarkQuotaCorrupt( IrpContext, Vcb );
  2213. }
  2214. }
  2215. //
  2216. // Start the object ID cleanup if we were mounted on 4.0 or had started
  2217. // in a previous mount.
  2218. //
  2219. if (FlagOn( VolumeFlags, VOLUME_REPAIR_OBJECT_ID )) {
  2220. NtfsPostSpecial( IrpContext, Vcb, NtfsRepairObjectId, NULL );
  2221. }
  2222. //
  2223. // Clear the MOUNTED_ON_40 and CHKDSK_MODIFIED flags if set.
  2224. //
  2225. if (FlagOn( VolumeFlags, VOLUME_MOUNTED_ON_40 | VOLUME_MODIFIED_BY_CHKDSK )) {
  2226. NtfsSetVolumeInfoFlagState( IrpContext,
  2227. Vcb,
  2228. VOLUME_MOUNTED_ON_40 | VOLUME_MODIFIED_BY_CHKDSK,
  2229. FALSE,
  2230. TRUE );
  2231. }
  2232. //
  2233. // Looks like this mount will succeed. Remember the root directory fileobject
  2234. // so we can use it for the notification later.
  2235. //
  2236. RootDirFileObject = Vcb->RootIndexScb->FileObject;
  2237. //
  2238. // Dereference the root file object if present. The absence of this doesn't
  2239. // indicate whether the volume was upgraded. Older 4K Mft records can contain
  2240. // all of the new streams.
  2241. //
  2242. if (RootDirFileObject != NULL) {
  2243. ObReferenceObject( RootDirFileObject );
  2244. }
  2245. //
  2246. //
  2247. // Set our return status and say that the mount succeeded
  2248. //
  2249. Status = STATUS_SUCCESS;
  2250. MountFailed = FALSE;
  2251. SetFlag( Vcb->VcbState, VCB_STATE_MOUNT_COMPLETED );
  2252. #ifdef SYSCACHE_DEBUG
  2253. if (!NtfsIsVolumeReadOnly( Vcb ) && !NtfsDisableSyscacheLogFile) {
  2254. NtfsInitializeSyscacheLogFile( IrpContext, Vcb );
  2255. }
  2256. #endif
  2257. } finally {
  2258. DebugUnwind( NtfsMountVolume );
  2259. NtfsUnpinBcb( IrpContext, &BootBcb );
  2260. if (DeviceObjectName != NULL) {
  2261. NtfsFreePool( DeviceObjectName );
  2262. }
  2263. if (CloseAttributes) { NtfsCloseAttributesFromRestart( IrpContext, Vcb ); }
  2264. for (i = 0; i < 8; i++) {
  2265. NtfsUnpinBcb( IrpContext, &Bcbs[i] );
  2266. //
  2267. // Get rid of the Mdls, if we haven't already.
  2268. //
  2269. if (Mdls[i] != NULL) {
  2270. if (FlagOn( Mdls[i]->MdlFlags, MDL_PAGES_LOCKED )) {
  2271. MmUnlockPages( Mdls[i] );
  2272. }
  2273. IoFreeMdl( Mdls[i] );
  2274. Mdls[i] = NULL;
  2275. }
  2276. }
  2277. if (BootScb != NULL) { NtfsDeleteInternalAttributeStream( BootScb, TRUE, FALSE ); }
  2278. if (VolDo != NULL) {
  2279. Vcb = &VolDo->Vcb;
  2280. if (Vcb->MftScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->MftScb ); }
  2281. if (Vcb->Mft2Scb != NULL) { NtfsReleaseScb( IrpContext, Vcb->Mft2Scb ); }
  2282. if (Vcb->LogFileScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->LogFileScb ); }
  2283. if (Vcb->VolumeDasdScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->VolumeDasdScb ); }
  2284. if (Vcb->AttributeDefTableScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->AttributeDefTableScb );
  2285. NtfsDeleteInternalAttributeStream( Vcb->AttributeDefTableScb, TRUE, FALSE );
  2286. Vcb->AttributeDefTableScb = NULL;}
  2287. if (Vcb->UpcaseTableScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->UpcaseTableScb );
  2288. NtfsDeleteInternalAttributeStream( Vcb->UpcaseTableScb, TRUE, FALSE );
  2289. Vcb->UpcaseTableScb = NULL;}
  2290. if (Vcb->RootIndexScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->RootIndexScb ); }
  2291. if (Vcb->BitmapScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->BitmapScb ); }
  2292. if (Vcb->BadClusterFileScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->BadClusterFileScb ); }
  2293. if (Vcb->MftBitmapScb != NULL) { NtfsReleaseScb( IrpContext, Vcb->MftBitmapScb ); }
  2294. //
  2295. // Drop the security data
  2296. //
  2297. if (Vcb->SecurityDescriptorStream != NULL) { NtfsReleaseScb( IrpContext, Vcb->SecurityDescriptorStream ); }
  2298. if (Vcb->UsnJournal != NULL) { NtfsReleaseScb( IrpContext, Vcb->UsnJournal ); }
  2299. if (Vcb->ExtendDirectory != NULL) { NtfsReleaseScb( IrpContext, Vcb->ExtendDirectory ); }
  2300. if (QuotaDataScb != NULL) {
  2301. NtfsReleaseScb( IrpContext, QuotaDataScb );
  2302. NtfsDeleteInternalAttributeStream( QuotaDataScb, TRUE, FALSE );
  2303. }
  2304. if (MountFailed) {
  2305. PVPB NewVpb;
  2306. //
  2307. // Release all resourcess we acquired now - before we delete away the
  2308. // volume they refer to. We must checkpoint first to remove any partial transactions
  2309. //
  2310. NtfsCheckpointCurrentTransaction( IrpContext );
  2311. NtfsReleaseAllResources( IrpContext );
  2312. NtfsPerformDismountOnVcb( IrpContext, Vcb, TRUE, &NewVpb );
  2313. //
  2314. // If the version upgrade failed, we will be coming back in here soon
  2315. // and we need to have the right vpb when we do. This is true if the
  2316. // upgrade failed or if we are processing a log file full condition.
  2317. //
  2318. if ((FlagOn( IrpContext->State, IRP_CONTEXT_STATE_VOL_UPGR_FAILED ) ||
  2319. (IrpContext->TopLevelIrpContext->ExceptionStatus == STATUS_LOG_FILE_FULL) ||
  2320. (IrpContext->TopLevelIrpContext->ExceptionStatus == STATUS_CANT_WAIT)) &&
  2321. (NewVpb != NULL)) {
  2322. IrpSp->Parameters.MountVolume.Vpb = NewVpb;
  2323. }
  2324. //
  2325. // On abnormal termination, someone will try to abort a transaction on
  2326. // this Vcb if we do not clear these fields.
  2327. //
  2328. ASSERT( Vcb->TransactionTable.DrainPending == FALSE );
  2329. IrpContext->TransactionId = 0;
  2330. IrpContext->Vcb = NULL;
  2331. }
  2332. }
  2333. if (VcbAcquired) {
  2334. NtfsReleaseVcbCheckDelete( IrpContext, Vcb, IRP_MJ_FILE_SYSTEM_CONTROL, NULL );
  2335. }
  2336. NtfsReleaseGlobal( IrpContext );
  2337. }
  2338. NtfsCompleteRequest( IrpContext, Irp, Status );
  2339. if (RootDirFileObject != NULL) {
  2340. FsRtlNotifyVolumeEvent( RootDirFileObject, FSRTL_VOLUME_MOUNT );
  2341. ObDereferenceObject( RootDirFileObject );
  2342. }
  2343. if (NT_SUCCESS( Status )) {
  2344. //
  2345. // Remove the extra object reference to the target device object
  2346. // because I/O system has already made one for this mount.
  2347. //
  2348. ObDereferenceObject( Vcb->TargetDeviceObject );
  2349. }
  2350. DebugTrace( -1, Dbg, ("NtfsMountVolume -> %08lx\n", Status) );
  2351. return Status;
  2352. }
  2353. //
  2354. // Local Support Routine
  2355. //
  2356. NTSTATUS
  2357. NtfsUpdateAttributeTable (
  2358. IN PIRP_CONTEXT IrpContext,
  2359. IN PVCB Vcb
  2360. )
  2361. /*++
  2362. Routine Description:
  2363. This routine updates the on-disk attribute definition table.
  2364. Arguments:
  2365. Vcb - Supplies the Vcb whose attribute table should be updated.
  2366. Return Value:
  2367. NTSTATUS - The return status for the operation
  2368. --*/
  2369. {
  2370. NTSTATUS Status = STATUS_SUCCESS;
  2371. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  2372. PATTRIBUTE_DEFINITION_COLUMNS AttrDefs = NULL;
  2373. PFCB AttributeTableFcb;
  2374. BOOLEAN FoundAttribute;
  2375. ASSERT_IRP_CONTEXT( IrpContext );
  2376. ASSERT_VCB( Vcb );
  2377. ASSERT( Vcb->AttributeDefTableScb == NULL );
  2378. PAGED_CODE();
  2379. DebugTrace( +1, Dbg, ("NtfsUpdateAttributeTable\n") );
  2380. NtfsOpenSystemFile( IrpContext,
  2381. &Vcb->AttributeDefTableScb,
  2382. Vcb,
  2383. ATTRIBUTE_DEF_TABLE_NUMBER,
  2384. 0,
  2385. $DATA,
  2386. FALSE );
  2387. AttributeTableFcb = Vcb->AttributeDefTableScb->Fcb;
  2388. NtfsInitializeAttributeContext( &AttrContext );
  2389. try {
  2390. //
  2391. // First, we find and delete the old attribute definition table.
  2392. //
  2393. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  2394. AttributeTableFcb,
  2395. &AttributeTableFcb->FileReference,
  2396. $DATA,
  2397. &AttrContext );
  2398. if (!FoundAttribute) {
  2399. try_return( Status = STATUS_DISK_CORRUPT_ERROR );
  2400. }
  2401. NtfsDeleteAttributeRecord( IrpContext,
  2402. AttributeTableFcb,
  2403. DELETE_LOG_OPERATION | DELETE_RELEASE_ALLOCATION,
  2404. &AttrContext );
  2405. //
  2406. // Now we write the current attribute definition table to disk.
  2407. //
  2408. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  2409. NtfsInitializeAttributeContext( &AttrContext );
  2410. //
  2411. // chkdsk for whistler doesn't recognize the attribute table in its current state
  2412. // so munge it so it does - move the last entry $EFS into the unused piece of the
  2413. // table 0xF0
  2414. //
  2415. AttrDefs = NtfsAllocatePool( PagedPool, sizeof( ATTRIBUTE_DEFINITION_COLUMNS ) * NtfsAttributeDefinitionsCount );
  2416. RtlCopyMemory( AttrDefs, NtfsAttributeDefinitions, sizeof( ATTRIBUTE_DEFINITION_COLUMNS ) * NtfsAttributeDefinitionsCount );
  2417. RtlMoveMemory( &AttrDefs[ NtfsAttributeDefinitionsCount - 3], &AttrDefs[ NtfsAttributeDefinitionsCount - 2], sizeof( ATTRIBUTE_DEFINITION_COLUMNS ) * 2);
  2418. NtfsCreateAttributeWithValue( IrpContext,
  2419. AttributeTableFcb,
  2420. $DATA,
  2421. NULL,
  2422. AttrDefs,
  2423. (NtfsAttributeDefinitionsCount - 1) * sizeof(*NtfsAttributeDefinitions),
  2424. 0,
  2425. NULL,
  2426. TRUE,
  2427. &AttrContext );
  2428. try_exit: NOTHING;
  2429. } finally {
  2430. if (AttrDefs != NULL) {
  2431. NtfsFreePool( AttrDefs );
  2432. }
  2433. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  2434. }
  2435. //
  2436. // And return to our caller
  2437. //
  2438. DebugTrace( -1, Dbg, ("NtfsUpdateAttributeTable -> %08lx\n", Status) );
  2439. return Status;
  2440. }
  2441. //
  2442. // Local Support Routine
  2443. //
  2444. NTSTATUS
  2445. NtfsVerifyVolume (
  2446. IN PIRP_CONTEXT IrpContext,
  2447. IN PIRP Irp
  2448. )
  2449. /*++
  2450. Routine Description:
  2451. This routine performs the verify volume operation. It is responsible for
  2452. either completing of enqueuing the input Irp.
  2453. Arguments:
  2454. Irp - Supplies the Irp to process
  2455. Return Value:
  2456. NTSTATUS - The return status for the operation
  2457. --*/
  2458. {
  2459. NTSTATUS Status;
  2460. PIO_STACK_LOCATION IrpSp;
  2461. ASSERT_IRP_CONTEXT( IrpContext );
  2462. ASSERT_IRP( Irp );
  2463. PAGED_CODE();
  2464. //
  2465. // Get the current Irp stack location
  2466. //
  2467. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2468. DebugTrace( +1, Dbg, ("NtfsVerifyVolume\n") );
  2469. //
  2470. // Do nothing for now
  2471. //
  2472. KdPrint(("NtfsVerifyVolume is not yet implemented\n")); //**** DbgBreakPoint();
  2473. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_NOT_IMPLEMENTED );
  2474. //
  2475. // And return to our caller
  2476. //
  2477. DebugTrace( -1, Dbg, ("NtfsVerifyVolume -> %08lx\n", Status) );
  2478. return Status;
  2479. }
  2480. //
  2481. // Local Support Routine
  2482. //
  2483. NTSTATUS
  2484. NtfsUserFsRequest (
  2485. IN PIRP_CONTEXT IrpContext,
  2486. IN PIRP Irp
  2487. )
  2488. /*++
  2489. Routine Description:
  2490. This is the common routine for implementing the user's requests made
  2491. through NtFsControlFile.
  2492. Arguments:
  2493. Irp - Supplies the Irp being processed
  2494. Wait - Indicates if the thread can block for a resource or I/O
  2495. Return Value:
  2496. NTSTATUS - The return status for the operation
  2497. --*/
  2498. {
  2499. NTSTATUS Status;
  2500. ULONG FsControlCode;
  2501. PIO_STACK_LOCATION IrpSp;
  2502. ASSERT_IRP_CONTEXT( IrpContext );
  2503. ASSERT_IRP( Irp );
  2504. PAGED_CODE();
  2505. //
  2506. // Get the current Irp stack location, and save some references
  2507. // to make our life a little easier.
  2508. //
  2509. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2510. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  2511. DebugTrace( +1, Dbg, ("NtfsUserFsRequest, FsControlCode = %08lx\n", FsControlCode) );
  2512. //
  2513. // Case on the control code.
  2514. //
  2515. switch (FsControlCode) {
  2516. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  2517. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  2518. case FSCTL_REQUEST_BATCH_OPLOCK:
  2519. case FSCTL_REQUEST_FILTER_OPLOCK:
  2520. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  2521. case FSCTL_OPLOCK_BREAK_NOTIFY:
  2522. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  2523. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  2524. Status = NtfsOplockRequest( IrpContext, Irp );
  2525. break;
  2526. case FSCTL_LOCK_VOLUME:
  2527. Status = NtfsLockVolume( IrpContext, Irp );
  2528. break;
  2529. case FSCTL_UNLOCK_VOLUME:
  2530. Status = NtfsUnlockVolume( IrpContext, Irp );
  2531. break;
  2532. case FSCTL_DISMOUNT_VOLUME:
  2533. Status = NtfsDismountVolume( IrpContext, Irp );
  2534. break;
  2535. case FSCTL_IS_VOLUME_MOUNTED:
  2536. Status = NtfsIsVolumeMounted( IrpContext, Irp );
  2537. break;
  2538. case FSCTL_MARK_VOLUME_DIRTY:
  2539. Status = NtfsDirtyVolume( IrpContext, Irp );
  2540. break;
  2541. case FSCTL_IS_PATHNAME_VALID:
  2542. //
  2543. // All names are potentially valid NTFS names
  2544. //
  2545. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_SUCCESS );
  2546. break;
  2547. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  2548. Status = NtfsQueryRetrievalPointers( IrpContext, Irp );
  2549. break;
  2550. case FSCTL_GET_COMPRESSION:
  2551. Status = NtfsGetCompression( IrpContext, Irp );
  2552. break;
  2553. case FSCTL_SET_COMPRESSION:
  2554. //
  2555. // Post this request if we can't wait.
  2556. //
  2557. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  2558. Status = NtfsPostRequest( IrpContext, Irp );
  2559. } else {
  2560. Status = NtfsSetCompression( IrpContext, Irp );
  2561. }
  2562. break;
  2563. case FSCTL_MARK_AS_SYSTEM_HIVE:
  2564. Status = NtfsMarkAsSystemHive( IrpContext, Irp );
  2565. break;
  2566. case FSCTL_FILESYSTEM_GET_STATISTICS:
  2567. Status = NtfsGetStatistics( IrpContext, Irp );
  2568. break;
  2569. case FSCTL_GET_NTFS_VOLUME_DATA:
  2570. Status = NtfsGetVolumeData( IrpContext, Irp );
  2571. break;
  2572. case FSCTL_GET_VOLUME_BITMAP:
  2573. Status = NtfsGetVolumeBitmap( IrpContext, Irp );
  2574. break;
  2575. case FSCTL_GET_RETRIEVAL_POINTERS:
  2576. Status = NtfsGetRetrievalPointers( IrpContext, Irp );
  2577. break;
  2578. case FSCTL_GET_NTFS_FILE_RECORD:
  2579. Status = NtfsGetMftRecord( IrpContext, Irp );
  2580. break;
  2581. case FSCTL_MOVE_FILE:
  2582. Status = NtfsDefragFile( IrpContext, Irp );
  2583. break;
  2584. case FSCTL_IS_VOLUME_DIRTY:
  2585. Status = NtfsIsVolumeDirty( IrpContext, Irp );
  2586. break;
  2587. case FSCTL_ALLOW_EXTENDED_DASD_IO:
  2588. Status = NtfsSetExtendedDasdIo( IrpContext, Irp );
  2589. break;
  2590. case FSCTL_SET_REPARSE_POINT:
  2591. Status = NtfsSetReparsePoint( IrpContext, Irp );
  2592. break;
  2593. case FSCTL_GET_REPARSE_POINT:
  2594. Status = NtfsGetReparsePoint( IrpContext, Irp );
  2595. break;
  2596. case FSCTL_DELETE_REPARSE_POINT:
  2597. Status = NtfsDeleteReparsePoint( IrpContext, Irp );
  2598. break;
  2599. case FSCTL_SET_OBJECT_ID:
  2600. Status = NtfsSetObjectId( IrpContext, Irp ); // In ObjIdSup.c
  2601. break;
  2602. case FSCTL_GET_OBJECT_ID:
  2603. Status = NtfsGetObjectId( IrpContext, Irp ); // In ObjIdSup.c
  2604. break;
  2605. case FSCTL_DELETE_OBJECT_ID:
  2606. Status = NtfsDeleteObjectId( IrpContext, Irp ); // In ObjIdSup.c
  2607. break;
  2608. case FSCTL_SET_OBJECT_ID_EXTENDED:
  2609. Status = NtfsSetObjectIdExtendedInfo( IrpContext, Irp ); // In ObjIdSup.c
  2610. break;
  2611. case FSCTL_CREATE_OR_GET_OBJECT_ID:
  2612. Status = NtfsCreateOrGetObjectId( IrpContext, Irp );
  2613. break;
  2614. case FSCTL_READ_USN_JOURNAL:
  2615. Status = NtfsReadUsnJournal( IrpContext, Irp, TRUE ); // In UsnSup.c
  2616. break;
  2617. case FSCTL_CREATE_USN_JOURNAL:
  2618. Status = NtfsCreateUsnJournal( IrpContext, Irp );
  2619. break;
  2620. case FSCTL_ENUM_USN_DATA:
  2621. Status = NtfsReadFileRecordUsnData( IrpContext, Irp );
  2622. break;
  2623. case FSCTL_READ_FILE_USN_DATA:
  2624. Status = NtfsReadFileUsnData( IrpContext, Irp );
  2625. break;
  2626. case FSCTL_WRITE_USN_CLOSE_RECORD:
  2627. Status = NtfsWriteUsnCloseRecord( IrpContext, Irp );
  2628. break;
  2629. case FSCTL_QUERY_USN_JOURNAL:
  2630. Status = NtfsQueryUsnJournal( IrpContext, Irp );
  2631. break;
  2632. case FSCTL_DELETE_USN_JOURNAL:
  2633. Status = NtfsDeleteUsnJournal( IrpContext, Irp );
  2634. break;
  2635. case FSCTL_MARK_HANDLE:
  2636. Status = NtfsMarkHandle( IrpContext, Irp );
  2637. break;
  2638. case FSCTL_SECURITY_ID_CHECK:
  2639. Status = NtfsBulkSecurityIdCheck( IrpContext, Irp );
  2640. break;
  2641. case FSCTL_FIND_FILES_BY_SID:
  2642. Status = NtfsFindFilesOwnedBySid( IrpContext, Irp );
  2643. break;
  2644. case FSCTL_SET_SPARSE :
  2645. Status = NtfsSetSparse( IrpContext, Irp );
  2646. break;
  2647. case FSCTL_SET_ZERO_DATA :
  2648. Status = NtfsZeroRange( IrpContext, Irp );
  2649. break;
  2650. case FSCTL_QUERY_ALLOCATED_RANGES :
  2651. Status = NtfsQueryAllocatedRanges( IrpContext, Irp );
  2652. break;
  2653. case FSCTL_ENCRYPTION_FSCTL_IO :
  2654. Status = NtfsEncryptionFsctl( IrpContext, Irp );
  2655. break;
  2656. case FSCTL_SET_ENCRYPTION :
  2657. Status = NtfsSetEncryption( IrpContext, Irp );
  2658. break;
  2659. case FSCTL_READ_RAW_ENCRYPTED:
  2660. Status = NtfsReadRawEncrypted( IrpContext, Irp );
  2661. break;
  2662. case FSCTL_WRITE_RAW_ENCRYPTED:
  2663. Status = NtfsWriteRawEncrypted( IrpContext, Irp );
  2664. break;
  2665. case FSCTL_EXTEND_VOLUME:
  2666. Status = NtfsExtendVolume( IrpContext, Irp );
  2667. break;
  2668. case FSCTL_READ_FROM_PLEX:
  2669. Status = NtfsReadFromPlex( IrpContext, Irp );
  2670. break;
  2671. case FSCTL_FILE_PREFETCH:
  2672. Status = NtfsPrefetchFile( IrpContext, Irp );
  2673. break;
  2674. #ifdef SYSCACHE_DEBUG
  2675. case FSCTL_ENABLE_SYSCACHE:
  2676. NtfsSyscacheTrackingActive = 1;
  2677. Status = STATUS_SUCCESS;
  2678. break;
  2679. #endif
  2680. default :
  2681. DebugTrace( 0, Dbg, ("Invalid control code -> %08lx\n", FsControlCode) );
  2682. NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST );
  2683. break;
  2684. }
  2685. //
  2686. // And return to our caller
  2687. //
  2688. DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) );
  2689. return Status;
  2690. }
  2691. //
  2692. // Local support routine
  2693. //
  2694. NTSTATUS
  2695. NtfsOplockRequest (
  2696. IN PIRP_CONTEXT IrpContext,
  2697. IN PIRP Irp
  2698. )
  2699. /*++
  2700. Routine Description:
  2701. This is the common routine to handle oplock requests made via the
  2702. NtFsControlFile call.
  2703. Arguments:
  2704. Irp - Supplies the Irp being processed
  2705. Return Value:
  2706. NTSTATUS - The return status for the operation
  2707. --*/
  2708. {
  2709. NTSTATUS Status;
  2710. PIO_STACK_LOCATION IrpSp;
  2711. ULONG FsControlCode;
  2712. ULONG OplockCount = 0;
  2713. PFILE_OBJECT FileObject;
  2714. TYPE_OF_OPEN TypeOfOpen;
  2715. PVCB Vcb;
  2716. PFCB Fcb;
  2717. PSCB Scb;
  2718. PCCB Ccb;
  2719. ASSERT_IRP_CONTEXT( IrpContext );
  2720. ASSERT_IRP( Irp );
  2721. PAGED_CODE();
  2722. //
  2723. // Get the current Irp stack location, and save some reference to
  2724. // make life easier
  2725. //
  2726. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2727. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  2728. DebugTrace( +1, Dbg, ("NtfsOplockRequest, FsControlCode = %08lx\n", FsControlCode) );
  2729. //
  2730. // Extract and decode the file object
  2731. //
  2732. FileObject = IrpSp->FileObject;
  2733. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  2734. //
  2735. // We only permit oplock requests on files.
  2736. //
  2737. if ((TypeOfOpen != UserFileOpen) ||
  2738. (SafeNodeType( Scb ) == NTFS_NTC_SCB_MFT)) {
  2739. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2740. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  2741. return STATUS_INVALID_PARAMETER;
  2742. }
  2743. //
  2744. // There should be no output buffer
  2745. //
  2746. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength > 0) {
  2747. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2748. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  2749. return STATUS_INVALID_PARAMETER;
  2750. }
  2751. //
  2752. // We jam Wait to TRUE in the IrpContext. This prevents us from returning
  2753. // STATUS_PENDING if we can't acquire the file. The caller would
  2754. // interpret that as having acquired an oplock.
  2755. //
  2756. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  2757. //
  2758. // Switch on the function control code. We grab the Fcb exclusively
  2759. // for oplock requests, shared for oplock break acknowledgement.
  2760. //
  2761. switch ( FsControlCode ) {
  2762. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  2763. case FSCTL_REQUEST_BATCH_OPLOCK:
  2764. case FSCTL_REQUEST_FILTER_OPLOCK:
  2765. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  2766. NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, 0 );
  2767. if (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
  2768. if (Scb->ScbType.Data.FileLock != NULL) {
  2769. OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Scb->ScbType.Data.FileLock );
  2770. }
  2771. } else {
  2772. OplockCount = Scb->CleanupCount;
  2773. }
  2774. break;
  2775. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  2776. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  2777. case FSCTL_OPLOCK_BREAK_NOTIFY:
  2778. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  2779. NtfsAcquireSharedFcb( IrpContext, Fcb, Scb, 0 );
  2780. break;
  2781. default:
  2782. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  2783. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  2784. return STATUS_INVALID_PARAMETER;
  2785. }
  2786. //
  2787. // Use a try finally to free the Fcb.
  2788. //
  2789. try {
  2790. //
  2791. // Call the FsRtl routine to grant/acknowledge oplock.
  2792. //
  2793. Status = FsRtlOplockFsctrl( &Scb->ScbType.Data.Oplock,
  2794. Irp,
  2795. OplockCount );
  2796. //
  2797. // Set the flag indicating if Fast I/O is possible
  2798. //
  2799. NtfsAcquireFsrtlHeader( Scb );
  2800. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  2801. NtfsReleaseFsrtlHeader( Scb );
  2802. } finally {
  2803. DebugUnwind( NtfsOplockRequest );
  2804. //
  2805. // Release all of our resources
  2806. //
  2807. NtfsReleaseFcb( IrpContext, Fcb );
  2808. //
  2809. // If this is not an abnormal termination then complete the irp
  2810. //
  2811. if (!AbnormalTermination()) {
  2812. NtfsCompleteRequest( IrpContext, NULL, 0 );
  2813. }
  2814. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> %08lx\n", Status) );
  2815. }
  2816. return Status;
  2817. }
  2818. NTSTATUS
  2819. NtfsLockVolumeInternal (
  2820. IN PIRP_CONTEXT IrpContext,
  2821. IN PVCB Vcb,
  2822. IN PFILE_OBJECT FileObjectWithVcbLocked,
  2823. IN OUT PULONG Retrying
  2824. )
  2825. /*++
  2826. Routine Description:
  2827. This routine performs the lock volume operation. You should be synchronized
  2828. with checkpoints before calling it
  2829. Arguments:
  2830. Vcb - Supplies the Vcb to lock
  2831. Return Value:
  2832. NTSTATUS - The return status for the operation
  2833. --*/
  2834. {
  2835. NTSTATUS Status = STATUS_SUCCESS;
  2836. BOOLEAN VcbAcquired = FALSE;
  2837. ASSERT_IRP_CONTEXT( IrpContext );
  2838. PAGED_CODE();
  2839. DebugTrace( +1, Dbg, ("NtfsLockVolumeInternal...\n") );
  2840. try {
  2841. #ifdef SYSCACHE_DEBUG
  2842. ULONG SystemHandleCount = 0;
  2843. #endif
  2844. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  2845. VcbAcquired = TRUE;
  2846. #ifdef SYSCACHE_DEBUG
  2847. if (Vcb->SyscacheScb != NULL) {
  2848. SystemHandleCount = Vcb->SyscacheScb->CleanupCount;
  2849. }
  2850. #endif
  2851. //
  2852. // Check if the Vcb is already locked, or if the open file count
  2853. // is greater than 1 (which implies that someone else also is
  2854. // currently using the volume, or a file on the volume). We also fail
  2855. // this request if the volume has already gone through the dismount
  2856. // vcb process.
  2857. //
  2858. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) ||
  2859. #ifdef SYSCACHE_DEBUG
  2860. (Vcb->CleanupCount > 1 + SystemHandleCount))
  2861. #else
  2862. (Vcb->CleanupCount > 1))
  2863. #endif
  2864. {
  2865. DebugTrace( 0, Dbg, ("Volume is currently in use\n") );
  2866. Status = STATUS_ACCESS_DENIED;
  2867. //
  2868. // If the volume is already locked then it might have been the result of an
  2869. // exclusive DASD open. Allow that user to explictly lock the volume.
  2870. //
  2871. } else if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
  2872. if (FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_LOCK )) {
  2873. DebugTrace( 0, Dbg, ("User has already locked volume\n") );
  2874. Status = STATUS_ACCESS_DENIED;
  2875. } else {
  2876. //
  2877. // The exclusive dasd open didn't do a partial dismount - do so now
  2878. // so we look the same at the unlock point
  2879. //
  2880. NtfsPerformDismountOnVcb( IrpContext, Vcb, FALSE, NULL );
  2881. SetFlag( Vcb->VcbState, VCB_STATE_EXPLICIT_LOCK );
  2882. Vcb->FileObjectWithVcbLocked = FileObjectWithVcbLocked;
  2883. Status = STATUS_SUCCESS;
  2884. }
  2885. //
  2886. // We can take this path if the volume has already been locked via
  2887. // create but has not taken the PerformDismountOnVcb path. We checked
  2888. // for this above by looking at the VOLUME_MOUNTED flag in the Vcb.
  2889. //
  2890. } else {
  2891. //
  2892. // There better be system files objects only at this point.
  2893. //
  2894. SetFlag( Vcb->VcbState, VCB_STATE_LOCK_IN_PROGRESS );
  2895. if (!NT_SUCCESS( NtfsFlushVolume( IrpContext, Vcb, TRUE, TRUE, TRUE, FALSE ))) {
  2896. DebugTrace( 0, Dbg, ("Volume has user file objects\n") );
  2897. Status = STATUS_ACCESS_DENIED;
  2898. //
  2899. // If there are still user files then try another flush. We're just being kind
  2900. // here. If the lazy writer has a flush queued then the file object can't go
  2901. // away. Let's raise CANT_WAIT and try one more time.
  2902. //
  2903. } else if (Vcb->CloseCount - Vcb->SystemFileCloseCount > 1) {
  2904. //
  2905. // Fail this request if we have already gone through before.
  2906. // Use the next stack location in the Irp as a convenient
  2907. // place to store this information.
  2908. //
  2909. if (*Retrying != 0) {
  2910. DebugTrace( 0, Dbg, ("Volume has user file objects\n") );
  2911. Status = STATUS_ACCESS_DENIED;
  2912. } else {
  2913. *Retrying = 1;
  2914. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  2915. }
  2916. } else {
  2917. //
  2918. // We don't really want to do all of the perform dismount here because
  2919. // that will cause us to remount a new volume before we're ready.
  2920. // At this time we only want to stop the log file and close up our
  2921. // internal attribute streams. When the user (i.e., chkdsk) does an
  2922. // unlock then we'll finish up with the dismount call
  2923. //
  2924. NtfsPerformDismountOnVcb( IrpContext, Vcb, FALSE, NULL );
  2925. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_EXPLICIT_LOCK );
  2926. Vcb->FileObjectWithVcbLocked = FileObjectWithVcbLocked;
  2927. Status = STATUS_SUCCESS;
  2928. }
  2929. }
  2930. } finally {
  2931. DebugUnwind( NtfsLockVolumeInternal );
  2932. if (VcbAcquired) {
  2933. ClearFlag( Vcb->VcbState, VCB_STATE_LOCK_IN_PROGRESS );
  2934. NtfsReleaseVcb( IrpContext, Vcb );
  2935. }
  2936. DebugTrace( -1, Dbg, ("NtfsLockVolumeInternal -> %08lx\n", Status) );
  2937. }
  2938. return Status;
  2939. }
  2940. //
  2941. // Local Support Routine
  2942. //
  2943. NTSTATUS
  2944. NtfsLockVolume (
  2945. IN PIRP_CONTEXT IrpContext,
  2946. IN PIRP Irp
  2947. )
  2948. /*++
  2949. Routine Description:
  2950. This routine performs the lock volume operation. It is responsible for
  2951. either completing of enqueuing the input Irp.
  2952. Arguments:
  2953. Irp - Supplies the Irp to process
  2954. Return Value:
  2955. NTSTATUS - The return status for the operation
  2956. --*/
  2957. {
  2958. NTSTATUS Status = STATUS_SUCCESS;
  2959. PIO_STACK_LOCATION IrpSp;
  2960. PIO_STACK_LOCATION NextIrpSp;
  2961. PFILE_OBJECT FileObject;
  2962. TYPE_OF_OPEN TypeOfOpen;
  2963. PVCB Vcb;
  2964. PFCB Fcb;
  2965. PSCB Scb;
  2966. PCCB Ccb;
  2967. ASSERT_IRP_CONTEXT( IrpContext );
  2968. ASSERT_IRP( Irp );
  2969. PAGED_CODE();
  2970. //
  2971. // Get the current Irp stack location
  2972. //
  2973. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2974. DebugTrace( +1, Dbg, ("NtfsLockVolume...\n") );
  2975. //
  2976. // Extract and decode the file object, and only permit user volume opens
  2977. //
  2978. FileObject = IrpSp->FileObject;
  2979. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  2980. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  2981. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  2982. DebugTrace( -1, Dbg, ("NtfsLockVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  2983. return STATUS_ACCESS_DENIED;
  2984. }
  2985. //
  2986. // If this is the retry path then perform a short delay so that the
  2987. // lazy writer can finish any queued writes.
  2988. //
  2989. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  2990. if (NextIrpSp->Parameters.FileSystemControl.FsControlCode != 0) {
  2991. //
  2992. // If retrying wait for the lazy write to do any delayed closes
  2993. //
  2994. CcWaitForCurrentLazyWriterActivity();
  2995. } else {
  2996. //
  2997. // Notify anyone who wants to close their handles when a lock operation
  2998. // is attempted. We should only do this once per lock request, so don't
  2999. // do it in the retry case.
  3000. //
  3001. DebugTrace( 0, Dbg, ("Sending lock notification\n") );
  3002. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK );
  3003. }
  3004. try {
  3005. NtfsAcquireCheckpointSynchronization( IrpContext, Vcb );
  3006. Status = NtfsLockVolumeInternal( IrpContext,
  3007. Vcb,
  3008. ((PFILE_OBJECT)(((UINT_PTR)IrpSp->FileObject) + 1)),
  3009. &(NextIrpSp->Parameters.FileSystemControl.FsControlCode) );
  3010. } finally {
  3011. DebugUnwind( NtfsLockVolume );
  3012. NtfsReleaseCheckpointSynchronization( IrpContext, Vcb );
  3013. if ((AbnormalTermination() &&
  3014. IrpContext->ExceptionStatus != STATUS_CANT_WAIT &&
  3015. IrpContext->ExceptionStatus != STATUS_LOG_FILE_FULL) ||
  3016. !NT_SUCCESS( Status )) {
  3017. //
  3018. // This lock operation has failed either by raising a status that
  3019. // will keep us from retrying, or else by returning an unsuccessful
  3020. // status. Notify anyone who wants to reopen their handles now.
  3021. // If we're about to retry the lock, we can notify everyone when/if
  3022. // the retry fails.
  3023. //
  3024. DebugTrace( 0, Dbg, ("Sending lock_failed notification\n") );
  3025. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK_FAILED );
  3026. }
  3027. }
  3028. DebugTrace( -1, Dbg, ("NtfsLockVolume -> %08lx\n", Status) );
  3029. NtfsCompleteRequest( IrpContext, Irp, Status );
  3030. return Status;
  3031. }
  3032. NTSTATUS
  3033. NtfsUnlockVolumeInternal (
  3034. IN PIRP_CONTEXT IrpContext,
  3035. IN PVCB Vcb
  3036. )
  3037. /*++
  3038. Routine Description:
  3039. This routine performs the unlock volume operation.
  3040. Arguments:
  3041. Vcb - Supplies the Vcb to unlock
  3042. Return Value:
  3043. NTSTATUS - The return status for the operation
  3044. --*/
  3045. {
  3046. NTSTATUS Status;
  3047. ASSERT_IRP_CONTEXT( IrpContext );
  3048. PAGED_CODE();
  3049. //
  3050. // Acquire exclusive access to the Vcb
  3051. //
  3052. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  3053. try {
  3054. if (FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_LOCK )) {
  3055. NtfsPerformDismountOnVcb( IrpContext, Vcb, TRUE, NULL );
  3056. //
  3057. // Unlock the volume and complete the Irp
  3058. //
  3059. ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_EXPLICIT_LOCK );
  3060. Vcb->FileObjectWithVcbLocked = NULL;
  3061. Status = STATUS_SUCCESS;
  3062. } else {
  3063. Status = STATUS_NOT_LOCKED;
  3064. }
  3065. } finally {
  3066. DebugUnwind( NtfsUnlockVolumeInternal );
  3067. //
  3068. // Release all of our resources
  3069. //
  3070. NtfsReleaseVcb( IrpContext, Vcb );
  3071. DebugTrace( -1, Dbg, ("NtfsUnlockVolumeInternal -> %08lx\n", Status) );
  3072. }
  3073. return Status;
  3074. }
  3075. //
  3076. // Local Support Routine
  3077. //
  3078. NTSTATUS
  3079. NtfsUnlockVolume (
  3080. IN PIRP_CONTEXT IrpContext,
  3081. IN PIRP Irp
  3082. )
  3083. /*++
  3084. Routine Description:
  3085. This routine performs the unlock volume operation. It is responsible for
  3086. either completing of enqueuing the input Irp.
  3087. Arguments:
  3088. Irp - Supplies the Irp to process
  3089. Return Value:
  3090. NTSTATUS - The return status for the operation
  3091. --*/
  3092. {
  3093. NTSTATUS Status;
  3094. PIO_STACK_LOCATION IrpSp;
  3095. PFILE_OBJECT FileObject;
  3096. TYPE_OF_OPEN TypeOfOpen;
  3097. PVCB Vcb;
  3098. PFCB Fcb;
  3099. PSCB Scb;
  3100. PCCB Ccb;
  3101. ASSERT_IRP_CONTEXT( IrpContext );
  3102. ASSERT_IRP( Irp );
  3103. PAGED_CODE();
  3104. //
  3105. // Get the current Irp stack location
  3106. //
  3107. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3108. DebugTrace( +1, Dbg, ("NtfsUnlockVolume...\n") );
  3109. //
  3110. // Extract and decode the file object, and only permit user volume opens
  3111. //
  3112. FileObject = IrpSp->FileObject;
  3113. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3114. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  3115. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  3116. DebugTrace( -1, Dbg, ("NtfsUnlockVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  3117. return STATUS_ACCESS_DENIED;
  3118. }
  3119. Status = NtfsUnlockVolumeInternal( IrpContext, Vcb );
  3120. //
  3121. // Notify anyone who wants to reopen their handles when after the
  3122. // volume is unlocked.
  3123. //
  3124. if (NT_SUCCESS(Status)) {
  3125. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
  3126. }
  3127. NtfsCompleteRequest( IrpContext, Irp, Status );
  3128. DebugTrace( -1, Dbg, ("NtfsUnlockVolume -> %08lx\n", Status) );
  3129. return Status;
  3130. }
  3131. //
  3132. // Local Support Routine
  3133. //
  3134. NTSTATUS
  3135. NtfsDismountVolume (
  3136. IN PIRP_CONTEXT IrpContext,
  3137. IN PIRP Irp
  3138. )
  3139. /*++
  3140. Routine Description:
  3141. This routine performs the dismount volume operation. It is responsible for
  3142. either completing of enqueuing the input Irp.
  3143. Arguments:
  3144. Irp - Supplies the Irp to process
  3145. Return Value:
  3146. NTSTATUS - The return status for the operation
  3147. --*/
  3148. {
  3149. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  3150. PIO_STACK_LOCATION IrpSp;
  3151. BOOLEAN VcbAcquired = FALSE;
  3152. BOOLEAN ExplicitDismount = FALSE;
  3153. PFILE_OBJECT FileObject;
  3154. TYPE_OF_OPEN TypeOfOpen;
  3155. PVCB Vcb;
  3156. PFCB Fcb;
  3157. PSCB Scb;
  3158. PCCB Ccb;
  3159. BOOLEAN ClearCheckpointActive = FALSE;
  3160. ASSERT_IRP_CONTEXT( IrpContext );
  3161. ASSERT_IRP( Irp );
  3162. PAGED_CODE();
  3163. //
  3164. // Get the current Irp stack location
  3165. //
  3166. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3167. DebugTrace( +1, Dbg, ("NtfsDismountVolume...\n") );
  3168. //
  3169. // Extract and decode the file object, and only permit user volume opens
  3170. //
  3171. FileObject = IrpSp->FileObject;
  3172. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3173. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  3174. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  3175. DebugTrace( -1, Dbg, ("NtfsDismountVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  3176. return STATUS_ACCESS_DENIED;
  3177. }
  3178. //
  3179. // Don't notify if we are retrying due to log file full.
  3180. //
  3181. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH )) {
  3182. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT );
  3183. }
  3184. try {
  3185. //
  3186. // Serialize this with the volume checkpoints.
  3187. //
  3188. NtfsAcquireCheckpoint( IrpContext, Vcb );
  3189. while (FlagOn( Vcb->CheckpointFlags, VCB_STOP_LOG_CHECKPOINT )) {
  3190. //
  3191. // Release the checkpoint event because we cannot stop the log file now.
  3192. //
  3193. NtfsReleaseCheckpoint( IrpContext, Vcb );
  3194. NtfsWaitOnCheckpointNotify( IrpContext, Vcb );
  3195. NtfsAcquireCheckpoint( IrpContext, Vcb );
  3196. }
  3197. SetFlag( Vcb->CheckpointFlags, VCB_STOP_LOG_CHECKPOINT );
  3198. NtfsResetCheckpointNotify( IrpContext, Vcb );
  3199. NtfsReleaseCheckpoint( IrpContext, Vcb );
  3200. ClearCheckpointActive = TRUE;
  3201. //
  3202. // Acquire the Vcb exclusively.
  3203. //
  3204. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  3205. VcbAcquired = TRUE;
  3206. //
  3207. // Take special action if there's a pagefile on this volume, or if this is the
  3208. // system volume.
  3209. //
  3210. if (FlagOn( Vcb->VcbState, VCB_STATE_DISALLOW_DISMOUNT )) {
  3211. //
  3212. // If the volume is not locked then fail immediately.
  3213. //
  3214. if (!FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
  3215. try_return( Status = STATUS_ACCESS_DENIED );
  3216. //
  3217. // If there are read-only files only then noop the request. This
  3218. // allows autochk to access the root volume.
  3219. //
  3220. } else if (Vcb->ReadOnlyCloseCount == ((Vcb->CloseCount - Vcb->SystemFileCloseCount) - 1)) {
  3221. DebugTrace( 0, Dbg, ("Volume has readonly files opened\n") );
  3222. try_return( Status = STATUS_SUCCESS );
  3223. }
  3224. }
  3225. //
  3226. // Remember that this is an explicit dismount.
  3227. //
  3228. ExplicitDismount = TRUE;
  3229. //
  3230. // Naturally, we can't dismount the volume if it's already dismounted.
  3231. //
  3232. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3233. //
  3234. // Return success if the user hasn't done an explicit dismount.
  3235. //
  3236. if (!FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_DISMOUNT )) {
  3237. Status = STATUS_SUCCESS;
  3238. } else {
  3239. Status = STATUS_VOLUME_DISMOUNTED;
  3240. }
  3241. try_return( NOTHING );
  3242. }
  3243. //
  3244. // Raise LogFile full once per dismount to force a clean checkpoint
  3245. // freeing logfile space.
  3246. //
  3247. if ((!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH )) &&
  3248. (!NtfsIsVolumeReadOnly( Vcb ))) {
  3249. #ifdef PERF_STATS
  3250. IrpContext->LogFullReason = LF_DISMOUNT;
  3251. #endif
  3252. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH );
  3253. NtfsRaiseStatus( IrpContext, STATUS_LOG_FILE_FULL, NULL, NULL );
  3254. }
  3255. //
  3256. // Get as many cached writes out to disk as we can and mark
  3257. // all the streams for dismount.
  3258. //
  3259. #ifdef BRIANDBG
  3260. try {
  3261. #endif
  3262. NtfsFlushVolume( IrpContext, Vcb, TRUE, TRUE, TRUE, TRUE );
  3263. //
  3264. // Call the function that does the real work. We leave the volume locked
  3265. // so the complete teardown occurs when the handle closes
  3266. //
  3267. NtfsPerformDismountOnVcb( IrpContext, Vcb, FALSE, NULL );
  3268. #ifdef BRIANDBG
  3269. } except( NtfsDismountExceptionFilter( GetExceptionInformation() )) {
  3270. NOTHING
  3271. }
  3272. #endif
  3273. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
  3274. Vcb->FileObjectWithVcbLocked = (PFILE_OBJECT)(((ULONG_PTR)FileObject)+1);
  3275. //
  3276. // Once we get this far the volume is really dismounted. We
  3277. // can ignore errors generated by recursive failures.
  3278. //
  3279. Status = STATUS_SUCCESS;
  3280. //
  3281. // Mark the volume as needs to be verified.
  3282. //
  3283. SetFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  3284. try_exit: NOTHING;
  3285. //
  3286. // Remember that the user did an explicit dismount.
  3287. //
  3288. if ((Status == STATUS_SUCCESS) && ExplicitDismount) {
  3289. SetFlag( Vcb->VcbState, VCB_STATE_EXPLICIT_DISMOUNT );
  3290. }
  3291. } finally {
  3292. DebugUnwind( NtfsDismountVolume );
  3293. if (ClearCheckpointActive) {
  3294. NtfsAcquireCheckpoint( IrpContext, Vcb );
  3295. ClearFlag( Vcb->CheckpointFlags, VCB_STOP_LOG_CHECKPOINT );
  3296. NtfsSetCheckpointNotify( IrpContext, Vcb );
  3297. NtfsReleaseCheckpoint( IrpContext, Vcb );
  3298. }
  3299. //
  3300. // Release all of our resources
  3301. //
  3302. if (VcbAcquired) {
  3303. NtfsReleaseVcb( IrpContext, Vcb );
  3304. }
  3305. if (!NT_SUCCESS( Status ) &&
  3306. (Status != STATUS_VOLUME_DISMOUNTED)) {
  3307. //
  3308. // No need to report the error if this is a retryable error.
  3309. //
  3310. if (!AbnormalTermination() ||
  3311. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH ) ||
  3312. ((IrpContext->ExceptionStatus != STATUS_LOG_FILE_FULL) &&
  3313. (IrpContext->ExceptionStatus != STATUS_CANT_WAIT))) {
  3314. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT_FAILED );
  3315. }
  3316. }
  3317. //
  3318. // If this is an abnormal termination then undo our work, otherwise
  3319. // complete the irp
  3320. //
  3321. if (!AbnormalTermination()) {
  3322. NtfsCompleteRequest( IrpContext, Irp, Status );
  3323. }
  3324. DebugTrace( -1, Dbg, ("NtfsDismountVolume -> %08lx\n", Status) );
  3325. }
  3326. return Status;
  3327. }
  3328. //
  3329. // Local Support Routine
  3330. //
  3331. NTSTATUS
  3332. NtfsIsVolumeMounted (
  3333. IN PIRP_CONTEXT IrpContext,
  3334. IN PIRP Irp
  3335. )
  3336. /*++
  3337. Routine Description:
  3338. This routine returns whether the volume is mounted. It is responsible for
  3339. either completing of enqueuing the input Irp.
  3340. Arguments:
  3341. Irp - Supplies the Irp to process
  3342. Return Value:
  3343. NTSTATUS - The return status for the operation
  3344. --*/
  3345. {
  3346. NTSTATUS Status = STATUS_SUCCESS;
  3347. PIO_STACK_LOCATION IrpSp;
  3348. TYPE_OF_OPEN TypeOfOpen;
  3349. PFILE_OBJECT FileObject;
  3350. PVCB Vcb;
  3351. PFCB Fcb;
  3352. PSCB Scb;
  3353. PCCB Ccb;
  3354. BOOLEAN AcquiredVcb = FALSE;
  3355. ASSERT_IRP_CONTEXT( IrpContext );
  3356. ASSERT_IRP( Irp );
  3357. PAGED_CODE();
  3358. //
  3359. // Get the current Irp stack location
  3360. //
  3361. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3362. DebugTrace( +1, Dbg, ("NtfsIsVolumeMounted...\n") );
  3363. //
  3364. // Extract and decode the file object.
  3365. //
  3366. FileObject = IrpSp->FileObject;
  3367. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3368. if (TypeOfOpen == UnopenedFileObject) {
  3369. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3370. return STATUS_INVALID_PARAMETER;
  3371. }
  3372. //
  3373. // Use a try-finally to release the Vcb if necessary.
  3374. //
  3375. try {
  3376. //
  3377. // If we know the volume is dismounted, we're all done.
  3378. // OK to do this without synchronization as the state can
  3379. // change to unmounted on return to the user.
  3380. //
  3381. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3382. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  3383. }
  3384. //
  3385. // Verify the volume if necessary.
  3386. //
  3387. NtfsPingVolume( IrpContext, Vcb, &AcquiredVcb );
  3388. try_exit: NOTHING;
  3389. } finally {
  3390. DebugUnwind( NtfsIsVolumeMounted );
  3391. //
  3392. // Release the Vcb.
  3393. //
  3394. if (AcquiredVcb) {
  3395. NtfsReleaseVcb( IrpContext, Vcb );
  3396. }
  3397. DebugTrace( -1, Dbg, ("NtfsIsVolumeMounted -> %08lx\n", Status) );
  3398. }
  3399. NtfsCompleteRequest( IrpContext, Irp, Status );
  3400. return Status;
  3401. }
  3402. //
  3403. // Local Support Routine
  3404. //
  3405. NTSTATUS
  3406. NtfsDirtyVolume (
  3407. IN PIRP_CONTEXT IrpContext,
  3408. IN PIRP Irp
  3409. )
  3410. /*++
  3411. Routine Description:
  3412. This routine marks the specified volume dirty.
  3413. Arguments:
  3414. Irp - Supplies the Irp to process
  3415. Return Value:
  3416. NTSTATUS - The return status for the operation
  3417. --*/
  3418. {
  3419. PIO_STACK_LOCATION IrpSp;
  3420. NTSTATUS Status = STATUS_SUCCESS;
  3421. PFILE_OBJECT FileObject;
  3422. TYPE_OF_OPEN TypeOfOpen;
  3423. PVCB Vcb;
  3424. PFCB Fcb;
  3425. PSCB Scb;
  3426. PCCB Ccb;
  3427. ASSERT_IRP_CONTEXT( IrpContext );
  3428. ASSERT_IRP( Irp );
  3429. PAGED_CODE();
  3430. //
  3431. // Get the current Irp stack location
  3432. //
  3433. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3434. DebugTrace( +1, Dbg, ("NtfsDirtyVolume...\n") );
  3435. //
  3436. // Extract and decode the file object, and only permit user volume opens
  3437. //
  3438. FileObject = IrpSp->FileObject;
  3439. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  3440. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  3441. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  3442. DebugTrace( -1, Dbg, ("NtfsDirtyVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  3443. return STATUS_ACCESS_DENIED;
  3444. }
  3445. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  3446. try {
  3447. //
  3448. // Fail this request if the volume is not mounted.
  3449. //
  3450. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3451. Status = STATUS_VOLUME_DISMOUNTED;
  3452. } else if (NtfsIsVolumeReadOnly( Vcb )) {
  3453. Status = STATUS_MEDIA_WRITE_PROTECTED;
  3454. } else {
  3455. NtfsPostVcbIsCorrupt( IrpContext, 0, NULL, NULL );
  3456. }
  3457. } finally {
  3458. NtfsReleaseVcb( IrpContext, Vcb );
  3459. }
  3460. NtfsCompleteRequest( IrpContext, Irp, Status );
  3461. DebugTrace( -1, Dbg, ("NtfsDirtyVolume -> STATUS_SUCCESS\n") );
  3462. return Status;
  3463. }
  3464. //
  3465. // Local support routine
  3466. //
  3467. BOOLEAN
  3468. NtfsGetDiskGeometry (
  3469. IN PIRP_CONTEXT IrpContext,
  3470. IN PDEVICE_OBJECT RealDevice,
  3471. IN PDISK_GEOMETRY DiskGeometry,
  3472. IN PLONGLONG Length
  3473. )
  3474. /*++
  3475. Routine Description:
  3476. This procedure gets the disk geometry of the specified device
  3477. Arguments:
  3478. RealDevice - Supplies the real device that is being queried
  3479. DiskGeometry - Receives the disk geometry
  3480. Length - Receives the number of bytes in the partition
  3481. Return Value:
  3482. BOOLEAN - TRUE if the media is write protected, FALSE otherwise
  3483. --*/
  3484. {
  3485. NTSTATUS Status;
  3486. PREVENT_MEDIA_REMOVAL Prevent;
  3487. BOOLEAN WriteProtected = FALSE;
  3488. GET_LENGTH_INFORMATION LengthInfo;
  3489. PAGED_CODE();
  3490. DebugTrace( +1, Dbg, ("NtfsGetDiskGeometry:\n") );
  3491. DebugTrace( 0, Dbg, ("RealDevice = %08lx\n", RealDevice) );
  3492. DebugTrace( 0, Dbg, ("DiskGeometry = %08lx\n", DiskGeometry) );
  3493. //
  3494. // Attempt to lock any removable media, ignoring status.
  3495. //
  3496. Prevent.PreventMediaRemoval = TRUE;
  3497. (VOID)NtfsDeviceIoControl( IrpContext,
  3498. RealDevice,
  3499. IOCTL_DISK_MEDIA_REMOVAL,
  3500. &Prevent,
  3501. sizeof(PREVENT_MEDIA_REMOVAL),
  3502. NULL,
  3503. 0,
  3504. NULL );
  3505. //
  3506. // See if the media is write protected. On success or any kind
  3507. // of error (possibly illegal device function), assume it is
  3508. // writeable, and only complain if he tells us he is write protected.
  3509. //
  3510. Status = NtfsDeviceIoControl( IrpContext,
  3511. RealDevice,
  3512. IOCTL_DISK_IS_WRITABLE,
  3513. NULL,
  3514. 0,
  3515. NULL,
  3516. 0,
  3517. NULL );
  3518. //
  3519. // Remember if the media is write protected but don't raise the error now.
  3520. // If the volume is not Ntfs then let another filesystem try.
  3521. //
  3522. if (Status == STATUS_MEDIA_WRITE_PROTECTED) {
  3523. WriteProtected = TRUE;
  3524. Status = STATUS_SUCCESS;
  3525. }
  3526. Status = NtfsDeviceIoControl( IrpContext,
  3527. RealDevice,
  3528. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  3529. NULL,
  3530. 0,
  3531. DiskGeometry,
  3532. sizeof(DISK_GEOMETRY),
  3533. NULL );
  3534. if (!NT_SUCCESS(Status)) {
  3535. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  3536. }
  3537. Status = NtfsDeviceIoControl( IrpContext,
  3538. RealDevice,
  3539. IOCTL_DISK_GET_LENGTH_INFO,
  3540. NULL,
  3541. 0,
  3542. &LengthInfo,
  3543. sizeof( LengthInfo ),
  3544. NULL );
  3545. if (!NT_SUCCESS(Status)) {
  3546. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  3547. }
  3548. *Length = LengthInfo.Length.QuadPart;
  3549. DebugTrace( -1, Dbg, ("NtfsGetDiskGeometry->VOID\n") );
  3550. return WriteProtected;
  3551. }
  3552. NTSTATUS
  3553. NtfsDeviceIoControl (
  3554. IN PIRP_CONTEXT IrpContext,
  3555. IN PDEVICE_OBJECT DeviceObject,
  3556. IN ULONG IoCtl,
  3557. IN PVOID InputBuffer OPTIONAL,
  3558. IN ULONG InputBufferLength,
  3559. IN PVOID OutputBuffer OPTIONAL,
  3560. IN ULONG OutputBufferLength,
  3561. OUT PULONG_PTR IosbInformation OPTIONAL
  3562. )
  3563. /*++
  3564. Routine Description:
  3565. This procedure issues an Ioctl to the lower device, and waits
  3566. for the answer.
  3567. Arguments:
  3568. DeviceObject - Supplies the device to issue the request to
  3569. IoCtl - Gives the IoCtl to be used
  3570. XxBuffer - Gives the buffer pointer for the ioctl, if any
  3571. XxBufferLength - Gives the length of the buffer, if any
  3572. Return Value:
  3573. None.
  3574. --*/
  3575. {
  3576. PIRP Irp;
  3577. KEVENT Event;
  3578. IO_STATUS_BLOCK Iosb;
  3579. NTSTATUS Status;
  3580. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  3581. Irp = IoBuildDeviceIoControlRequest( IoCtl,
  3582. DeviceObject,
  3583. InputBuffer,
  3584. InputBufferLength,
  3585. OutputBuffer,
  3586. OutputBufferLength,
  3587. FALSE,
  3588. &Event,
  3589. &Iosb );
  3590. if (Irp == NULL) {
  3591. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  3592. }
  3593. Status = IoCallDriver( DeviceObject, Irp );
  3594. if (Status == STATUS_PENDING) {
  3595. (VOID)KeWaitForSingleObject( &Event,
  3596. Executive,
  3597. KernelMode,
  3598. FALSE,
  3599. (PLARGE_INTEGER)NULL );
  3600. Status = Iosb.Status;
  3601. }
  3602. //
  3603. // Get the information field from the completed Irp.
  3604. //
  3605. if ((NT_SUCCESS( Status )) && ARGUMENT_PRESENT( IosbInformation )) {
  3606. *IosbInformation = Iosb.Information;
  3607. }
  3608. return Status;
  3609. }
  3610. //
  3611. // Local support routine
  3612. //
  3613. VOID
  3614. NtfsReadBootSector (
  3615. IN PIRP_CONTEXT IrpContext,
  3616. IN PVCB Vcb,
  3617. OUT PSCB *BootScb,
  3618. OUT PBCB *BootBcb,
  3619. OUT PVOID *BootSector
  3620. )
  3621. /*++
  3622. Routine Description:
  3623. This routine reads and returns a pointer to the boot sector for the volume.
  3624. Volumes formatted under 3.51 and earlier will have a boot sector at sector
  3625. 0 and another halfway through the disk. Volumes formatted with NT 4.0
  3626. will have a boot sector at the end of the disk, in the sector beyond the
  3627. stated size of the volume in the boot sector. When this call is made the
  3628. Vcb has the sector count from the device driver so we subtract one to find
  3629. the last sector.
  3630. Arguments:
  3631. Vcb - Supplies the Vcb for the operation
  3632. BootScb - Receives the Scb for the boot file
  3633. BootBcb - Receives the bcb for the boot sector
  3634. BootSector - Receives a pointer to the boot sector
  3635. Return Value:
  3636. None.
  3637. --*/
  3638. {
  3639. PSCB Scb = NULL;
  3640. BOOLEAN Error = FALSE;
  3641. FILE_REFERENCE FileReference = { BOOT_FILE_NUMBER, 0, BOOT_FILE_NUMBER };
  3642. PAGED_CODE();
  3643. DebugTrace( +1, Dbg, ("NtfsReadBootSector:\n") );
  3644. DebugTrace( 0, Dbg, ("Vcb = %08lx\n", Vcb) );
  3645. //
  3646. // Create a temporary scb for reading in the boot sector and initialize the
  3647. // mcb for it.
  3648. //
  3649. Scb = NtfsCreatePrerestartScb( IrpContext,
  3650. Vcb,
  3651. &FileReference,
  3652. $DATA,
  3653. NULL,
  3654. 0 );
  3655. *BootScb = Scb;
  3656. Scb->Header.AllocationSize.QuadPart =
  3657. Scb->Header.FileSize.QuadPart =
  3658. Scb->Header.ValidDataLength.QuadPart = (PAGE_SIZE * 2) + Vcb->BytesPerSector;
  3659. //
  3660. // We don't want to look up the size for this Scb.
  3661. //
  3662. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  3663. SetFlag( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED );
  3664. (VOID)NtfsAddNtfsMcbEntry( &Scb->Mcb,
  3665. (LONGLONG)0,
  3666. (LONGLONG)0,
  3667. (LONGLONG)Vcb->ClustersPerPage,
  3668. FALSE );
  3669. (VOID)NtfsAddNtfsMcbEntry( &Scb->Mcb,
  3670. (LONGLONG)Vcb->ClustersPerPage,
  3671. Vcb->NumberSectors >> 1,
  3672. (LONGLONG)Vcb->ClustersPerPage,
  3673. FALSE );
  3674. (VOID)NtfsAddNtfsMcbEntry( &Scb->Mcb,
  3675. Int64ShllMod32( (LONGLONG) Vcb->ClustersPerPage, 1 ),
  3676. Vcb->NumberSectors - 1,
  3677. 1,
  3678. FALSE );
  3679. //
  3680. // Try reading in the first boot sector
  3681. //
  3682. try {
  3683. NtfsMapStream( IrpContext,
  3684. Scb,
  3685. (LONGLONG)0,
  3686. Vcb->BytesPerSector,
  3687. BootBcb,
  3688. BootSector );
  3689. //
  3690. // If we got an exception trying to read the first boot sector,
  3691. // then handle the exception by trying to read the second boot
  3692. // sector. If that faults too, then we just allow ourselves to
  3693. // unwind and return the error.
  3694. //
  3695. } except (FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  3696. EXCEPTION_EXECUTE_HANDLER :
  3697. EXCEPTION_CONTINUE_SEARCH) {
  3698. Error = TRUE;
  3699. }
  3700. //
  3701. // Get out if we didn't get an error. Otherwise try the middle sector.
  3702. // We want to read this next because we know that 4.0 format will clear
  3703. // this before writing the last sector. Otherwise we could see a
  3704. // stale boot sector in the last sector even though a 3.51 format was
  3705. // the last to run.
  3706. //
  3707. if (!Error) { return; }
  3708. Error = FALSE;
  3709. try {
  3710. NtfsMapStream( IrpContext,
  3711. Scb,
  3712. (LONGLONG)PAGE_SIZE,
  3713. Vcb->BytesPerSector,
  3714. BootBcb,
  3715. BootSector );
  3716. //
  3717. // Ignore this sector if not Ntfs. This could be the case for
  3718. // a bad sector 0 on a FAT volume.
  3719. //
  3720. if (!NtfsIsBootSectorNtfs( *BootSector, Vcb )) {
  3721. NtfsUnpinBcb( IrpContext, BootBcb );
  3722. Error = TRUE;
  3723. }
  3724. //
  3725. // If we got an exception trying to read the first boot sector,
  3726. // then handle the exception by trying to read the second boot
  3727. // sector. If that faults too, then we just allow ourselves to
  3728. // unwind and return the error.
  3729. //
  3730. } except (FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  3731. EXCEPTION_EXECUTE_HANDLER :
  3732. EXCEPTION_CONTINUE_SEARCH) {
  3733. Error = TRUE;
  3734. }
  3735. //
  3736. // Get out if we didn't get an error. Otherwise try the middle sector.
  3737. //
  3738. if (!Error) { return; }
  3739. NtfsMapStream( IrpContext,
  3740. Scb,
  3741. (LONGLONG) (PAGE_SIZE * 2),
  3742. Vcb->BytesPerSector,
  3743. BootBcb,
  3744. BootSector );
  3745. //
  3746. // Clear the header flag in the Scb.
  3747. //
  3748. ClearFlag( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED );
  3749. //
  3750. // And return to our caller
  3751. //
  3752. DebugTrace( 0, Dbg, ("BootScb > %08lx\n", *BootScb) );
  3753. DebugTrace( 0, Dbg, ("BootBcb > %08lx\n", *BootBcb) );
  3754. DebugTrace( 0, Dbg, ("BootSector > %08lx\n", *BootSector) );
  3755. DebugTrace( -1, Dbg, ("NtfsReadBootSector->VOID\n") );
  3756. return;
  3757. }
  3758. //
  3759. // Local support routine
  3760. //
  3761. //
  3762. // First define a local macro to number the tests for the debug case.
  3763. //
  3764. #ifdef NTFSDBG
  3765. #define NextTest ++CheckNumber &&
  3766. #else
  3767. #define NextTest TRUE &&
  3768. #endif
  3769. BOOLEAN
  3770. NtfsIsBootSectorNtfs (
  3771. IN PPACKED_BOOT_SECTOR BootSector,
  3772. IN PVCB Vcb
  3773. )
  3774. /*++
  3775. Routine Description:
  3776. This routine checks the boot sector to determine if it is an NTFS partition.
  3777. The Vcb must alread be initialized from the device object to contain the
  3778. parts of the device geometry we care about here: bytes per sector and
  3779. total number of sectors in the partition.
  3780. Arguments:
  3781. BootSector - Pointer to the boot sector which has been read in.
  3782. Vcb - Pointer to a Vcb which has been initialized with sector size and
  3783. number of sectors on the partition.
  3784. Return Value:
  3785. FALSE - If the boot sector is not for Ntfs.
  3786. TRUE - If the boot sector is for Ntfs.
  3787. --*/
  3788. {
  3789. #ifdef NTFSDBG
  3790. ULONG CheckNumber = 0;
  3791. #endif
  3792. // PULONG l;
  3793. // ULONG Checksum = 0;
  3794. PAGED_CODE();
  3795. DebugTrace( +1, Dbg, ("NtfsIsBootSectorNtfs\n") );
  3796. DebugTrace( 0, Dbg, ("BootSector = %08lx\n", BootSector) );
  3797. //
  3798. // First calculate the boot sector checksum
  3799. //
  3800. //
  3801. // for (l = (PULONG)BootSector; l < (PULONG)&BootSector->Checksum; l++) {
  3802. // Checksum += *l;
  3803. // }
  3804. //
  3805. // Now perform all the checks, starting with the Name and Checksum.
  3806. // The remaining checks should be obvious, including some fields which
  3807. // must be 0 and other fields which must be a small power of 2.
  3808. //
  3809. if (NextTest
  3810. (BootSector->Oem[0] == 'N') &&
  3811. (BootSector->Oem[1] == 'T') &&
  3812. (BootSector->Oem[2] == 'F') &&
  3813. (BootSector->Oem[3] == 'S') &&
  3814. (BootSector->Oem[4] == ' ') &&
  3815. (BootSector->Oem[5] == ' ') &&
  3816. (BootSector->Oem[6] == ' ') &&
  3817. (BootSector->Oem[7] == ' ')
  3818. &&
  3819. // NextTest
  3820. // (BootSector->Checksum == Checksum)
  3821. //
  3822. // &&
  3823. //
  3824. // Check number of bytes per sector. The low order byte of this
  3825. // number must be zero (smallest sector size = 0x100) and the
  3826. // high order byte shifted must equal the bytes per sector gotten
  3827. // from the device and stored in the Vcb. And just to be sure,
  3828. // sector size must be less than page size.
  3829. //
  3830. NextTest
  3831. (BootSector->PackedBpb.BytesPerSector[0] == 0)
  3832. &&
  3833. NextTest
  3834. ((ULONG)(BootSector->PackedBpb.BytesPerSector[1] << 8) == Vcb->BytesPerSector)
  3835. &&
  3836. NextTest
  3837. (BootSector->PackedBpb.BytesPerSector[1] << 8 <= PAGE_SIZE)
  3838. &&
  3839. //
  3840. // Sectors per cluster must be a power of 2.
  3841. //
  3842. NextTest
  3843. ((BootSector->PackedBpb.SectorsPerCluster[0] == 0x1) ||
  3844. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x2) ||
  3845. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x4) ||
  3846. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x8) ||
  3847. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x10) ||
  3848. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x20) ||
  3849. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x40) ||
  3850. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x80))
  3851. &&
  3852. //
  3853. // These fields must all be zero. For both Fat and HPFS, some of
  3854. // these fields must be nonzero.
  3855. //
  3856. NextTest
  3857. (BootSector->PackedBpb.ReservedSectors[0] == 0) &&
  3858. (BootSector->PackedBpb.ReservedSectors[1] == 0) &&
  3859. (BootSector->PackedBpb.Fats[0] == 0) &&
  3860. (BootSector->PackedBpb.RootEntries[0] == 0) &&
  3861. (BootSector->PackedBpb.RootEntries[1] == 0) &&
  3862. (BootSector->PackedBpb.Sectors[0] == 0) &&
  3863. (BootSector->PackedBpb.Sectors[1] == 0) &&
  3864. (BootSector->PackedBpb.SectorsPerFat[0] == 0) &&
  3865. (BootSector->PackedBpb.SectorsPerFat[1] == 0) &&
  3866. // (BootSector->PackedBpb.HiddenSectors[0] == 0) &&
  3867. // (BootSector->PackedBpb.HiddenSectors[1] == 0) &&
  3868. // (BootSector->PackedBpb.HiddenSectors[2] == 0) &&
  3869. // (BootSector->PackedBpb.HiddenSectors[3] == 0) &&
  3870. (BootSector->PackedBpb.LargeSectors[0] == 0) &&
  3871. (BootSector->PackedBpb.LargeSectors[1] == 0) &&
  3872. (BootSector->PackedBpb.LargeSectors[2] == 0) &&
  3873. (BootSector->PackedBpb.LargeSectors[3] == 0)
  3874. &&
  3875. //
  3876. // Number of Sectors cannot be greater than the number of sectors
  3877. // on the partition.
  3878. //
  3879. NextTest
  3880. (BootSector->NumberSectors <= Vcb->NumberSectors)
  3881. &&
  3882. //
  3883. // Check that both Lcn values are for sectors within the partition.
  3884. //
  3885. NextTest
  3886. ((BootSector->MftStartLcn * BootSector->PackedBpb.SectorsPerCluster[0]) <=
  3887. Vcb->NumberSectors)
  3888. &&
  3889. NextTest
  3890. ((BootSector->Mft2StartLcn * BootSector->PackedBpb.SectorsPerCluster[0]) <=
  3891. Vcb->NumberSectors)
  3892. &&
  3893. //
  3894. // Clusters per file record segment and default clusters for Index
  3895. // Allocation Buffers must be a power of 2. A zero indicates that the
  3896. // size of these structures is the default size.
  3897. //
  3898. NextTest
  3899. (((BootSector->ClustersPerFileRecordSegment >= -31) &&
  3900. (BootSector->ClustersPerFileRecordSegment <= -9)) ||
  3901. (BootSector->ClustersPerFileRecordSegment == 0x1) ||
  3902. (BootSector->ClustersPerFileRecordSegment == 0x2) ||
  3903. (BootSector->ClustersPerFileRecordSegment == 0x4) ||
  3904. (BootSector->ClustersPerFileRecordSegment == 0x8) ||
  3905. (BootSector->ClustersPerFileRecordSegment == 0x10) ||
  3906. (BootSector->ClustersPerFileRecordSegment == 0x20) ||
  3907. (BootSector->ClustersPerFileRecordSegment == 0x40))
  3908. &&
  3909. NextTest
  3910. (((BootSector->DefaultClustersPerIndexAllocationBuffer >= -31) &&
  3911. (BootSector->DefaultClustersPerIndexAllocationBuffer <= -9)) ||
  3912. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x1) ||
  3913. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x2) ||
  3914. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x4) ||
  3915. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x8) ||
  3916. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x10) ||
  3917. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x20) ||
  3918. (BootSector->DefaultClustersPerIndexAllocationBuffer == 0x40))) {
  3919. DebugTrace( -1, Dbg, ("NtfsIsBootSectorNtfs->TRUE\n") );
  3920. return TRUE;
  3921. } else {
  3922. //
  3923. // If a check failed, print its check number with Debug Trace.
  3924. //
  3925. DebugTrace( 0, Dbg, ("Boot Sector failed test number %08lx\n", CheckNumber) );
  3926. DebugTrace( -1, Dbg, ("NtfsIsBootSectorNtfs->FALSE\n") );
  3927. return FALSE;
  3928. }
  3929. }
  3930. //
  3931. // Local support routine
  3932. //
  3933. VOID
  3934. NtfsGetVolumeInformation (
  3935. IN PIRP_CONTEXT IrpContext,
  3936. IN PVPB Vpb OPTIONAL,
  3937. IN PVCB Vcb,
  3938. OUT PUSHORT VolumeFlags
  3939. )
  3940. /*++
  3941. Routine Description:
  3942. This routine gets the serial number and volume label for an NTFS volume. It also
  3943. returns the current volume flags for the volume.
  3944. Arguments:
  3945. Vpb - Supplies the Vpb for the volume. The Vpb will receive a copy of
  3946. the volume label and serial number, if a Vpb is specified.
  3947. Vcb - Supplies the Vcb for the operation.
  3948. VolumeFlags - Address to store the current volume flags.
  3949. Return Value:
  3950. None.
  3951. --*/
  3952. {
  3953. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  3954. PVOLUME_INFORMATION VolumeInformation;
  3955. PAGED_CODE();
  3956. DebugTrace( 0, Dbg, ("NtfsGetVolumeInformation...\n") );
  3957. *VolumeFlags = 0;
  3958. //
  3959. // We read in the volume label attribute to get the volume label.
  3960. //
  3961. try {
  3962. if (ARGUMENT_PRESENT(Vpb)) {
  3963. NtfsInitializeAttributeContext( &AttributeContext );
  3964. if (NtfsLookupAttributeByCode( IrpContext,
  3965. Vcb->VolumeDasdScb->Fcb,
  3966. &Vcb->VolumeDasdScb->Fcb->FileReference,
  3967. $VOLUME_NAME,
  3968. &AttributeContext )) {
  3969. Vpb->VolumeLabelLength = (USHORT)
  3970. NtfsFoundAttribute( &AttributeContext )->Form.Resident.ValueLength;
  3971. if ( Vpb->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH) {
  3972. Vpb->VolumeLabelLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  3973. }
  3974. RtlCopyMemory( &Vpb->VolumeLabel[0],
  3975. NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ) ),
  3976. Vpb->VolumeLabelLength );
  3977. } else {
  3978. Vpb->VolumeLabelLength = 0;
  3979. }
  3980. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  3981. }
  3982. NtfsInitializeAttributeContext( &AttributeContext );
  3983. //
  3984. // Remember if the volume is dirty when we are mounting it.
  3985. //
  3986. if (NtfsLookupAttributeByCode( IrpContext,
  3987. Vcb->VolumeDasdScb->Fcb,
  3988. &Vcb->VolumeDasdScb->Fcb->FileReference,
  3989. $VOLUME_INFORMATION,
  3990. &AttributeContext )) {
  3991. VolumeInformation =
  3992. (PVOLUME_INFORMATION)NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  3993. if (FlagOn( VolumeInformation->VolumeFlags, VOLUME_DIRTY )) {
  3994. SetFlag( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY );
  3995. } else {
  3996. ClearFlag( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY );
  3997. }
  3998. *VolumeFlags = VolumeInformation->VolumeFlags;
  3999. }
  4000. } finally {
  4001. DebugUnwind( NtfsGetVolumeInformation );
  4002. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  4003. }
  4004. //
  4005. // And return to our caller
  4006. //
  4007. return;
  4008. }
  4009. //
  4010. // Local support routine
  4011. //
  4012. VOID
  4013. NtfsSetAndGetVolumeTimes (
  4014. IN PIRP_CONTEXT IrpContext,
  4015. IN PVCB Vcb,
  4016. IN BOOLEAN MarkDirty
  4017. )
  4018. /*++
  4019. Routine Description:
  4020. This routine reads in the volume times from the standard information attribute
  4021. of the volume file and also updates the access time to be the current
  4022. time
  4023. Arguments:
  4024. Vcb - Supplies the vcb for the operation.
  4025. MarkDirty - Supplies TRUE if volume is to be marked dirty
  4026. UpdateInTransaction - Indicates if we should mark the volume dirty in a transaction.
  4027. Return Value:
  4028. None.
  4029. --*/
  4030. {
  4031. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  4032. PSTANDARD_INFORMATION StandardInformation;
  4033. LONGLONG MountTime;
  4034. PAGED_CODE();
  4035. DebugTrace( 0, Dbg, ("NtfsSetAndGetVolumeTimes...\n") );
  4036. try {
  4037. //
  4038. // Lookup the standard information attribute of the dasd file
  4039. //
  4040. NtfsInitializeAttributeContext( &AttributeContext );
  4041. if (!NtfsLookupAttributeByCode( IrpContext,
  4042. Vcb->VolumeDasdScb->Fcb,
  4043. &Vcb->VolumeDasdScb->Fcb->FileReference,
  4044. $STANDARD_INFORMATION,
  4045. &AttributeContext )) {
  4046. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  4047. }
  4048. StandardInformation = (PSTANDARD_INFORMATION)NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  4049. //
  4050. // Get the current time and make sure it differs from the time stored
  4051. // in last access time and then store the new last access time
  4052. //
  4053. NtfsGetCurrentTime( IrpContext, MountTime );
  4054. if (MountTime == StandardInformation->LastAccessTime) {
  4055. MountTime = MountTime + 1;
  4056. }
  4057. //****
  4058. //**** Hold back on the update for now.
  4059. //****
  4060. //**** NtfsChangeAttributeValue( IrpContext,
  4061. //**** Vcb->VolumeDasdScb->Fcb,
  4062. //**** FIELD_OFFSET(STANDARD_INFORMATION, LastAccessTime),
  4063. //**** &MountTime,
  4064. //**** sizeof(MountTime),
  4065. //**** FALSE,
  4066. //**** FALSE,
  4067. //**** &AttributeContext );
  4068. //
  4069. // Now save all the time fields in our vcb
  4070. //
  4071. Vcb->VolumeCreationTime = StandardInformation->CreationTime;
  4072. Vcb->VolumeLastModificationTime = StandardInformation->LastModificationTime;
  4073. Vcb->VolumeLastChangeTime = StandardInformation->LastChangeTime;
  4074. Vcb->VolumeLastAccessTime = StandardInformation->LastAccessTime; //****Also hold back = MountTime;
  4075. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  4076. //
  4077. // If the volume was mounted dirty, then set the dirty bit here.
  4078. //
  4079. if (MarkDirty) {
  4080. NtfsMarkVolumeDirty( IrpContext, Vcb );
  4081. }
  4082. } finally {
  4083. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  4084. }
  4085. //
  4086. // And return to our caller
  4087. //
  4088. return;
  4089. }
  4090. //
  4091. // Local support routine
  4092. //
  4093. VOID
  4094. NtfsOpenSystemFile (
  4095. IN PIRP_CONTEXT IrpContext,
  4096. IN OUT PSCB *Scb,
  4097. IN PVCB Vcb,
  4098. IN ULONG FileNumber,
  4099. IN LONGLONG Size,
  4100. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  4101. IN BOOLEAN ModifiedNoWrite
  4102. )
  4103. /*++
  4104. Routine Description:
  4105. This routine is called to open one of the system files by its file number
  4106. during the mount process. An initial allocation is looked up for the file,
  4107. unless the optional initial size is specified (in which case this size is
  4108. used).
  4109. Parameters:
  4110. Scb - Pointer to where the Scb pointer is to be stored. If Scb pointer
  4111. pointed to is NULL, then a PreRestart Scb is created, otherwise the
  4112. existing Scb is used and only the stream file is set up.
  4113. FileNumber - Number of the system file to open.
  4114. Size - If nonzero, this size is used as the initial size, rather
  4115. than consulting the file record in the Mft.
  4116. AttributeTypeCode - Supplies the attribute to open, e.g., $DATA or $BITMAP
  4117. ModifiedNoWrite - Indicates if the Memory Manager is not to write this
  4118. attribute to disk. Applies to streams under transaction
  4119. control.
  4120. Return Value:
  4121. None.
  4122. --*/
  4123. {
  4124. PSCB NewScb = *Scb;
  4125. FILE_REFERENCE FileReference;
  4126. UNICODE_STRING $BadName;
  4127. PUNICODE_STRING AttributeName = NULL;
  4128. BOOLEAN AcquiredScb = FALSE;
  4129. PAGED_CODE();
  4130. DebugTrace( +1, Dbg, ("NtfsOpenSystemFile:\n") );
  4131. DebugTrace( 0, Dbg, ("*Scb = %08lx\n", *Scb) );
  4132. DebugTrace( 0, Dbg, ("FileNumber = %08lx\n", FileNumber) );
  4133. DebugTrace( 0, Dbg, ("ModifiedNoWrite = %04x\n", ModifiedNoWrite) );
  4134. try {
  4135. //
  4136. // The Bad Cluster data attribute has a name.
  4137. //
  4138. if (FileNumber == BAD_CLUSTER_FILE_NUMBER) {
  4139. RtlInitUnicodeString( &$BadName, L"$Bad" );
  4140. AttributeName = &$BadName;
  4141. }
  4142. //
  4143. // If the Scb does not already exist, create it.
  4144. //
  4145. if (NewScb == NULL) {
  4146. NtfsSetSegmentNumber( &FileReference, 0, FileNumber );
  4147. FileReference.SequenceNumber = (FileNumber == 0 ? 1 : (USHORT)FileNumber);
  4148. //
  4149. // Create the Scb.
  4150. //
  4151. NewScb = NtfsCreatePrerestartScb( IrpContext,
  4152. Vcb,
  4153. &FileReference,
  4154. AttributeTypeCode,
  4155. AttributeName,
  4156. 0 );
  4157. NtfsAcquireExclusiveScb( IrpContext, NewScb );
  4158. AcquiredScb = TRUE;
  4159. }
  4160. //
  4161. // Set the modified-no-write bit in the Scb if necessary.
  4162. //
  4163. if (ModifiedNoWrite) {
  4164. SetFlag( NewScb->ScbState, SCB_STATE_MODIFIED_NO_WRITE );
  4165. }
  4166. //
  4167. // Lookup the file sizes.
  4168. //
  4169. if (Size == 0) {
  4170. NtfsUpdateScbFromAttribute( IrpContext, NewScb, NULL );
  4171. //
  4172. // Make sure the file size isn't larger than allocation size.
  4173. //
  4174. if (NewScb->Header.FileSize.QuadPart > NewScb->Header.AllocationSize.QuadPart) {
  4175. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, NewScb->Fcb );
  4176. }
  4177. //
  4178. // Otherwise, just set the size we were given.
  4179. //
  4180. } else {
  4181. NewScb->Header.FileSize.QuadPart =
  4182. NewScb->Header.ValidDataLength.QuadPart = Size;
  4183. NewScb->Header.AllocationSize.QuadPart = LlClustersFromBytes( Vcb, Size );
  4184. NewScb->Header.AllocationSize.QuadPart = LlBytesFromClusters( Vcb,
  4185. NewScb->Header.AllocationSize.QuadPart );
  4186. SetFlag( NewScb->ScbState, SCB_STATE_HEADER_INITIALIZED );
  4187. }
  4188. //
  4189. // Make sure that our system streams are not marked as compressed.
  4190. //
  4191. if (AttributeTypeCode != $INDEX_ALLOCATION) {
  4192. ClearFlag( NewScb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  4193. ClearFlag( NewScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  4194. if (!FlagOn( NewScb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  4195. NewScb->CompressionUnit = 0;
  4196. NewScb->CompressionUnitShift = 0;
  4197. }
  4198. }
  4199. //
  4200. // Finally, create the stream, if not already there.
  4201. // And check if we should increment the counters
  4202. // If this is the volume file or the bad cluster file, we only increment the counts.
  4203. //
  4204. if ((FileNumber == VOLUME_DASD_NUMBER) ||
  4205. (FileNumber == BAD_CLUSTER_FILE_NUMBER)) {
  4206. if (NewScb->FileObject == 0) {
  4207. NtfsIncrementCloseCounts( NewScb, TRUE, FALSE );
  4208. NewScb->FileObject = (PFILE_OBJECT) 1;
  4209. }
  4210. } else {
  4211. NtfsCreateInternalAttributeStream( IrpContext,
  4212. NewScb,
  4213. TRUE,
  4214. &NtfsSystemFiles[FileNumber] );
  4215. }
  4216. } finally {
  4217. if (AbnormalTermination()) {
  4218. if (AcquiredScb) {
  4219. BOOLEAN RemovedFcb = FALSE;
  4220. PFCB Fcb = NewScb->Fcb;
  4221. //
  4222. // We created the Scb / so tear it down in the exceptional case
  4223. //
  4224. NtfsTeardownStructures( IrpContext,
  4225. NewScb,
  4226. NULL,
  4227. FALSE,
  4228. 0,
  4229. &RemovedFcb );
  4230. if (!RemovedFcb) {
  4231. NtfsReleaseFcb( IrpContext, Fcb );
  4232. }
  4233. }
  4234. }
  4235. }
  4236. *Scb = NewScb;
  4237. DebugTrace( 0, Dbg, ("*Scb > %08lx\n", *Scb) );
  4238. DebugTrace( -1, Dbg, ("NtfsOpenSystemFile -> VOID\n") );
  4239. return;
  4240. }
  4241. //
  4242. // Local support routine
  4243. //
  4244. VOID
  4245. NtfsOpenRootDirectory (
  4246. IN PIRP_CONTEXT IrpContext,
  4247. IN PVCB Vcb
  4248. )
  4249. /*++
  4250. Routine Description:
  4251. This routine opens the root directory by file number, and fills in the
  4252. related pointers in the Vcb.
  4253. Arguments:
  4254. Vcb - Pointer to the Vcb for the volume
  4255. Return Value:
  4256. None.
  4257. --*/
  4258. {
  4259. PFCB RootFcb;
  4260. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  4261. FILE_REFERENCE FileReference;
  4262. BOOLEAN MustBeFalse;
  4263. PAGED_CODE();
  4264. //
  4265. // Put special code here to do initial open of Root Index.
  4266. //
  4267. RootFcb = NtfsCreateRootFcb( IrpContext, Vcb );
  4268. NtfsSetSegmentNumber( &FileReference, 0, ROOT_FILE_NAME_INDEX_NUMBER );
  4269. FileReference.SequenceNumber = ROOT_FILE_NAME_INDEX_NUMBER;
  4270. //
  4271. // Now create its Scb and acquire it exclusive.
  4272. //
  4273. Vcb->RootIndexScb = NtfsCreateScb( IrpContext,
  4274. RootFcb,
  4275. $INDEX_ALLOCATION,
  4276. &NtfsFileNameIndex,
  4277. FALSE,
  4278. &MustBeFalse );
  4279. //
  4280. // Now allocate a buffer to hold the normalized name for the root.
  4281. //
  4282. Vcb->RootIndexScb->ScbType.Index.NormalizedName.Buffer = NtfsAllocatePool( PagedPool, 2 );
  4283. Vcb->RootIndexScb->ScbType.Index.NormalizedName.MaximumLength =
  4284. Vcb->RootIndexScb->ScbType.Index.NormalizedName.Length = 2;
  4285. Vcb->RootIndexScb->ScbType.Index.NormalizedName.Buffer[0] = '\\';
  4286. Vcb->RootIndexScb->ScbType.Index.HashValue = 0;
  4287. NtfsConvertNameToHash( Vcb->RootIndexScb->ScbType.Index.NormalizedName.Buffer,
  4288. sizeof( WCHAR ),
  4289. Vcb->UpcaseTable,
  4290. &Vcb->RootIndexScb->ScbType.Index.HashValue );
  4291. NtfsAcquireExclusiveScb( IrpContext, Vcb->RootIndexScb );
  4292. //
  4293. // Lookup the attribute and it better be there
  4294. //
  4295. NtfsInitializeAttributeContext( &Context );
  4296. //
  4297. // Use a try-finally to facilitate cleanup.
  4298. //
  4299. try {
  4300. if (!NtfsLookupAttributeByCode( IrpContext,
  4301. RootFcb,
  4302. &FileReference,
  4303. $INDEX_ROOT,
  4304. &Context ) ) {
  4305. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  4306. }
  4307. //
  4308. // We need to update the duplicated information in the
  4309. // Fcb.
  4310. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, RootFcb, NULL );
  4311. //
  4312. // Initialize the Scb. Force it to refer to a file name.
  4313. //
  4314. NtfsUpdateIndexScbFromAttribute( IrpContext,
  4315. Vcb->RootIndexScb,
  4316. NtfsFoundAttribute( &Context ),
  4317. TRUE );
  4318. } finally {
  4319. NtfsCleanupAttributeContext( IrpContext, &Context );
  4320. }
  4321. return;
  4322. }
  4323. //
  4324. // Local support routine
  4325. //
  4326. VOID
  4327. NtfsInitializeSecurityFile (
  4328. IN PIRP_CONTEXT IrpContext,
  4329. IN PVCB Vcb
  4330. )
  4331. /*++
  4332. Routine Description:
  4333. This routine creates/opens the security file, and initializes the security
  4334. support.
  4335. Arguments:
  4336. Vcb - Pointer to the Vcb for the volume
  4337. Return Value:
  4338. None.
  4339. --*/
  4340. {
  4341. PFCB Fcb;
  4342. FILE_REFERENCE FileReference;
  4343. //
  4344. // Set the file number for the security file.
  4345. //
  4346. NtfsSetSegmentNumber( &FileReference, 0, SECURITY_FILE_NUMBER );
  4347. FileReference.SequenceNumber = SECURITY_FILE_NUMBER;
  4348. //
  4349. // Create the Fcb.
  4350. //
  4351. Fcb = NtfsCreateFcb( IrpContext,
  4352. Vcb,
  4353. FileReference,
  4354. FALSE,
  4355. TRUE,
  4356. NULL );
  4357. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  4358. //
  4359. // Use a try-finally to facilitate cleanup.
  4360. //
  4361. try {
  4362. //
  4363. // Now call the Security system to initialize itself.
  4364. //
  4365. NtfsInitializeSecurity( IrpContext, Vcb, Fcb );
  4366. } finally {
  4367. //
  4368. // If some error caused him to not get any Scbs created, then delete
  4369. // the Fcb, because we are the only ones who will.
  4370. //
  4371. if (IsListEmpty(&Fcb->ScbQueue)) {
  4372. BOOLEAN AcquiredFcbTable = TRUE;
  4373. NtfsAcquireFcbTable( IrpContext, Vcb );
  4374. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4375. ASSERT(!AcquiredFcbTable);
  4376. }
  4377. }
  4378. }
  4379. //
  4380. // Local support routine
  4381. //
  4382. VOID
  4383. NtfsUpgradeSecurity (
  4384. IN PIRP_CONTEXT IrpContext,
  4385. IN PVCB Vcb
  4386. )
  4387. /*++
  4388. Routine Description:
  4389. This routine upgrades the security descriptors and names for system
  4390. scbs.
  4391. Arguments:
  4392. Vcb - Pointer to the Vcb for the volume
  4393. Return Value:
  4394. None.
  4395. --*/
  4396. {
  4397. PFCB Fcb = Vcb->SecurityDescriptorStream->Fcb;
  4398. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  4399. PSCB *ScbPtr;
  4400. //
  4401. // Get set for some attribute lookups/creates
  4402. //
  4403. NtfsInitializeAttributeContext( &Context );
  4404. //
  4405. // Use a try-finally to facilitate cleanup.
  4406. //
  4407. try {
  4408. struct {
  4409. FILE_NAME FileName;
  4410. WCHAR FileNameChars[10];
  4411. } FileNameAttr;
  4412. PFILE_NAME CurrentFileName;
  4413. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  4414. //
  4415. // Initialize a FileName attribute for this file.
  4416. //
  4417. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  4418. FileNameAttr.FileName.ParentDirectory = Fcb->FileReference;
  4419. FileNameAttr.FileName.FileNameLength = 7;
  4420. RtlCopyMemory( FileNameAttr.FileName.FileName, L"$Secure", 14 );
  4421. ASSERT_EXCLUSIVE_FCB( Fcb );
  4422. //
  4423. // If this file still has an unnamed data attribute from format, delete it.
  4424. //
  4425. if (NtfsLookupAttributeByName( IrpContext,
  4426. Fcb,
  4427. &Fcb->FileReference,
  4428. $DATA,
  4429. &NoName,
  4430. NULL,
  4431. FALSE,
  4432. &Context ) ) {
  4433. NtfsDeleteAttributeRecord( IrpContext,
  4434. Fcb,
  4435. DELETE_LOG_OPERATION |
  4436. DELETE_RELEASE_FILE_RECORD |
  4437. DELETE_RELEASE_ALLOCATION,
  4438. &Context );
  4439. }
  4440. NtfsCleanupAttributeContext( IrpContext, &Context );
  4441. //
  4442. // If there is an old name from format, remove it and put the right one there.
  4443. //
  4444. NtfsInitializeAttributeContext( &Context );
  4445. if (NtfsLookupAttributeByCode( IrpContext,
  4446. Fcb,
  4447. &Fcb->FileReference,
  4448. $FILE_NAME,
  4449. &Context ) &&
  4450. (((CurrentFileName = (PFILE_NAME)NtfsAttributeValue(NtfsFoundAttribute(&Context)))->FileNameLength != 7) ||
  4451. (RtlCompareMemory(CurrentFileName->FileName, FileNameAttr.FileName.FileName, 14) != 14))) {
  4452. UCHAR FileNameFlags;
  4453. UNICODE_STRING LinkName;
  4454. LinkName.Length = LinkName.MaximumLength = CurrentFileName->FileNameLength * sizeof( WCHAR );
  4455. LinkName.Buffer = CurrentFileName->FileName;
  4456. //
  4457. // Yank the old name.
  4458. //
  4459. NtfsRemoveLink( IrpContext, Fcb, Vcb->RootIndexScb, LinkName, NULL, NULL );
  4460. //
  4461. // Create the new name.
  4462. //
  4463. NtfsAddLink( IrpContext,
  4464. TRUE,
  4465. Vcb->RootIndexScb,
  4466. Fcb,
  4467. (PFILE_NAME)&FileNameAttr,
  4468. NULL,
  4469. &FileNameFlags,
  4470. NULL,
  4471. NULL,
  4472. NULL );
  4473. }
  4474. } finally {
  4475. NtfsCleanupAttributeContext( IrpContext, &Context );
  4476. }
  4477. //
  4478. // To free some space in our system file records, let's verify that their security
  4479. // is converted.
  4480. //
  4481. // **** conditionalize now until chkdsk supports the new security.
  4482. //
  4483. for (ScbPtr = &Vcb->MftScb; ScbPtr < &Vcb->MftBitmapScb; ScbPtr++) {
  4484. PFCB SystemFcb;
  4485. //
  4486. // Do only Scb's that are currently open
  4487. //
  4488. if (*ScbPtr == NULL)
  4489. continue;
  4490. SystemFcb = (*ScbPtr)->Fcb;
  4491. //
  4492. // Skip the root index and volume dasd for backwards compatibility.
  4493. //
  4494. if (SystemFcb == NULL ||
  4495. ScbPtr == &Vcb->RootIndexScb ||
  4496. ScbPtr == &Vcb->VolumeDasdScb) {
  4497. continue;
  4498. }
  4499. //
  4500. // Initialize the Fcb and load the security descriptor.
  4501. //
  4502. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, SystemFcb, NULL );
  4503. //
  4504. // Skip this Fcb if we've already given it an Id or if it has no
  4505. // security whatsoever.
  4506. //
  4507. if (SystemFcb->SecurityId != SECURITY_ID_INVALID ||
  4508. SystemFcb->SharedSecurity == NULL) {
  4509. continue;
  4510. }
  4511. //
  4512. // Delete the $SECURITY_DESCRIPTOR attribute if it has one
  4513. //
  4514. NtfsInitializeAttributeContext( &Context );
  4515. try {
  4516. //
  4517. // Find the $SECURITY_DESCRIPTOR attribute.
  4518. //
  4519. if (NtfsLookupAttributeByCode( IrpContext,
  4520. SystemFcb,
  4521. &SystemFcb->FileReference,
  4522. $SECURITY_DESCRIPTOR,
  4523. &Context )) {
  4524. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  4525. PSCB Scb;
  4526. DebugTrace( 0, DbgAcl, ("NtfsUpgradeSecurity deleting existing Security Descriptor\n") );
  4527. NtfsDeleteAttributeRecord( IrpContext,
  4528. SystemFcb,
  4529. DELETE_LOG_OPERATION |
  4530. DELETE_RELEASE_FILE_RECORD |
  4531. DELETE_RELEASE_ALLOCATION,
  4532. &Context );
  4533. //
  4534. // If the $SECURITY_DESCRIPTOR was non resident, the above
  4535. // delete call created one for us under the covers. We
  4536. // need to mark it as deleted otherwise, we detect the
  4537. // volume as being corrupt.
  4538. //
  4539. Scb = NtfsCreateScb( IrpContext,
  4540. SystemFcb,
  4541. $SECURITY_DESCRIPTOR,
  4542. &NoName,
  4543. TRUE,
  4544. NULL );
  4545. if (Scb != NULL) {
  4546. ASSERT_EXCLUSIVE_SCB( Scb );
  4547. SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  4548. }
  4549. }
  4550. } finally {
  4551. NtfsCleanupAttributeContext( IrpContext, &Context );
  4552. }
  4553. //
  4554. // Make sure we have a large $STANDARD_INFORMATION for this file
  4555. //
  4556. if (!FlagOn( SystemFcb->FcbState, FCB_STATE_LARGE_STD_INFO ) ) {
  4557. DebugTrace( 0, DbgAcl, ("NtfsUpgradeSecurity growing standard information\n") );
  4558. NtfsGrowStandardInformation( IrpContext, SystemFcb );
  4559. }
  4560. //
  4561. // Assign a security Id if we don't have one already
  4562. //
  4563. if (SystemFcb->SharedSecurity->Header.HashKey.SecurityId == SECURITY_ID_INVALID) {
  4564. NtfsAcquireFcbSecurity( Vcb );
  4565. try {
  4566. GetSecurityIdFromSecurityDescriptorUnsafe( IrpContext, SystemFcb->SharedSecurity );
  4567. } finally {
  4568. NtfsReleaseFcbSecurity( Vcb );
  4569. }
  4570. ASSERT( SystemFcb->SharedSecurity->Header.HashKey.SecurityId != SECURITY_ID_INVALID );
  4571. }
  4572. //
  4573. // Copy the security Id into the Fcb so we can store it out
  4574. //
  4575. SystemFcb->SecurityId = SystemFcb->SharedSecurity->Header.HashKey.SecurityId;
  4576. //
  4577. // Update the $STANDARD_INFORMATION for the operation
  4578. //
  4579. NtfsUpdateStandardInformation( IrpContext, SystemFcb );
  4580. }
  4581. }
  4582. //
  4583. // Local support routine
  4584. //
  4585. VOID
  4586. NtfsInitializeExtendDirectory (
  4587. IN PIRP_CONTEXT IrpContext,
  4588. IN PVCB Vcb
  4589. )
  4590. /*++
  4591. Routine Description:
  4592. This routine opens the $Extend directory by file number, and fills in the
  4593. related pointers in the Vcb.
  4594. Arguments:
  4595. Vcb - Pointer to the Vcb for the volume
  4596. Return Value:
  4597. None.
  4598. --*/
  4599. {
  4600. struct {
  4601. FILE_NAME FileName;
  4602. WCHAR FileNameChars[10];
  4603. } FileNameAttr;
  4604. PFCB Fcb;
  4605. PFCB PreviousFcb = NULL;
  4606. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  4607. FILE_REFERENCE FileReference;
  4608. PBCB FileRecordBcb = NULL;
  4609. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  4610. LONGLONG FileRecordOffset;
  4611. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  4612. UNICODE_STRING ExtendName;
  4613. PFILE_NAME ExtendFileNameAttr;
  4614. USHORT ExtendFileNameAttrLength;
  4615. PINDEX_ENTRY IndexEntry;
  4616. PBCB IndexEntryBcb = NULL;
  4617. PSTANDARD_INFORMATION StandardInformation;
  4618. ULONG CorruptHint;
  4619. //
  4620. // Initialize with the known FileReference and name.
  4621. //
  4622. FileReference = ExtendFileReference;
  4623. //
  4624. // Now create the Fcb.
  4625. //
  4626. Fcb = NtfsCreateFcb( IrpContext,
  4627. Vcb,
  4628. FileReference,
  4629. FALSE,
  4630. TRUE,
  4631. NULL );
  4632. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  4633. //
  4634. // Get ready for some attribute lookups/creates.
  4635. //
  4636. NtfsInitializeAttributeContext( &Context );
  4637. //
  4638. // Use a try-finally to facilitate cleanup.
  4639. //
  4640. try {
  4641. //
  4642. // Check to see if there is an existing $Extend entry in the root.
  4643. //
  4644. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  4645. RtlCopyMemory( FileNameAttr.FileName.FileName, NtfsExtendName.Buffer, NtfsExtendName.Length );
  4646. ExtendName.MaximumLength = ExtendName.Length = NtfsExtendName.Length;
  4647. ExtendName.Buffer = FileNameAttr.FileName.FileName;
  4648. ExtendFileNameAttr = (PFILE_NAME) &FileNameAttr;
  4649. ExtendFileNameAttrLength = sizeof( FileNameAttr );
  4650. if (NtfsLookupEntry( IrpContext,
  4651. Vcb->RootIndexScb,
  4652. TRUE,
  4653. &ExtendName,
  4654. &ExtendFileNameAttr,
  4655. &ExtendFileNameAttrLength,
  4656. NULL,
  4657. &IndexEntry,
  4658. &IndexEntryBcb,
  4659. NULL )) {
  4660. //
  4661. // If this is not for file record 11 then we want to orphan this entry.
  4662. // The user will have to use chkdsk to recover to a FOUND directory.
  4663. //
  4664. if (NtfsSegmentNumber( &IndexEntry->FileReference ) != EXTEND_NUMBER) {
  4665. //
  4666. // Now create the Fcb for the previous link.
  4667. //
  4668. PreviousFcb = NtfsCreateFcb( IrpContext,
  4669. Vcb,
  4670. IndexEntry->FileReference,
  4671. FALSE,
  4672. FALSE,
  4673. NULL );
  4674. ExtendName.Buffer = ((PFILE_NAME) NtfsFoundIndexEntry( IndexEntry ))->FileName;
  4675. NtfsRemoveLink( IrpContext,
  4676. PreviousFcb,
  4677. Vcb->RootIndexScb,
  4678. ExtendName,
  4679. NULL,
  4680. NULL );
  4681. }
  4682. }
  4683. //
  4684. // We better not be trying to deallocate the file name attribute on the stack.
  4685. //
  4686. ASSERT( ExtendFileNameAttr == (PFILE_NAME) &FileNameAttr );
  4687. //
  4688. // Reinitialize the file name attribute for the FileRecord fixup.
  4689. //
  4690. //
  4691. // If this file still has an unnamed data attribute from format, delete it.
  4692. //
  4693. if (NtfsLookupAttributeByName( IrpContext,
  4694. Fcb,
  4695. &FileReference,
  4696. $DATA,
  4697. &NoName,
  4698. NULL,
  4699. FALSE,
  4700. &Context ) ) {
  4701. NtfsDeleteAttributeRecord( IrpContext,
  4702. Fcb,
  4703. DELETE_LOG_OPERATION |
  4704. DELETE_RELEASE_FILE_RECORD |
  4705. DELETE_RELEASE_ALLOCATION,
  4706. &Context );
  4707. }
  4708. NtfsCleanupAttributeContext( IrpContext, &Context );
  4709. //
  4710. // Capture the standard information values in the Fcb and set the file name index
  4711. // flag if necessary.
  4712. //
  4713. NtfsInitializeAttributeContext( &Context );
  4714. if (!NtfsLookupAttributeByCode( IrpContext,
  4715. Fcb,
  4716. &FileReference,
  4717. $STANDARD_INFORMATION,
  4718. &Context )) {
  4719. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, &FileReference, NULL );
  4720. }
  4721. //
  4722. // Check that the $Extend file record is valid.
  4723. //
  4724. if (!NtfsCheckFileRecord( Vcb, NtfsContainingFileRecord( &Context ), &FileReference, &CorruptHint)) {
  4725. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, &FileReference, NULL );
  4726. }
  4727. //
  4728. // Copy the existing standard information into the Fcb and set the file name
  4729. // index flag.
  4730. //
  4731. StandardInformation = (PSTANDARD_INFORMATION) NtfsAttributeValue( NtfsFoundAttribute( &Context ));
  4732. Fcb->Info.CreationTime = StandardInformation->CreationTime;
  4733. Fcb->Info.LastModificationTime = StandardInformation->LastModificationTime;
  4734. Fcb->Info.LastChangeTime = StandardInformation->LastChangeTime;
  4735. Fcb->Info.LastAccessTime = StandardInformation->LastAccessTime;
  4736. Fcb->CurrentLastAccess = Fcb->Info.LastAccessTime;
  4737. Fcb->Info.FileAttributes = StandardInformation->FileAttributes;
  4738. NtfsCleanupAttributeContext( IrpContext, &Context );
  4739. SetFlag( Fcb->Info.FileAttributes, DUP_FILE_NAME_INDEX_PRESENT );
  4740. //
  4741. // If the name isn't there yet, add it.
  4742. //
  4743. NtfsInitializeAttributeContext( &Context );
  4744. if (!NtfsLookupAttributeByCode( IrpContext,
  4745. Fcb,
  4746. &FileReference,
  4747. $FILE_NAME,
  4748. &Context )) {
  4749. UCHAR FileNameFlags;
  4750. //
  4751. // Update the file name attribute for the create.
  4752. //
  4753. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  4754. FileNameAttr.FileName.FileNameLength = NtfsExtendName.Length/2;
  4755. RtlCopyMemory( FileNameAttr.FileName.FileName, NtfsExtendName.Buffer, NtfsExtendName.Length );
  4756. NtfsAddLink( IrpContext,
  4757. TRUE,
  4758. Vcb->RootIndexScb,
  4759. Fcb,
  4760. (PFILE_NAME)&FileNameAttr,
  4761. NULL,
  4762. &FileNameFlags,
  4763. NULL,
  4764. NULL,
  4765. NULL );
  4766. }
  4767. //
  4768. // Now see if the file name index is there, and if not create it.
  4769. //
  4770. NtfsCleanupAttributeContext( IrpContext, &Context );
  4771. NtfsInitializeAttributeContext( &Context );
  4772. if (!NtfsLookupAttributeByCode( IrpContext,
  4773. Fcb,
  4774. &FileReference,
  4775. $INDEX_ROOT,
  4776. &Context ) ) {
  4777. NtfsCreateIndex( IrpContext,
  4778. Fcb,
  4779. $FILE_NAME,
  4780. COLLATION_FILE_NAME,
  4781. Vcb->DefaultBytesPerIndexAllocationBuffer,
  4782. (UCHAR)Vcb->DefaultBlocksPerIndexAllocationBuffer,
  4783. NULL,
  4784. 0,
  4785. TRUE,
  4786. TRUE );
  4787. //
  4788. // We have to set the index present bit, so read it, save the old data
  4789. // and set the flag here.
  4790. //
  4791. NtfsPinMftRecord( IrpContext,
  4792. Vcb,
  4793. &FileReference,
  4794. FALSE,
  4795. &FileRecordBcb,
  4796. &FileRecord,
  4797. &FileRecordOffset );
  4798. //
  4799. // We have to be very careful when using the InitialzeFileRecordSegment
  4800. // log record. This action is applied unconditionally. DoAction doesn't
  4801. // check the previous LSN in the page. It may be garbage on a newly initialized
  4802. // file record. We log the entire file record to avoid the case where we
  4803. // might overwrite a later Lsn with this earlier Lsn during restart.
  4804. //
  4805. //
  4806. // Log the existing file record as the undo action.
  4807. //
  4808. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  4809. Vcb->MftScb,
  4810. FileRecordBcb,
  4811. Noop,
  4812. NULL,
  4813. 0,
  4814. InitializeFileRecordSegment,
  4815. FileRecord,
  4816. FileRecord->FirstFreeByte,
  4817. FileRecordOffset,
  4818. 0,
  4819. 0,
  4820. Vcb->BytesPerFileRecordSegment );
  4821. //
  4822. // Now update the record in place.
  4823. //
  4824. SetFlag( FileRecord->Flags, FILE_FILE_NAME_INDEX_PRESENT );
  4825. //
  4826. // Log the new file record.
  4827. //
  4828. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  4829. Vcb->MftScb,
  4830. FileRecordBcb,
  4831. InitializeFileRecordSegment,
  4832. FileRecord,
  4833. FileRecord->FirstFreeByte,
  4834. Noop,
  4835. NULL,
  4836. 0,
  4837. FileRecordOffset,
  4838. 0,
  4839. 0,
  4840. Vcb->BytesPerFileRecordSegment );
  4841. //
  4842. // Reload it so we can pass the attribute when initializing the Scb.
  4843. //
  4844. NtfsCleanupAttributeContext( IrpContext, &Context );
  4845. NtfsInitializeAttributeContext( &Context );
  4846. NtfsLookupAttributeByCode( IrpContext,
  4847. Fcb,
  4848. &FileReference,
  4849. $INDEX_ROOT,
  4850. &Context );
  4851. }
  4852. //
  4853. // Initialize the Fcb and load the security descriptor.
  4854. //
  4855. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, Fcb, NULL );
  4856. if (Fcb->SharedSecurity == NULL) {
  4857. NtfsLoadSecurityDescriptor( IrpContext, Fcb );
  4858. }
  4859. ASSERT( Fcb->SharedSecurity != NULL );
  4860. //
  4861. // Now create its Scb and store it.
  4862. //
  4863. Vcb->ExtendDirectory = NtfsCreateScb( IrpContext,
  4864. Fcb,
  4865. $INDEX_ALLOCATION,
  4866. &NtfsFileNameIndex,
  4867. FALSE,
  4868. NULL );
  4869. NtfsUpdateIndexScbFromAttribute( IrpContext,
  4870. Vcb->ExtendDirectory,
  4871. NtfsFoundAttribute( &Context ),
  4872. TRUE );
  4873. NtfsCreateInternalAttributeStream( IrpContext,
  4874. Vcb->ExtendDirectory,
  4875. FALSE,
  4876. NULL );
  4877. //
  4878. // Now allocate a buffer to hold the normalized name for $Extend
  4879. //
  4880. Vcb->ExtendDirectory->ScbType.Index.NormalizedName.Buffer = NtfsAllocatePool( PagedPool, 8 * sizeof( WCHAR ) );
  4881. Vcb->ExtendDirectory->ScbType.Index.NormalizedName.MaximumLength =
  4882. Vcb->ExtendDirectory->ScbType.Index.NormalizedName.Length = 8 * sizeof( WCHAR );
  4883. wcsncpy( Vcb->ExtendDirectory->ScbType.Index.NormalizedName.Buffer, L"\\$Extend", 8 );
  4884. Vcb->ExtendDirectory->ScbType.Index.HashValue = 0;
  4885. NtfsConvertNameToHash( Vcb->ExtendDirectory->ScbType.Index.NormalizedName.Buffer,
  4886. sizeof( WCHAR ),
  4887. Vcb->UpcaseTable,
  4888. &Vcb->ExtendDirectory->ScbType.Index.HashValue );
  4889. } finally {
  4890. NtfsCleanupAttributeContext( IrpContext, &Context );
  4891. NtfsUnpinBcb( IrpContext, &FileRecordBcb );
  4892. NtfsUnpinBcb( IrpContext, &IndexEntryBcb );
  4893. //
  4894. // If some error caused us to not get the Scb created, then delete
  4895. // the Fcb, because we are the only ones who will.
  4896. //
  4897. if (Vcb->ExtendDirectory == NULL) {
  4898. BOOLEAN AcquiredFcbTable = TRUE;
  4899. NtfsAcquireFcbTable( IrpContext, Vcb );
  4900. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4901. ASSERT(!AcquiredFcbTable);
  4902. }
  4903. }
  4904. }
  4905. //
  4906. // Local support routine
  4907. //
  4908. VOID
  4909. NtfsInitializeQuotaFile (
  4910. IN PIRP_CONTEXT IrpContext,
  4911. IN PVCB Vcb
  4912. )
  4913. /*++
  4914. Routine Description:
  4915. This routine creates/opens the quota file, and initializes the quota support.
  4916. Arguments:
  4917. Vcb - Pointer to the Vcb for the volume
  4918. Return Value:
  4919. None.
  4920. --*/
  4921. {
  4922. PFCB Fcb;
  4923. //
  4924. // Create/open the quota file in $Extend
  4925. //
  4926. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsQuotaName, TRUE, TRUE );
  4927. try {
  4928. //
  4929. // Initialize the Quota subsystem.
  4930. //
  4931. NtfsInitializeQuotaIndex( IrpContext, Fcb, Vcb );
  4932. } finally {
  4933. //
  4934. // If some error caused him to not get any Scbs created, then delete
  4935. // the Fcb, because we are the only ones who will.
  4936. //
  4937. if (IsListEmpty(&Fcb->ScbQueue)) {
  4938. BOOLEAN AcquiredFcbTable = TRUE;
  4939. NtfsAcquireFcbTable( IrpContext, Vcb );
  4940. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4941. ASSERT(!AcquiredFcbTable);
  4942. }
  4943. }
  4944. }
  4945. //
  4946. // Local support routine
  4947. //
  4948. VOID
  4949. NtfsInitializeObjectIdFile (
  4950. IN PIRP_CONTEXT IrpContext,
  4951. IN PVCB Vcb
  4952. )
  4953. /*++
  4954. Routine Description:
  4955. This routine creates/opens the object Id table, and initializes Object Ids.
  4956. Arguments:
  4957. Vcb - Pointer to the Vcb for the volume
  4958. Return Value:
  4959. None.
  4960. --*/
  4961. {
  4962. PFCB Fcb;
  4963. //
  4964. // Create/open the quota file in $Extend
  4965. //
  4966. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsObjectIdName, TRUE, TRUE );
  4967. try {
  4968. //
  4969. // Initialize the Object Id subsystem.
  4970. //
  4971. NtfsInitializeObjectIdIndex( IrpContext, Fcb, Vcb );
  4972. } finally {
  4973. //
  4974. // If some error caused him to not get any Scbs created, then delete
  4975. // the Fcb, because we are the only ones who will.
  4976. //
  4977. if (IsListEmpty(&Fcb->ScbQueue)) {
  4978. BOOLEAN AcquiredFcbTable = TRUE;
  4979. NtfsAcquireFcbTable( IrpContext, Vcb );
  4980. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  4981. ASSERT(!AcquiredFcbTable);
  4982. }
  4983. }
  4984. }
  4985. //
  4986. // Local support routine
  4987. //
  4988. VOID
  4989. NtfsInitializeReparseFile (
  4990. IN PIRP_CONTEXT IrpContext,
  4991. IN PVCB Vcb
  4992. )
  4993. /*++
  4994. Routine Description:
  4995. This routine creates/opens the mount file table, creating it if it does not exist.
  4996. Arguments:
  4997. Vcb - Pointer to the Vcb for the volume
  4998. Return Value:
  4999. None.
  5000. --*/
  5001. {
  5002. PFCB Fcb;
  5003. //
  5004. // Create/open the quota file in $Extend
  5005. //
  5006. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsMountTableName, TRUE, TRUE );
  5007. try {
  5008. //
  5009. // Initialize the Object Id subsystem.
  5010. //
  5011. NtfsInitializeReparsePointIndex( IrpContext, Fcb, Vcb );
  5012. } finally {
  5013. //
  5014. // If some error caused her to not get any Scbs created, then delete
  5015. // the Fcb, because we are the only ones who will.
  5016. //
  5017. if (IsListEmpty(&Fcb->ScbQueue)) {
  5018. BOOLEAN AcquiredFcbTable = TRUE;
  5019. NtfsAcquireFcbTable( IrpContext, Vcb );
  5020. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  5021. ASSERT(!AcquiredFcbTable);
  5022. }
  5023. }
  5024. }
  5025. //
  5026. // Local support routine
  5027. //
  5028. VOID
  5029. NtfsInitializeUsnJournal (
  5030. IN PIRP_CONTEXT IrpContext,
  5031. IN PVCB Vcb,
  5032. IN ULONG CreateIfNotExist,
  5033. IN ULONG Restamp,
  5034. IN PCREATE_USN_JOURNAL_DATA JournalData
  5035. )
  5036. /*++
  5037. Routine Description:
  5038. This routine creates/opens the Usn journal, and initializes it.
  5039. Arguments:
  5040. Vcb - Pointer to the Vcb for the volume
  5041. CreateIfNotExist - Supplies TRUE if file should be created if it does not
  5042. already exist, or FALSE if file should not be created.
  5043. Restamp - Indicates if we want to restamp the journal.
  5044. JournalData - This is the allocation and delta to use for the journal, unless
  5045. we read it from disk.
  5046. Return Value:
  5047. None.
  5048. --*/
  5049. {
  5050. FILE_REFERENCE PriorFileReference;
  5051. PFCB Fcb = NULL;
  5052. BOOLEAN ReleaseExtend = FALSE;
  5053. PriorFileReference = Vcb->UsnJournalReference;
  5054. try {
  5055. //
  5056. // Acquire Mft now to preserve locking order
  5057. //
  5058. NtfsAcquireExclusiveScb( IrpContext, Vcb->MftScb );
  5059. //
  5060. // Create/open the USN file in $Extend
  5061. //
  5062. if ( Vcb->UsnJournal) {
  5063. Fcb = Vcb->UsnJournal->Fcb;
  5064. //
  5065. // Acquire in canonical order
  5066. //
  5067. NtfsAcquireExclusiveScb( IrpContext, Vcb->UsnJournal );
  5068. } else {
  5069. NtfsAcquireExclusiveScb( IrpContext, Vcb->ExtendDirectory );
  5070. ReleaseExtend = TRUE;
  5071. Fcb = NtfsInitializeFileInExtendDirectory( IrpContext, Vcb, &NtfsUsnJrnlName, FALSE, CreateIfNotExist );
  5072. #ifdef NTFSDBG
  5073. //
  5074. // Compensate for misclassification of usnjournal during real create
  5075. //
  5076. if (IrpContext->OwnershipState == NtfsOwns_ExVcb_Mft_Extend_File) {
  5077. IrpContext->OwnershipState = NtfsOwns_ExVcb_Mft_Extend_Journal;
  5078. }
  5079. #endif
  5080. }
  5081. //
  5082. // We are done if it is not there.
  5083. //
  5084. if (Fcb != NULL) {
  5085. Vcb->UsnJournalReference = Fcb->FileReference;
  5086. //
  5087. // If we only want to open an existing journal then this is mount. Make sure
  5088. // to note that there is a journal on the disk. We can't depend on the next
  5089. // call to succeed in that case.
  5090. //
  5091. if (!CreateIfNotExist) {
  5092. ASSERT( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  5093. (IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) );
  5094. SetFlag( Vcb->VcbState, VCB_STATE_USN_JOURNAL_PRESENT );
  5095. }
  5096. //
  5097. // Open or create the the Usn Journal.
  5098. //
  5099. NtfsSetupUsnJournal( IrpContext, Vcb, Fcb, CreateIfNotExist, Restamp, JournalData );
  5100. }
  5101. } finally {
  5102. if (ReleaseExtend) {
  5103. NtfsReleaseScb( IrpContext, Vcb->ExtendDirectory );
  5104. }
  5105. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  5106. if (AbnormalTermination()) {
  5107. Vcb->UsnJournalReference = PriorFileReference;
  5108. }
  5109. }
  5110. }
  5111. //
  5112. // Local Support Routine
  5113. //
  5114. NTSTATUS
  5115. NtfsQueryRetrievalPointers (
  5116. IN PIRP_CONTEXT IrpContext,
  5117. IN PIRP Irp
  5118. )
  5119. /*++
  5120. Routine Description:
  5121. This routine performs the query retrieval pointers operation.
  5122. It returns the retrieval pointers for the specified input
  5123. file from the start of the file to the request map size specified
  5124. in the input buffer.
  5125. Arguments:
  5126. Irp - Supplies the Irp to process
  5127. Return Value:
  5128. NTSTATUS - The return status for the operation
  5129. --*/
  5130. {
  5131. NTSTATUS Status;
  5132. PIO_STACK_LOCATION IrpSp;
  5133. PVCB Vcb;
  5134. PFCB Fcb;
  5135. PSCB Scb;
  5136. PCCB Ccb;
  5137. PLONGLONG RequestedMapSize;
  5138. PLONGLONG *MappingPairs;
  5139. PVOID RangePtr;
  5140. ULONG Index;
  5141. ULONG i;
  5142. LONGLONG SectorCount;
  5143. LONGLONG Lbo;
  5144. LONGLONG Vbo;
  5145. LONGLONG Vcn;
  5146. LONGLONG MapSize;
  5147. //
  5148. // Always make this synchronous.
  5149. //
  5150. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  5151. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  5152. //
  5153. // Only Kernel mode clients may query retrieval pointer information about
  5154. // a file, and then only the paging file. Ensure that this is the case
  5155. // for this caller.
  5156. //
  5157. if (Irp->RequestorMode != KernelMode) {
  5158. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5159. return STATUS_INVALID_PARAMETER;
  5160. }
  5161. //
  5162. // Get the current stack location and extract the input and output
  5163. // buffer information. The input contains the requested size of
  5164. // the mappings in terms of VBO. The output parameter will receive
  5165. // a pointer to nonpaged pool where the mapping pairs are stored.
  5166. //
  5167. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  5168. ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof(LARGE_INTEGER) );
  5169. ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength == sizeof(PVOID) );
  5170. RequestedMapSize = (PLONGLONG)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  5171. MappingPairs = (PLONGLONG *)Irp->UserBuffer;
  5172. //
  5173. // Decode the file object and assert that it is the paging file
  5174. //
  5175. //
  5176. (VOID)NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  5177. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  5178. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5179. return STATUS_INVALID_PARAMETER;
  5180. }
  5181. //
  5182. // Acquire exclusive access to the Scb
  5183. //
  5184. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5185. try {
  5186. //
  5187. // Check if the mapping the caller requested is too large
  5188. //
  5189. if (*RequestedMapSize > Scb->Header.FileSize.QuadPart) {
  5190. try_return( Status = STATUS_INVALID_PARAMETER );
  5191. }
  5192. //
  5193. // Now get the index for the mcb entry that will contain the
  5194. // callers request and allocate enough pool to hold the
  5195. // output mapping pairs.
  5196. //
  5197. //
  5198. // Compute the Vcn which contains the byte just before the offset size
  5199. // passed in.
  5200. //
  5201. MapSize = *RequestedMapSize - 1;
  5202. if (*RequestedMapSize == 0) {
  5203. Index = 0;
  5204. } else {
  5205. Vcn = Int64ShraMod32( MapSize, Vcb->ClusterShift );
  5206. (VOID)NtfsLookupNtfsMcbEntry( &Scb->Mcb, Vcn, NULL, NULL, NULL, NULL, &RangePtr, &Index );
  5207. }
  5208. *MappingPairs = NtfsAllocatePool( NonPagedPool, (Index + 2) * (2 * sizeof(LARGE_INTEGER)) );
  5209. //
  5210. // Now copy over the mapping pairs from the mcb
  5211. // to the output buffer. We store in [sector count, lbo]
  5212. // mapping pairs and end with a zero sector count.
  5213. //
  5214. MapSize = *RequestedMapSize;
  5215. i = 0;
  5216. if (MapSize != 0) {
  5217. for (; i <= Index; i += 1) {
  5218. (VOID)NtfsGetNextNtfsMcbEntry( &Scb->Mcb, &RangePtr, i, &Vbo, &Lbo, &SectorCount );
  5219. SectorCount = LlBytesFromClusters( Vcb, SectorCount );
  5220. if (SectorCount > MapSize) {
  5221. SectorCount = MapSize;
  5222. }
  5223. (*MappingPairs)[ i*2 + 0 ] = SectorCount;
  5224. (*MappingPairs)[ i*2 + 1 ] = LlBytesFromClusters( Vcb, Lbo );
  5225. MapSize = MapSize - SectorCount;
  5226. }
  5227. }
  5228. (*MappingPairs)[ i*2 + 0 ] = 0;
  5229. Status = STATUS_SUCCESS;
  5230. try_exit: NOTHING;
  5231. } finally {
  5232. DebugUnwind( NtfsQueryRetrievalPointers );
  5233. //
  5234. // Release all of our resources
  5235. //
  5236. NtfsReleaseScb( IrpContext, Scb );
  5237. //
  5238. // If this is an abnormal termination then undo our work, otherwise
  5239. // complete the irp
  5240. //
  5241. if (!AbnormalTermination()) {
  5242. NtfsCompleteRequest( IrpContext, Irp, Status );
  5243. }
  5244. }
  5245. return Status;
  5246. }
  5247. //
  5248. // Local Support Routine
  5249. //
  5250. NTSTATUS
  5251. NtfsGetCompression (
  5252. IN PIRP_CONTEXT IrpContext,
  5253. IN PIRP Irp
  5254. )
  5255. /*++
  5256. Routine Description:
  5257. This routine returns the compression state of the opened file/directory
  5258. Arguments:
  5259. Irp - Supplies the Irp to process
  5260. Return Value:
  5261. NTSTATUS - The return status for the operation
  5262. --*/
  5263. {
  5264. PIO_STACK_LOCATION IrpSp;
  5265. TYPE_OF_OPEN TypeOfOpen;
  5266. PVCB Vcb;
  5267. PFCB Fcb;
  5268. PSCB Scb;
  5269. PCCB Ccb;
  5270. PUSHORT CompressionState;
  5271. PAGED_CODE();
  5272. //
  5273. // Get the current stack location and extract the output
  5274. // buffer information. The output parameter will receive
  5275. // the compressed state of the file/directory.
  5276. //
  5277. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  5278. //
  5279. // Get a pointer to the output buffer. Look at the system buffer field in th
  5280. // irp first. Then the Irp Mdl.
  5281. //
  5282. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  5283. CompressionState = Irp->AssociatedIrp.SystemBuffer;
  5284. } else if (Irp->MdlAddress != NULL) {
  5285. CompressionState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  5286. if (CompressionState == NULL) {
  5287. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  5288. return STATUS_INSUFFICIENT_RESOURCES;
  5289. }
  5290. } else {
  5291. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  5292. return STATUS_INVALID_USER_BUFFER;
  5293. }
  5294. //
  5295. // Make sure the output buffer is large enough and then initialize
  5296. // the answer to be that the file isn't compressed
  5297. //
  5298. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(USHORT)) {
  5299. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5300. return STATUS_INVALID_PARAMETER;
  5301. }
  5302. *CompressionState = 0;
  5303. //
  5304. // Decode the file object
  5305. //
  5306. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  5307. if ((TypeOfOpen != UserFileOpen) &&
  5308. (TypeOfOpen != UserDirectoryOpen)) {
  5309. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5310. return STATUS_INVALID_PARAMETER;
  5311. }
  5312. //
  5313. // Acquire shared access to the Scb
  5314. //
  5315. NtfsAcquireSharedScb( IrpContext, Scb );
  5316. //
  5317. // If this is the index allocation Scb and it has not been initialized then
  5318. // lookup the index root and perform the initialization.
  5319. //
  5320. if ((Scb->AttributeTypeCode == $INDEX_ALLOCATION) &&
  5321. (Scb->ScbType.Index.BytesPerIndexBuffer == 0)) {
  5322. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  5323. NtfsInitializeAttributeContext( &Context );
  5324. //
  5325. // Use a try-finally to perform cleanup.
  5326. //
  5327. try {
  5328. if (!NtfsLookupAttributeByName( IrpContext,
  5329. Scb->Fcb,
  5330. &Scb->Fcb->FileReference,
  5331. $INDEX_ROOT,
  5332. &Scb->AttributeName,
  5333. NULL,
  5334. FALSE,
  5335. &Context )) {
  5336. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  5337. }
  5338. NtfsUpdateIndexScbFromAttribute( IrpContext,
  5339. Scb,
  5340. NtfsFoundAttribute( &Context ),
  5341. FALSE );
  5342. } finally {
  5343. NtfsCleanupAttributeContext( IrpContext, &Context );
  5344. if (AbnormalTermination()) { NtfsReleaseScb( IrpContext, Scb ); }
  5345. }
  5346. }
  5347. //
  5348. // Return the compression state and the size of the returned data.
  5349. //
  5350. *CompressionState = (USHORT)(Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK);
  5351. if (*CompressionState != 0) {
  5352. *CompressionState += 1;
  5353. }
  5354. Irp->IoStatus.Information = sizeof( USHORT );
  5355. //
  5356. // Release all of our resources
  5357. //
  5358. NtfsReleaseScb( IrpContext, Scb );
  5359. //
  5360. // If this is an abnormal termination then undo our work, otherwise
  5361. // complete the irp
  5362. //
  5363. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  5364. return STATUS_SUCCESS;
  5365. }
  5366. //
  5367. // Local Support Routine
  5368. //
  5369. VOID
  5370. NtfsChangeAttributeCompression (
  5371. IN PIRP_CONTEXT IrpContext,
  5372. IN PSCB Scb,
  5373. IN PVCB Vcb,
  5374. IN PCCB Ccb,
  5375. IN USHORT CompressionState
  5376. )
  5377. /*++
  5378. Routine Description:
  5379. This routine changes the compression state of an attribute on disk,
  5380. from not compressed to compressed, or visa versa.
  5381. To turn compression off, the caller must already have the Scb acquired
  5382. exclusive, and guarantee that the entire file is not compressed.
  5383. Arguments:
  5384. Scb - Scb for affected stream
  5385. Vcb - Vcb for volume
  5386. Ccb - Ccb for the open handle
  5387. CompressionState - 0 for no compression or nonzero for Rtl compression code - 1
  5388. Return Value:
  5389. None.
  5390. --*/
  5391. {
  5392. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  5393. ATTRIBUTE_RECORD_HEADER NewAttribute;
  5394. PATTRIBUTE_RECORD_HEADER Attribute;
  5395. ULONG AttributeSizeChange;
  5396. ULONG OriginalFileAttributes;
  5397. UCHAR OriginalCompressionUnitShift;
  5398. ULONG OriginalCompressionUnit;
  5399. PFCB Fcb = Scb->Fcb;
  5400. ULONG NewCompressionUnit;
  5401. UCHAR NewCompressionUnitShift;
  5402. PAGED_CODE( );
  5403. //
  5404. // Prepare to lookup and change attribute.
  5405. //
  5406. NtfsInitializeAttributeContext( &AttrContext );
  5407. ASSERT( (Scb->Header.PagingIoResource == NULL) ||
  5408. (IrpContext->CleanupStructure == Fcb) ||
  5409. (IrpContext->CleanupStructure == Scb) );
  5410. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5411. OriginalFileAttributes = Fcb->Info.FileAttributes;
  5412. OriginalCompressionUnitShift = Scb->CompressionUnitShift;
  5413. OriginalCompressionUnit = Scb->CompressionUnit;
  5414. //
  5415. // Capture the ccb source information.
  5416. //
  5417. if (Ccb != NULL) {
  5418. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  5419. }
  5420. try {
  5421. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  5422. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  5423. }
  5424. //
  5425. // Post the change to the Usn Journal (on errors change is backed out)
  5426. //
  5427. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_COMPRESSION_CHANGE );
  5428. //
  5429. // Lookup the attribute and pin it so that we can modify it.
  5430. //
  5431. if ((Scb->Header.NodeTypeCode == NTFS_NTC_SCB_INDEX) ||
  5432. (Scb->Header.NodeTypeCode == NTFS_NTC_SCB_ROOT_INDEX)) {
  5433. //
  5434. // Lookup the attribute record from the Scb.
  5435. //
  5436. if (!NtfsLookupAttributeByName( IrpContext,
  5437. Fcb,
  5438. &Fcb->FileReference,
  5439. $INDEX_ROOT,
  5440. &Scb->AttributeName,
  5441. NULL,
  5442. FALSE,
  5443. &AttrContext )) {
  5444. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, NULL );
  5445. }
  5446. } else {
  5447. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &AttrContext );
  5448. }
  5449. NtfsPinMappedAttribute( IrpContext, Vcb, &AttrContext );
  5450. Attribute = NtfsFoundAttribute( &AttrContext );
  5451. if ((CompressionState != 0) &&
  5452. !NtfsIsAttributeResident(Attribute) &&
  5453. !FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5454. LONGLONG Temp;
  5455. ULONG CompressionUnitInClusters;
  5456. //
  5457. // If we are turning compression on, then we need to fill out the
  5458. // allocation of the compression unit containing file size, or else
  5459. // it will be interpreted as compressed when we fault it in. This
  5460. // is peanuts compared to the dual copies of clusters we keep around
  5461. // in the loop below when we rewrite the file. We don't do this
  5462. // work if the file is sparse because the allocation has already
  5463. // been rounded up.
  5464. //
  5465. CompressionUnitInClusters =
  5466. ClustersFromBytes( Vcb, Vcb->BytesPerCluster << NTFS_CLUSTERS_PER_COMPRESSION );
  5467. Temp = LlClustersFromBytes(Vcb, Scb->Header.AllocationSize.QuadPart);
  5468. //
  5469. // If FileSize is not already at a cluster boundary, then add
  5470. // allocation.
  5471. //
  5472. if ((ULONG)Temp & (CompressionUnitInClusters - 1)) {
  5473. NtfsAddAllocation( IrpContext,
  5474. NULL,
  5475. Scb,
  5476. Temp,
  5477. CompressionUnitInClusters - ((ULONG)Temp & (CompressionUnitInClusters - 1)),
  5478. FALSE,
  5479. NULL );
  5480. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  5481. Scb->Fcb->Info.AllocatedLength = Scb->TotalAllocated;
  5482. SetFlag( Scb->Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
  5483. }
  5484. NtfsWriteFileSizes( IrpContext,
  5485. Scb,
  5486. &Scb->Header.ValidDataLength.QuadPart,
  5487. FALSE,
  5488. TRUE,
  5489. TRUE );
  5490. //
  5491. // The attribute may have moved. We will cleanup the attribute
  5492. // context and look it up again.
  5493. //
  5494. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  5495. NtfsInitializeAttributeContext( &AttrContext );
  5496. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &AttrContext );
  5497. NtfsPinMappedAttribute( IrpContext, Vcb, &AttrContext );
  5498. Attribute = NtfsFoundAttribute( &AttrContext );
  5499. }
  5500. }
  5501. //
  5502. // Remember the current compression values.
  5503. //
  5504. NewCompressionUnit = Scb->CompressionUnit;
  5505. NewCompressionUnitShift = Scb->CompressionUnitShift;
  5506. //
  5507. // If the attribute is resident, copy it here and remember its
  5508. // header size.
  5509. //
  5510. if (NtfsIsAttributeResident(Attribute)) {
  5511. RtlCopyMemory( &NewAttribute, Attribute, SIZEOF_RESIDENT_ATTRIBUTE_HEADER );
  5512. AttributeSizeChange = SIZEOF_RESIDENT_ATTRIBUTE_HEADER;
  5513. //
  5514. // Set the correct compression unit but only for data streams. We
  5515. // don't want to change this value for the Index Root.
  5516. //
  5517. if (NtfsIsTypeCodeCompressible( Attribute->TypeCode ) &&
  5518. !FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5519. if (CompressionState != 0) {
  5520. NewCompressionUnit = BytesFromClusters( Scb->Vcb, 1 << NTFS_CLUSTERS_PER_COMPRESSION );
  5521. NewCompressionUnitShift = NTFS_CLUSTERS_PER_COMPRESSION;
  5522. } else {
  5523. NewCompressionUnit = 0;
  5524. NewCompressionUnitShift = 0;
  5525. }
  5526. }
  5527. //
  5528. // Else if it is nonresident, copy it here, set the compression parameter,
  5529. // and remember its size.
  5530. //
  5531. } else {
  5532. AttributeSizeChange = Attribute->Form.Nonresident.MappingPairsOffset;
  5533. if (Attribute->NameOffset != 0) {
  5534. AttributeSizeChange = Attribute->NameOffset;
  5535. }
  5536. RtlCopyMemory( &NewAttribute, Attribute, AttributeSizeChange );
  5537. //
  5538. // The compression numbers are already correct if the file is compressed.
  5539. //
  5540. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5541. if (CompressionState != 0) {
  5542. NewAttribute.Form.Nonresident.CompressionUnit = NTFS_CLUSTERS_PER_COMPRESSION;
  5543. NewCompressionUnit = Vcb->BytesPerCluster << NTFS_CLUSTERS_PER_COMPRESSION;
  5544. NewCompressionUnitShift = NTFS_CLUSTERS_PER_COMPRESSION;
  5545. } else {
  5546. NewAttribute.Form.Nonresident.CompressionUnit = 0;
  5547. NewCompressionUnit = 0;
  5548. NewCompressionUnitShift = 0;
  5549. }
  5550. }
  5551. ASSERT((NewCompressionUnit == 0) ||
  5552. (Scb->AttributeTypeCode == $INDEX_ALLOCATION) ||
  5553. NtfsIsTypeCodeCompressible( Scb->AttributeTypeCode ));
  5554. }
  5555. //
  5556. // Turn compression on/off.
  5557. //
  5558. NewAttribute.Flags = Scb->AttributeFlags & ~ATTRIBUTE_FLAG_COMPRESSION_MASK;
  5559. SetFlag( NewAttribute.Flags, CompressionState );
  5560. //
  5561. // Now, log the changed attribute.
  5562. //
  5563. (VOID)NtfsWriteLog( IrpContext,
  5564. Vcb->MftScb,
  5565. NtfsFoundBcb(&AttrContext),
  5566. UpdateResidentValue,
  5567. &NewAttribute,
  5568. AttributeSizeChange,
  5569. UpdateResidentValue,
  5570. Attribute,
  5571. AttributeSizeChange,
  5572. NtfsMftOffset( &AttrContext ),
  5573. PtrOffset(NtfsContainingFileRecord(&AttrContext), Attribute),
  5574. 0,
  5575. Vcb->BytesPerFileRecordSegment );
  5576. //
  5577. // Change the attribute by calling the same routine called at restart.
  5578. //
  5579. NtfsRestartChangeValue( IrpContext,
  5580. NtfsContainingFileRecord(&AttrContext),
  5581. PtrOffset(NtfsContainingFileRecord(&AttrContext), Attribute),
  5582. 0,
  5583. &NewAttribute,
  5584. AttributeSizeChange,
  5585. FALSE );
  5586. //
  5587. // If this is the main stream for a file we want to change the file attribute
  5588. // for this stream in both the standard information and duplicate
  5589. // information structure.
  5590. //
  5591. if (FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
  5592. if (CompressionState != 0) {
  5593. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_COMPRESSED );
  5594. } else {
  5595. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_COMPRESSED );
  5596. }
  5597. ASSERTMSG( "conflict with flush",
  5598. ExIsResourceAcquiredSharedLite( Fcb->Resource ) ||
  5599. (Fcb->PagingIoResource != NULL &&
  5600. ExIsResourceAcquiredSharedLite( Fcb->PagingIoResource )));
  5601. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  5602. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5603. }
  5604. //
  5605. // Now lets add or remove the total allocated field in the attribute
  5606. // header. Add if going to uncompressed, non-sparse. Remove if going
  5607. // to compressed and non-sparse.
  5608. //
  5609. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  5610. NtfsSetTotalAllocatedField( IrpContext, Scb, CompressionState );
  5611. }
  5612. //
  5613. // At this point we will change the compression unit in the Scb.
  5614. //
  5615. Scb->CompressionUnit = NewCompressionUnit;
  5616. Scb->CompressionUnitShift = NewCompressionUnitShift;
  5617. if (FlagOn( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  5618. NtfsUpdateStandardInformation( IrpContext, Fcb );
  5619. ClearFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5620. }
  5621. //
  5622. // Checkpoint the transaction now to secure this change.
  5623. //
  5624. NtfsCheckpointCurrentTransaction( IrpContext );
  5625. //
  5626. // Update the FastIoField.
  5627. //
  5628. NtfsAcquireFsrtlHeader( Scb );
  5629. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  5630. NtfsReleaseFsrtlHeader( Scb );
  5631. //
  5632. // Cleanup on the way out.
  5633. //
  5634. } finally {
  5635. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  5636. //
  5637. // If this requests aborts then we want to back out any changes to the
  5638. // in-memory structures.
  5639. //
  5640. if (AbnormalTermination()) {
  5641. Fcb->Info.FileAttributes = OriginalFileAttributes;
  5642. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5643. Scb->CompressionUnitShift = OriginalCompressionUnitShift;
  5644. Scb->CompressionUnit = OriginalCompressionUnit;
  5645. }
  5646. //
  5647. // This routine is self contained - it commits a transaction and we don't
  5648. // want to leave with anything extra acquired
  5649. //
  5650. NtfsReleaseScb( IrpContext, Scb );
  5651. }
  5652. }
  5653. //
  5654. // Local Support Routine
  5655. //
  5656. NTSTATUS
  5657. NtfsSetCompression (
  5658. IN PIRP_CONTEXT IrpContext,
  5659. IN PIRP Irp
  5660. )
  5661. /*++
  5662. Routine Description:
  5663. This routine compresses or decompresses an entire stream in place,
  5664. by walking through the stream and forcing it to be written with the
  5665. new compression parameters. As it writes the stream it sets a flag
  5666. in the Scb to tell NtfsCommonWrite to delete all allocation at the
  5667. outset, to force the space to be reallocated.
  5668. Arguments:
  5669. Irp - Irp describing the compress or decompress change.
  5670. Return Value:
  5671. NSTATUS - Status of the request.
  5672. --*/
  5673. {
  5674. PIO_STACK_LOCATION IrpSp;
  5675. PIO_STACK_LOCATION NextIrpSp;
  5676. TYPE_OF_OPEN TypeOfOpen;
  5677. PVCB Vcb;
  5678. PFCB Fcb;
  5679. PSCB Scb;
  5680. PCCB Ccb;
  5681. PUSHORT CompressionStatePtr;
  5682. PFILE_OBJECT FileObject;
  5683. LONGLONG FileOffset;
  5684. LONGLONG ByteCount;
  5685. USHORT CompressionState = 0;
  5686. BOOLEAN PagingIoAcquired = FALSE;
  5687. BOOLEAN FsRtlHeaderLocked = FALSE;
  5688. ULONG ScbRestoreState = SCB_STATE_WRITE_COMPRESSED;
  5689. IO_STATUS_BLOCK Iosb;
  5690. PMDL ReadMdl;
  5691. PMDL WriteMdl;
  5692. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  5693. PAGED_CODE( );
  5694. //
  5695. // Get the current stack location and extract the output
  5696. // buffer information. The output parameter will receive
  5697. // the compressed state of the file/directory.
  5698. //
  5699. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  5700. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  5701. FileObject = IrpSp->FileObject;
  5702. CompressionStatePtr = Irp->AssociatedIrp.SystemBuffer;
  5703. //
  5704. // Make sure the input buffer is big enough
  5705. //
  5706. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(USHORT)) {
  5707. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5708. return STATUS_INVALID_PARAMETER;
  5709. }
  5710. //
  5711. // Decode the file object. We don't care to raise on dismounts here
  5712. // because we check for that further down anyway. So send FALSE.
  5713. //
  5714. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  5715. if (((TypeOfOpen != UserFileOpen) &&
  5716. (TypeOfOpen != UserDirectoryOpen)) ||
  5717. FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  5718. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5719. return STATUS_INVALID_PARAMETER;
  5720. }
  5721. //
  5722. // See if we are compressing, and only accept the default case or
  5723. // lznt1.
  5724. //
  5725. if (*CompressionStatePtr != 0) {
  5726. if ((*CompressionStatePtr == COMPRESSION_FORMAT_DEFAULT) ||
  5727. (*CompressionStatePtr == COMPRESSION_FORMAT_LZNT1)) {
  5728. CompressionState = COMPRESSION_FORMAT_LZNT1 - 1;
  5729. //
  5730. // Check that we can compress on this volume.
  5731. //
  5732. if (!FlagOn( Vcb->AttributeFlagsMask, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  5733. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  5734. return STATUS_INVALID_DEVICE_REQUEST;
  5735. }
  5736. } else {
  5737. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  5738. return STATUS_INVALID_PARAMETER;
  5739. }
  5740. }
  5741. //
  5742. // Readonly mount should be just that: read only.
  5743. //
  5744. if (NtfsIsVolumeReadOnly( Vcb )) {
  5745. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  5746. return STATUS_MEDIA_WRITE_PROTECTED;
  5747. }
  5748. try {
  5749. //
  5750. // We now want to acquire the Scb to check if we can continue.
  5751. //
  5752. if (Scb->Header.PagingIoResource != NULL) {
  5753. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  5754. PagingIoAcquired = TRUE;
  5755. }
  5756. NtfsAcquireExclusiveScb( IrpContext, Scb );
  5757. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  5758. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  5759. }
  5760. //
  5761. // compression not allowed on encrypted streams - this mirrors
  5762. // the error code efs gives for this kind of attempt - initially we
  5763. // precall efs to weed these out but that still leaves a race that this
  5764. // plugs
  5765. //
  5766. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  5767. try_return( Status = STATUS_INVALID_DEVICE_REQUEST );
  5768. }
  5769. //
  5770. // Handle the simple directory case here.
  5771. //
  5772. if ((Scb->Header.NodeTypeCode == NTFS_NTC_SCB_INDEX) ||
  5773. (Scb->Header.NodeTypeCode == NTFS_NTC_SCB_ROOT_INDEX)) {
  5774. NtfsChangeAttributeCompression( IrpContext, Scb, Vcb, Ccb, CompressionState );
  5775. ClearFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  5776. SetFlag( Scb->AttributeFlags, CompressionState );
  5777. try_return( Status = STATUS_SUCCESS );
  5778. }
  5779. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  5780. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  5781. }
  5782. //
  5783. // Set the WRITE_ACCESS_SEEN flag so that we will enforce the
  5784. // reservation strategy.
  5785. //
  5786. if (!FlagOn( Scb->ScbState, SCB_STATE_WRITE_ACCESS_SEEN )) {
  5787. LONGLONG ClusterCount;
  5788. NtfsAcquireReservedClusters( Vcb );
  5789. //
  5790. // Does this Scb have reserved space that causes us to exceed the free
  5791. // space on the volume?
  5792. //
  5793. ClusterCount = LlClustersFromBytesTruncate( Vcb, Scb->ScbType.Data.TotalReserved );
  5794. if ((Scb->ScbType.Data.TotalReserved != 0) &&
  5795. ((ClusterCount + Vcb->TotalReserved) > Vcb->FreeClusters)) {
  5796. NtfsReleaseReservedClusters( Vcb );
  5797. try_return( Status = STATUS_DISK_FULL );
  5798. }
  5799. //
  5800. // Otherwise tally in the reserved space now for this Scb, and
  5801. // remember that we have seen write access.
  5802. //
  5803. Vcb->TotalReserved += ClusterCount;
  5804. SetFlag( Scb->ScbState, SCB_STATE_WRITE_ACCESS_SEEN );
  5805. NtfsReleaseReservedClusters( Vcb );
  5806. }
  5807. //
  5808. // If this is the first pass through SetCompression we need to set this
  5809. // request up as the top-level change compression operation. This means
  5810. // setting the REALLOCATE_ON_WRITE flag, changing the attribute state
  5811. // and putting the SCB_STATE_WRITE_COMPRESSED flag in the correct state.
  5812. //
  5813. if (NextIrpSp->Parameters.FileSystemControl.OutputBufferLength == MAXULONG) {
  5814. //
  5815. // If the REALLOCATE_ON_WRITE flag is set it means that someone is
  5816. // already changing the compression state. Return STATUS_SUCCESS in
  5817. // that case.
  5818. //
  5819. if (FlagOn( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE )) {
  5820. try_return( Status = STATUS_SUCCESS );
  5821. }
  5822. //
  5823. // If we are turning off compression and the file is uncompressed then
  5824. // we can just get out.
  5825. //
  5826. if ((CompressionState == 0) && ((Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) == 0)) {
  5827. try_return( Status = STATUS_SUCCESS );
  5828. }
  5829. //
  5830. // If we are compressing, change the compressed state now.
  5831. //
  5832. if (CompressionState != 0) {
  5833. //
  5834. // See if we have to create an internal attribute stream. Do this first even though
  5835. // we don't need it for the next operation. We want to find out if we can't
  5836. // create the stream object (maybe the file is so large mm can't cache it) before
  5837. // changing the compression state. Otherwise the user will never be able to
  5838. // access the file.
  5839. //
  5840. if (Scb->FileObject == NULL) {
  5841. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  5842. }
  5843. NtfsChangeAttributeCompression( IrpContext, Scb, Vcb, Ccb, CompressionState );
  5844. Scb->AttributeFlags = (USHORT)((Scb->AttributeFlags & ~ATTRIBUTE_FLAG_COMPRESSION_MASK) |
  5845. CompressionState);
  5846. SetFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  5847. //
  5848. // Otherwise, we must clear the compress flag in the Scb to
  5849. // start writing decompressed.
  5850. //
  5851. } else {
  5852. ClearFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  5853. }
  5854. //
  5855. // Set ourselves up as the top level request.
  5856. //
  5857. SetFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  5858. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
  5859. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = 0;
  5860. //
  5861. // If we are turning off compression and the file is uncompressed then
  5862. // we can just get out. Even if we raised while decompressing. If
  5863. // the state is now uncompressed then we have committed the change.
  5864. //
  5865. } else if (CompressionState == 0) {
  5866. ASSERT( !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ));
  5867. //
  5868. // If the flag is set then make sure to start back at offset zero in
  5869. // the file.
  5870. //
  5871. if (FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED )) {
  5872. ClearFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  5873. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
  5874. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = 0;
  5875. }
  5876. if ((Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) == 0) {
  5877. try_return( Status = STATUS_SUCCESS );
  5878. }
  5879. }
  5880. //
  5881. // In the Fsd entry we clear the following two parameter fields in the Irp,
  5882. // and then we update them to our current position on all abnormal terminations.
  5883. // That way if we get a log file full, we only have to resume where we left
  5884. // off.
  5885. //
  5886. ((PLARGE_INTEGER)&FileOffset)->LowPart = NextIrpSp->Parameters.FileSystemControl.OutputBufferLength;
  5887. ((PLARGE_INTEGER)&FileOffset)->HighPart = NextIrpSp->Parameters.FileSystemControl.InputBufferLength;
  5888. //
  5889. // Make sure to flush and purge the compressed stream if present.
  5890. //
  5891. #ifdef COMPRESS_ON_WIRE
  5892. if (Scb->Header.FileObjectC != NULL) {
  5893. PCOMPRESSION_SYNC CompressionSync = NULL;
  5894. //
  5895. // Use a try-finally to clean up the compression sync.
  5896. //
  5897. try {
  5898. Status = NtfsSynchronizeUncompressedIo( Scb,
  5899. NULL,
  5900. 0,
  5901. TRUE,
  5902. &CompressionSync );
  5903. } finally {
  5904. NtfsReleaseCompressionSync( CompressionSync );
  5905. }
  5906. NtfsNormalizeAndCleanupTransaction( IrpContext, &Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  5907. NtfsDeleteInternalAttributeStream( Scb, TRUE, TRUE );
  5908. ASSERT( Scb->Header.FileObjectC == NULL );
  5909. }
  5910. #endif
  5911. //
  5912. // If the stream is resident there is no need rewrite any of the data.
  5913. //
  5914. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  5915. //
  5916. // Release all of the files held by this Irp Context. The Mft
  5917. // may have been grabbed to make space for the TotalAllocated field.
  5918. // This will automatically also release the pageingio
  5919. //
  5920. ASSERT(IrpContext->TransactionId == 0);
  5921. NtfsReleaseAllResources( IrpContext );
  5922. PagingIoAcquired = FALSE;
  5923. while (TRUE) {
  5924. //
  5925. // We must throttle our writes.
  5926. //
  5927. CcCanIWrite( FileObject, 0x40000, TRUE, FALSE );
  5928. //
  5929. // Lock the FsRtl header so we can freeze FileSize.
  5930. // Acquire paging io exclusive if uncompressing so
  5931. // we can guarantee that all of the pages get written
  5932. // before we mark the file as uncompressed. Otherwise a
  5933. // a competing LazyWrite in a range may block after
  5934. // going through Mm and Mm will report to this routine
  5935. // that the flush has occurred.
  5936. //
  5937. if (CompressionState == 0) {
  5938. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  5939. } else {
  5940. ExAcquireResourceSharedLite( Scb->Header.PagingIoResource, TRUE );
  5941. }
  5942. FsRtlLockFsRtlHeader( &Scb->Header );
  5943. IrpContext->CleanupStructure = Scb;
  5944. FsRtlHeaderLocked = TRUE;
  5945. //
  5946. // Also check if the volume is mounted.
  5947. //
  5948. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  5949. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  5950. }
  5951. //
  5952. // Jump out right here if the attribute is resident.
  5953. //
  5954. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  5955. break;
  5956. }
  5957. //
  5958. // Let's round the file offset down to a sparse unit boundary to
  5959. // clean up the sparse file support.
  5960. //
  5961. if (Scb->CompressionUnit != 0) {
  5962. ((PLARGE_INTEGER)&FileOffset)->LowPart &= ~(Vcb->SparseFileUnit - 1);
  5963. }
  5964. //
  5965. // See if we have to create an internal attribute stream. We do
  5966. // it in the loop, because the Scb must be acquired.
  5967. //
  5968. if (Scb->FileObject == NULL) {
  5969. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  5970. }
  5971. //
  5972. // Loop through the current view looking for deallocated ranges.
  5973. //
  5974. do {
  5975. //
  5976. // Calculate the bytes left in the file to write.
  5977. //
  5978. ByteCount = Scb->Header.FileSize.QuadPart - FileOffset;
  5979. //
  5980. // This is how we exit, seeing that we have finally rewritten
  5981. // everything. It is possible that the file was truncated
  5982. // between passes through this loop so we test for 0 bytes or
  5983. // a negative value.
  5984. //
  5985. // Note that we exit with the Scb still acquired,
  5986. // so that we can reliably turn compression off.
  5987. //
  5988. if (ByteCount <= 0) {
  5989. break;
  5990. }
  5991. //
  5992. // If there is more than our max, then reduce the byte count for this
  5993. // pass to our maximum.
  5994. //
  5995. if (((ULONG)FileOffset & 0x3ffff) + ByteCount > 0x40000) {
  5996. ByteCount = 0x40000 - ((ULONG)FileOffset & 0x3ffff);
  5997. }
  5998. //
  5999. // If the file is sparse then skip any deallocated regions. Note that
  6000. // this is safe even if there are dirty pages in the data section.
  6001. // Space will be correctly allocated when the writes occur at some point.
  6002. // We are only concerned with ranges that need to be reallocated.
  6003. //
  6004. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  6005. VCN RangeStartVcn;
  6006. LONGLONG RangeClusterCount;
  6007. VCN RangeFinalVcn;
  6008. ULONG RangeByteCount;
  6009. RangeStartVcn = LlClustersFromBytesTruncate( Vcb, FileOffset );
  6010. RangeFinalVcn = LlClustersFromBytes( Vcb, FileOffset + ByteCount );
  6011. //
  6012. // Preload the allocation to check for sparse ranges.
  6013. //
  6014. NtfsAcquireExclusiveScb( IrpContext, Scb );
  6015. NtfsPreloadAllocation( IrpContext,
  6016. Scb,
  6017. RangeStartVcn,
  6018. RangeFinalVcn - 1 );
  6019. do {
  6020. BOOLEAN IsAllocated;
  6021. //
  6022. // If the current block is allocated then perform
  6023. // the compression operation on this range.
  6024. //
  6025. IsAllocated = NtfsIsRangeAllocated( Scb,
  6026. RangeStartVcn,
  6027. RangeFinalVcn,
  6028. TRUE,
  6029. &RangeClusterCount );
  6030. RangeByteCount = BytesFromClusters( Vcb, (ULONG) RangeClusterCount );
  6031. //
  6032. // Remember if the number of bytes to change
  6033. // the compression on has shrunk.
  6034. //
  6035. if (IsAllocated) {
  6036. if (ByteCount > RangeByteCount) {
  6037. ByteCount = RangeByteCount;
  6038. }
  6039. //
  6040. // Break out to the outer loop.
  6041. //
  6042. break;
  6043. }
  6044. //
  6045. // Extend ValidDataLength if we the current range leaves no
  6046. // gaps. This will prevent the next write from reallocating
  6047. // a previous range in a ZeroData call.
  6048. //
  6049. if ((FileOffset + RangeByteCount > Scb->Header.ValidDataLength.QuadPart) &&
  6050. (FileOffset <= Scb->Header.ValidDataLength.QuadPart)) {
  6051. Scb->Header.ValidDataLength.QuadPart = FileOffset + RangeByteCount;
  6052. if (Scb->Header.ValidDataLength.QuadPart > Scb->Header.FileSize.QuadPart) {
  6053. Scb->Header.ValidDataLength.QuadPart = Scb->Header.FileSize.QuadPart;
  6054. }
  6055. #ifdef SYSCACHE_DEBUG
  6056. if (ScbIsBeingLogged( Scb )) {
  6057. FsRtlLogSyscacheEvent( Scb, SCE_SETCOMPRESS, SCE_FLAG_SET_VDL, FileOffset, RangeByteCount, Scb->Header.ValidDataLength.QuadPart );
  6058. }
  6059. #endif
  6060. }
  6061. //
  6062. // If we have found the last requested cluster then break out.
  6063. //
  6064. if ((RangeFinalVcn - RangeStartVcn) <= RangeClusterCount) {
  6065. ByteCount = 0;
  6066. FileOffset += LlBytesFromClusters( Vcb, RangeFinalVcn - RangeStartVcn );
  6067. break;
  6068. //
  6069. // The range is not allocated but we need to check whether
  6070. // there are any dirty pages in this range.
  6071. //
  6072. } else if (NtfsCheckForReservedClusters( Scb,
  6073. RangeStartVcn,
  6074. &RangeClusterCount ) &&
  6075. (RangeClusterCount < Vcb->SparseFileClusters)) {
  6076. if (ByteCount > Vcb->SparseFileUnit) {
  6077. ByteCount = Vcb->SparseFileUnit;
  6078. }
  6079. break;
  6080. }
  6081. //
  6082. // There is a hole at the current location. Move
  6083. // to the next block to consider.
  6084. //
  6085. RangeStartVcn += RangeClusterCount;
  6086. RangeByteCount = BytesFromClusters( Vcb, (ULONG) RangeClusterCount );
  6087. ByteCount -= RangeByteCount;
  6088. FileOffset += RangeByteCount;
  6089. } while (ByteCount != 0);
  6090. NtfsReleaseScb( IrpContext, Scb );
  6091. }
  6092. } while (ByteCount == 0);
  6093. //
  6094. // Check if have reached the end of the file.
  6095. // Note that we exit with the Scb still acquired,
  6096. // so that we can reliably turn compression off.
  6097. //
  6098. if (ByteCount <= 0) {
  6099. break;
  6100. }
  6101. //
  6102. // Make sure there are enough available clusters in the range
  6103. // we want to rewrite.
  6104. //
  6105. NtfsPurgeFileRecordCache( IrpContext );
  6106. if (!NtfsReserveClusters( IrpContext, Scb, FileOffset, (ULONG) ByteCount )) {
  6107. //
  6108. // If this transaction has already deallocated clusters
  6109. // then raise log file full to allow those to become
  6110. // available.
  6111. //
  6112. if (IrpContext->DeallocatedClusters != 0) {
  6113. #ifdef PERF_STATS
  6114. IrpContext->LogFullReason = LF_COMPRESSION;
  6115. #endif
  6116. NtfsRaiseStatus( IrpContext, STATUS_LOG_FILE_FULL, NULL, NULL );
  6117. //
  6118. // Otherwise there is insufficient space to guarantee
  6119. // we can perform the compression operation.
  6120. //
  6121. } else {
  6122. NtfsRaiseStatus( IrpContext, STATUS_DISK_FULL, NULL, NULL );
  6123. }
  6124. }
  6125. //
  6126. // Map the next range of the file, and make the pages dirty.
  6127. //
  6128. #ifdef BENL_DBG
  6129. ASSERT( (FileOffset % Scb->CompressionUnit == 0) && (ByteCount % Scb->CompressionUnit == 0 || FileOffset + ByteCount == Scb->Header.FileSize.QuadPart) );
  6130. #endif
  6131. //
  6132. // Do an empty MDL read and write to lock the range down and set it dirty for the subsequent flushcache
  6133. //
  6134. try {
  6135. ReadMdl = NULL;
  6136. WriteMdl = NULL;
  6137. //
  6138. // Page it all in
  6139. //
  6140. CcMdlRead( Scb->FileObject, (PLARGE_INTEGER)&FileOffset, (ULONG)ByteCount, &ReadMdl, &Iosb );
  6141. ASSERT( STATUS_SUCCESS == Iosb.Status );
  6142. //
  6143. // Mark it as modified
  6144. //
  6145. CcPrepareMdlWrite( Scb->FileObject, (PLARGE_INTEGER)&FileOffset, (ULONG)ByteCount, &WriteMdl, &Iosb );
  6146. ASSERT( STATUS_SUCCESS == Iosb.Status );
  6147. } finally {
  6148. if (WriteMdl) {
  6149. CcMdlWriteComplete( Scb->FileObject, (PLARGE_INTEGER)&FileOffset, WriteMdl );
  6150. }
  6151. if (ReadMdl) {
  6152. CcMdlReadComplete( Scb->FileObject, ReadMdl );
  6153. }
  6154. }
  6155. #ifdef SYSCACHE
  6156. //
  6157. // Clear write mask before the flush
  6158. //
  6159. {
  6160. PULONG WriteMask;
  6161. ULONG Len;
  6162. ULONG Off = (ULONG)FileOffset;
  6163. WriteMask = Scb->ScbType.Data.WriteMask;
  6164. if (WriteMask == NULL) {
  6165. WriteMask = NtfsAllocatePool( NonPagedPool, (((0x2000000) / PAGE_SIZE) / 8) );
  6166. Scb->ScbType.Data.WriteMask = WriteMask;
  6167. RtlZeroMemory(WriteMask, (((0x2000000) / PAGE_SIZE) / 8));
  6168. }
  6169. if (Off < 0x2000000) {
  6170. Len = (ULONG)ByteCount;
  6171. if ((Off + Len) > 0x2000000) {
  6172. Len = 0x2000000 - Off;
  6173. }
  6174. while (Len != 0) {
  6175. ASSERT( !FlagOn( Scb->ScbState, SCB_STATE_SYSCACHE_FILE ) ||
  6176. (WriteMask[(Off / PAGE_SIZE)/32] & (1 << ((Off / PAGE_SIZE) % 32))));
  6177. Off += PAGE_SIZE;
  6178. if (Len <= PAGE_SIZE) {
  6179. break;
  6180. }
  6181. Len -= PAGE_SIZE;
  6182. }
  6183. }
  6184. #endif
  6185. //
  6186. // Now flush these pages to reallocate them.
  6187. //
  6188. Irp->IoStatus.Status = NtfsFlushUserStream( IrpContext,
  6189. Scb,
  6190. &FileOffset,
  6191. (ULONG)ByteCount );
  6192. //
  6193. // On error get out.
  6194. //
  6195. #ifdef PERF_STATS
  6196. if (IrpContext->ExceptionStatus == STATUS_LOG_FILE_FULL) {
  6197. IrpContext->LogFullReason = LF_RECURSIVE_COMPRESSION;
  6198. }
  6199. #endif
  6200. NtfsNormalizeAndCleanupTransaction( IrpContext,
  6201. &Irp->IoStatus.Status,
  6202. TRUE,
  6203. STATUS_UNEXPECTED_IO_ERROR );
  6204. #ifdef SYSCACHE
  6205. //
  6206. // Verify writes occurred after the flush
  6207. //
  6208. Off = (ULONG)FileOffset;
  6209. WriteMask = Scb->ScbType.Data.WriteMask;
  6210. if (Off < 0x2000000) {
  6211. Len = (ULONG)ByteCount;
  6212. if ((Off + Len) > 0x2000000) {
  6213. Len = 0x2000000 - Off;
  6214. }
  6215. while (Len != 0) {
  6216. ASSERT(WriteMask[(Off / PAGE_SIZE)/32] & (1 << ((Off / PAGE_SIZE) % 32)));
  6217. Off += PAGE_SIZE;
  6218. if (Len <= PAGE_SIZE) {
  6219. break;
  6220. }
  6221. Len -= PAGE_SIZE;
  6222. }
  6223. }
  6224. }
  6225. #endif
  6226. //
  6227. // Release any remaing reserved clusters in this range.
  6228. //
  6229. NtfsFreeReservedClusters( Scb, FileOffset, (ULONG) ByteCount );
  6230. //
  6231. // Advance the FileOffset.
  6232. //
  6233. FileOffset += ByteCount;
  6234. //
  6235. // If we hit the end of the file then exit while holding the
  6236. // resource so we can turn compression off.
  6237. //
  6238. if (FileOffset == Scb->Header.FileSize.QuadPart) {
  6239. break;
  6240. }
  6241. //
  6242. // Unlock the header an let anyone else access the file before
  6243. // looping back.
  6244. //
  6245. FsRtlUnlockFsRtlHeader( &Scb->Header );
  6246. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  6247. IrpContext->CleanupStructure = NULL;
  6248. FsRtlHeaderLocked = FALSE;
  6249. }
  6250. }
  6251. //
  6252. // We have finished the conversion. Now is the time to turn compression
  6253. // off. Note that the compression flag in the Scb is already off.
  6254. //
  6255. if (CompressionState == 0) {
  6256. VCN StartingCluster;
  6257. //
  6258. // The paging Io resource may already be acquired.
  6259. //
  6260. if (!PagingIoAcquired && !FsRtlHeaderLocked) {
  6261. if (Scb->Header.PagingIoResource != NULL) {
  6262. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  6263. PagingIoAcquired = TRUE;
  6264. }
  6265. }
  6266. NtfsAcquireExclusiveScb( IrpContext, Scb );
  6267. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6268. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  6269. }
  6270. //
  6271. // Changing the compression state to uncompressed is a ticklish thing.
  6272. // We need to make sure that all of the compression units are valid for
  6273. // the entire allocation for the file. For non-sparse files all compression
  6274. // units should be fully allocation. For sparse files all compression
  6275. // units should be either fully allocated or fully unallocated. The interesting
  6276. // case is typically when the file size of a compressed file is dropped but
  6277. // the allocation remains. The allocation in that range may be in the compressed
  6278. // format. We need to proactively remove it.
  6279. //
  6280. // In the non-sparse case we have already rewritten the data all the way
  6281. // through file size. We only have to remove the allocation past the
  6282. // cluster containing Eof.
  6283. //
  6284. // In the sparse case we actually have to deal with allocated ranges
  6285. // in the range between valid data length and file size as well. We
  6286. // didn't rewrite this in the flush path above because we don't want
  6287. // to allocate clusters for zeroes.
  6288. //
  6289. // The action of deallocating the clusters past file size must be tied
  6290. // in with the transaction of flipping the compression state.
  6291. //
  6292. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  6293. //
  6294. // In all cases we can remove the clusters in the compression
  6295. // units past that containing Eof.
  6296. //
  6297. StartingCluster = BlockAlign( Scb->Header.FileSize.QuadPart, (LONG)Scb->CompressionUnit );
  6298. if (StartingCluster < Scb->Header.AllocationSize.QuadPart) {
  6299. //
  6300. // Deallocate the space past the filesize
  6301. //
  6302. NtfsDeleteAllocation( IrpContext,
  6303. IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->FileObject,
  6304. Scb,
  6305. LlClustersFromBytesTruncate( Vcb, StartingCluster ),
  6306. MAXLONGLONG,
  6307. TRUE,
  6308. TRUE );
  6309. }
  6310. //
  6311. // For sparse files we need to handle the allocation between valid data length
  6312. // and allocation size.
  6313. //
  6314. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  6315. //
  6316. // Assume that the data up to either ValidDataLength or ValidDataToDisk
  6317. // is valid. Start at the compression unit after that.
  6318. //
  6319. StartingCluster = Scb->Header.ValidDataLength.QuadPart;
  6320. if (Scb->ValidDataToDisk > StartingCluster) {
  6321. StartingCluster = Scb->ValidDataToDisk;
  6322. }
  6323. StartingCluster = BlockAlign( StartingCluster, (LONG)Scb->CompressionUnit );
  6324. if (StartingCluster < Scb->Header.AllocationSize.QuadPart) {
  6325. NtfsDeleteAllocation( IrpContext,
  6326. IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->FileObject,
  6327. Scb,
  6328. LlClustersFromBytesTruncate( Vcb, StartingCluster ),
  6329. LlClustersFromBytesTruncate( Vcb, Scb->Header.AllocationSize.QuadPart ) - 1,
  6330. TRUE,
  6331. TRUE );
  6332. }
  6333. }
  6334. //
  6335. // If total allocated has changed then remember to report it.
  6336. //
  6337. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
  6338. (Scb->Fcb->Info.AllocatedLength != Scb->TotalAllocated)) {
  6339. Scb->Fcb->Info.AllocatedLength = Scb->TotalAllocated;
  6340. SetFlag( Scb->Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
  6341. }
  6342. //
  6343. // Check whether there is more to be truncated when the handle is closed.
  6344. //
  6345. SetFlag( Scb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE );
  6346. }
  6347. NtfsChangeAttributeCompression( IrpContext, Scb, Vcb, Ccb, 0 );
  6348. Scb->AttributeFlags &= (USHORT)~ATTRIBUTE_FLAG_COMPRESSION_MASK;
  6349. //
  6350. // Reset the VDD since its not used for uncompressed files
  6351. //
  6352. Scb->ValidDataToDisk = 0;
  6353. //
  6354. // No need to set the WRITE_COMPRESSED flag on error.
  6355. //
  6356. ClearFlag( ScbRestoreState, SCB_STATE_WRITE_COMPRESSED );
  6357. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT ) &&
  6358. (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE ))) {
  6359. if (Scb->ScbType.Data.ReservedBitMap != NULL) {
  6360. NtfsDeleteReservedBitmap( Scb );
  6361. }
  6362. }
  6363. //
  6364. // Now clear the REALLOCATE_ON_WRITE flag while holding both resources.
  6365. //
  6366. ClearFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  6367. }
  6368. //
  6369. // Unlock the header if we locked it.
  6370. //
  6371. if (FsRtlHeaderLocked) {
  6372. FsRtlUnlockFsRtlHeader( &Scb->Header );
  6373. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  6374. IrpContext->CleanupStructure = NULL;
  6375. FsRtlHeaderLocked = FALSE;
  6376. }
  6377. Status = STATUS_SUCCESS;
  6378. #ifdef SYSCACHE_DEBUG
  6379. if (ScbIsBeingLogged( Scb )) {
  6380. FsRtlLogSyscacheEvent( Scb, SCE_SETCOMPRESS, 0, Scb->ValidDataToDisk, Scb->Header.ValidDataLength.QuadPart, 0 );
  6381. }
  6382. #endif
  6383. try_exit: NOTHING;
  6384. //
  6385. // Now clear the reallocate flag in the Scb if we set it.
  6386. //
  6387. if (NextIrpSp->Parameters.FileSystemControl.OutputBufferLength != MAXULONG) {
  6388. ClearFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  6389. }
  6390. } finally {
  6391. DebugUnwind( NtfsSetCompression );
  6392. //
  6393. // NtfsCompleteRequest will clean up the Fsrtl header but
  6394. // we still need to release the paging resource if held.
  6395. //
  6396. if (FsRtlHeaderLocked) {
  6397. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  6398. }
  6399. //
  6400. // If this is an abnormal termination then undo our work
  6401. //
  6402. if (AbnormalTermination()) {
  6403. //
  6404. // If we have started the transformation and are in the exception path
  6405. // we are either going to continue the operation after a clean
  6406. // checkpoint or we are done.
  6407. //
  6408. if (NextIrpSp->Parameters.FileSystemControl.OutputBufferLength != MAXULONG) {
  6409. //
  6410. // If we are continuing the operation, save the current file offset.
  6411. //
  6412. if (IrpContext->ExceptionStatus == STATUS_LOG_FILE_FULL ||
  6413. IrpContext->ExceptionStatus == STATUS_CANT_WAIT) {
  6414. NextIrpSp->Parameters.FileSystemControl.OutputBufferLength = (ULONG)FileOffset;
  6415. NextIrpSp->Parameters.FileSystemControl.InputBufferLength = ((PLARGE_INTEGER)&FileOffset)->HighPart;
  6416. //
  6417. // Otherwise clear the REALLOCATE_ON_WRITE flag and set the
  6418. // COMPRESSED flag if needed.
  6419. //
  6420. } else {
  6421. ClearFlag( Scb->ScbState, SCB_STATE_REALLOCATE_ON_WRITE | SCB_STATE_COMPRESSION_CHANGE );
  6422. SetFlag( Scb->ScbState, ScbRestoreState );
  6423. ASSERT( !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) ||
  6424. (Scb->CompressionUnit != 0) );
  6425. }
  6426. }
  6427. }
  6428. }
  6429. ASSERT( !NT_SUCCESS( Status ) ||
  6430. (CompressionState != 0) ||
  6431. !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) ||
  6432. (Scb->CompressionUnit != 0) );
  6433. NtfsCompleteRequest( IrpContext, Irp, Status );
  6434. return Status;
  6435. }
  6436. //
  6437. // Local Support Routine
  6438. //
  6439. NTSTATUS
  6440. NtfsMarkAsSystemHive (
  6441. IN PIRP_CONTEXT IrpContext,
  6442. IN PIRP Irp
  6443. )
  6444. /*++
  6445. Routine Description:
  6446. This routine is called by the registry to identify the registry handles. We
  6447. will mark this in the Ccb and use it during FlushBuffers to know to do a
  6448. careful flush.
  6449. Arguments:
  6450. Irp - Supplies the Irp being processed.
  6451. Return Value:
  6452. NTSTATUS - The return status for the operation
  6453. --*/
  6454. {
  6455. PIO_STACK_LOCATION IrpSp;
  6456. TYPE_OF_OPEN TypeOfOpen;
  6457. PVCB Vcb;
  6458. PFCB Fcb;
  6459. PSCB Scb;
  6460. PCCB Ccb;
  6461. PAGED_CODE();
  6462. //
  6463. // Always make this synchronous.
  6464. //
  6465. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6466. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  6467. //
  6468. // Extract and decode the file object
  6469. //
  6470. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6471. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  6472. //
  6473. // We only permit this request on files and we must be called from kernel mode.
  6474. //
  6475. if ((Irp->RequestorMode != KernelMode) ||
  6476. (TypeOfOpen != UserFileOpen)) {
  6477. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6478. DebugTrace( -1, Dbg, ("NtfsOplockRequest -> STATUS_INVALID_PARAMETER\n") );
  6479. return STATUS_INVALID_PARAMETER;
  6480. }
  6481. //
  6482. // Now acquire the file and mark the Ccb and return SUCCESS.
  6483. //
  6484. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6485. NtfsAcquireExclusiveScb( IrpContext, Scb );
  6486. SetFlag( Ccb->Flags, CCB_FLAG_SYSTEM_HIVE );
  6487. NtfsReleaseScb( IrpContext, Scb );
  6488. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  6489. return STATUS_SUCCESS;
  6490. }
  6491. //
  6492. // Local Support Routine
  6493. //
  6494. NTSTATUS
  6495. NtfsGetStatistics (
  6496. IN PIRP_CONTEXT IrpContext,
  6497. IN PIRP Irp
  6498. )
  6499. /*++
  6500. Routine Description:
  6501. This routine returns the filesystem performance counters for the
  6502. volume referred to.
  6503. Arguments:
  6504. Irp - Supplies the Irp being processed.
  6505. Return Value:
  6506. NTSTATUS - The return status for the operation
  6507. --*/
  6508. {
  6509. PIO_STACK_LOCATION IrpSp;
  6510. NTSTATUS Status;
  6511. TYPE_OF_OPEN TypeOfOpen;
  6512. PVCB Vcb;
  6513. PFCB Fcb;
  6514. PSCB Scb;
  6515. PCCB Ccb;
  6516. PFILE_SYSTEM_STATISTICS Buffer;
  6517. ULONG BufferLength;
  6518. ULONG StatsSize;
  6519. ULONG BytesToCopy;
  6520. PAGED_CODE();
  6521. //
  6522. // Get the current stack location and extract the output
  6523. // buffer information. The output parameter will receive
  6524. // the performance counters.
  6525. //
  6526. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6527. //
  6528. // Extract the buffer
  6529. //
  6530. Buffer = Irp->AssociatedIrp.SystemBuffer;
  6531. BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6532. //
  6533. // Make sure the buffer is big enough for at least the common part.
  6534. //
  6535. if (BufferLength < sizeof( FILESYSTEM_STATISTICS )) {
  6536. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6537. return STATUS_BUFFER_TOO_SMALL;
  6538. }
  6539. //
  6540. // Now see how many bytes we can copy.
  6541. //
  6542. StatsSize = sizeof( FILE_SYSTEM_STATISTICS ) * KeNumberProcessors;
  6543. if (BufferLength < StatsSize) {
  6544. BytesToCopy = BufferLength;
  6545. Status = STATUS_BUFFER_OVERFLOW;
  6546. } else {
  6547. BytesToCopy = StatsSize;
  6548. Status = STATUS_SUCCESS;
  6549. }
  6550. //
  6551. // Decode the file object
  6552. //
  6553. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb,
  6554. &Fcb, &Scb, &Ccb, TRUE );
  6555. if (TypeOfOpen == UnopenedFileObject) {
  6556. Status = STATUS_INVALID_PARAMETER;
  6557. } else {
  6558. //
  6559. // Fill in the output buffer
  6560. //
  6561. RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
  6562. Irp->IoStatus.Information = BytesToCopy;
  6563. }
  6564. NtfsCompleteRequest( IrpContext, Irp, Status );
  6565. return Status;
  6566. }
  6567. //
  6568. // Local Support Routine
  6569. //
  6570. NTSTATUS
  6571. NtfsGetVolumeData (
  6572. IN PIRP_CONTEXT IrpContext,
  6573. IN PIRP Irp
  6574. )
  6575. /*++
  6576. Routine Description:
  6577. Returns a filled in VOLUME_DATA structure in the user output buffer.
  6578. Arguments:
  6579. Irp - Supplies the Irp being processed.
  6580. Return Value:
  6581. NTSTATUS - The return status for the operation.
  6582. --*/
  6583. {
  6584. PIO_STACK_LOCATION IrpSp;
  6585. ULONG FsControlCode;
  6586. NTSTATUS Status = STATUS_SUCCESS;
  6587. PFILE_OBJECT FileObject;
  6588. TYPE_OF_OPEN TypeOfOpen;
  6589. PVCB Vcb;
  6590. PFCB Fcb;
  6591. PSCB Scb;
  6592. PCCB Ccb;
  6593. BOOLEAN AcquiredScb = FALSE;
  6594. BOOLEAN AcquiredVcb = FALSE;
  6595. PNTFS_VOLUME_DATA_BUFFER VolumeData;
  6596. PNTFS_EXTENDED_VOLUME_DATA ExtendedBuffer;
  6597. ULONG ExtendedBufferLength;
  6598. ULONG VolumeDataLength;
  6599. //
  6600. // Get the current Irp stack location and save some references.
  6601. //
  6602. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6603. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  6604. DebugTrace( +1, Dbg, ("NtfsGetVolumeData, FsControlCode = %08lx\n", FsControlCode) );
  6605. //
  6606. // Extract and decode the file object and check for type of open.
  6607. //
  6608. FileObject = IrpSp->FileObject;
  6609. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  6610. if (TypeOfOpen == UnopenedFileObject) {
  6611. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6612. return STATUS_INVALID_PARAMETER;
  6613. }
  6614. //
  6615. // Get the output buffer length and pointer.
  6616. //
  6617. VolumeDataLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6618. VolumeData = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  6619. //
  6620. // Check for a minimum length on the ouput buffer.
  6621. //
  6622. if (VolumeDataLength < sizeof(NTFS_VOLUME_DATA_BUFFER)) {
  6623. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6624. return STATUS_BUFFER_TOO_SMALL;
  6625. }
  6626. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  6627. AcquiredVcb = TRUE;
  6628. try {
  6629. //
  6630. // Make sure the volume is still mounted.
  6631. //
  6632. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  6633. Status = STATUS_VOLUME_DISMOUNTED;
  6634. leave;
  6635. }
  6636. //
  6637. // Acquire the volume bitmap and fill in the volume data structure.
  6638. //
  6639. NtfsAcquireExclusiveScb( IrpContext, Vcb->BitmapScb );
  6640. AcquiredScb = TRUE;
  6641. NtfsReleaseVcb( IrpContext, Vcb );
  6642. AcquiredVcb = FALSE;
  6643. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6644. Status = STATUS_VOLUME_DISMOUNTED;
  6645. leave;
  6646. }
  6647. //
  6648. // We may need to rescan the bitmap if there is a chance we have
  6649. // performed the upgrade to get an accurate count of free clusters.
  6650. //
  6651. if (FlagOn( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS ) &&
  6652. FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  6653. NtfsScanEntireBitmap( IrpContext, Vcb, FALSE );
  6654. }
  6655. VolumeData->VolumeSerialNumber.QuadPart = Vcb->VolumeSerialNumber;
  6656. VolumeData->NumberSectors.QuadPart = Vcb->NumberSectors;
  6657. VolumeData->TotalClusters.QuadPart = Vcb->TotalClusters;
  6658. VolumeData->FreeClusters.QuadPart = Vcb->FreeClusters;
  6659. VolumeData->TotalReserved.QuadPart = Vcb->TotalReserved;
  6660. VolumeData->BytesPerSector = Vcb->BytesPerSector;
  6661. VolumeData->BytesPerCluster = Vcb->BytesPerCluster;
  6662. VolumeData->BytesPerFileRecordSegment = Vcb->BytesPerFileRecordSegment;
  6663. VolumeData->ClustersPerFileRecordSegment = Vcb->ClustersPerFileRecordSegment;
  6664. VolumeData->MftValidDataLength = Vcb->MftScb->Header.ValidDataLength;
  6665. VolumeData->MftStartLcn.QuadPart = Vcb->MftStartLcn;
  6666. VolumeData->Mft2StartLcn.QuadPart = Vcb->Mft2StartLcn;
  6667. VolumeData->MftZoneStart.QuadPart = Vcb->MftZoneStart;
  6668. VolumeData->MftZoneEnd.QuadPart = Vcb->MftZoneEnd;
  6669. if (VolumeData->MftZoneEnd.QuadPart > Vcb->TotalClusters) {
  6670. VolumeData->MftZoneEnd.QuadPart = Vcb->TotalClusters;
  6671. }
  6672. //
  6673. // Check if there is anything to add in the extended data.
  6674. //
  6675. ExtendedBufferLength = VolumeDataLength - sizeof( NTFS_VOLUME_DATA_BUFFER );
  6676. VolumeDataLength = sizeof( NTFS_VOLUME_DATA_BUFFER );
  6677. ExtendedBuffer = (PNTFS_EXTENDED_VOLUME_DATA) Add2Ptr( VolumeData, sizeof( NTFS_VOLUME_DATA_BUFFER ));
  6678. if (ExtendedBufferLength >= sizeof( NTFS_EXTENDED_VOLUME_DATA )) {
  6679. ExtendedBuffer->ByteCount = sizeof( NTFS_EXTENDED_VOLUME_DATA );
  6680. ExtendedBuffer->MajorVersion = Vcb->MajorVersion;
  6681. ExtendedBuffer->MinorVersion = Vcb->MinorVersion;
  6682. } else if (ExtendedBufferLength >= FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MinorVersion )) {
  6683. ExtendedBuffer->ByteCount = FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MinorVersion );
  6684. ExtendedBuffer->MajorVersion = Vcb->MajorVersion;
  6685. } else if (ExtendedBufferLength >= FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MajorVersion )) {
  6686. ExtendedBuffer->ByteCount = FIELD_OFFSET( NTFS_EXTENDED_VOLUME_DATA, MajorVersion );
  6687. } else {
  6688. leave;
  6689. }
  6690. VolumeDataLength += ExtendedBuffer->ByteCount;
  6691. } finally {
  6692. if (AcquiredScb) {
  6693. NtfsReleaseScb( IrpContext, Vcb->BitmapScb );
  6694. }
  6695. if (AcquiredVcb) {
  6696. NtfsReleaseVcb( IrpContext, Vcb );
  6697. }
  6698. }
  6699. //
  6700. // If nothing raised then complete the irp.
  6701. //
  6702. Irp->IoStatus.Information = VolumeDataLength;
  6703. NtfsCompleteRequest( IrpContext, Irp, Status );
  6704. DebugTrace( -1, Dbg, ("NtfsGetVolumeData -> VOID\n") );
  6705. return Status;
  6706. }
  6707. //
  6708. // Local Support Routine
  6709. //
  6710. NTSTATUS
  6711. NtfsGetVolumeBitmap (
  6712. IN PIRP_CONTEXT IrpContext,
  6713. IN PIRP Irp
  6714. )
  6715. /*++
  6716. Routine Description:
  6717. This routine scans volume bitmap and returns the requested range.
  6718. Input = the GET_BITMAP data structure is passed in through the input buffer.
  6719. Output = the VOLUME_BITMAP data structure is returned through the output buffer.
  6720. Arguments:
  6721. Irp - Supplies the Irp being processed.
  6722. Return Value:
  6723. NTSTATUS - The return status for the operation.
  6724. --*/
  6725. {
  6726. NTSTATUS Status = STATUS_SUCCESS;
  6727. PIO_STACK_LOCATION IrpSp;
  6728. ULONG FsControlCode;
  6729. PFILE_OBJECT FileObject;
  6730. TYPE_OF_OPEN TypeOfOpen;
  6731. PVCB Vcb;
  6732. PFCB Fcb;
  6733. PSCB Scb;
  6734. PCCB Ccb;
  6735. PSTARTING_LCN_INPUT_BUFFER GetBitmap;
  6736. ULONG GetBitmapLength;
  6737. PVOLUME_BITMAP_BUFFER VolumeBitmap;
  6738. ULONG VolumeBitmapLength;
  6739. ULONG BitsWritten;
  6740. LCN Lcn;
  6741. LCN StartingLcn;
  6742. ULONG Offset;
  6743. RTL_BITMAP Bitmap;
  6744. PBCB BitmapBcb = NULL;
  6745. BOOLEAN AccessingUserBuffer = FALSE;
  6746. BOOLEAN ReleaseScb = FALSE;
  6747. //
  6748. // Don't post this request, we can't lock both input and output buffers.
  6749. //
  6750. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6751. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  6752. //
  6753. // Get the current Irp stack location and save some references.
  6754. //
  6755. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6756. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  6757. DebugTrace( +1, Dbg, ("NtfsGetVolumeBitmap, FsControlCode = %08lx\n", FsControlCode) );
  6758. //
  6759. // Extract and decode the file object and check for type of open.
  6760. // Send FALSE to indicate that we don't want to raise on dismounts
  6761. // because we'll check for that further down anyway.
  6762. //
  6763. FileObject = IrpSp->FileObject;
  6764. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  6765. //
  6766. // Get the input & output buffer lengths and pointers.
  6767. //
  6768. GetBitmapLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  6769. GetBitmap = (PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  6770. VolumeBitmapLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6771. VolumeBitmap = (PVOLUME_BITMAP_BUFFER)NtfsMapUserBuffer( Irp, NormalPagePriority );
  6772. //
  6773. // Check the type of open and minimum requirements for the IO buffers.
  6774. //
  6775. if ((Ccb == NULL) ||
  6776. !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  6777. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  6778. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_ACCESS_DENIED\n") );
  6779. return STATUS_ACCESS_DENIED;
  6780. } else if (VolumeBitmapLength < sizeof( VOLUME_BITMAP_BUFFER )) {
  6781. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  6782. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_BUFFER_TOO_SMALL\n") );
  6783. return STATUS_BUFFER_TOO_SMALL;
  6784. } else if (GetBitmapLength < sizeof( STARTING_LCN_INPUT_BUFFER )) {
  6785. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6786. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_INVALID_PARAMETER\n") );
  6787. return STATUS_INVALID_PARAMETER;
  6788. }
  6789. //
  6790. // Probe the user's buffers and capture the input values.
  6791. //
  6792. try {
  6793. if (Irp->RequestorMode != KernelMode) {
  6794. ProbeForRead( GetBitmap, GetBitmapLength, sizeof( UCHAR ));
  6795. ProbeForWrite( VolumeBitmap, VolumeBitmapLength, sizeof( UCHAR ));
  6796. }
  6797. StartingLcn = GetBitmap->StartingLcn.QuadPart;
  6798. } except(EXCEPTION_EXECUTE_HANDLER) {
  6799. NtfsRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER, NULL, NULL);
  6800. }
  6801. //
  6802. // Acquire the volume bitmap and check for a valid requested Lcn.
  6803. //
  6804. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  6805. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  6806. NtfsReleaseVcb( IrpContext, Vcb );
  6807. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  6808. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> STATUS_VOLUME_DISMOUNTED\n") );
  6809. return STATUS_VOLUME_DISMOUNTED;
  6810. }
  6811. try {
  6812. //
  6813. // Acquire the volume bitmap and check for a valid requested Lcn.
  6814. // We no longer care about the Scb we were called with.
  6815. //
  6816. Scb = Vcb->BitmapScb;
  6817. NtfsAcquireSharedScb( IrpContext, Scb );
  6818. NtfsReleaseVcb( IrpContext, Vcb );
  6819. //
  6820. // Setting this flag to TRUE indicates we have the Scb but not the Vcb.
  6821. //
  6822. ReleaseScb = TRUE;
  6823. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  6824. Status = STATUS_VOLUME_DISMOUNTED;
  6825. leave;
  6826. }
  6827. if ((StartingLcn < 0L) ||
  6828. (StartingLcn >= Vcb->TotalClusters)) {
  6829. Status = STATUS_INVALID_PARAMETER;
  6830. leave;
  6831. }
  6832. //
  6833. // Read in the volume bitmap page by page and copy it into the UserBuffer.
  6834. //
  6835. VolumeBitmapLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
  6836. //
  6837. // Use a try-except to catch user buffer problems.
  6838. //
  6839. try {
  6840. for (Lcn = StartingLcn, BitsWritten = 0;
  6841. Lcn < Vcb->TotalClusters;
  6842. Lcn = Lcn + Bitmap.SizeOfBitMap) {
  6843. ULONG BytesToCopy;
  6844. //
  6845. // Read in the bitmap page and make sure that we haven't messed up the math.
  6846. //
  6847. DebugTrace( 0, Dbg, ("Mapping bitmap from Lcn %I64x\n", (LONGLONG) Lcn) );
  6848. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  6849. NtfsMapPageInBitmap( IrpContext, Vcb, Lcn, &Lcn, &Bitmap, &BitmapBcb );
  6850. //
  6851. // If this is first iteration, update StartingLcn with actual
  6852. // starting cluster returned.
  6853. //
  6854. if (BitsWritten == 0) {
  6855. Offset = (ULONG)(StartingLcn - Lcn) / 8;
  6856. }
  6857. //
  6858. // Check to see if we have enough user buffer. If have some but
  6859. // not enough, copy what we can and return STATUS_BUFFER_OVERFLOW.
  6860. // If we are down to 0 (i.e. previous iteration used all the
  6861. // buffer), break right now.
  6862. //
  6863. BytesToCopy = ((Bitmap.SizeOfBitMap + 7) / 8) - Offset;
  6864. if (BytesToCopy > VolumeBitmapLength) {
  6865. BytesToCopy = VolumeBitmapLength;
  6866. Status = STATUS_BUFFER_OVERFLOW;
  6867. if (BytesToCopy == 0) {
  6868. break;
  6869. }
  6870. }
  6871. //
  6872. // Now copy it into the UserBuffer.
  6873. //
  6874. AccessingUserBuffer = TRUE;
  6875. RtlCopyMemory(&VolumeBitmap->Buffer[BitsWritten / 8], (PUCHAR)Bitmap.Buffer + Offset, BytesToCopy);
  6876. AccessingUserBuffer = FALSE;
  6877. //
  6878. // If this was an overflow, bump up bits written and continue
  6879. //
  6880. if (Status != STATUS_BUFFER_OVERFLOW) {
  6881. BitsWritten += Bitmap.SizeOfBitMap - (Offset * 8);
  6882. VolumeBitmapLength -= BytesToCopy;
  6883. } else {
  6884. BitsWritten += BytesToCopy * 8;
  6885. break;
  6886. }
  6887. Offset = 0;
  6888. }
  6889. AccessingUserBuffer = TRUE;
  6890. //
  6891. // Lower StartingLcn to the byte we started on
  6892. //
  6893. VolumeBitmap->StartingLcn.QuadPart = StartingLcn & ~7L;
  6894. VolumeBitmap->BitmapSize.QuadPart = Vcb->TotalClusters - VolumeBitmap->StartingLcn.QuadPart;
  6895. AccessingUserBuffer = FALSE;
  6896. Irp->IoStatus.Information =
  6897. FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + (BitsWritten + 7) / 8;
  6898. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  6899. //
  6900. // Convert any unexpected error to INVALID_USER_BUFFER if we
  6901. // are writing in the user's buffer.
  6902. //
  6903. NtfsRaiseStatus( IrpContext,
  6904. STATUS_INVALID_USER_BUFFER,
  6905. NULL,
  6906. NULL );
  6907. }
  6908. } finally {
  6909. DebugUnwind( NtfsGetVolumeBitmap );
  6910. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  6911. if (ReleaseScb) {
  6912. NtfsReleaseScb( IrpContext, Scb );
  6913. } else {
  6914. NtfsReleaseVcb( IrpContext, Vcb );
  6915. }
  6916. }
  6917. //
  6918. // If nothing raised then complete the irp.
  6919. //
  6920. NtfsCompleteRequest( IrpContext, Irp, Status );
  6921. DebugTrace( -1, Dbg, ("NtfsGetVolumeBitmap -> VOID\n") );
  6922. return Status;
  6923. }
  6924. //
  6925. // Local Support Routine
  6926. //
  6927. NTSTATUS
  6928. NtfsGetRetrievalPointers (
  6929. IN PIRP_CONTEXT IrpContext,
  6930. IN PIRP Irp
  6931. )
  6932. /*++
  6933. Routine Description:
  6934. This routine scans the array of MCBs for the given SCB and builds an extent
  6935. list. The first run in the output extent list will start at the begining
  6936. of the contiguous run specified by the input parameter.
  6937. Input = STARTING_VCN_INPUT_BUFFER;
  6938. Output = RETRIEVAL_POINTERS_BUFFER.
  6939. Arguments:
  6940. Irp - Supplies the Irp being processed.
  6941. Return Value:
  6942. NTSTATUS - The return status for the operation.
  6943. --*/
  6944. {
  6945. NTSTATUS Status;
  6946. PIO_STACK_LOCATION IrpSp;
  6947. TYPE_OF_OPEN TypeOfOpen;
  6948. PVCB Vcb;
  6949. PFCB Fcb;
  6950. PSCB Scb;
  6951. PCCB Ccb;
  6952. VCN Vcn;
  6953. VCN LastVcnInFile;
  6954. LCN Lcn;
  6955. LONGLONG ClusterCount;
  6956. LONGLONG CountFromStartingVcn;
  6957. LONGLONG StartingVcn;
  6958. ULONG FileRunIndex = 0;
  6959. ULONG RangeRunIndex;
  6960. ULONG InputBufferLength;
  6961. ULONG OutputBufferLength;
  6962. PVOID RangePtr;
  6963. PRETRIEVAL_POINTERS_BUFFER OutputBuffer;
  6964. BOOLEAN AccessingUserBuffer = FALSE;
  6965. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  6966. BOOLEAN CleanupAttributeContext = FALSE;
  6967. //
  6968. // Don't post this request, we can't lock both input and output buffers.
  6969. //
  6970. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  6971. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  6972. //
  6973. // Get the current Irp stack location and save some references.
  6974. //
  6975. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  6976. DebugTrace( +1, Dbg, ("NtfsGetRetrievalPointers\n") );
  6977. //
  6978. // Extract and decode the file object and check for type of open.
  6979. // If we ever decide to support UserDirectoryOpen also, make sure
  6980. // to check for Scb->AttributeTypeCode != $INDEX_ALLOCATION when
  6981. // checking whether the Scb header is initialized. Otherwise we'll
  6982. // have trouble with phantom Scbs created for small directories.
  6983. //
  6984. //
  6985. // Get the input and output buffer lengths and pointers.
  6986. // Initialize some variables.
  6987. //
  6988. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  6989. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  6990. OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)NtfsMapUserBuffer( Irp, NormalPagePriority );
  6991. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  6992. if (((TypeOfOpen != UserFileOpen) &&
  6993. (TypeOfOpen != UserDirectoryOpen) &&
  6994. (TypeOfOpen != UserViewIndexOpen)) ||
  6995. (InputBufferLength < sizeof( STARTING_VCN_INPUT_BUFFER ))) {
  6996. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  6997. return STATUS_INVALID_PARAMETER;
  6998. }
  6999. if (OutputBufferLength < sizeof( RETRIEVAL_POINTERS_BUFFER )) {
  7000. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  7001. return STATUS_BUFFER_TOO_SMALL;
  7002. }
  7003. //
  7004. // Acquire exclusive access to the Scb. We don't want other threads
  7005. // to extend or move the file while we're trying to return the
  7006. // retrieval pointers for it. We need it exclusve to call PreloadAllocation.
  7007. //
  7008. NtfsAcquireExclusiveScb( IrpContext, Scb );
  7009. try {
  7010. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  7011. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  7012. }
  7013. //
  7014. // There are three separate places inside this try/except where we
  7015. // access the user-supplied buffer. We want to handle exceptions
  7016. // differently if they happen while we are trying to access the user
  7017. // buffer than if they happen elsewhere in the try/except. We set
  7018. // this boolean immediately before touching the user buffer, and
  7019. // clear it immediately after.
  7020. //
  7021. try {
  7022. AccessingUserBuffer = TRUE;
  7023. if (Irp->RequestorMode != KernelMode) {
  7024. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  7025. InputBufferLength,
  7026. sizeof(UCHAR) );
  7027. ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
  7028. }
  7029. StartingVcn = ((PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingVcn.QuadPart;
  7030. //
  7031. // While we have AccessingUserBuffer set to TRUE, let's initialize the
  7032. // extentcount. We increment this for each run in the mcb, so we need
  7033. // to initialize it outside the main do while loop.
  7034. //
  7035. OutputBuffer->ExtentCount = 0;
  7036. OutputBuffer->StartingVcn.QuadPart = 0;
  7037. AccessingUserBuffer = FALSE;
  7038. //
  7039. // If the Scb is uninitialized, we initialize it now.
  7040. //
  7041. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  7042. //
  7043. // Non-index Scb's are trivial to initialize; index Scb's
  7044. // do not necessarily have an attribute to back them up:
  7045. // the index Scb is for the index allocation attribute which
  7046. // may not be present if the entire index fits in the $INDEX_ROOT.
  7047. //
  7048. // We look for the attribute on disk. If it is there, we
  7049. // update from it. Otherwise, if it is $INDEX_ALLOCATION we
  7050. // treat it as a resident attribute. Finally, we fail it.
  7051. //
  7052. NtfsInitializeAttributeContext( &AttributeContext );
  7053. CleanupAttributeContext = TRUE;
  7054. if (!NtfsLookupAttributeByName( IrpContext,
  7055. Scb->Fcb,
  7056. &Scb->Fcb->FileReference,
  7057. Scb->AttributeTypeCode,
  7058. &Scb->AttributeName,
  7059. NULL,
  7060. FALSE,
  7061. &AttributeContext )) {
  7062. //
  7063. // Verify that this is an index allocation attribute.
  7064. // If not, raise an error.
  7065. //
  7066. if (Scb->AttributeTypeCode != $INDEX_ALLOCATION) {
  7067. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  7068. }
  7069. Irp->IoStatus.Information = 0;
  7070. Status = STATUS_SUCCESS;
  7071. leave;
  7072. } else {
  7073. NtfsUpdateScbFromAttribute( IrpContext,
  7074. Scb,
  7075. NtfsFoundAttribute( &AttributeContext ));
  7076. }
  7077. }
  7078. //
  7079. // If the data attribute is resident (typically for a small file),
  7080. // it is not safe to call NtfsPreloadAllocation. There won't be
  7081. // any runs, and we've already set ExtentCount to 0, so we're done.
  7082. // FAT returns STATUS_END_OF_FILE for a zero-length file, so for
  7083. // consistency's sake, we'll return that in the resident case.
  7084. //
  7085. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  7086. Irp->IoStatus.Information = 0;
  7087. Status = STATUS_END_OF_FILE;
  7088. leave;
  7089. }
  7090. //
  7091. // Check if a starting cluster was specified.
  7092. //
  7093. LastVcnInFile = LlClustersFromBytesTruncate( Vcb, Scb->Header.AllocationSize.QuadPart ) - 1;
  7094. if (StartingVcn > LastVcnInFile) {
  7095. //
  7096. // It's possible that the Vcn we were given is past the end of the file.
  7097. //
  7098. Status = STATUS_END_OF_FILE;
  7099. leave;
  7100. } else if (StartingVcn < 0) {
  7101. //
  7102. // It's possible that the Vcn we were given is negative, and
  7103. // NtfsMcbLookupArrayIndex doesn't handle that very well.
  7104. //
  7105. Status = STATUS_INVALID_PARAMETER;
  7106. leave;
  7107. } else {
  7108. //
  7109. // We need to call NtfsPreloadAllocation to make sure all the
  7110. // ranges in this NtfsMcb are loaded.
  7111. //
  7112. NtfsPreloadAllocation( IrpContext,
  7113. Scb,
  7114. StartingVcn,
  7115. LastVcnInFile );
  7116. //
  7117. // Decide which Mcb contains the starting Vcn.
  7118. //
  7119. (VOID)NtfsLookupNtfsMcbEntry( &Scb->Mcb,
  7120. StartingVcn,
  7121. NULL,
  7122. &CountFromStartingVcn,
  7123. &Lcn,
  7124. &ClusterCount,
  7125. &RangePtr,
  7126. &RangeRunIndex );
  7127. }
  7128. //
  7129. // Fill in the Vcn where the run containing StartingVcn truly starts.
  7130. //
  7131. AccessingUserBuffer = TRUE;
  7132. OutputBuffer->StartingVcn.QuadPart = Vcn = StartingVcn - (ClusterCount - CountFromStartingVcn);
  7133. AccessingUserBuffer = FALSE;
  7134. //
  7135. // FileRunIndex is the index of a given run within an entire
  7136. // file, as opposed to RangeRunIndex which is the index of a
  7137. // given run within its range. RangeRunIndex is reset to 0 for
  7138. // each range, where FileRunIndex is set to 0 once out here.
  7139. //
  7140. FileRunIndex = 0;
  7141. do {
  7142. //
  7143. // Now copy over the mapping pairs from the mcb
  7144. // to the output buffer. We store in [sector count, lbo]
  7145. // mapping pairs and end with a zero sector count.
  7146. //
  7147. //
  7148. // Check for an exhausted output buffer.
  7149. //
  7150. if ((ULONG)FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[FileRunIndex+1]) > OutputBufferLength) {
  7151. //
  7152. // We know that we're out of room in the output buffer, so we won't be looking up
  7153. // any more runs. ExtentCount currently reflects how many runs we stored in the
  7154. // user buffer, so we can safely quit. There are indeed ExtentCount extents stored
  7155. // in the array, and returning STATUS_BUFFER_OVERFLOW informs our caller that we
  7156. // didn't have enough room to return all the runs.
  7157. //
  7158. Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[FileRunIndex]);
  7159. Status = STATUS_BUFFER_OVERFLOW;
  7160. leave;
  7161. }
  7162. //
  7163. // Here's the interesting part -- we fill in the next array element in the ouput buffer
  7164. // with the current run's information.
  7165. //
  7166. AccessingUserBuffer = TRUE;
  7167. OutputBuffer->Extents[FileRunIndex].NextVcn.QuadPart = Vcn + ClusterCount;
  7168. OutputBuffer->Extents[FileRunIndex].Lcn.QuadPart = Lcn;
  7169. OutputBuffer->ExtentCount += 1;
  7170. AccessingUserBuffer = FALSE;
  7171. FileRunIndex += 1;
  7172. RangeRunIndex += 1;
  7173. } while (NtfsGetSequentialMcbEntry( &Scb->Mcb, &RangePtr, RangeRunIndex, &Vcn, &Lcn, &ClusterCount));
  7174. //
  7175. // We successfully retrieved extent info to the end of the allocation.
  7176. //
  7177. Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[FileRunIndex]);
  7178. Status = STATUS_SUCCESS;
  7179. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  7180. NtfsRaiseStatus( IrpContext,
  7181. STATUS_INVALID_USER_BUFFER,
  7182. NULL,
  7183. NULL );
  7184. }
  7185. } finally {
  7186. DebugUnwind( NtfsGetRetrievalPointers );
  7187. //
  7188. // Release resources.
  7189. //
  7190. NtfsReleaseScb( IrpContext, Scb );
  7191. if (CleanupAttributeContext) {
  7192. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  7193. }
  7194. DebugTrace( -1, Dbg, ("NtfsGetRetrievalPointers -> VOID\n") );
  7195. }
  7196. //
  7197. // If nothing raised then complete the irp.
  7198. //
  7199. NtfsCompleteRequest( IrpContext, Irp, Status );
  7200. return Status;
  7201. }
  7202. //
  7203. // Local Support Routine
  7204. //
  7205. NTSTATUS
  7206. NtfsGetMftRecord (
  7207. IN PIRP_CONTEXT IrpContext,
  7208. IN PIRP Irp
  7209. )
  7210. /*++
  7211. Routine Description:
  7212. This routine returns a copy of the requested File Record Segment. A
  7213. hint File Reference Number is passed in. If the hint File Record
  7214. Segment is "not in use" then the MFT bitmap is scanned backwards
  7215. from the hint until an "in use" File Record Segment is found. This
  7216. File Record Segment is then returned along with the identifying File Reference Number.
  7217. Input = the LONGLONG File Reference Number is passed in through the input buffer.
  7218. Output = the FILE_RECORD data structure is returned through the output buffer.
  7219. Arguments:
  7220. Irp - Supplies the Irp being processed.
  7221. Return Value:
  7222. NTSTATUS - The return status for the operation.
  7223. --*/
  7224. {
  7225. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  7226. PIO_STACK_LOCATION IrpSp;
  7227. ULONG FsControlCode;
  7228. PFILE_OBJECT FileObject;
  7229. TYPE_OF_OPEN TypeOfOpen;
  7230. PVCB Vcb;
  7231. PFCB Fcb;
  7232. PSCB Scb;
  7233. PCCB Ccb;
  7234. PNTFS_FILE_RECORD_INPUT_BUFFER GetFileRecord;
  7235. ULONG GetFileRecordLength;
  7236. PNTFS_FILE_RECORD_OUTPUT_BUFFER FileRecord;
  7237. ULONG FileRecordLength;
  7238. ULONG FileReferenceNumber;
  7239. PFILE_RECORD_SEGMENT_HEADER MftBuffer;
  7240. PBCB Bcb = NULL;
  7241. PBCB BitmapBcb = NULL;
  7242. BOOLEAN AcquiredMft = FALSE;
  7243. RTL_BITMAP Bitmap;
  7244. LONG BaseIndex;
  7245. LONG Index;
  7246. LONGLONG StartingByte;
  7247. PUCHAR BitmapBuffer;
  7248. ULONG SizeToMap;
  7249. ULONG BytesToCopy;
  7250. //
  7251. // Get the current Irp stack location and save some references.
  7252. //
  7253. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7254. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  7255. DebugTrace( +1, Dbg, ("NtfsGetMftRecord, FsControlCode = %08lx\n", FsControlCode) );
  7256. //
  7257. // Extract and decode the file object and check for type of open.
  7258. //
  7259. FileObject = IrpSp->FileObject;
  7260. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  7261. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  7262. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  7263. return STATUS_ACCESS_DENIED;
  7264. }
  7265. //
  7266. // Get the input & output buffer lengths and pointers.
  7267. //
  7268. GetFileRecordLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  7269. GetFileRecord = (PNTFS_FILE_RECORD_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  7270. FileRecordLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  7271. FileRecord = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;;
  7272. //
  7273. // Check for a minimum length on the input and ouput buffers.
  7274. //
  7275. if ((GetFileRecordLength < sizeof(NTFS_FILE_RECORD_INPUT_BUFFER)) ||
  7276. (FileRecordLength < sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER))) {
  7277. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  7278. return STATUS_BUFFER_TOO_SMALL;
  7279. }
  7280. FileRecordLength -= FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer);
  7281. FileReferenceNumber = GetFileRecord->FileReferenceNumber.LowPart;
  7282. //
  7283. // Make this request synchronous.
  7284. //
  7285. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  7286. //
  7287. // Acquire the vcb to test for dismounted volume
  7288. //
  7289. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  7290. try {
  7291. LONGLONG ValidDataLength;
  7292. //
  7293. // Synchronize the lookup by acquiring the Mft. First test the vcb we were
  7294. // called with in order to check for dismount. The MftScb may have already been
  7295. // torn down.
  7296. //
  7297. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  7298. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  7299. }
  7300. NtfsAcquireSharedScb( IrpContext, Vcb->MftScb );
  7301. AcquiredMft = TRUE;
  7302. //
  7303. // Raise if the File Reference Number is not within the MFT valid data length.
  7304. //
  7305. ValidDataLength = Vcb->MftScb->Header.ValidDataLength.QuadPart;
  7306. if (FileReferenceNumber >= (ValidDataLength / Vcb->BytesPerFileRecordSegment)) {
  7307. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  7308. }
  7309. //
  7310. // Fill in the record size and determine how much of it we can copy.
  7311. //
  7312. FileRecord->FileRecordLength = Vcb->BytesPerFileRecordSegment;
  7313. if (FileRecordLength >= Vcb->BytesPerFileRecordSegment) {
  7314. BytesToCopy = Vcb->BytesPerFileRecordSegment;
  7315. Status = STATUS_SUCCESS;
  7316. } else {
  7317. BytesToCopy = FileRecordLength;
  7318. Status = STATUS_BUFFER_OVERFLOW;
  7319. }
  7320. //
  7321. // If it is the MFT file record then just get it and we are done.
  7322. //
  7323. if (FileReferenceNumber == 0) {
  7324. NTSTATUS ErrorStatus;
  7325. try {
  7326. NtfsMapStream( IrpContext,
  7327. Vcb->MftScb,
  7328. 0,
  7329. Vcb->BytesPerFileRecordSegment,
  7330. &Bcb,
  7331. (PVOID *)&MftBuffer );
  7332. } except ( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &ErrorStatus )) {
  7333. //
  7334. // Clear the status field in the IrpContext. We're going to retry in the mirror
  7335. //
  7336. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  7337. NtfsMapStream( IrpContext,
  7338. Vcb->Mft2Scb,
  7339. 0,
  7340. Vcb->BytesPerFileRecordSegment,
  7341. &Bcb,
  7342. (PVOID *)&MftBuffer );
  7343. }
  7344. //
  7345. // Return the File Reference Number and the File Record.
  7346. //
  7347. RtlCopyMemory(FileRecord->FileRecordBuffer, MftBuffer, BytesToCopy);
  7348. FileRecord->FileReferenceNumber.QuadPart = 0;
  7349. try_return( Status );
  7350. }
  7351. //
  7352. // Scan through the MFT Bitmap to find an "in use" file.
  7353. //
  7354. while (FileReferenceNumber > 0) {
  7355. //
  7356. // Compute some values for the bitmap, convert the index to the offset of
  7357. // this page and get the base index for the File Reference number. Then
  7358. // map the page in the bitmap that contains the file record. Note we have to convert
  7359. // from bits to bytes to find it.
  7360. //
  7361. Index = FileReferenceNumber & (BITS_PER_PAGE - 1);
  7362. BaseIndex = FileReferenceNumber - Index;
  7363. StartingByte = BlockAlignTruncate( FileReferenceNumber / 8 , PAGE_SIZE );
  7364. SizeToMap = min( PAGE_SIZE, (ULONG)(Vcb->MftBitmapScb->Header.ValidDataLength.QuadPart - StartingByte) );
  7365. NtfsMapStream( IrpContext,
  7366. Vcb->MftBitmapScb,
  7367. StartingByte,
  7368. SizeToMap,
  7369. &BitmapBcb,
  7370. &BitmapBuffer );
  7371. RtlInitializeBitMap(&Bitmap, (PULONG)BitmapBuffer, SizeToMap * 8);
  7372. //
  7373. // Scan thru this page for an "in use" File Record.
  7374. //
  7375. for (; Index >= 0; Index --) {
  7376. if (RtlCheckBit(&Bitmap, Index)) {
  7377. NTSTATUS ErrorStatus;
  7378. //
  7379. // Found one "in use" on this page so get it and we are done.
  7380. //
  7381. try {
  7382. NtfsMapStream( IrpContext,
  7383. Vcb->MftScb,
  7384. Int64ShllMod32(BaseIndex + Index, Vcb->MftShift),
  7385. Vcb->BytesPerFileRecordSegment,
  7386. &Bcb,
  7387. (PVOID *)&MftBuffer );
  7388. } except (NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &ErrorStatus)) {
  7389. //
  7390. // Reset status for retry in the mirror
  7391. //
  7392. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  7393. NtfsMapStream( IrpContext,
  7394. Vcb->Mft2Scb,
  7395. Int64ShllMod32(BaseIndex + Index, Vcb->MftShift),
  7396. Vcb->BytesPerFileRecordSegment,
  7397. &Bcb,
  7398. (PVOID *)&MftBuffer );
  7399. }
  7400. //
  7401. // Return the File Reference Number and the File Record.
  7402. //
  7403. RtlCopyMemory(FileRecord->FileRecordBuffer, MftBuffer, BytesToCopy);
  7404. FileRecord->FileReferenceNumber.QuadPart = BaseIndex + Index;
  7405. try_return( Status );
  7406. }
  7407. }
  7408. //
  7409. // Cleanup for next time through and decrement the File Reference Number.
  7410. //
  7411. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  7412. FileReferenceNumber = BaseIndex - 1;
  7413. }
  7414. try_exit: NOTHING;
  7415. Irp->IoStatus.Information =
  7416. FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) +
  7417. BytesToCopy;
  7418. } finally {
  7419. //
  7420. // Release resources and exit.
  7421. //
  7422. NtfsUnpinBcb( IrpContext, &BitmapBcb );
  7423. NtfsUnpinBcb( IrpContext, &Bcb );
  7424. if (AcquiredMft) {
  7425. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  7426. }
  7427. NtfsReleaseVcb( IrpContext, Vcb );
  7428. DebugTrace( -1, Dbg, ("NtfsGetMftRecord: Exit\n") );
  7429. }
  7430. //
  7431. // If nothing raised then complete the Irp.
  7432. //
  7433. NtfsCompleteRequest( IrpContext, Irp, Status );
  7434. DebugTrace( -1, Dbg, ("NtfsGetMftRecord -> VOID\n") );
  7435. return Status;
  7436. }
  7437. //
  7438. // Local support routine
  7439. //
  7440. NTSTATUS
  7441. NtfsIsVolumeDirty (
  7442. IN PIRP_CONTEXT IrpContext,
  7443. IN PIRP Irp
  7444. )
  7445. /*++
  7446. Routine Description:
  7447. This routine returns the dirty state of the volume.
  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;
  7455. TYPE_OF_OPEN TypeOfOpen;
  7456. PVCB Vcb;
  7457. PFCB Fcb;
  7458. PSCB Scb;
  7459. PCCB Ccb;
  7460. PULONG VolumeState;
  7461. PVOLUME_INFORMATION VolumeInfo;
  7462. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  7463. //
  7464. // Get the current stack location and extract the output
  7465. // buffer information.
  7466. //
  7467. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7468. //
  7469. // Get a pointer to the output buffer. Look at the system buffer field in the
  7470. // irp first. Then the Irp Mdl.
  7471. //
  7472. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  7473. VolumeState = Irp->AssociatedIrp.SystemBuffer;
  7474. } else if (Irp->MdlAddress != NULL) {
  7475. VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  7476. if (VolumeState == NULL) {
  7477. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  7478. return STATUS_INSUFFICIENT_RESOURCES;
  7479. }
  7480. } else {
  7481. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  7482. return STATUS_INVALID_USER_BUFFER;
  7483. }
  7484. //
  7485. // Make sure the output buffer is large enough and then initialize
  7486. // the answer to be that the volume isn't corrupt.
  7487. //
  7488. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
  7489. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  7490. return STATUS_INVALID_PARAMETER;
  7491. }
  7492. *VolumeState = 0;
  7493. //
  7494. // Decode the file object. We don't care to raise on dismounts here
  7495. // because we check for that further down anyway. Hence, RaiseOnError=FALSE.
  7496. //
  7497. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  7498. if (TypeOfOpen != UserVolumeOpen) {
  7499. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  7500. return STATUS_INVALID_PARAMETER;
  7501. }
  7502. //
  7503. // Acquire the Scb shared.
  7504. //
  7505. NtfsAcquireSharedScb( IrpContext, Scb );
  7506. //
  7507. // Make sure the volume is still mounted.
  7508. //
  7509. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  7510. NtfsReleaseScb( IrpContext, Scb );
  7511. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  7512. return STATUS_VOLUME_DISMOUNTED;
  7513. }
  7514. //
  7515. // Look up the VOLUME_INFORMATION attribute.
  7516. //
  7517. NtfsInitializeAttributeContext( &Context );
  7518. //
  7519. // Use a try-finally to perform cleanup.
  7520. //
  7521. try {
  7522. if (!NtfsLookupAttributeByCode( IrpContext,
  7523. Vcb->VolumeDasdScb->Fcb,
  7524. &Vcb->VolumeDasdScb->Fcb->FileReference,
  7525. $VOLUME_INFORMATION,
  7526. &Context )) {
  7527. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  7528. }
  7529. //
  7530. // Return the volume state and the size of the returned data.
  7531. //
  7532. VolumeInfo = (PVOLUME_INFORMATION) NtfsAttributeValue( NtfsFoundAttribute( &Context ));
  7533. if (FlagOn( VolumeInfo->VolumeFlags, VOLUME_DIRTY )) {
  7534. SetFlag( *VolumeState, VOLUME_IS_DIRTY );
  7535. }
  7536. if (FlagOn( VolumeInfo->VolumeFlags, VOLUME_UPGRADE_ON_MOUNT )) {
  7537. SetFlag( *VolumeState, VOLUME_UPGRADE_SCHEDULED );
  7538. }
  7539. Irp->IoStatus.Information = sizeof( ULONG );
  7540. } finally {
  7541. NtfsReleaseScb( IrpContext, Scb );
  7542. NtfsCleanupAttributeContext( IrpContext, &Context );
  7543. DebugUnwind( NtfsIsVolumeDirty );
  7544. }
  7545. //
  7546. // If this is an abnormal termination then undo our work, otherwise
  7547. // complete the irp
  7548. //
  7549. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  7550. return STATUS_SUCCESS;
  7551. }
  7552. //
  7553. // Local support routine
  7554. //
  7555. NTSTATUS
  7556. NtfsSetExtendedDasdIo (
  7557. IN PIRP_CONTEXT IrpContext,
  7558. IN PIRP Irp
  7559. )
  7560. /*++
  7561. Routine Description:
  7562. This routine will mark a Dasd handle to perform IO outside the logical bounds of
  7563. the partition. Any subsequent IO will be passed to the driver which can either
  7564. complete it or return an error.
  7565. Arguments:
  7566. Irp - Supplies the Irp to process
  7567. Return Value:
  7568. NTSTATUS - The return status for the operation
  7569. --*/
  7570. {
  7571. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7572. TYPE_OF_OPEN TypeOfOpen;
  7573. PVCB Vcb;
  7574. PFCB Fcb;
  7575. PSCB Scb;
  7576. PCCB Ccb;
  7577. PAGED_CODE();
  7578. //
  7579. // Decode the file object
  7580. //
  7581. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  7582. //
  7583. // Make sure this is a volume open.
  7584. //
  7585. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  7586. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  7587. return STATUS_ACCESS_DENIED;
  7588. }
  7589. //
  7590. // Mark the Ccb for extended Io and return.
  7591. //
  7592. SetFlag( Ccb->Flags, CCB_FLAG_ALLOW_XTENDED_DASD_IO );
  7593. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  7594. return STATUS_SUCCESS;
  7595. }
  7596. //
  7597. // Local support routine
  7598. //
  7599. NTSTATUS
  7600. NtfsSetReparsePoint (
  7601. IN PIRP_CONTEXT IrpContext,
  7602. IN PIRP Irp
  7603. )
  7604. /*++
  7605. Routine Description:
  7606. This routine sets the reparse point attribute at the file object entry
  7607. specified in the IRP.
  7608. NtfsSetReparsePoint does not care whether the base file object is a user file or a
  7609. user directory.
  7610. If the file object has the FILE_ATTRIBUTE_REPARSE_POINT bit set then the
  7611. $REPARSE_POINT attribute is expected to be in the file.
  7612. If this file object already is a reparse point, and the tag of the incomming
  7613. reparse point request coincides with that present in existing $REPARSE_POINT,
  7614. then the contents of the $REPARSE_POINT attribute present will be overwritten.
  7615. There is to be an IN buffer to bring the caller's data for the call.
  7616. This function inserts an entry into the reparse point table.
  7617. Arguments:
  7618. IrpContext - Supplies the Irp context of the call
  7619. Irp - Supplies the Irp to process
  7620. Return Value:
  7621. NTSTATUS - The return status for the operation
  7622. --*/
  7623. {
  7624. NTSTATUS Status = STATUS_SUCCESS;
  7625. PIO_STACK_LOCATION IrpSp;
  7626. ULONG FsControlCode;
  7627. TYPE_OF_OPEN TypeOfOpen;
  7628. PVCB Vcb;
  7629. PFCB Fcb;
  7630. PSCB Scb;
  7631. PCCB Ccb;
  7632. PBCB Bcb = NULL; // does not get initialized below in NtfsDecodeFileObject
  7633. PREPARSE_DATA_BUFFER ReparseBuffer = NULL;
  7634. PREPARSE_GUID_DATA_BUFFER ReparseGuidBuffer = NULL;
  7635. ULONG ReparseTag;
  7636. USHORT ReparseDataLength = 0; // invalid value as it denotes no data
  7637. ULONG InputBufferLength = 0; // invalid value as we need an input buffer
  7638. ULONG OutputBufferLength = 0; // only valid value as we have no output buffer
  7639. ULONG IncomingFileAttributes = 0; // invalid value
  7640. ULONG IncomingReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; // invalid value
  7641. BOOLEAN CleanupAttributeContext = FALSE;
  7642. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  7643. BOOLEAN PagingIoAcquired = FALSE;
  7644. ASSERT_IRP_CONTEXT( IrpContext );
  7645. ASSERT_IRP( Irp );
  7646. PAGED_CODE();
  7647. //
  7648. // Get the current Irp stack location
  7649. //
  7650. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  7651. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  7652. DebugTrace( +1, Dbg, ("NtfsSetReparsePoint, FsControlCode = %08lx\n", FsControlCode) );
  7653. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  7654. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  7655. //
  7656. // Decode all the relevant File System data structures.
  7657. //
  7658. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  7659. IrpSp->FileObject,
  7660. &Vcb,
  7661. &Fcb,
  7662. &Scb,
  7663. &Ccb,
  7664. TRUE ); // Raise an exeption if error is encountered
  7665. //
  7666. // Check for the correct type of open.
  7667. //
  7668. //
  7669. // See that we have a file or a directory open.
  7670. //
  7671. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  7672. //
  7673. // Return an invalid parameter error.
  7674. //
  7675. Status = STATUS_INVALID_PARAMETER;
  7676. //
  7677. // Return to caller.
  7678. //
  7679. NtfsCompleteRequest( IrpContext, Irp, Status );
  7680. DebugTrace( 0, Dbg, ("Invalid parameter passed by caller.\n") );
  7681. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7682. return Status;
  7683. }
  7684. //
  7685. // The caller has FILE_SPECIAL_ACCESS. The NTFS driver enforces access checks more stringent
  7686. // than FILE_ANY_ACCESS:
  7687. // (a) FILE_WRITE_DATA or FILE_WRITE_ATTRIBUTES_ACCESS
  7688. //
  7689. if (!FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS ) &&
  7690. //
  7691. // Temporary KLUDGE for DavePr.
  7692. // The Ccb->AccessFlags and the FileObject->WriteAccess may not coincide as a
  7693. // filter may change the "visible" file object after the open. The Ccb flags do
  7694. // not change after open.
  7695. //
  7696. !IrpSp->FileObject->WriteAccess) {
  7697. //
  7698. // Return access denied.
  7699. //
  7700. Status = STATUS_ACCESS_DENIED;
  7701. //
  7702. // Return to caller.
  7703. //
  7704. NtfsCompleteRequest( IrpContext, Irp, Status );
  7705. DebugTrace( 0, Dbg, ("Ccb->AccessFlags %x\n", Ccb->AccessFlags) );
  7706. DebugTrace( 0, Dbg, ("Caller did not have the appropriate access rights.\n") );
  7707. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7708. return Status;
  7709. }
  7710. ASSERT_VCB( Vcb );
  7711. ASSERT_FCB( Fcb );
  7712. ASSERT_SCB( Scb );
  7713. ASSERT_CCB( Ccb );
  7714. //
  7715. // Read only volumes stay read only.
  7716. //
  7717. if (NtfsIsVolumeReadOnly( Vcb )) {
  7718. Status = STATUS_MEDIA_WRITE_PROTECTED;
  7719. NtfsCompleteRequest( IrpContext, Irp, Status );
  7720. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7721. return Status;
  7722. }
  7723. if (!NtfsVolumeVersionCheck( Vcb, NTFS_REPARSE_POINT_VERSION )) {
  7724. //
  7725. // Return a volume not upgraded error.
  7726. //
  7727. Status = STATUS_VOLUME_NOT_UPGRADED;
  7728. //
  7729. // Return to caller.
  7730. //
  7731. NtfsCompleteRequest( IrpContext, Irp, Status );
  7732. DebugTrace( 0, Dbg, ("Non-upgraded volume passed by caller.\n") );
  7733. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7734. return Status;
  7735. }
  7736. //
  7737. // Get the length of the input and output buffers.
  7738. //
  7739. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  7740. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  7741. DebugTrace( 0, Dbg, ("InputBufferLength %08lx [d]%08d OutputBufferLength %08lx\n", InputBufferLength, InputBufferLength, OutputBufferLength) );
  7742. //
  7743. // Do not allow output buffer in the set command.
  7744. //
  7745. if (OutputBufferLength > 0) {
  7746. //
  7747. // Return an invalid parameter error.
  7748. //
  7749. Status = STATUS_INVALID_PARAMETER;
  7750. //
  7751. // Return to caller.
  7752. //
  7753. NtfsCompleteRequest( IrpContext, Irp, Status );
  7754. DebugTrace( 0, Dbg, ("Non-null output buffer.\n") );
  7755. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7756. return Status;
  7757. }
  7758. //
  7759. // Zero the Information field in IoStatus.
  7760. //
  7761. Irp->IoStatus.Information = 0;
  7762. //
  7763. // Verify that we have the required system input buffer.
  7764. //
  7765. if (Irp->AssociatedIrp.SystemBuffer == NULL) {
  7766. //
  7767. // Return an invalid buffer error.
  7768. //
  7769. Status = STATUS_INVALID_BUFFER_SIZE;
  7770. //
  7771. // Return to caller.
  7772. //
  7773. NtfsCompleteRequest( IrpContext, Irp, Status );
  7774. DebugTrace( 0, Dbg, ("Null buffer passed by system.\n") );
  7775. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7776. return Status;
  7777. }
  7778. Status = NtfsValidateReparsePointBuffer( InputBufferLength,
  7779. (PREPARSE_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer );
  7780. if (!NT_SUCCESS( Status )) {
  7781. //
  7782. // Return to caller.
  7783. //
  7784. NtfsCompleteRequest( IrpContext, Irp, Status );
  7785. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7786. return Status;
  7787. }
  7788. //
  7789. // Get the header information brought in the input buffer.
  7790. // While all the headers coincide in the layout of the first three fields we are home free.
  7791. //
  7792. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseTag) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseTag) );
  7793. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseDataLength) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseDataLength) );
  7794. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, Reserved) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, Reserved) );
  7795. ReparseBuffer = (PREPARSE_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  7796. ReparseTag = ReparseBuffer->ReparseTag;
  7797. ReparseDataLength = ReparseBuffer->ReparseDataLength;
  7798. ReparseGuidBuffer = (PREPARSE_GUID_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  7799. DebugTrace( 0, Dbg, ("ReparseTag = %08lx, ReparseDataLength = [x]%08lx [d]%08ld\n", ReparseTag, ReparseDataLength, ReparseDataLength) );
  7800. //
  7801. // NTFS directory junctions are only to be set at directories and have a valid buffer.
  7802. //
  7803. if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  7804. HANDLE TestHandle;
  7805. OBJECT_ATTRIBUTES Oa;
  7806. IO_STATUS_BLOCK Iosb;
  7807. UNICODE_STRING Path;
  7808. //
  7809. // The tag needs to come together with a UserDirectoryOpen mode.
  7810. //
  7811. if (TypeOfOpen != UserDirectoryOpen) {
  7812. Status = STATUS_NOT_A_DIRECTORY;
  7813. //
  7814. // Return to caller.
  7815. //
  7816. NtfsCompleteRequest( IrpContext, Irp, Status );
  7817. DebugTrace( 0, Dbg, ("Cannot set a mount point at a non-directory.\n") );
  7818. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7819. return Status;
  7820. }
  7821. //
  7822. // While we don't hold any of our resources open the target path to
  7823. // check what it points to. We only allow mount points to local
  7824. // disks and cdroms
  7825. //
  7826. Path.Length = Path.MaximumLength = ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength;
  7827. Path.Buffer = &ReparseBuffer->MountPointReparseBuffer.PathBuffer[0];
  7828. if (Path.Buffer[ (Path.Length / sizeof( WCHAR )) - 1] == L'\\') {
  7829. Path.Length -= sizeof( WCHAR );
  7830. }
  7831. //
  7832. // Set the call self flag so status can't wait is handled in the create and
  7833. // not returned back
  7834. //
  7835. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  7836. InitializeObjectAttributes( &Oa, &Path, OBJ_CASE_INSENSITIVE, NULL, NULL );
  7837. Status = ZwCreateFile( &TestHandle,
  7838. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  7839. &Oa,
  7840. &Iosb,
  7841. NULL,
  7842. FILE_ATTRIBUTE_NORMAL,
  7843. FILE_SHARE_READ | FILE_SHARE_WRITE,
  7844. FILE_OPEN,
  7845. FILE_SYNCHRONOUS_IO_NONALERT,
  7846. NULL,
  7847. 0 );
  7848. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  7849. if (NT_SUCCESS( Status )) {
  7850. PFILE_OBJECT TestFileObject;
  7851. Status = ObReferenceObjectByHandle( TestHandle,
  7852. FILE_READ_ATTRIBUTES,
  7853. *IoFileObjectType,
  7854. KernelMode,
  7855. (PVOID *) &TestFileObject,
  7856. NULL );
  7857. if (NT_SUCCESS( Status )) {
  7858. if ((TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_DISK) &&
  7859. (TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_CD_ROM) &&
  7860. (TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK) &&
  7861. (TestFileObject->DeviceObject->DeviceType != FILE_DEVICE_TAPE)) {
  7862. Status = STATUS_IO_REPARSE_DATA_INVALID;
  7863. }
  7864. ObDereferenceObject( TestFileObject );
  7865. }
  7866. ZwClose( TestHandle );
  7867. } else if (FlagOn( Ccb->AccessFlags, RESTORE_ACCESS)) {
  7868. //
  7869. // Allow restore operators to create a reparse point - even if the target doesn't
  7870. // exist
  7871. //
  7872. Status = STATUS_SUCCESS;
  7873. }
  7874. if (!NT_SUCCESS( Status )) {
  7875. //
  7876. // Return to caller.
  7877. //
  7878. NtfsCompleteRequest( IrpContext, Irp, STATUS_IO_REPARSE_DATA_INVALID );
  7879. DebugTrace( 0, Dbg, ("Name grafting data buffer is incorrect.\n") );
  7880. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  7881. return STATUS_IO_REPARSE_DATA_INVALID;
  7882. }
  7883. }
  7884. //
  7885. // We set the IrpContext flag to indicate that we can wait, making this a synchronous
  7886. // call.
  7887. //
  7888. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  7889. //
  7890. // Capture the source information.
  7891. //
  7892. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  7893. //
  7894. // The parameters look good. We begin real work.
  7895. //
  7896. // Now it is time ot use a try-finally to facilitate cleanup.
  7897. //
  7898. try {
  7899. //
  7900. // If there is a paging io resource then acquire it exclusively. This is to
  7901. // protect us from a collided page wait if we go to convert another stream
  7902. // to non-resident at the same time a different thread is faulting into it.
  7903. //
  7904. if (Scb->Header.PagingIoResource != NULL) {
  7905. NtfsAcquirePagingResourceExclusive( IrpContext, Scb, TRUE );
  7906. PagingIoAcquired = TRUE;
  7907. }
  7908. //
  7909. // Acquire the Fcb exclusively. The volume could've gotten dismounted,
  7910. // so check that too.
  7911. //
  7912. NtfsAcquireExclusiveScb( IrpContext, Scb );
  7913. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  7914. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  7915. }
  7916. //
  7917. // If the file object is a directory, we want it to be empty and to remain
  7918. // empty. Thus our check after the Fcb has been acquired. As reparse points
  7919. // impede the normal flow down through the name hierarchy we want to make
  7920. // it difficult for a caller to inadvertently block a name subtree by
  7921. // establishing a reparse point.
  7922. //
  7923. if (TypeOfOpen == UserDirectoryOpen) {
  7924. BOOLEAN NonEmptyIndex;
  7925. //
  7926. // The directory is deleteable if all the $INDEX_ROOT attributes are empty.
  7927. // Just what we need to establish a reparse point.
  7928. //
  7929. if (!NtfsIsFileDeleteable( IrpContext, Fcb, &NonEmptyIndex )) {
  7930. //
  7931. // This directory is not empty. Do not establish a reparse point in it.
  7932. // Return to caller an invalid parameter error.
  7933. //
  7934. DebugTrace( 0, Dbg, ("Non-empty directory used by caller.\n") );
  7935. Status = STATUS_DIRECTORY_NOT_EMPTY;
  7936. //
  7937. // Return to caller.
  7938. //
  7939. try_return( Status );
  7940. }
  7941. }
  7942. //
  7943. // EA attributes and reparse points are not to exist simultaneously.
  7944. // If the non-reparse point file object has EA attributes, we do not set
  7945. // a reparse point.
  7946. // We verify this condition after the Fcb resource has been acquired to
  7947. // impede a change in this state till we complete.
  7948. //
  7949. if ((!FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) &&
  7950. (Fcb->Info.PackedEaSize > 0)) {
  7951. //
  7952. // This non-reparse point file object has EAs. Do not establish a
  7953. // reparse point in it.
  7954. // Return to caller STATUS_EAS_NOT_SUPPORTED.
  7955. //
  7956. DebugTrace( 0, Dbg, ("EAs present, cannot establish reparse point.\n") );
  7957. Status = STATUS_EAS_NOT_SUPPORTED;
  7958. //
  7959. // Return to caller.
  7960. //
  7961. try_return( Status );
  7962. }
  7963. //
  7964. // Remember the values of the file attribute flags and of the reparse tag
  7965. // for abnormal termination recovery.
  7966. //
  7967. IncomingFileAttributes = Fcb->Info.FileAttributes;
  7968. IncomingReparsePointTag = Fcb->Info.ReparsePointTag;
  7969. //
  7970. // Initialize the context structure to search for the attribute.
  7971. //
  7972. NtfsInitializeAttributeContext( &AttributeContext );
  7973. CleanupAttributeContext = TRUE;
  7974. //
  7975. // Establish whether the file has the $REPARSE_POINT attribute.
  7976. // If it exists, it will be updated with the new data.
  7977. //
  7978. if (NtfsLookupAttributeByCode( IrpContext,
  7979. Fcb,
  7980. &Fcb->FileReference,
  7981. $REPARSE_POINT,
  7982. &AttributeContext )) {
  7983. ULONG ValueLength = 0;
  7984. if (!FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  7985. DebugTrace( 0, Dbg, ("The FILE_ATTRIBUTE_REPARSE_POINT flag is not set.\n") );
  7986. //
  7987. // Should not happen. Raise an exeption as we are in an inconsistent state.
  7988. // The presence of the $REPARSE_POINT attribute says that the flag has to
  7989. // be set.
  7990. //
  7991. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  7992. }
  7993. //
  7994. // Verify that the incomming tag value matches the tag value present in
  7995. // the $REPARSE_POINT attribute.
  7996. //
  7997. {
  7998. PREPARSE_GUID_DATA_BUFFER ReparseBufferTwo = NULL;
  7999. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  8000. PVOID AttributeData = NULL;
  8001. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  8002. //
  8003. // Map the reparse point if the attribute is non-resident. Otherwise
  8004. // the attribute is already mapped and we have a Bcb in the attribute
  8005. // context.
  8006. //
  8007. if (NtfsIsAttributeResident( AttributeHeader )) {
  8008. //
  8009. // Point to the value of the arribute.
  8010. //
  8011. AttributeData = NtfsAttributeValue( AttributeHeader );
  8012. ValueLength = AttributeHeader->Form.Resident.ValueLength;
  8013. DebugTrace( 0, Dbg, ("Existing attribute is resident.\n") );
  8014. } else {
  8015. if (AttributeHeader->Form.Nonresident.FileSize > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  8016. NtfsRaiseStatus( IrpContext,STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8017. }
  8018. DebugTrace( 0, Dbg, ("Existing attribute is non-resident.\n") );
  8019. NtfsMapAttributeValue( IrpContext,
  8020. Fcb,
  8021. &AttributeData, // point to the value
  8022. &ValueLength,
  8023. &Bcb,
  8024. &AttributeContext );
  8025. }
  8026. //
  8027. // Verify that the two tag values match.
  8028. //
  8029. ReparseBufferTwo = (PREPARSE_GUID_DATA_BUFFER)AttributeData;
  8030. DebugTrace( 0, Dbg, ("Existing tag is [d]%03ld - New tag is [d]%03ld\n", ReparseTag, ReparseBufferTwo->ReparseTag) );
  8031. if (ReparseTag != ReparseBufferTwo->ReparseTag) {
  8032. //
  8033. // Return status STATUS_IO_REPARSE_TAG_MISMATCH
  8034. //
  8035. DebugTrace( 0, Dbg, ("Tag mismatch with the existing reparse point.\n") );
  8036. Status = STATUS_IO_REPARSE_TAG_MISMATCH;
  8037. try_return( Status );
  8038. }
  8039. //
  8040. // For non-Microsoft tags, verify that the GUIDs match.
  8041. //
  8042. if (!IsReparseTagMicrosoft( ReparseTag )) {
  8043. if (!((ReparseGuidBuffer->ReparseGuid.Data1 == ReparseBufferTwo->ReparseGuid.Data1) &&
  8044. (ReparseGuidBuffer->ReparseGuid.Data2 == ReparseBufferTwo->ReparseGuid.Data2) &&
  8045. (ReparseGuidBuffer->ReparseGuid.Data3 == ReparseBufferTwo->ReparseGuid.Data3) &&
  8046. (ReparseGuidBuffer->ReparseGuid.Data4[0] == ReparseBufferTwo->ReparseGuid.Data4[0]) &&
  8047. (ReparseGuidBuffer->ReparseGuid.Data4[1] == ReparseBufferTwo->ReparseGuid.Data4[1]) &&
  8048. (ReparseGuidBuffer->ReparseGuid.Data4[2] == ReparseBufferTwo->ReparseGuid.Data4[2]) &&
  8049. (ReparseGuidBuffer->ReparseGuid.Data4[3] == ReparseBufferTwo->ReparseGuid.Data4[3]) &&
  8050. (ReparseGuidBuffer->ReparseGuid.Data4[4] == ReparseBufferTwo->ReparseGuid.Data4[4]) &&
  8051. (ReparseGuidBuffer->ReparseGuid.Data4[5] == ReparseBufferTwo->ReparseGuid.Data4[5]) &&
  8052. (ReparseGuidBuffer->ReparseGuid.Data4[6] == ReparseBufferTwo->ReparseGuid.Data4[6]) &&
  8053. (ReparseGuidBuffer->ReparseGuid.Data4[7] == ReparseBufferTwo->ReparseGuid.Data4[7]))) {
  8054. //
  8055. // Return status STATUS_REPARSE_ATTRIBUTE_CONFLICT
  8056. //
  8057. DebugTrace( 0, Dbg, ("GUID mismatch with the existing reparse point.\n") );
  8058. Status = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
  8059. try_return( Status );
  8060. }
  8061. }
  8062. //
  8063. // Unpin the Bcb. The unpin routine checks for NULL.
  8064. //
  8065. NtfsUnpinBcb( IrpContext, &Bcb );
  8066. }
  8067. //
  8068. // If we're growing throttle ourselves through cc, we can't wait because we own resources
  8069. // here and this would deadlock
  8070. //
  8071. if (InputBufferLength > ValueLength) {
  8072. if (!CcCanIWrite(IrpSp->FileObject,
  8073. InputBufferLength - ValueLength,
  8074. FALSE,
  8075. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) {
  8076. BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE);
  8077. //
  8078. // PrePosting the irp will free the resources so fcb will not be acquired afterwards
  8079. //
  8080. NtfsPrePostIrp( IrpContext, Irp );
  8081. ASSERT( !NtfsIsExclusiveFcb( Fcb ) );
  8082. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE );
  8083. CcDeferWrite( IrpSp->FileObject,
  8084. (PCC_POST_DEFERRED_WRITE)NtfsAddToWorkque,
  8085. IrpContext,
  8086. Irp,
  8087. InputBufferLength - ValueLength,
  8088. Retrying );
  8089. try_return( Status = STATUS_PENDING );
  8090. }
  8091. }
  8092. //
  8093. // Update the value of the attribute.
  8094. //
  8095. NtfsChangeAttributeValue( IrpContext,
  8096. Fcb,
  8097. (ULONG) 0, // ValueOffset
  8098. (PVOID)(Irp->AssociatedIrp.SystemBuffer), // Value
  8099. InputBufferLength, // ValueLength
  8100. TRUE, // SetNewLength
  8101. TRUE, // LogNonresidentToo
  8102. FALSE, // CreateSectionUnderway
  8103. FALSE, // PreserveContext
  8104. &AttributeContext ); // Context
  8105. //
  8106. // Cleanup the attribute context state
  8107. //
  8108. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8109. CleanupAttributeContext = FALSE;
  8110. } else {
  8111. //
  8112. // The $REPARSE_POINT attribute is not present.
  8113. //
  8114. if (FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8115. DebugTrace( 0, Dbg, ("The FILE_ATTRIBUTE_REPARSE_POINT flag is set.\n") );
  8116. //
  8117. // Should not happen. Raise an exeption as we are in an inconsistent state.
  8118. // The absence of the $REPARSE_POINT attribute says that the flag has to
  8119. // not be set.
  8120. //
  8121. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8122. }
  8123. //
  8124. // throttle ourselves throuch cc
  8125. //
  8126. if (!CcCanIWrite(IrpSp->FileObject,
  8127. InputBufferLength,
  8128. FALSE,
  8129. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) {
  8130. BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE);
  8131. //
  8132. // PrePosting the irp will free the resources so fcb will not be acquired afterwards
  8133. //
  8134. NtfsPrePostIrp( IrpContext, Irp );
  8135. ASSERT( !NtfsIsExclusiveFcb( Fcb ) );
  8136. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE );
  8137. CcDeferWrite( IrpSp->FileObject,
  8138. (PCC_POST_DEFERRED_WRITE)NtfsAddToWorkque,
  8139. IrpContext,
  8140. Irp,
  8141. InputBufferLength,
  8142. Retrying );
  8143. try_return( Status = STATUS_PENDING );
  8144. }
  8145. //
  8146. // Insert the record into the reparse point index.
  8147. //
  8148. {
  8149. INDEX_KEY IndexKey;
  8150. INDEX_ROW IndexRow;
  8151. REPARSE_INDEX_KEY KeyValue;
  8152. //
  8153. // Acquire the ReparsePointIndex Scb. We still hold the target fcb resource,
  8154. // so the volume couldn't have gotten dismounted under us.
  8155. //
  8156. NtfsAcquireExclusiveScb( IrpContext, Vcb->ReparsePointTableScb );
  8157. ASSERT( NtfsIsExclusiveFcb( Fcb ));
  8158. ASSERT( !FlagOn( Vcb->ReparsePointTableScb->ScbState, SCB_STATE_VOLUME_DISMOUNTED ));
  8159. //
  8160. // Add the file Id to the reparse point index.
  8161. //
  8162. KeyValue.FileReparseTag = ReparseTag;
  8163. KeyValue.FileId = *(PLARGE_INTEGER)&Scb->Fcb->FileReference;
  8164. IndexKey.Key = (PVOID)&KeyValue;
  8165. IndexKey.KeyLength = sizeof(KeyValue);
  8166. IndexRow.KeyPart = IndexKey;
  8167. IndexRow.DataPart.DataLength = 0;
  8168. IndexRow.DataPart.Data = NULL;
  8169. //
  8170. // NtOfsAddRecords will raise if the file id already belongs in the index.
  8171. //
  8172. NtOfsAddRecords( IrpContext,
  8173. Vcb->ReparsePointTableScb,
  8174. 1, // adding one record to the index
  8175. &IndexRow,
  8176. FALSE ); // sequential insert
  8177. }
  8178. //
  8179. // Create the $REPARSE_POINT attribute with the data being sent in.
  8180. //
  8181. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8182. NtfsInitializeAttributeContext( &AttributeContext );
  8183. NtfsCreateAttributeWithValue( IrpContext,
  8184. Fcb,
  8185. $REPARSE_POINT,
  8186. NULL,
  8187. (PVOID) ( Irp->AssociatedIrp.SystemBuffer ),
  8188. InputBufferLength,
  8189. (USHORT) 0, // Attribute flags
  8190. NULL,
  8191. TRUE, // LogIt
  8192. &AttributeContext );
  8193. //
  8194. // Cleanup the attribute context state
  8195. //
  8196. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8197. CleanupAttributeContext = FALSE;
  8198. //
  8199. // Set the duplicate file attribute to Reparse Point.
  8200. //
  8201. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT );
  8202. //
  8203. // Set the ReparsePointTag field.
  8204. //
  8205. Fcb->Info.ReparsePointTag = ReparseTag;
  8206. //
  8207. // Set the change attribute flag.
  8208. //
  8209. ASSERTMSG( "conflict with flush",
  8210. NtfsIsSharedFcb( Fcb ) ||
  8211. (Fcb->PagingIoResource != NULL &&
  8212. NtfsIsSharedFcbPagingIo( Fcb )) );
  8213. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  8214. }
  8215. //
  8216. // Set the archive bit in the Ccb.
  8217. //
  8218. if (!IsDirectory( &Fcb->Info )) {
  8219. SetFlag( Ccb->Flags, CCB_FLAG_SET_ARCHIVE );
  8220. }
  8221. //
  8222. // Flag to set the change time in the Ccb.
  8223. //
  8224. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  8225. //
  8226. // Update the standard information in the file record to reflect its a reparse pt.
  8227. //
  8228. NtfsUpdateStandardInformation( IrpContext, Fcb );
  8229. //
  8230. // Post the change to the Usn Journal (on errors change is backed out)
  8231. //
  8232. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_REPARSE_POINT_CHANGE );
  8233. //
  8234. // Checkpoint the Txn to commit the changes.
  8235. //
  8236. NtfsCleanupTransactionAndCommit( IrpContext, STATUS_SUCCESS, TRUE );
  8237. try_exit: NOTHING;
  8238. } finally {
  8239. DebugUnwind( NtfsSetReparsePoint );
  8240. //
  8241. // Unpin the Bcb. The unpin routine checks for NULL.
  8242. //
  8243. NtfsUnpinBcb( IrpContext, &Bcb );
  8244. //
  8245. // Clean-up all the pertinent state.
  8246. //
  8247. if (CleanupAttributeContext) {
  8248. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8249. }
  8250. //
  8251. // Need to roll-back the value of the reparse point flag in case of
  8252. // problems. I leave the archive bit set anyway.
  8253. //
  8254. if (AbnormalTermination()) {
  8255. Fcb->Info.FileAttributes = IncomingFileAttributes;
  8256. Fcb->Info.ReparsePointTag = IncomingReparsePointTag;
  8257. }
  8258. //
  8259. // Release the paging io resource if held.
  8260. //
  8261. if (PagingIoAcquired) {
  8262. NtfsReleasePagingResource( IrpContext, Fcb );
  8263. }
  8264. }
  8265. if (Status != STATUS_PENDING) {
  8266. NtfsCompleteRequest( IrpContext, Irp, Status );
  8267. }
  8268. DebugTrace( -1, Dbg, ("NtfsSetReparsePoint -> %08lx\n", Status) );
  8269. return Status;
  8270. }
  8271. //
  8272. // Local support routine
  8273. //
  8274. NTSTATUS
  8275. NtfsGetReparsePoint (
  8276. IN PIRP_CONTEXT IrpContext,
  8277. IN PIRP Irp
  8278. )
  8279. /*++
  8280. Routine Description:
  8281. This routine finds the specified reparse point returning the value
  8282. of the corresponding attribute.
  8283. The value of the reparse point attribute is the linearized version of
  8284. the buffer sent in the NtfsSetReparsePoint call including the header
  8285. fields ReparseTag and ReparseDataLength. We retrieve all fields, unmodified,
  8286. so that the caller can decode it using the same buffer template used in the
  8287. set operation.
  8288. Arguments:
  8289. IrpContext - Supplies the Irp context of the call
  8290. Irp - Supplies the Irp to process
  8291. Return Value:
  8292. NTSTATUS - The return status for the operation
  8293. --*/
  8294. {
  8295. NTSTATUS Status = STATUS_SUCCESS;
  8296. PIO_STACK_LOCATION IrpSp;
  8297. ULONG FsControlCode;
  8298. TYPE_OF_OPEN TypeOfOpen;
  8299. PVCB Vcb;
  8300. PFCB Fcb;
  8301. PSCB Scb;
  8302. PCCB Ccb;
  8303. PBCB Bcb = NULL; // does not get initialized below in NtfsDecodeFileObject
  8304. PCHAR OutputBuffer = NULL;
  8305. ULONG OutputBufferLength = 0; // invalid value as we need an output buffer
  8306. ULONG InputBufferLength = 0; // invalid value as we need an input buffer
  8307. BOOLEAN CleanupAttributeContext = FALSE;
  8308. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  8309. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  8310. PATTRIBUTE_LIST_ENTRY AttributeListEntry = NULL;
  8311. ULONG AttributeLengthInBytes = 0;
  8312. PVOID AttributeData = NULL;
  8313. BOOLEAN ScbAcquired = FALSE;
  8314. ASSERT_IRP_CONTEXT( IrpContext );
  8315. ASSERT_IRP( Irp );
  8316. PAGED_CODE();
  8317. //
  8318. // Get the current Irp stack location
  8319. //
  8320. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  8321. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  8322. DebugTrace( +1, Dbg, ("NtfsGetReparsePoint, FsControlCode = %08lx\n", FsControlCode) );
  8323. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  8324. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  8325. //
  8326. // Decode all the relevant File System data structures.
  8327. //
  8328. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  8329. IrpSp->FileObject,
  8330. &Vcb,
  8331. &Fcb,
  8332. &Scb,
  8333. &Ccb,
  8334. TRUE ); // Raise an exeption if error is encountered
  8335. //
  8336. // Check for the correct type of open.
  8337. //
  8338. //
  8339. // See that we have a file or a directory open.
  8340. //
  8341. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  8342. //
  8343. // Return an invalid parameter error
  8344. //
  8345. Status = STATUS_INVALID_PARAMETER;
  8346. //
  8347. // Return to caller.
  8348. //
  8349. NtfsCompleteRequest( IrpContext, Irp, Status );
  8350. DebugTrace( 0, Dbg, ("Invalid parameter passed by caller\n") );
  8351. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8352. return Status;
  8353. }
  8354. ASSERT_VCB( Vcb );
  8355. ASSERT_FCB( Fcb );
  8356. ASSERT_SCB( Scb );
  8357. ASSERT_CCB( Ccb );
  8358. if (!NtfsVolumeVersionCheck( Vcb, NTFS_REPARSE_POINT_VERSION )) {
  8359. //
  8360. // Return a volume not upgraded error.
  8361. //
  8362. Status = STATUS_VOLUME_NOT_UPGRADED;
  8363. //
  8364. // Return to caller.
  8365. //
  8366. NtfsCompleteRequest( IrpContext, Irp, Status );
  8367. DebugTrace( 0, Dbg, ("Non-upgraded volume passed by caller.\n") );
  8368. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8369. return Status;
  8370. }
  8371. //
  8372. // Get the length of the output buffer.
  8373. //
  8374. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  8375. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  8376. DebugTrace( 0, Dbg, ("InputBufferLength %08lx [d]%08d OutputBufferLength %08lx\n", InputBufferLength, InputBufferLength, OutputBufferLength) );
  8377. //
  8378. // Do not allow input buffer in the get command.
  8379. //
  8380. if (InputBufferLength > 0) {
  8381. //
  8382. // Return an invalid parameter error.
  8383. //
  8384. Status = STATUS_INVALID_PARAMETER;
  8385. //
  8386. // Return to caller.
  8387. //
  8388. NtfsCompleteRequest( IrpContext, Irp, Status );
  8389. DebugTrace( 0, Dbg, ("Non-null input buffer.\n") );
  8390. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8391. return Status;
  8392. }
  8393. //
  8394. // Get a pointer to the output buffer. First look at the system buffer field in
  8395. // the IRP. Then look in the IRP Mdl.
  8396. //
  8397. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  8398. OutputBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
  8399. } else if (Irp->MdlAddress != NULL) {
  8400. OutputBuffer = (PCHAR)MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  8401. if (OutputBuffer == NULL) {
  8402. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  8403. return STATUS_INSUFFICIENT_RESOURCES;
  8404. }
  8405. } else {
  8406. //
  8407. // Return an invalid user buffer error.
  8408. //
  8409. Status = STATUS_INVALID_USER_BUFFER;
  8410. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  8411. DebugTrace( 0, Dbg, ("User buffer is not good.\n") );
  8412. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8413. return Status;
  8414. }
  8415. //
  8416. // Zero the Information field in IoStatus.
  8417. //
  8418. Irp->IoStatus.Information = 0;
  8419. //
  8420. // We set the IrpContext flag to indicate that we can wait, making htis a synchronous
  8421. // call.
  8422. //
  8423. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  8424. //
  8425. // Now it is time ot use a try-finally to facilitate cleanup.
  8426. //
  8427. try {
  8428. //
  8429. // We acquire the Scb in shared mode so that the underlying Fcb remains stable.
  8430. //
  8431. NtfsAcquireSharedScb( IrpContext, Scb );
  8432. ScbAcquired = TRUE;
  8433. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  8434. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  8435. }
  8436. //
  8437. // The parameters and boundary conditions look good and we have a reparse point.
  8438. // We begin real work.
  8439. //
  8440. // Find the reparse point attribute.
  8441. //
  8442. NtfsInitializeAttributeContext( &AttributeContext );
  8443. CleanupAttributeContext = TRUE;
  8444. if (!NtfsLookupAttributeByCode( IrpContext,
  8445. Fcb,
  8446. &Fcb->FileReference,
  8447. $REPARSE_POINT,
  8448. &AttributeContext )) {
  8449. DebugTrace( 0, Dbg, ("Can't find the $REPARSE_POINT attribute.\n") );
  8450. //
  8451. // Verify that the information in FileAttributes is consistent.
  8452. //
  8453. if (FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8454. DebugTrace( 0, Dbg, ("The Fcb says this IS a reparse point.\n") );
  8455. //
  8456. // Should not happen. Raise an exeption as we are in an inconsistent state.
  8457. // The attribute flag says that $REPARSE_POINT has to be present.
  8458. //
  8459. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8460. }
  8461. //
  8462. // Return STATUS_NOT_A_REPARSE_POINT
  8463. //
  8464. Status = STATUS_NOT_A_REPARSE_POINT;
  8465. try_return( Status );
  8466. }
  8467. //
  8468. // Find the size of the attribute.
  8469. // Determine whether we have enough buffer to return it to the caller.
  8470. //
  8471. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  8472. if (NtfsIsAttributeResident( AttributeHeader )) {
  8473. AttributeLengthInBytes = AttributeHeader->Form.Resident.ValueLength;
  8474. DebugTrace( 0, Dbg, ("Resident attribute with length %05lx\n", AttributeLengthInBytes) );
  8475. if (AttributeLengthInBytes > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  8476. //
  8477. // Return STATUS_IO_REPARSE_DATA_INVALID
  8478. //
  8479. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8480. DebugTrace( 0, Dbg, ("AttributeLengthInBytes is [x]%08lx is too long.\n", AttributeLengthInBytes) );
  8481. try_return( Status );
  8482. }
  8483. //
  8484. // Point to the value of the arribute.
  8485. //
  8486. AttributeData = NtfsAttributeValue( AttributeHeader );
  8487. ASSERT( Bcb == NULL );
  8488. } else {
  8489. ULONG Length;
  8490. if (AttributeHeader->Form.Nonresident.FileSize > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  8491. //
  8492. // Return STATUS_IO_REPARSE_DATA_INVALID
  8493. //
  8494. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8495. DebugTrace( 0, Dbg, ("Nonresident.FileSize is too long.\n") );
  8496. try_return( Status );
  8497. }
  8498. //
  8499. // Note that we coerse different LENGTHs
  8500. //
  8501. AttributeLengthInBytes = (ULONG)AttributeHeader->Form.Nonresident.FileSize;
  8502. DebugTrace( 0, Dbg, ("Non-resident attribute with length %05lx\n", AttributeLengthInBytes) );
  8503. //
  8504. // Map the attribute list if the attribute is non-resident. Otherwise the
  8505. // attribute is already mapped and we have a Bcb in the attribute context.
  8506. //
  8507. NtfsMapAttributeValue( IrpContext,
  8508. Fcb,
  8509. &AttributeData, // point to the value
  8510. &Length,
  8511. &Bcb,
  8512. &AttributeContext );
  8513. if (AttributeLengthInBytes != Length) {
  8514. DebugTrace( 0, Dbg, ("AttributeLengthInBytes %05lx and Length %05lx differ.\n", AttributeLengthInBytes, Length) );
  8515. }
  8516. ASSERT( AttributeLengthInBytes == Length );
  8517. }
  8518. DebugTrace( 0, Dbg, ("AttributeLengthInBytes is [d]%06ld %05lx\n", AttributeLengthInBytes, AttributeLengthInBytes) );
  8519. Status = NtfsValidateReparsePointBuffer( AttributeLengthInBytes,
  8520. AttributeData );
  8521. if (!NT_SUCCESS( Status )) {
  8522. leave;
  8523. }
  8524. if (AttributeLengthInBytes > OutputBufferLength) {
  8525. DebugTrace( 0, Dbg, ("Insufficient output buffer passed by caller.\n") );
  8526. //
  8527. // Check whether the fixed portion will fit.
  8528. //
  8529. if (OutputBufferLength < sizeof( REPARSE_GUID_DATA_BUFFER )) {
  8530. //
  8531. // This is the error path. Don't return anything.
  8532. //
  8533. try_return( Status = STATUS_BUFFER_TOO_SMALL );
  8534. } else {
  8535. Status = STATUS_BUFFER_OVERFLOW;
  8536. }
  8537. //
  8538. // Remember the smaller number of returned bytes.
  8539. //
  8540. AttributeLengthInBytes = OutputBufferLength;
  8541. }
  8542. //
  8543. // Copy the value of the reparse point attribute to the buffer.
  8544. // Return all the value including the system header fields (e.g., Tag and Length)
  8545. // stored at the beginning of the value of the reparse point attribute.
  8546. //
  8547. RtlCopyMemory( OutputBuffer,
  8548. AttributeData,
  8549. AttributeLengthInBytes );
  8550. //
  8551. // Set the information field to the length of the buffer returned.
  8552. // This tells the re-director to do the corresponding data transmission.
  8553. //
  8554. Irp->IoStatus.Information = AttributeLengthInBytes;
  8555. //
  8556. // Cleanup the attribute context state.
  8557. //
  8558. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8559. CleanupAttributeContext = FALSE;
  8560. try_exit: NOTHING;
  8561. } finally {
  8562. //
  8563. // Clean-up all the pertinent state.
  8564. //
  8565. DebugUnwind( NtfsGetReparsePoint );
  8566. if (CleanupAttributeContext) {
  8567. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  8568. }
  8569. //
  8570. // Unpin the Bcb ... in case you needed to pin it above.
  8571. // The unpin routine checks for NULL.
  8572. //
  8573. NtfsUnpinBcb( IrpContext, &Bcb );
  8574. //
  8575. // Relase the Fcb.
  8576. //
  8577. if (ScbAcquired) {
  8578. NtfsReleaseScb( IrpContext, Scb );
  8579. } else {
  8580. //
  8581. // We must have raised an exception in NtfsAcquireSharedFcb.
  8582. // Because we check for the existence of the file this must mean
  8583. // that it has been deleted from under us.
  8584. //
  8585. // Nothing is to be done as exception processing sets the correct
  8586. // return code.
  8587. //
  8588. }
  8589. }
  8590. NtfsCompleteRequest( IrpContext, Irp, Status );
  8591. DebugTrace( -1, Dbg, ("NtfsGetReparsePoint -> %08lx\n", Status) );
  8592. return Status;
  8593. }
  8594. //
  8595. // Local support routine
  8596. //
  8597. NTSTATUS
  8598. NtfsDeleteReparsePoint (
  8599. IN PIRP_CONTEXT IrpContext,
  8600. IN PIRP Irp
  8601. )
  8602. /*++
  8603. Routine Description:
  8604. This routine deletes a reparse point at the file object entry
  8605. specified in the IRP.
  8606. The IN buffer specified by the caller has the value of the Tag of the reparse point
  8607. being deleted, and no data, thus needing to have a value of zero for DataLength.
  8608. If the tags do not match the delete fails.
  8609. If the file object has the FILE_ATTRIBUTE_REPARSE_POINT bit set then the
  8610. $REPARSE_POINT attribute is expected to be in the file.
  8611. There is no OUT buffer sent by the caller.
  8612. This function deletes the corresponding entry from the reparse point table.
  8613. Arguments:
  8614. IrpContext - Supplies the Irp context of the call
  8615. Irp - Supplies the Irp to process
  8616. Return Value:
  8617. NTSTATUS - The return status for the operation
  8618. --*/
  8619. {
  8620. NTSTATUS Status = STATUS_SUCCESS;
  8621. PIO_STACK_LOCATION IrpSp;
  8622. ULONG FsControlCode;
  8623. TYPE_OF_OPEN TypeOfOpen;
  8624. PVCB Vcb;
  8625. PFCB Fcb;
  8626. PSCB Scb;
  8627. PSCB NonResidentScb = NULL;
  8628. PCCB Ccb;
  8629. PBCB Bcb = NULL; // does not get initialized below in NtfsDecodeFileObject
  8630. PREPARSE_DATA_BUFFER ReparseBuffer = NULL;
  8631. ULONG ReparseTag;
  8632. USHORT ReparseDataLength = 0; // only valid value
  8633. ULONG InputBufferLength = 0; // invalid value as the header is needed
  8634. ULONG OutputBufferLength = 2; // invalid value as no output buffer is used
  8635. ULONG IncomingFileAttributes = 0; // invalid value
  8636. ULONG IncomingReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; // invalid value
  8637. BOOLEAN CleanupAttributeContext = FALSE;
  8638. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  8639. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  8640. MAP_HANDLE MapHandle;
  8641. BOOLEAN NonResidentScbAcquired = FALSE;
  8642. BOOLEAN InitializedMapHandle = FALSE;
  8643. ASSERT_IRP_CONTEXT( IrpContext );
  8644. ASSERT_IRP( Irp );
  8645. PAGED_CODE();
  8646. //
  8647. // Get the current Irp stack location
  8648. //
  8649. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  8650. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  8651. DebugTrace( +1, Dbg, ("NtfsDeleteReparsePoint, FsControlCode = %08lx\n", FsControlCode) );
  8652. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  8653. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  8654. //
  8655. // Get the length of the input and output buffers.
  8656. //
  8657. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  8658. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  8659. DebugTrace( 0, Dbg, ("InputBufferLength = %08lx, OutputBufferLength = %08lx\n", InputBufferLength, OutputBufferLength) );
  8660. //
  8661. // Do not allow output buffer in the delete command.
  8662. //
  8663. if (OutputBufferLength > 0) {
  8664. //
  8665. // Return an invalid parameter error.
  8666. //
  8667. Status = STATUS_INVALID_PARAMETER;
  8668. //
  8669. // Return to caller.
  8670. //
  8671. NtfsCompleteRequest( IrpContext, Irp, Status );
  8672. DebugTrace( 0, Dbg, ("Non-null output buffer.\n") );
  8673. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8674. return Status;
  8675. }
  8676. //
  8677. // Decode all the relevant File System data structures.
  8678. //
  8679. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  8680. IrpSp->FileObject,
  8681. &Vcb,
  8682. &Fcb,
  8683. &Scb,
  8684. &Ccb,
  8685. TRUE ); // Raise an exeption if error is encountered
  8686. //
  8687. // Check for the correct type of open.
  8688. //
  8689. if (
  8690. //
  8691. // See that we have a file or a directory.
  8692. //
  8693. ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen))) {
  8694. //
  8695. // Return an invalid parameter error
  8696. //
  8697. Status = STATUS_INVALID_PARAMETER;
  8698. //
  8699. // Return to caller.
  8700. //
  8701. NtfsCompleteRequest( IrpContext, Irp, Status );
  8702. DebugTrace( 0, Dbg, ("Invalid TypeOfOpen\n") );
  8703. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8704. return Status;
  8705. }
  8706. //
  8707. // The caller has FILE_SPECIAL_ACCESS. The NTFS driver enforces access checks more stringent
  8708. // than FILE_ANY_ACCESS:
  8709. // (a) FILE_WRITE_DATA or FILE_WRITE_ATTRIBUTES_ACCESS
  8710. //
  8711. if (!FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS ) &&
  8712. //
  8713. // Temporary KLUDGE for DavePr.
  8714. // The Ccb->AccessFlags and the FileObject->WriteAccess may not coincide as a
  8715. // filter may change the "visible" file object after the open. The Ccb flags do
  8716. // not change after open.
  8717. //
  8718. !(IrpSp->FileObject->WriteAccess == TRUE)) {
  8719. //
  8720. // Return access denied.
  8721. //
  8722. Status = STATUS_ACCESS_DENIED;
  8723. //
  8724. // Return to caller.
  8725. //
  8726. NtfsCompleteRequest( IrpContext, Irp, Status );
  8727. DebugTrace( 0, Dbg, ("Ccb->AccessFlags %x\n", Ccb->AccessFlags) );
  8728. DebugTrace( 0, Dbg, ("Caller did not have the appropriate access rights.\n") );
  8729. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8730. return Status;
  8731. }
  8732. ASSERT_VCB( Vcb );
  8733. ASSERT_FCB( Fcb );
  8734. ASSERT_SCB( Scb );
  8735. ASSERT_CCB( Ccb );
  8736. //
  8737. // Read only volumes stay read only.
  8738. //
  8739. if (NtfsIsVolumeReadOnly( Vcb )) {
  8740. Status = STATUS_MEDIA_WRITE_PROTECTED;
  8741. NtfsCompleteRequest( IrpContext, Irp, Status );
  8742. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8743. return Status;
  8744. }
  8745. if (!NtfsVolumeVersionCheck( Vcb, NTFS_REPARSE_POINT_VERSION )) {
  8746. //
  8747. // Return a volume not upgraded error.
  8748. //
  8749. Status = STATUS_VOLUME_NOT_UPGRADED;
  8750. //
  8751. // Return to caller.
  8752. //
  8753. NtfsCompleteRequest( IrpContext, Irp, Status );
  8754. DebugTrace( 0, Dbg, ("Non-upgraded volume passed by caller.\n") );
  8755. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8756. return Status;
  8757. }
  8758. //
  8759. // Check for invalid conditions in the parameters.
  8760. //
  8761. if (
  8762. //
  8763. // Verify that we have the required system input buffer.
  8764. //
  8765. (Irp->AssociatedIrp.SystemBuffer == NULL)) {
  8766. //
  8767. // Return an invalid buffer error.
  8768. //
  8769. Status = STATUS_INVALID_BUFFER_SIZE;
  8770. //
  8771. // Return to caller.
  8772. //
  8773. NtfsCompleteRequest( IrpContext, Irp, Status );
  8774. DebugTrace( 0, Dbg, ("Null buffer passed by system.\n") );
  8775. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8776. return Status;
  8777. }
  8778. //
  8779. // See that the buffer sent in by the caller is the exact header.
  8780. //
  8781. if ((InputBufferLength != REPARSE_DATA_BUFFER_HEADER_SIZE) &&
  8782. (InputBufferLength != REPARSE_GUID_DATA_BUFFER_HEADER_SIZE)) {
  8783. //
  8784. // Return an invalid reparse data.
  8785. //
  8786. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8787. //
  8788. // Return to caller.
  8789. //
  8790. NtfsCompleteRequest( IrpContext, Irp, Status );
  8791. DebugTrace( 0, Dbg, ("Invalid parameter reparse data passed by caller\n") );
  8792. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8793. return Status;
  8794. }
  8795. //
  8796. // Get the header information brought in the input buffer.
  8797. // While the first two fields coincide in REPARSE_DATA_BUFFER and REPARSE_GUID_DATA_BUFFER,
  8798. // a common assignment can be used below.
  8799. //
  8800. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseTag) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseTag) );
  8801. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseDataLength) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseDataLength) );
  8802. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, Reserved) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, Reserved) );
  8803. ReparseBuffer = (PREPARSE_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  8804. ReparseTag = ReparseBuffer->ReparseTag;
  8805. ReparseDataLength = ReparseBuffer->ReparseDataLength;
  8806. DebugTrace( 0, Dbg, ("ReparseTag = %08lx, ReparseDataLength = %05lx [d]%d\n", ReparseTag, ReparseDataLength, ReparseDataLength) );
  8807. //
  8808. // We verify that ReparseDataLength is zero.
  8809. //
  8810. if (ReparseDataLength != 0) {
  8811. //
  8812. // Return an invalid reparse data.
  8813. //
  8814. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8815. //
  8816. // Return to caller.
  8817. //
  8818. NtfsCompleteRequest( IrpContext, Irp, Status );
  8819. DebugTrace( 0, Dbg, ("Invalid header value passed by caller\n") );
  8820. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8821. return Status;
  8822. }
  8823. //
  8824. // We verify that the caller uses one of the non-reserved tags.
  8825. //
  8826. if ((ReparseTag == IO_REPARSE_TAG_RESERVED_ZERO) ||
  8827. (ReparseTag == IO_REPARSE_TAG_RESERVED_ONE)) {
  8828. //
  8829. // Return an invalid reparse tag.
  8830. //
  8831. Status = STATUS_IO_REPARSE_TAG_INVALID;
  8832. //
  8833. // Return to caller.
  8834. //
  8835. NtfsCompleteRequest( IrpContext, Irp, Status );
  8836. DebugTrace( 0, Dbg, ("Caller passed in a reserved tag for the reparse data.\n") );
  8837. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8838. return Status;
  8839. }
  8840. //
  8841. // We verify that for non-Microsoft tags the caller has the GUID header.
  8842. //
  8843. if (!IsReparseTagMicrosoft( ReparseTag ) &&
  8844. (InputBufferLength != REPARSE_GUID_DATA_BUFFER_HEADER_SIZE)) {
  8845. //
  8846. // Return an invalid reparse data.
  8847. //
  8848. Status = STATUS_IO_REPARSE_DATA_INVALID;
  8849. //
  8850. // Return to caller.
  8851. //
  8852. NtfsCompleteRequest( IrpContext, Irp, Status );
  8853. DebugTrace( 0, Dbg, ("Caller used non-Microsoft tag and did not use the GUID buffer.\n") );
  8854. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  8855. return Status;
  8856. }
  8857. //
  8858. // We set the IrpContext flag to indicate that we can wait, making this a synchronous
  8859. // call.
  8860. //
  8861. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  8862. //
  8863. // Capture the source information.
  8864. //
  8865. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  8866. //
  8867. // Now it is time ot use a try-finally to facilitate cleanup.
  8868. //
  8869. try {
  8870. //
  8871. // Acquire exclusive the Fcb.
  8872. //
  8873. NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, 0 );
  8874. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  8875. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  8876. }
  8877. //
  8878. // Remember the value of the file attribute flags and of the reparse point.
  8879. //
  8880. IncomingFileAttributes = Fcb->Info.FileAttributes;
  8881. IncomingReparsePointTag = Fcb->Info.ReparsePointTag;
  8882. //
  8883. // All the parameters and boundary conditions look good. We begin real work.
  8884. //
  8885. // Delete the appropriate system defined reparse point attribute.
  8886. // First point to it and then nuke it.
  8887. //
  8888. NtfsInitializeAttributeContext( &AttributeContext );
  8889. CleanupAttributeContext = TRUE;
  8890. if (!(NtfsLookupAttributeByCode( IrpContext,
  8891. Fcb,
  8892. &Fcb->FileReference,
  8893. $REPARSE_POINT,
  8894. &AttributeContext ) ) ) {
  8895. DebugTrace( 0, Dbg, ("Can't find the $REPARSE_POINT attribute\n") );
  8896. //
  8897. // See if FileAttributes agrees that we do not have a reparse point.
  8898. //
  8899. if (FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  8900. DebugTrace( 0, Dbg, ("The Fcb says this IS a reparse point.\n") );
  8901. //
  8902. // Should not happen. Raise an exeption as we are in an
  8903. // inconsistent state. The attribute flag says that
  8904. // $REPARSE_POINT has to be present.
  8905. //
  8906. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  8907. }
  8908. //
  8909. // Return STATUS_NOT_A_REPARSE_POINT
  8910. //
  8911. Status = STATUS_NOT_A_REPARSE_POINT;
  8912. try_return( Status );
  8913. }
  8914. //
  8915. // Verify that the incomming tag value matches the tag value present in
  8916. // the $REPARSE_POINT attribute.
  8917. //
  8918. {
  8919. PREPARSE_GUID_DATA_BUFFER ReparseBufferTwo = NULL;
  8920. PVOID AttributeData = NULL;
  8921. ULONG Length = 0;
  8922. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  8923. if (NtfsIsAttributeResident( AttributeHeader )) {
  8924. //
  8925. // Point to the value of the arribute.
  8926. //
  8927. AttributeData = NtfsAttributeValue( AttributeHeader );
  8928. DebugTrace( 0, Dbg, ("Existing attribute is resident.\n") );
  8929. } else {
  8930. //
  8931. // Map the attribute list if the attribute is non-resident. Otherwise the
  8932. // attribute is already mapped and we have a Bcb in the attribute context.
  8933. //
  8934. DebugTrace( 0, Dbg, ("Existing attribute is non-resident.\n") );
  8935. NtfsMapAttributeValue( IrpContext,
  8936. Fcb,
  8937. &AttributeData, // point to the value
  8938. &Length,
  8939. &Bcb,
  8940. &AttributeContext );
  8941. }
  8942. //
  8943. // Verify that the two tag values match.
  8944. //
  8945. ReparseBufferTwo = (PREPARSE_GUID_DATA_BUFFER)AttributeData;
  8946. DebugTrace( 0, Dbg, ("Existing tag is [d]%03ld - New tag is [d]%03ld\n", ReparseBufferTwo->ReparseTag, ReparseBuffer->ReparseTag) );
  8947. if (ReparseBuffer->ReparseTag != ReparseBufferTwo->ReparseTag) {
  8948. //
  8949. // Return status STATUS_IO_REPARSE_TAG_MISMATCH
  8950. //
  8951. DebugTrace( 0, Dbg, ("Tag mismatch with the existing reparse point.\n") );
  8952. Status = STATUS_IO_REPARSE_TAG_MISMATCH;
  8953. try_return( Status );
  8954. }
  8955. //
  8956. // For non-Microsoft tags, verify that the GUIDs match.
  8957. //
  8958. if (!IsReparseTagMicrosoft( ReparseTag )) {
  8959. PREPARSE_GUID_DATA_BUFFER ReparseGuidBuffer = NULL;
  8960. ReparseGuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer;
  8961. if (!((ReparseGuidBuffer->ReparseGuid.Data1 == ReparseBufferTwo->ReparseGuid.Data1) &&
  8962. (ReparseGuidBuffer->ReparseGuid.Data2 == ReparseBufferTwo->ReparseGuid.Data2) &&
  8963. (ReparseGuidBuffer->ReparseGuid.Data3 == ReparseBufferTwo->ReparseGuid.Data3) &&
  8964. (ReparseGuidBuffer->ReparseGuid.Data4[0] == ReparseBufferTwo->ReparseGuid.Data4[0]) &&
  8965. (ReparseGuidBuffer->ReparseGuid.Data4[1] == ReparseBufferTwo->ReparseGuid.Data4[1]) &&
  8966. (ReparseGuidBuffer->ReparseGuid.Data4[2] == ReparseBufferTwo->ReparseGuid.Data4[2]) &&
  8967. (ReparseGuidBuffer->ReparseGuid.Data4[3] == ReparseBufferTwo->ReparseGuid.Data4[3]) &&
  8968. (ReparseGuidBuffer->ReparseGuid.Data4[4] == ReparseBufferTwo->ReparseGuid.Data4[4]) &&
  8969. (ReparseGuidBuffer->ReparseGuid.Data4[5] == ReparseBufferTwo->ReparseGuid.Data4[5]) &&
  8970. (ReparseGuidBuffer->ReparseGuid.Data4[6] == ReparseBufferTwo->ReparseGuid.Data4[6]) &&
  8971. (ReparseGuidBuffer->ReparseGuid.Data4[7] == ReparseBufferTwo->ReparseGuid.Data4[7]))) {
  8972. //
  8973. // Return status STATUS_REPARSE_ATTRIBUTE_CONFLICT
  8974. //
  8975. DebugTrace( 0, Dbg, ("GUID mismatch with the existing reparse point.\n") );
  8976. Status = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
  8977. try_return( Status );
  8978. }
  8979. }
  8980. //
  8981. // Unpin the Bcb. The unpin routine checks for NULL.
  8982. //
  8983. NtfsUnpinBcb( IrpContext, &Bcb );
  8984. }
  8985. //
  8986. // Delete the record from the reparse point index.
  8987. //
  8988. {
  8989. INDEX_KEY IndexKey;
  8990. INDEX_ROW IndexRow;
  8991. REPARSE_INDEX_KEY KeyValue;
  8992. //
  8993. // Acquire the mount table index so that the following two operations on it
  8994. // are atomic for this call.
  8995. //
  8996. NtfsAcquireExclusiveScb( IrpContext, Vcb->ReparsePointTableScb );
  8997. //
  8998. // Verify that this file is in the reparse point index and delete it.
  8999. //
  9000. KeyValue.FileReparseTag = ReparseTag;
  9001. KeyValue.FileId = *(PLARGE_INTEGER)&Scb->Fcb->FileReference;
  9002. IndexKey.Key = (PVOID)&KeyValue;
  9003. IndexKey.KeyLength = sizeof(KeyValue);
  9004. NtOfsInitializeMapHandle( &MapHandle );
  9005. InitializedMapHandle = TRUE;
  9006. //
  9007. // NtOfsFindRecord will return an error status if the key is not found.
  9008. //
  9009. Status = NtOfsFindRecord( IrpContext,
  9010. Vcb->ReparsePointTableScb,
  9011. &IndexKey,
  9012. &IndexRow,
  9013. &MapHandle,
  9014. NULL );
  9015. if (!NT_SUCCESS(Status)) {
  9016. //
  9017. // Should not happen. The reparse point should be in the index.
  9018. //
  9019. DebugTrace( 0, Dbg, ("Record not found in the reparse point index.\n") );
  9020. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  9021. }
  9022. //
  9023. // Remove the entry from the reparse point index.
  9024. //
  9025. NtOfsDeleteRecords( IrpContext,
  9026. Vcb->ReparsePointTableScb,
  9027. 1, // deleting one record from the index
  9028. &IndexKey );
  9029. }
  9030. //
  9031. // If the stream is non-resident, then get hold of an Scb for it.
  9032. //
  9033. if (!NtfsIsAttributeResident( AttributeHeader )) {
  9034. NonResidentScb = NtfsCreateScb( IrpContext,
  9035. Fcb,
  9036. $REPARSE_POINT,
  9037. &NtfsEmptyString,
  9038. FALSE,
  9039. NULL );
  9040. NtfsAcquireExclusiveScb( IrpContext, NonResidentScb );
  9041. NonResidentScbAcquired = TRUE;
  9042. }
  9043. //
  9044. // Nuke the attribute.
  9045. //
  9046. NtfsDeleteAttributeRecord( IrpContext,
  9047. Fcb,
  9048. DELETE_LOG_OPERATION |
  9049. DELETE_RELEASE_FILE_RECORD |
  9050. DELETE_RELEASE_ALLOCATION,
  9051. &AttributeContext );
  9052. //
  9053. // Cleanup the attribute context.
  9054. //
  9055. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  9056. CleanupAttributeContext = FALSE;
  9057. //
  9058. // Set the change attribute flag.
  9059. //
  9060. ASSERTMSG( "conflict with flush",
  9061. NtfsIsSharedFcb( Fcb ) ||
  9062. (Fcb->PagingIoResource != NULL &&
  9063. NtfsIsSharedFcbPagingIo( Fcb )) );
  9064. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  9065. //
  9066. // Clear the reparse point bit in the duplicate file attribute.
  9067. //
  9068. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT );
  9069. //
  9070. // Clear the ReparsePointTag field in the duplicate file attribute.
  9071. //
  9072. Fcb->Info.ReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO;
  9073. //
  9074. // Update the standard information in the file record.
  9075. //
  9076. NtfsUpdateStandardInformation( IrpContext, Fcb );
  9077. //
  9078. // Post the change to the Usn Journal (on errors change is backed out)
  9079. //
  9080. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_REPARSE_POINT_CHANGE );
  9081. //
  9082. // Checkpoint the Txn to commit the changes.
  9083. //
  9084. NtfsCleanupTransactionAndCommit( IrpContext, STATUS_SUCCESS, TRUE );
  9085. //
  9086. // Flag the change time change in the Ccb.
  9087. //
  9088. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  9089. //
  9090. // Don't set the archive bit on a directory. Otherwise we break existing
  9091. // apps that don't expect to see this flag.
  9092. //
  9093. if (!IsDirectory( &Fcb->Info )) {
  9094. SetFlag( Ccb->Flags, CCB_FLAG_SET_ARCHIVE );
  9095. }
  9096. //
  9097. // Reflect that the attribute is gone in the corresponding Scb.
  9098. //
  9099. if (NonResidentScbAcquired) {
  9100. NonResidentScb->AttributeTypeCode = $UNUSED;
  9101. //
  9102. // If we have acquired the Scb then set the sizes back to zero.
  9103. // Flag that the attribute has been deleted.
  9104. //
  9105. NonResidentScb->Header.FileSize =
  9106. NonResidentScb->Header.ValidDataLength =
  9107. NonResidentScb->Header.AllocationSize = Li0;
  9108. //
  9109. // Set the Scb flag to indicate that the attribute is gone.
  9110. //
  9111. SetFlag( NonResidentScb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  9112. //
  9113. // Go ahead and dereference any internal file object. No sense in keeping it around.
  9114. //
  9115. NtfsDeleteInternalAttributeStream( NonResidentScb, FALSE, 0 );
  9116. }
  9117. try_exit: NOTHING;
  9118. } finally {
  9119. DebugUnwind( NtfsDeleteReparsePoint );
  9120. //
  9121. // Unpin the Bcb. The unpin routine checks for NULL.
  9122. //
  9123. NtfsUnpinBcb( IrpContext, &Bcb );
  9124. if (CleanupAttributeContext) {
  9125. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  9126. }
  9127. //
  9128. // Need to roll-back the value of the reparse point flag in case of
  9129. // problems. I leave the archive bit set anyway.
  9130. //
  9131. if (AbnormalTermination()) {
  9132. Fcb->Info.FileAttributes = IncomingFileAttributes;
  9133. Fcb->Info.ReparsePointTag = IncomingReparsePointTag;
  9134. }
  9135. //
  9136. // Release the reparse point index Scb and the map handle.
  9137. //
  9138. if (InitializedMapHandle) {
  9139. NtOfsReleaseMap( IrpContext, &MapHandle );
  9140. }
  9141. }
  9142. NtfsCompleteRequest( IrpContext, Irp, Status );
  9143. DebugTrace( -1, Dbg, ("NtfsDeleteReparsePoint -> %08lx\n", Status) );
  9144. return Status;
  9145. }
  9146. NTSTATUS
  9147. NtfsGetTunneledData (
  9148. IN PIRP_CONTEXT IrpContext,
  9149. IN PFCB Fcb,
  9150. IN OUT PNTFS_TUNNELED_DATA TunneledData
  9151. )
  9152. /*++
  9153. Routine Description:
  9154. This routine will get the tunneled data for the
  9155. given Fcb. Currently, this means getting the Fcb's
  9156. creation time.
  9157. Arguments:
  9158. Fcb - Supplies the Fcb for which to get the data.
  9159. TunneledData - Where to store the tunneled data.
  9160. Return Value:
  9161. NTSTATUS - The return status for the operation
  9162. --*/
  9163. {
  9164. PAGED_CODE();
  9165. UNREFERENCED_PARAMETER( IrpContext );
  9166. TunneledData->CreationTime = Fcb->Info.CreationTime;
  9167. return STATUS_SUCCESS;
  9168. }
  9169. NTSTATUS
  9170. NtfsSetTunneledData (
  9171. IN PIRP_CONTEXT IrpContext,
  9172. IN PFCB Fcb,
  9173. IN PNTFS_TUNNELED_DATA TunneledData
  9174. )
  9175. /*++
  9176. Routine Description:
  9177. This routine will set the tunneled data for the
  9178. given Fcb. Currently, this means setting the Fcb's
  9179. creation time and setting its object id, if any.
  9180. Arguments:
  9181. Fcb - Supplies the Fcb whose tunneled data should be set.
  9182. TunneledData - Supplies the data to set for the Fcb.
  9183. Return Value:
  9184. NTSTATUS - The return status for the operation
  9185. --*/
  9186. {
  9187. NTSTATUS Status = STATUS_SUCCESS;
  9188. PAGED_CODE();
  9189. Fcb->Info.CreationTime = TunneledData->CreationTime;
  9190. if (TunneledData->HasObjectId) {
  9191. try {
  9192. Status = NtfsSetObjectIdInternal( IrpContext,
  9193. Fcb,
  9194. Fcb->Vcb,
  9195. &TunneledData->ObjectIdBuffer );
  9196. } except( EXCEPTION_EXECUTE_HANDLER ) {
  9197. Status = GetExceptionCode();
  9198. NtfsMinimumExceptionProcessing( IrpContext );
  9199. //
  9200. // If setting the object id failed just because the id is in use
  9201. // for another file, or if the file already has an object id,
  9202. // there's no point in failing the entire create operation.
  9203. // We'll just say that all went well in that case, and only raise
  9204. // if something unexpected happened.
  9205. //
  9206. if ((Status == STATUS_DUPLICATE_NAME) ||
  9207. (Status == STATUS_OBJECT_NAME_COLLISION)) {
  9208. //
  9209. // We notify anyone watching the object id index that this
  9210. // object id couldn't be tunnelled. This lets a link tracking
  9211. // service decide for itself how to handle this case.
  9212. //
  9213. if (Fcb->Vcb->ViewIndexNotifyCount != 0) {
  9214. FILE_OBJECTID_INFORMATION FileObjectIdInfo;
  9215. RtlCopyMemory( &FileObjectIdInfo.FileReference,
  9216. &Fcb->FileReference,
  9217. sizeof(FILE_REFERENCE) );
  9218. RtlCopyMemory( FileObjectIdInfo.ObjectId,
  9219. TunneledData->ObjectIdBuffer.ObjectId,
  9220. OBJECT_ID_KEY_LENGTH );
  9221. RtlCopyMemory( FileObjectIdInfo.ExtendedInfo,
  9222. TunneledData->ObjectIdBuffer.ExtendedInfo,
  9223. OBJECT_ID_EXT_INFO_LENGTH );
  9224. NtfsReportViewIndexNotify( Fcb->Vcb,
  9225. Fcb->Vcb->ObjectIdTableScb->Fcb,
  9226. FILE_NOTIFY_CHANGE_FILE_NAME,
  9227. (Status == STATUS_DUPLICATE_NAME ?
  9228. FILE_ACTION_ID_NOT_TUNNELLED :
  9229. FILE_ACTION_TUNNELLED_ID_COLLISION),
  9230. &FileObjectIdInfo,
  9231. sizeof(FILE_OBJECTID_INFORMATION) );
  9232. }
  9233. IrpContext->ExceptionStatus = Status = STATUS_SUCCESS;
  9234. } else {
  9235. NtfsRaiseStatus( IrpContext, Status, NULL, NULL);
  9236. }
  9237. }
  9238. }
  9239. return Status;
  9240. }
  9241. //
  9242. // Local Support Routine
  9243. //
  9244. NTSTATUS
  9245. NtfsCreateUsnJournal (
  9246. IN PIRP_CONTEXT IrpContext,
  9247. IN PIRP Irp
  9248. )
  9249. /*++
  9250. Routine Description:
  9251. This routine creates the Usn journal for the first time, and is a noop
  9252. if Usn journal already exists.
  9253. Arguments:
  9254. IrpContext - context of the call
  9255. Irp - request being serviced
  9256. Return Value:
  9257. NTSTATUS - The return status for the operation
  9258. --*/
  9259. {
  9260. PIO_STACK_LOCATION IrpSp;
  9261. NTSTATUS Status = STATUS_SUCCESS;
  9262. PFILE_OBJECT FileObject;
  9263. TYPE_OF_OPEN TypeOfOpen;
  9264. PVCB Vcb;
  9265. PFCB Fcb;
  9266. PSCB Scb;
  9267. PCCB Ccb;
  9268. CREATE_USN_JOURNAL_DATA CapturedData;
  9269. //
  9270. // Don't post this request, we can't lock the input buffer.
  9271. //
  9272. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9273. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9274. //
  9275. // Get the current Irp stack location and save some references.
  9276. //
  9277. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  9278. //
  9279. // Extract and decode the file object and check for type of open.
  9280. //
  9281. FileObject = IrpSp->FileObject;
  9282. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  9283. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  9284. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  9285. return STATUS_ACCESS_DENIED;
  9286. }
  9287. if (NtfsIsVolumeReadOnly( Vcb )) {
  9288. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  9289. return STATUS_MEDIA_WRITE_PROTECTED;
  9290. }
  9291. if (Vcb->ExtendDirectory == NULL) {
  9292. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  9293. return STATUS_VOLUME_NOT_UPGRADED;
  9294. }
  9295. //
  9296. // Check for a minimum length on the input buffer.
  9297. //
  9298. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( CREATE_USN_JOURNAL_DATA )) {
  9299. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  9300. return STATUS_INVALID_PARAMETER;
  9301. }
  9302. //
  9303. // Do the work, if needed. Acquire the VCB exclusive to lock out creates which
  9304. // have a locking order vis a vis the usn journal / extend directory / mft opposed
  9305. // to this path
  9306. //
  9307. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  9308. try {
  9309. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  9310. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  9311. }
  9312. //
  9313. // Also fail if the journal is currently being deleted.
  9314. //
  9315. if (FlagOn( Vcb->VcbState, VCB_STATE_USN_DELETE )) {
  9316. NtfsRaiseStatus( IrpContext, STATUS_JOURNAL_DELETE_IN_PROGRESS, NULL, NULL );
  9317. }
  9318. //
  9319. // Capture the JournalData from the unsafe user buffer.
  9320. //
  9321. try {
  9322. if (Irp->RequestorMode != KernelMode) {
  9323. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9324. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  9325. NTFS_TYPE_ALIGNMENT( CREATE_USN_JOURNAL_DATA ));
  9326. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9327. CREATE_USN_JOURNAL_DATA )){
  9328. Status = STATUS_INVALID_USER_BUFFER;
  9329. leave;
  9330. }
  9331. CapturedData = *(PCREATE_USN_JOURNAL_DATA)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  9332. } except(EXCEPTION_EXECUTE_HANDLER) {
  9333. NtfsRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER, NULL, NULL);
  9334. }
  9335. //
  9336. // Create or change the Usn Journal parameters.
  9337. //
  9338. NtfsInitializeUsnJournal( IrpContext, Vcb, TRUE, FALSE, &CapturedData );
  9339. } finally {
  9340. NtfsReleaseVcb( IrpContext, Vcb );
  9341. }
  9342. NtfsCompleteRequest( IrpContext, Irp, Status );
  9343. return Status;
  9344. }
  9345. //
  9346. // Local Support Routine
  9347. //
  9348. typedef struct _USN_DATA_CONTEXT {
  9349. USN_RECORD UNALIGNED *UsnRecord;
  9350. ULONG RoomLeft;
  9351. ULONG BytesUsed;
  9352. USN LowUsn;
  9353. USN HighUsn;
  9354. FILE_REFERENCE FileReference;
  9355. } USN_DATA_CONTEXT, *PUSN_DATA_CONTEXT;
  9356. NTSTATUS
  9357. NtfsReadUsnWorker (
  9358. IN PIRP_CONTEXT IrpContext,
  9359. IN PFCB Fcb,
  9360. IN PVOID Context
  9361. )
  9362. /*++
  9363. Routine Description:
  9364. This routine reads the USN data from the file record and returns
  9365. it in the user's buffer.
  9366. Arguments:
  9367. Fcb - Fcb for the file to be processed.
  9368. Context - Pointer to USN_DATA_CONTEXT.
  9369. Return Value:
  9370. STATUS_SUCCESS if a record was successfully stored
  9371. STATUS_BUFFER_OVERFLOW if buffer was not big enough for record
  9372. --*/
  9373. {
  9374. ATTRIBUTE_ENUMERATION_CONTEXT NameContext;
  9375. PUSN_DATA_CONTEXT UsnContext = (PUSN_DATA_CONTEXT) Context;
  9376. PFILE_NAME FileName;
  9377. ULONG RecordLength;
  9378. ULONG FileAttributes;
  9379. NTSTATUS Status = STATUS_SUCCESS;
  9380. BOOLEAN MoreToGo;
  9381. //
  9382. // Find name record; Initialize the context structure.
  9383. //
  9384. try {
  9385. NtfsInitializeAttributeContext( &NameContext );
  9386. //
  9387. // Locate a file name with the FILE_NAME_NTFS bit set
  9388. //
  9389. MoreToGo = NtfsLookupAttributeByCode( IrpContext,
  9390. Fcb,
  9391. &Fcb->FileReference,
  9392. $FILE_NAME,
  9393. &NameContext );
  9394. //
  9395. // While we've found an attribute
  9396. //
  9397. while (MoreToGo) {
  9398. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &NameContext ));
  9399. //
  9400. // See if the NTFS name is set for this name.
  9401. //
  9402. if (FlagOn( FileName->Flags, FILE_NAME_NTFS )) {
  9403. break;
  9404. }
  9405. //
  9406. // The last one wasn't it. Let's try again.
  9407. //
  9408. MoreToGo = NtfsLookupNextAttributeByCode( IrpContext,
  9409. Fcb,
  9410. $FILE_NAME,
  9411. &NameContext );
  9412. }
  9413. if (!MoreToGo) {
  9414. NtfsCleanupAttributeContext( IrpContext, &NameContext );
  9415. NtfsInitializeAttributeContext( &NameContext );
  9416. //
  9417. // Couldn't find an Ntfs name, check for any hard link.
  9418. //
  9419. MoreToGo = NtfsLookupAttributeByCode( IrpContext,
  9420. Fcb,
  9421. &Fcb->FileReference,
  9422. $FILE_NAME,
  9423. &NameContext );
  9424. //
  9425. // While we've found an attribute
  9426. //
  9427. while (MoreToGo) {
  9428. FileName = (PFILE_NAME) NtfsAttributeValue( NtfsFoundAttribute( &NameContext ));
  9429. //
  9430. // See if the DOS name is not set for this name.
  9431. //
  9432. if (!FlagOn( FileName->Flags, FILE_NAME_DOS )) {
  9433. break;
  9434. }
  9435. //
  9436. // The last one wasn't it. Let's try again.
  9437. //
  9438. MoreToGo = NtfsLookupNextAttributeByCode( IrpContext,
  9439. Fcb,
  9440. $FILE_NAME,
  9441. &NameContext );
  9442. }
  9443. if (!MoreToGo) {
  9444. ASSERTMSG( "Couldn't find a name string for file\n", FALSE );
  9445. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  9446. }
  9447. }
  9448. //
  9449. // Check there's enough room for a USN record.
  9450. //
  9451. // Record length is a function of the filename length and the structure the
  9452. // user expects.
  9453. //
  9454. RecordLength = FIELD_OFFSET( USN_RECORD, FileName ) + (FileName->FileNameLength * sizeof( WCHAR ));
  9455. RecordLength = QuadAlign( RecordLength );
  9456. if (RecordLength > UsnContext->RoomLeft) {
  9457. Status = STATUS_BUFFER_TOO_SMALL;
  9458. leave;
  9459. }
  9460. if (Fcb->Usn < UsnContext->LowUsn ||
  9461. Fcb->Usn > UsnContext->HighUsn ) {
  9462. leave;
  9463. }
  9464. //
  9465. // Set up fixed portion of USN record. The following fields are the
  9466. // same for either version.
  9467. //
  9468. UsnContext->UsnRecord->RecordLength = RecordLength;
  9469. UsnContext->UsnRecord->FileReferenceNumber = *(PULONGLONG)&Fcb->FileReference;
  9470. UsnContext->UsnRecord->ParentFileReferenceNumber = *(PULONGLONG)&FileName->ParentDirectory;
  9471. UsnContext->UsnRecord->Usn = Fcb->Usn;
  9472. //
  9473. // Presumably the caller is not interested in the TimeStamp while scanning the Mft,
  9474. // but if he is, then he may need to go read the Usn we are returning.
  9475. //
  9476. UsnContext->UsnRecord->TimeStamp.QuadPart = 0;
  9477. UsnContext->UsnRecord->Reason = 0;
  9478. //
  9479. // Build the FileAttributes from the Fcb.
  9480. //
  9481. FileAttributes = Fcb->Info.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS;
  9482. //
  9483. // We have to generate the DIRECTORY attribute.
  9484. //
  9485. if (IsDirectory( &Fcb->Info ) || IsViewIndex( &Fcb->Info )) {
  9486. SetFlag( FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
  9487. }
  9488. //
  9489. // If there are no flags set then explicitly set the NORMAL flag.
  9490. //
  9491. if (FileAttributes == 0) {
  9492. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  9493. }
  9494. //
  9495. // Now set the other fields.
  9496. //
  9497. UsnContext->UsnRecord->MajorVersion = 2;
  9498. UsnContext->UsnRecord->MinorVersion = 0;
  9499. UsnContext->UsnRecord->SourceInfo = 0;
  9500. UsnContext->UsnRecord->SecurityId = (ULONG) Fcb->SecurityId;
  9501. UsnContext->UsnRecord->FileAttributes = FileAttributes;
  9502. //
  9503. // Copy file name to Usn record
  9504. //
  9505. UsnContext->UsnRecord->FileNameLength = (USHORT)(FileName->FileNameLength * sizeof( WCHAR ));
  9506. UsnContext->UsnRecord->FileNameOffset = FIELD_OFFSET( USN_RECORD, FileName );
  9507. RtlCopyMemory( &UsnContext->UsnRecord->FileName[0],
  9508. &FileName->FileName[0],
  9509. FileName->FileNameLength * sizeof( WCHAR ));
  9510. //
  9511. // Adjust context for next record
  9512. //
  9513. UsnContext->UsnRecord = (PUSN_RECORD) Add2Ptr( UsnContext->UsnRecord, RecordLength );
  9514. UsnContext->RoomLeft -= RecordLength;
  9515. UsnContext->BytesUsed += RecordLength;
  9516. } finally {
  9517. NtfsCleanupAttributeContext( IrpContext, &NameContext );
  9518. }
  9519. return Status;
  9520. }
  9521. //
  9522. // Local Support Routine
  9523. //
  9524. NTSTATUS
  9525. NtfsReadFileRecordUsnData (
  9526. IN PIRP_CONTEXT IrpContext,
  9527. IN PIRP Irp
  9528. )
  9529. /*++
  9530. Routine Description:
  9531. This routine enumerates base file records beginning at a specified
  9532. one and returns USN data from the found records.
  9533. Arguments:
  9534. IrpContext - context of the call
  9535. Irp - request being serviced
  9536. Return Value:
  9537. NTSTATUS - The return status for the operation
  9538. --*/
  9539. {
  9540. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  9541. NTSTATUS Status = STATUS_SUCCESS;
  9542. USN_DATA_CONTEXT Context;
  9543. MFT_ENUM_DATA UNALIGNED *EnumData = (PMFT_ENUM_DATA) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  9544. BOOLEAN LockedMdl = FALSE;
  9545. PVCB Vcb;
  9546. PFCB Fcb;
  9547. PSCB Scb;
  9548. PCCB Ccb;
  9549. TYPE_OF_OPEN TypeOfOpen;
  9550. //
  9551. // Don't post this request.
  9552. //
  9553. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9554. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9555. //
  9556. // We'll catch dismounted volumes explicitly in iterate mft so don't raise on error
  9557. //
  9558. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  9559. IrpSp->FileObject,
  9560. &Vcb,
  9561. &Fcb,
  9562. &Scb,
  9563. &Ccb,
  9564. FALSE );
  9565. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  9566. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  9567. return STATUS_ACCESS_DENIED;
  9568. }
  9569. //
  9570. // Check for a minimum length on the input and output buffers.
  9571. //
  9572. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MFT_ENUM_DATA )) {
  9573. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  9574. return STATUS_INVALID_PARAMETER;
  9575. }
  9576. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof( FILE_REFERENCE )) {
  9577. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  9578. return STATUS_BUFFER_TOO_SMALL;
  9579. }
  9580. try {
  9581. //
  9582. // Probe the input and output buffers.
  9583. //
  9584. if (Irp->RequestorMode != KernelMode) {
  9585. ProbeForRead( EnumData,
  9586. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  9587. NTFS_TYPE_ALIGNMENT( MFT_ENUM_DATA ));
  9588. ProbeForWrite( Irp->UserBuffer,
  9589. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  9590. NTFS_TYPE_ALIGNMENT( FILE_REFERENCE ));
  9591. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9592. MFT_ENUM_DATA ) ||
  9593. !IsTypeAligned( Irp->UserBuffer, FILE_REFERENCE )) {
  9594. Status = STATUS_INVALID_USER_BUFFER;
  9595. leave;
  9596. }
  9597. //
  9598. // Capture the starting file reference
  9599. //
  9600. Context.FileReference = *(PFILE_REFERENCE) &EnumData->StartFileReferenceNumber;
  9601. if (NtfsFullSegmentNumber( &Context.FileReference ) < FIRST_USER_FILE_NUMBER) {
  9602. NtfsSetSegmentNumber( &Context.FileReference, 0, FIRST_USER_FILE_NUMBER );
  9603. }
  9604. //
  9605. // Set up for filling output records
  9606. //
  9607. Context.RoomLeft = IrpSp->Parameters.FileSystemControl.OutputBufferLength - sizeof( FILE_REFERENCE );
  9608. Context.UsnRecord = (PUSN_RECORD) Add2Ptr( Irp->UserBuffer, sizeof( FILE_REFERENCE ));
  9609. Context.BytesUsed = sizeof( FILE_REFERENCE );
  9610. Context.LowUsn = EnumData->LowUsn;
  9611. Context.HighUsn = EnumData->HighUsn;
  9612. //
  9613. // Iterate through the Mft beginning at the specified file reference
  9614. //
  9615. Status = NtfsIterateMft( IrpContext,
  9616. Vcb,
  9617. &Context.FileReference,
  9618. NtfsReadUsnWorker,
  9619. &Context );
  9620. if ((Status == STATUS_BUFFER_TOO_SMALL) ||
  9621. ((Status == STATUS_END_OF_FILE) && (Context.BytesUsed != sizeof( FILE_REFERENCE )))) {
  9622. Status = STATUS_SUCCESS;
  9623. }
  9624. if (NT_SUCCESS( Status )) {
  9625. //
  9626. // Set the returned file reference number and bytes used. Note: UserBuffer
  9627. // is a raw user mode ptr and must be in a try-except
  9628. //
  9629. Irp->IoStatus.Information = Context.BytesUsed;
  9630. *((PFILE_REFERENCE) Irp->UserBuffer) = Context.FileReference;
  9631. }
  9632. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  9633. NtfsRaiseStatus( IrpContext,
  9634. STATUS_INVALID_USER_BUFFER,
  9635. NULL,
  9636. NULL);
  9637. }
  9638. NtfsCompleteRequest( IrpContext, Irp, Status);
  9639. return Status;
  9640. }
  9641. //
  9642. // Local Support Routine
  9643. //
  9644. typedef struct _SID_MATCH_CONTEXT {
  9645. FILE_NAME_INFORMATION UNALIGNED *FileNames;
  9646. ULONG RoomLeft;
  9647. ULONG BytesUsed;
  9648. ULONG OwnerId;
  9649. FILE_REFERENCE Parent;
  9650. } SID_MATCH_CONTEXT, *PSID_MATCH_CONTEXT;
  9651. NTSTATUS
  9652. NtfsFindBySidWorker (
  9653. IN PIRP_CONTEXT IrpContext,
  9654. IN PFCB Fcb,
  9655. IN PVOID Context
  9656. )
  9657. /*++
  9658. Routine Description:
  9659. This routine finds files owned by a Sid in a given context.
  9660. Arguments:
  9661. Fcb - Fcb for the file to be processed.
  9662. Context - Pointer to SID_MATCH_CONTEXT.
  9663. Return Value:
  9664. STATUS_SUCCESS if file did not match SID or
  9665. matched sid but wasn't in scope or
  9666. matched sid and was in scope and was stored.
  9667. STATUS_BUFFER_OVERFLOW if buffer was not big enough for record
  9668. --*/
  9669. {
  9670. PSID_MATCH_CONTEXT SidContext = (PSID_MATCH_CONTEXT) Context;
  9671. SCOPE_CONTEXT ScopeContext;
  9672. NTSTATUS Status;
  9673. //
  9674. // See if the file is owned by the specified Sid
  9675. //
  9676. if (Fcb->OwnerId != SidContext->OwnerId) {
  9677. return STATUS_SUCCESS;
  9678. }
  9679. //
  9680. // Find name record; Initialize the context structure.
  9681. //
  9682. try {
  9683. //
  9684. // If we're at the root of the scope, then build the name directly
  9685. //
  9686. if (NtfsEqualMftRef( &SidContext->Parent, &Fcb->FileReference )) {
  9687. ScopeContext.Name.Buffer = NtfsAllocatePool(PagedPool, 2 );
  9688. ScopeContext.Name.MaximumLength = ScopeContext.Name.Length = 2;
  9689. ScopeContext.Name.Buffer[0] = '\\';
  9690. Status = STATUS_NO_MORE_FILES;
  9691. //
  9692. // Otherwise, walk up the tree
  9693. //
  9694. } else {
  9695. ScopeContext.IsRoot = NtfsEqualMftRef( &RootIndexFileReference, &SidContext->Parent );
  9696. ScopeContext.Name.Buffer = NULL;
  9697. ScopeContext.Name.Length = 0;
  9698. ScopeContext.Name.MaximumLength = 0;
  9699. ScopeContext.Scope = SidContext->Parent;
  9700. Status = NtfsWalkUpTree( IrpContext, Fcb, NtfsBuildRelativeName, &ScopeContext );
  9701. }
  9702. //
  9703. // If we either received SUCCESS (i.e., walked to root successfully)
  9704. // or NO_MORE_FILES (walked to scope successfully)
  9705. //
  9706. if (Status == STATUS_SUCCESS || Status == STATUS_NO_MORE_FILES) {
  9707. ULONG Length =
  9708. QuadAlign( ScopeContext.Name.Length - sizeof( WCHAR ) +
  9709. sizeof( FILE_NAME_INFORMATION ) - sizeof( WCHAR ));
  9710. //
  9711. // Verify that there is enough room for this file name
  9712. //
  9713. if (Length > SidContext->RoomLeft) {
  9714. Status = STATUS_BUFFER_TOO_SMALL;
  9715. leave;
  9716. }
  9717. //
  9718. // Emit the file name to the caller's buffer
  9719. //
  9720. SidContext->FileNames->FileNameLength = ScopeContext.Name.Length - sizeof( WCHAR );
  9721. RtlCopyMemory( SidContext->FileNames->FileName,
  9722. ScopeContext.Name.Buffer + 1,
  9723. ScopeContext.Name.Length - sizeof( WCHAR ));
  9724. //
  9725. // Adjust for next name
  9726. //
  9727. SidContext->BytesUsed += Length;
  9728. SidContext->RoomLeft -= Length;
  9729. SidContext->FileNames = (PFILE_NAME_INFORMATION) Add2Ptr( SidContext->FileNames, Length );
  9730. }
  9731. Status = STATUS_SUCCESS;
  9732. } finally {
  9733. if (ScopeContext.Name.Buffer != NULL) {
  9734. NtfsFreePool( ScopeContext.Name.Buffer );
  9735. }
  9736. }
  9737. return Status;
  9738. }
  9739. //
  9740. // Local Support Routine
  9741. //
  9742. NTSTATUS
  9743. NtfsFindFilesOwnedBySid (
  9744. IN PIRP_CONTEXT IrpContext,
  9745. IN PIRP Irp
  9746. )
  9747. /*++
  9748. Routine Description:
  9749. This routine enumerates file records, finds entries owned by a
  9750. specified Sid and returns the path relative to the called-on Fcb
  9751. of the found file.
  9752. We hide the details of this Mft-based scan by encapsulating this
  9753. a find-first/next structure.
  9754. Arguments:
  9755. IrpContext - context of the call. The input buffer contains a ULONG
  9756. followed by a SID:
  9757. 0 = continue enumeration
  9758. 1 = start enumeration
  9759. Irp - request being serviced
  9760. Return Value:
  9761. NTSTATUS - The return status for the operation
  9762. --*/
  9763. {
  9764. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  9765. FILE_REFERENCE FileReference;
  9766. NTSTATUS Status = STATUS_SUCCESS;
  9767. SID_MATCH_CONTEXT Context;
  9768. PFIND_BY_SID_DATA FindData =
  9769. (PFIND_BY_SID_DATA)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  9770. PFIND_BY_SID_DATA CapturedFindData = NULL;
  9771. TYPE_OF_OPEN TypeOfOpen;
  9772. PVCB Vcb;
  9773. PFCB Fcb;
  9774. PSCB Scb;
  9775. PCCB Ccb;
  9776. BOOLEAN ReleaseVcb = FALSE;
  9777. PAGED_CODE();
  9778. //
  9779. // Don't post this request, we can't lock both input and output buffers.
  9780. //
  9781. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9782. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9783. //
  9784. // Decode the file object, fail this request if not a user data stream.
  9785. //
  9786. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  9787. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  9788. &Vcb,
  9789. &Fcb,
  9790. &Scb,
  9791. &Ccb,
  9792. TRUE );
  9793. if (TypeOfOpen != UserDirectoryOpen || Ccb == NULL) {
  9794. Status = STATUS_INVALID_PARAMETER;
  9795. NtfsCompleteRequest( IrpContext, Irp, Status );
  9796. return Status;
  9797. }
  9798. try {
  9799. try {
  9800. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  9801. ReleaseVcb = TRUE;
  9802. if (Irp->RequestorMode != KernelMode) {
  9803. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9804. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  9805. NTFS_TYPE_ALIGNMENT( FIND_BY_SID_DATA ));
  9806. ProbeForWrite( Irp->UserBuffer,
  9807. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  9808. NTFS_TYPE_ALIGNMENT( FILE_NAME_INFORMATION ));
  9809. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9810. FIND_BY_SID_DATA ) ||
  9811. !IsTypeAligned( Irp->UserBuffer, FILE_NAME_INFORMATION )) {
  9812. Status = STATUS_INVALID_USER_BUFFER;
  9813. leave;
  9814. }
  9815. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  9816. Status = STATUS_VOLUME_DISMOUNTED;
  9817. leave;
  9818. }
  9819. if (Vcb->OwnerIdTableScb == NULL) {
  9820. Status = STATUS_VOLUME_NOT_UPGRADED;
  9821. leave;
  9822. }
  9823. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( ULONG )) {
  9824. Status = STATUS_INVALID_USER_BUFFER;
  9825. leave;
  9826. }
  9827. //
  9828. // Allocate a buffer to capture the input buffer.
  9829. //
  9830. CapturedFindData = NtfsAllocatePool( PagedPool,
  9831. IrpSp->Parameters.FileSystemControl.InputBufferLength );
  9832. RtlCopyMemory( CapturedFindData,
  9833. FindData,
  9834. IrpSp->Parameters.FileSystemControl.InputBufferLength );
  9835. //
  9836. // Do some final checks on the input and output buffers.
  9837. //
  9838. if (
  9839. //
  9840. // The input and output buffers must be aligned
  9841. //
  9842. !IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  9843. FIND_BY_SID_DATA )
  9844. DebugDoit( && DebugPrint(( "Input buffer not long aligned" ))) ||
  9845. !IsTypeAligned( Irp->UserBuffer, FILE_NAME_INFORMATION )
  9846. DebugDoit( && DebugPrint(( "Output buffer not long aligned" ))) ||
  9847. //
  9848. // There must be enough room in the output buffer.
  9849. // (Input buffer is already verified).
  9850. //
  9851. IrpSp->Parameters.FileSystemControl.OutputBufferLength <
  9852. sizeof( FILE_NAME_INFORMATION )
  9853. DebugDoit( && DebugPrint(( "Output buffer shorter than FILE_NAME_INFORMATION" ))) ||
  9854. //
  9855. // The input flag must be 0 or 1
  9856. //
  9857. CapturedFindData->Restart > 1
  9858. DebugDoit( && DebugPrint(( "Restart not 0/1" ))) ||
  9859. //
  9860. // There must be enough room for a SID in the input
  9861. //
  9862. sizeof( ULONG ) + RtlLengthSid( &FindData->Sid ) >
  9863. IrpSp->Parameters.FileSystemControl.InputBufferLength
  9864. DebugDoit( && DebugPrint(( "Not enough room for input SID" ))) ||
  9865. //
  9866. // Also verify the captured data in case our caller is playing games.
  9867. //
  9868. sizeof( ULONG ) + RtlLengthSid( &CapturedFindData->Sid ) >
  9869. IrpSp->Parameters.FileSystemControl.InputBufferLength
  9870. DebugDoit( && DebugPrint(( "Not enough room for captured input SID" )))
  9871. ) {
  9872. Status = STATUS_INVALID_USER_BUFFER;
  9873. leave;
  9874. }
  9875. //
  9876. // Set up starting file reference either from where the user left off
  9877. // or from the next position
  9878. //
  9879. if (CapturedFindData->Restart) {
  9880. NtfsSetSegmentNumber( &FileReference, 0, ROOT_FILE_NAME_INDEX_NUMBER );
  9881. } else {
  9882. ASSERT( Ccb->NodeByteSize == sizeof( CCB ) );
  9883. FileReference = Ccb->MftScanFileReference;
  9884. if (NtfsSegmentNumber( &FileReference ) < ROOT_FILE_NAME_INDEX_NUMBER) {
  9885. NtfsSetSegmentNumber( &FileReference, 0, ROOT_FILE_NAME_INDEX_NUMBER );
  9886. }
  9887. }
  9888. //
  9889. // Set up for filling output records
  9890. //
  9891. Context.RoomLeft = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  9892. Context.FileNames = (PFILE_NAME_INFORMATION) Irp->UserBuffer;
  9893. Context.BytesUsed = 0;
  9894. //
  9895. // Convert input Sid into OWNER_ID. If we haven't seen this SID before
  9896. // then we are done! We use the copy of the Sid so we don't take an access
  9897. // violation in the user frees the memory. Some of our internal routines
  9898. // never expect a failure touching this buffer.
  9899. //
  9900. Context.OwnerId = NtfsGetOwnerId( IrpContext, &CapturedFindData->Sid, FALSE, NULL );
  9901. if (Context.OwnerId == QUOTA_INVALID_ID) {
  9902. Status = STATUS_SUCCESS;
  9903. leave;
  9904. }
  9905. Context.Parent = Fcb->FileReference;
  9906. //
  9907. // Iterate through the Mft beginning at the specified file reference.
  9908. // Release the Vcb now because the worker routine will acquire and
  9909. // drop as necessary. We don't want to block out critical operations
  9910. // like clean checkpoints during a full Mft scan.
  9911. //
  9912. NtfsReleaseVcb( IrpContext, Vcb );
  9913. ReleaseVcb = FALSE;
  9914. Status = NtfsIterateMft( IrpContext,
  9915. Vcb,
  9916. &FileReference,
  9917. NtfsFindBySidWorker,
  9918. &Context );
  9919. //
  9920. // If we failed due to running out of space and we stored something or
  9921. // if we ran off the end of the MFT, then this is really a successful
  9922. // return.
  9923. //
  9924. Irp->IoStatus.Information = Context.BytesUsed;
  9925. if (!NT_SUCCESS( Status )) {
  9926. if ((Status == STATUS_BUFFER_TOO_SMALL && Context.BytesUsed != 0)
  9927. || Status == STATUS_END_OF_FILE) {
  9928. Status = STATUS_SUCCESS;
  9929. } else {
  9930. leave;
  9931. }
  9932. }
  9933. Ccb->MftScanFileReference = FileReference;
  9934. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  9935. NtfsRaiseStatus( IrpContext,
  9936. STATUS_INVALID_USER_BUFFER,
  9937. NULL,
  9938. NULL);
  9939. }
  9940. } finally {
  9941. //
  9942. // Free the Vcb if still held.
  9943. //
  9944. if (ReleaseVcb) {
  9945. NtfsReleaseVcb( IrpContext, Vcb );
  9946. }
  9947. //
  9948. // Free the captured input buffer if allocated.
  9949. //
  9950. if (CapturedFindData != NULL) {
  9951. NtfsFreePool( CapturedFindData );
  9952. }
  9953. }
  9954. //
  9955. // If nothing raised then complete the irp.
  9956. //
  9957. NtfsCompleteRequest( IrpContext, Irp, Status );
  9958. return Status;
  9959. }
  9960. //
  9961. // Local Support Routine
  9962. //
  9963. NTSTATUS
  9964. NtfsReadFileUsnData (
  9965. IN PIRP_CONTEXT IrpContext,
  9966. IN PIRP Irp
  9967. )
  9968. /*++
  9969. Routine Description:
  9970. This routine enumerates base file records beginning at a specified
  9971. one and returns USN data from the found records.
  9972. Arguments:
  9973. IrpContext - context of the call
  9974. Irp - request being serviced
  9975. RecordVersion - format for the usn record to return
  9976. Return Value:
  9977. NTSTATUS - The return status for the operation
  9978. --*/
  9979. {
  9980. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  9981. NTSTATUS Status = STATUS_SUCCESS;
  9982. USN_DATA_CONTEXT Context;
  9983. PFILE_OBJECT FileObject;
  9984. TYPE_OF_OPEN TypeOfOpen;
  9985. PVCB Vcb;
  9986. PFCB Fcb;
  9987. PSCB Scb;
  9988. PCCB Ccb;
  9989. //
  9990. // Don't post this request.
  9991. //
  9992. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  9993. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  9994. //
  9995. // Get the current Irp stack location and save some references.
  9996. //
  9997. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  9998. //
  9999. // Extract and decode the file object and check for type of open.
  10000. // We don't want to raise on dismounts here because we check for that further down
  10001. // anyway. So send FALSE.
  10002. //
  10003. FileObject = IrpSp->FileObject;
  10004. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  10005. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  10006. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10007. return STATUS_INVALID_PARAMETER;
  10008. }
  10009. //
  10010. // Check that the user's buffer is large enough.
  10011. //
  10012. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof( USN_RECORD )) {
  10013. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  10014. return STATUS_BUFFER_TOO_SMALL;
  10015. }
  10016. //
  10017. // Set up for filling output records
  10018. //
  10019. Context.RoomLeft = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  10020. Context.UsnRecord = Irp->UserBuffer;
  10021. Context.BytesUsed = 0;
  10022. Context.LowUsn = 0;
  10023. Context.HighUsn = MAXLONGLONG;
  10024. NtfsAcquireSharedScb( IrpContext, Scb );
  10025. try {
  10026. //
  10027. // Verify the volume is mounted.
  10028. //
  10029. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10030. Status = STATUS_VOLUME_DISMOUNTED;
  10031. leave;
  10032. }
  10033. //
  10034. // Careful access to the user's buffer.
  10035. //
  10036. try {
  10037. //
  10038. // Probe the output buffer.
  10039. //
  10040. if (Irp->RequestorMode != KernelMode) {
  10041. ProbeForWrite( Irp->UserBuffer,
  10042. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  10043. NTFS_TYPE_ALIGNMENT( USN_DATA_CONTEXT ));
  10044. } else if (!IsTypeAligned( Irp->UserBuffer, USN_DATA_CONTEXT )) {
  10045. Status = STATUS_INVALID_USER_BUFFER;
  10046. leave;
  10047. }
  10048. //
  10049. // Now read the Usn data.
  10050. //
  10051. Status = NtfsReadUsnWorker( IrpContext, Fcb, &Context );
  10052. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  10053. NtfsRaiseStatus( IrpContext,
  10054. STATUS_INVALID_USER_BUFFER,
  10055. NULL,
  10056. NULL );
  10057. }
  10058. } finally {
  10059. NtfsReleaseScb( IrpContext, Scb );
  10060. }
  10061. //
  10062. // On success return bytes in Usn Record.
  10063. //
  10064. if (NT_SUCCESS(Status)) {
  10065. Irp->IoStatus.Information = Context.BytesUsed;
  10066. }
  10067. NtfsCompleteRequest( IrpContext, Irp, Status);
  10068. return Status;
  10069. }
  10070. //
  10071. // Local Support Routine
  10072. //
  10073. NTSTATUS
  10074. NtfsWriteUsnCloseRecord (
  10075. IN PIRP_CONTEXT IrpContext,
  10076. IN PIRP Irp
  10077. )
  10078. /*++
  10079. Routine Description:
  10080. This routine writes a close Usn record for the current file, and returns
  10081. its Usn.
  10082. Arguments:
  10083. IrpContext - context of the call
  10084. Irp - request being serviced
  10085. Return Value:
  10086. NTSTATUS - The return status for the operation
  10087. --*/
  10088. {
  10089. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10090. NTSTATUS Status = STATUS_SUCCESS;
  10091. PFILE_OBJECT FileObject;
  10092. TYPE_OF_OPEN TypeOfOpen;
  10093. PVCB Vcb;
  10094. PFCB Fcb;
  10095. PSCB Scb;
  10096. PCCB Ccb;
  10097. PVOID UserBuffer;
  10098. BOOLEAN AccessingUserBuffer = FALSE;
  10099. //
  10100. // Go ahead and make this operation synchronous.
  10101. //
  10102. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10103. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10104. //
  10105. // Get the current Irp stack location and save some references.
  10106. //
  10107. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  10108. //
  10109. // Extract and decode the file object and check for type of open.
  10110. // We check for dismount further below, so send FALSE to not raise here.
  10111. //
  10112. FileObject = IrpSp->FileObject;
  10113. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  10114. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  10115. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10116. return STATUS_INVALID_PARAMETER;
  10117. }
  10118. if (NtfsIsVolumeReadOnly( Vcb )) {
  10119. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  10120. return STATUS_MEDIA_WRITE_PROTECTED;
  10121. }
  10122. //
  10123. // There must be room in the output buffer.
  10124. //
  10125. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof( USN )) {
  10126. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10127. return STATUS_INVALID_PARAMETER;
  10128. }
  10129. UserBuffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  10130. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10131. try {
  10132. //
  10133. // Verify the volume is mounted.
  10134. //
  10135. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10136. Status = STATUS_VOLUME_DISMOUNTED;
  10137. leave;
  10138. }
  10139. //
  10140. // Fail this request if the journal is being deleted or is not running.
  10141. //
  10142. if (FlagOn( Vcb->VcbState, VCB_STATE_USN_DELETE )) {
  10143. Status = STATUS_JOURNAL_DELETE_IN_PROGRESS;
  10144. leave;
  10145. }
  10146. if (!FlagOn( Vcb->VcbState, VCB_STATE_USN_JOURNAL_ACTIVE )) {
  10147. Status = STATUS_JOURNAL_NOT_ACTIVE;
  10148. leave;
  10149. }
  10150. //
  10151. // Use a try-except to check our access to the user buffer.
  10152. //
  10153. try {
  10154. //
  10155. // Probe the output buffer.
  10156. //
  10157. if (Irp->RequestorMode != KernelMode) {
  10158. AccessingUserBuffer = TRUE;
  10159. ProbeForWrite( UserBuffer,
  10160. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  10161. NTFS_TYPE_ALIGNMENT( USN ));
  10162. AccessingUserBuffer = FALSE;
  10163. } else if (!IsTypeAligned( UserBuffer, USN )) {
  10164. Status = STATUS_INVALID_USER_BUFFER;
  10165. leave;
  10166. }
  10167. //
  10168. // Now write the close record.
  10169. //
  10170. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_CLOSE );
  10171. //
  10172. // Now, if anything at all is posted to the Usn Journal, we must write it now
  10173. // so that we do not get a log file full later.
  10174. //
  10175. ASSERT( IrpContext->Usn.NextUsnFcb == NULL );
  10176. if (IrpContext->Usn.CurrentUsnFcb != NULL) {
  10177. //
  10178. // Now write the journal, checkpoint the transaction, and free the UsnJournal to
  10179. // reduce contention.
  10180. //
  10181. NtfsWriteUsnJournalChanges( IrpContext );
  10182. NtfsCheckpointCurrentTransaction( IrpContext );
  10183. }
  10184. //
  10185. // Set the returned Usn.
  10186. //
  10187. AccessingUserBuffer = TRUE;
  10188. *((USN *) UserBuffer) = Fcb->Usn;
  10189. AccessingUserBuffer = FALSE;
  10190. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status )) {
  10191. NtfsRaiseStatus( IrpContext,
  10192. STATUS_INVALID_USER_BUFFER,
  10193. NULL,
  10194. NULL );
  10195. }
  10196. } finally {
  10197. NtfsReleaseScb( IrpContext, Scb );
  10198. }
  10199. //
  10200. // On success return bytes in Usn Record.
  10201. //
  10202. if (NT_SUCCESS( Status )) {
  10203. Irp->IoStatus.Information = sizeof( USN );
  10204. }
  10205. NtfsCompleteRequest( IrpContext, Irp, Status );
  10206. return Status;
  10207. }
  10208. //
  10209. // Local Support Routine
  10210. //
  10211. NTSTATUS
  10212. NtfsBulkSecurityIdCheck (
  10213. IN PIRP_CONTEXT IrpContext,
  10214. IN PIRP Irp
  10215. )
  10216. /*++
  10217. Routine Description:
  10218. This routine performs a check to see if the current subject is granted access by
  10219. the security descriptors identified by the security Ids.
  10220. Arguments:
  10221. IrpContext - context of the call
  10222. Irp - request being serviced
  10223. Return Value:
  10224. NTSTATUS - The return status for the operation
  10225. --*/
  10226. {
  10227. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10228. NTSTATUS Status = STATUS_SUCCESS;
  10229. PBULK_SECURITY_TEST_DATA SecurityData =
  10230. (PBULK_SECURITY_TEST_DATA) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  10231. PNTSTATUS OutputStatus = (PNTSTATUS) Irp->UserBuffer;
  10232. ACCESS_MASK DesiredAccess;
  10233. BOOLEAN AccessGranted;
  10234. ACCESS_MASK GrantedAccess;
  10235. ULONG i, SecurityIdCount;
  10236. SECURITY_SUBJECT_CONTEXT SecurityContext;
  10237. TYPE_OF_OPEN TypeOfOpen;
  10238. PVCB Vcb;
  10239. PFCB Fcb;
  10240. PSCB Scb;
  10241. PCCB Ccb;
  10242. ASSERT_IRP_CONTEXT( IrpContext );
  10243. ASSERT_IRP( Irp );
  10244. PAGED_CODE();
  10245. DebugTrace( +1, Dbg, ("NtfsBulkSecurityIdCheck...\n") );
  10246. //
  10247. // Don't post this request, we can't lock both input and output buffers.
  10248. //
  10249. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10250. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10251. //
  10252. // Verify this is a valid type of open.
  10253. //
  10254. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  10255. IrpSp->FileObject,
  10256. &Vcb,
  10257. &Fcb,
  10258. &Scb,
  10259. &Ccb,
  10260. TRUE );
  10261. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  10262. Status = STATUS_ACCESS_DENIED;
  10263. DebugTrace( -1, Dbg, ("NtfsBulkSecurityIdCheck -> %08lx\n", Status) );
  10264. NtfsCompleteRequest( IrpContext, Irp, Status );
  10265. return Status;
  10266. }
  10267. try {
  10268. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  10269. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  10270. Status = STATUS_VOLUME_DISMOUNTED;
  10271. leave;
  10272. }
  10273. try {
  10274. if (Irp->RequestorMode != KernelMode) {
  10275. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10276. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  10277. NTFS_TYPE_ALIGNMENT( BULK_SECURITY_TEST_DATA ));
  10278. ProbeForWrite( Irp->UserBuffer,
  10279. IrpSp->Parameters.FileSystemControl.OutputBufferLength,
  10280. sizeof( ULONG ));
  10281. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10282. BULK_SECURITY_TEST_DATA ) ||
  10283. !IsTypeAligned( Irp->UserBuffer, ULONG )) {
  10284. Status = STATUS_INVALID_USER_BUFFER;
  10285. leave;
  10286. }
  10287. SecurityIdCount =
  10288. (IrpSp->Parameters.FileSystemControl.InputBufferLength
  10289. - FIELD_OFFSET( BULK_SECURITY_TEST_DATA, SecurityIds )) / sizeof( SECURITY_ID );
  10290. //
  10291. // The output buffer must contain the same number of NTSTATUS
  10292. // as SECURITY_IDs
  10293. //
  10294. if (SecurityIdCount * sizeof( NTSTATUS ) != IrpSp->Parameters.FileSystemControl.OutputBufferLength) {
  10295. NtfsRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER, NULL, NULL );
  10296. }
  10297. //
  10298. // Capture the desired access so we can modify it
  10299. //
  10300. DesiredAccess = SecurityData->DesiredAccess;
  10301. RtlMapGenericMask( &DesiredAccess, IoGetFileObjectGenericMapping() );
  10302. SeCaptureSubjectContext( &SecurityContext );
  10303. SeLockSubjectContext( &SecurityContext );
  10304. try {
  10305. for (i = 0; i < SecurityIdCount; i++) {
  10306. PSHARED_SECURITY SharedSecurity;
  10307. SharedSecurity = NtfsCacheSharedSecurityBySecurityId( IrpContext,
  10308. Vcb,
  10309. SecurityData->SecurityIds[i] );
  10310. //
  10311. // Do the access check
  10312. //
  10313. AccessGranted = SeAccessCheck( SharedSecurity->SecurityDescriptor,
  10314. &SecurityContext,
  10315. TRUE, // Tokens are locked
  10316. DesiredAccess,
  10317. 0,
  10318. NULL,
  10319. IoGetFileObjectGenericMapping(),
  10320. UserMode,
  10321. &GrantedAccess,
  10322. &OutputStatus[i] );
  10323. NtfsAcquireFcbSecurity( Vcb );
  10324. RemoveReferenceSharedSecurityUnsafe( &SharedSecurity );
  10325. NtfsReleaseFcbSecurity( Vcb );
  10326. }
  10327. } finally {
  10328. SeUnlockSubjectContext( &SecurityContext );
  10329. SeReleaseSubjectContext( &SecurityContext );
  10330. }
  10331. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  10332. NtfsRaiseStatus( IrpContext,
  10333. STATUS_INVALID_USER_BUFFER,
  10334. NULL,
  10335. NULL );
  10336. }
  10337. } finally {
  10338. NtfsReleaseVcb( IrpContext, Vcb );
  10339. }
  10340. NtfsCompleteRequest( IrpContext, Irp, Status);
  10341. return Status;
  10342. }
  10343. //
  10344. // Local support routine.
  10345. //
  10346. NTSTATUS
  10347. NtfsQueryAllocatedRanges (
  10348. IN PIRP_CONTEXT IrpContext,
  10349. IN PIRP Irp
  10350. )
  10351. /*++
  10352. Routine Description:
  10353. This routines scans the allocation of the file looking for allocated ranges
  10354. starting from some offset given by our caller. An allocated range is one
  10355. which either has any allocation within the defined sparse block size (64K) or
  10356. has any clusters reserved within this same block. Sparse file support is meant
  10357. to optimize the case where the user has a large unallocated range. We will
  10358. force him to read zeroes from the file where the deallocated ranges are
  10359. smaller than 64K.
  10360. If the file is not marked as sparse then we will return the entire file as
  10361. allocated even for the compressed stream case where large blocks of
  10362. zeroes are represented by holes.
  10363. The Irp contains the input and output buffers for this request. This fsctrl
  10364. specifies METHOD_NEITHER so we must carefully access these buffers.
  10365. Arguments:
  10366. Irp - Request being serviced
  10367. Return Value:
  10368. NTSTATUS - The return status for the operation
  10369. --*/
  10370. {
  10371. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10372. NTSTATUS Status = STATUS_SUCCESS;
  10373. BOOLEAN AcquiredScb = FALSE;
  10374. PVCB Vcb;
  10375. PFCB Fcb;
  10376. PSCB Scb;
  10377. PCCB Ccb;
  10378. BOOLEAN AccessingUserBuffer = FALSE;
  10379. BOOLEAN Allocated;
  10380. ULONG RemainingBytes;
  10381. LONGLONG StartingOffset;
  10382. LONGLONG Length;
  10383. PFILE_ALLOCATED_RANGE_BUFFER OutputBuffer;
  10384. PFILE_ALLOCATED_RANGE_BUFFER CurrentBuffer;
  10385. VCN NextVcn;
  10386. VCN CurrentVcn;
  10387. LONGLONG RemainingClusters;
  10388. LONGLONG ThisClusterCount;
  10389. LONGLONG TwoGigInClusters;
  10390. BOOLEAN UserMappedView;
  10391. ASSERT_IRP_CONTEXT( IrpContext );
  10392. ASSERT_IRP( Irp );
  10393. PAGED_CODE();
  10394. Irp->IoStatus.Information = 0;
  10395. //
  10396. // Don't post this request, we can't lock both input and output buffers.
  10397. //
  10398. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  10399. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  10400. //
  10401. // Extract and decode the file object.
  10402. // We only allow this operation on user data files.
  10403. // We check for dismount further below, so send FALSE to not raise here.
  10404. //
  10405. if (NtfsDecodeFileObject( IrpContext,
  10406. IrpSp->FileObject,
  10407. &Vcb,
  10408. &Fcb,
  10409. &Scb,
  10410. &Ccb,
  10411. FALSE ) != UserFileOpen) {
  10412. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10413. return STATUS_INVALID_PARAMETER;
  10414. }
  10415. //
  10416. // Acquired exclusive access to the paging Io resource because we might
  10417. // need to extend the file when flushing the cache
  10418. //
  10419. NtfsAcquireExclusivePagingIo( IrpContext, Scb->Fcb );
  10420. //
  10421. // Use a try-finally to facilitate cleanup.
  10422. //
  10423. try {
  10424. //
  10425. // If the volume isn't mounted then fail immediately.
  10426. //
  10427. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10428. Status = STATUS_VOLUME_DISMOUNTED;
  10429. leave;
  10430. }
  10431. //
  10432. // Check the length of the input buffer.
  10433. //
  10434. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  10435. Status = STATUS_INVALID_PARAMETER;
  10436. leave;
  10437. }
  10438. //
  10439. // Use a try-except to catch any errors accessing the user's buffers.
  10440. // We will maintain a boolean which indicates if we are accessing
  10441. // the user's buffer.
  10442. //
  10443. AccessingUserBuffer = TRUE;
  10444. try {
  10445. //
  10446. // If our caller is not kernel mode then probe the input and
  10447. // output buffers.
  10448. //
  10449. RemainingBytes = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  10450. OutputBuffer = (PFILE_ALLOCATED_RANGE_BUFFER) NtfsMapUserBuffer( Irp, NormalPagePriority );
  10451. CurrentBuffer = OutputBuffer - 1;
  10452. if (Irp->RequestorMode != KernelMode) {
  10453. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10454. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  10455. NTFS_TYPE_ALIGNMENT( FILE_ALLOCATED_RANGE_BUFFER ));
  10456. ProbeForWrite( OutputBuffer,
  10457. RemainingBytes,
  10458. NTFS_TYPE_ALIGNMENT( FILE_ALLOCATED_RANGE_BUFFER ));
  10459. } else if (!IsTypeAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  10460. FILE_ALLOCATED_RANGE_BUFFER ) ||
  10461. !IsTypeAligned( OutputBuffer, FILE_ALLOCATED_RANGE_BUFFER )) {
  10462. Status = STATUS_INVALID_USER_BUFFER;
  10463. leave;
  10464. }
  10465. //
  10466. // Carefully extract the starting offset and length from
  10467. // the input buffer. If we are beyond the end of the file
  10468. // or the length is zero then return immediately. Otherwise
  10469. // trim the length to file size.
  10470. //
  10471. StartingOffset = ((PFILE_ALLOCATED_RANGE_BUFFER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->FileOffset.QuadPart;
  10472. Length = ((PFILE_ALLOCATED_RANGE_BUFFER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->Length.QuadPart;
  10473. AccessingUserBuffer = FALSE;
  10474. //
  10475. // Check that the input parameters are valid.
  10476. //
  10477. if ((Length < 0) ||
  10478. (StartingOffset < 0) ||
  10479. (Length > MAXLONGLONG - StartingOffset)) {
  10480. Status = STATUS_INVALID_PARAMETER;
  10481. leave;
  10482. }
  10483. //
  10484. // Check that the requested range is within file size
  10485. // and has a non-zero length.
  10486. //
  10487. if (Length == 0) {
  10488. leave;
  10489. }
  10490. //
  10491. // Lets acquire the Scb for the file as well.
  10492. //
  10493. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10494. AcquiredScb = TRUE;
  10495. NtfsAcquireFsrtlHeader( Scb );
  10496. if (StartingOffset >= Scb->Header.FileSize.QuadPart) {
  10497. NtfsReleaseFsrtlHeader( Scb );
  10498. leave;
  10499. }
  10500. if (Scb->Header.FileSize.QuadPart - StartingOffset < Length) {
  10501. Length = Scb->Header.FileSize.QuadPart - StartingOffset;
  10502. }
  10503. NtfsReleaseFsrtlHeader( Scb );
  10504. //
  10505. // If the file is not sparse or is resident then show that
  10506. // the entire requested range is allocated.
  10507. //
  10508. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE ) ||
  10509. FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  10510. if (RemainingBytes < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  10511. Status = STATUS_BUFFER_TOO_SMALL;
  10512. } else {
  10513. CurrentBuffer += 1;
  10514. AccessingUserBuffer = TRUE;
  10515. CurrentBuffer->FileOffset.QuadPart = StartingOffset;
  10516. CurrentBuffer->Length.QuadPart = Length;
  10517. Irp->IoStatus.Information = sizeof( FILE_ALLOCATED_RANGE_BUFFER );
  10518. }
  10519. leave;
  10520. }
  10521. //
  10522. // Convert the range to check to Vcns so we can use the
  10523. // allocation routines.
  10524. //
  10525. NextVcn = -1;
  10526. CurrentVcn = LlClustersFromBytesTruncate( Vcb, StartingOffset );
  10527. CurrentVcn = BlockAlignTruncate( CurrentVcn, (LONG)Vcb->SparseFileClusters );
  10528. RemainingClusters = LlClustersFromBytesTruncate( Vcb,
  10529. StartingOffset + Length + Vcb->SparseFileUnit - 1 );
  10530. RemainingClusters = BlockAlignTruncate( RemainingClusters, (LONG)Vcb->SparseFileClusters );
  10531. RemainingClusters -= CurrentVcn;
  10532. TwoGigInClusters = LlClustersFromBytesTruncate( Vcb, (LONGLONG) 0x80000000 );
  10533. //
  10534. // We will walk through the file in two gigabyte chunks.
  10535. //
  10536. do {
  10537. //
  10538. // We will try to swallow two gig at a time.
  10539. //
  10540. ThisClusterCount = TwoGigInClusters;
  10541. if (ThisClusterCount > RemainingClusters) {
  10542. ThisClusterCount = RemainingClusters;
  10543. }
  10544. RemainingClusters -= ThisClusterCount;
  10545. //
  10546. // Preload two gigabytes of allocation information at our Current Vcn.
  10547. //
  10548. NtfsPreloadAllocation( IrpContext,
  10549. Scb,
  10550. CurrentVcn,
  10551. CurrentVcn + ThisClusterCount );
  10552. //
  10553. // If the file is mapped then flush the data so we can simply
  10554. // trust the Mcb. There is a performance cost here but otherwise
  10555. // we would be returning the entire file as allocated.
  10556. //
  10557. if (FlagOn( Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE ) &&
  10558. FlagOn( Scb->ScbState, SCB_STATE_WRITE_ACCESS_SEEN ) &&
  10559. (Scb->NonpagedScb->SegmentObject.DataSectionObject != NULL)) {
  10560. LONGLONG CheckClusterCount;
  10561. LONGLONG RemainingCheckClusterCount = ThisClusterCount;
  10562. LONGLONG FlushOffset;
  10563. VCN CheckVcn = CurrentVcn;
  10564. BOOLEAN ReloadAllocation = FALSE;
  10565. PRESERVED_BITMAP_RANGE BitMap = Scb->ScbType.Data.ReservedBitMap;
  10566. ASSERT( Scb->Header.NodeTypeCode == NTFS_NTC_SCB_DATA );
  10567. while (TRUE) {
  10568. //
  10569. // Check to see if this range is allocated.
  10570. //
  10571. Allocated = NtfsIsRangeAllocated( Scb,
  10572. CheckVcn,
  10573. CheckVcn + RemainingCheckClusterCount,
  10574. TRUE,
  10575. &CheckClusterCount );
  10576. if (!Allocated) {
  10577. if (Scb->FileObject == NULL) {
  10578. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  10579. }
  10580. NtfsReleaseScb( IrpContext, Scb );
  10581. AcquiredScb = FALSE;
  10582. FlushOffset = LlBytesFromClusters( Vcb, CheckVcn );
  10583. CcFlushCache( &Scb->NonpagedScb->SegmentObject,
  10584. (PLARGE_INTEGER) &FlushOffset,
  10585. (ULONG) LlBytesFromClusters( Vcb, CheckClusterCount ),
  10586. &Irp->IoStatus );
  10587. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10588. AcquiredScb = TRUE;
  10589. //
  10590. // On error get out.
  10591. //
  10592. NtfsNormalizeAndCleanupTransaction( IrpContext,
  10593. &Irp->IoStatus.Status,
  10594. TRUE,
  10595. STATUS_UNEXPECTED_IO_ERROR );
  10596. ReloadAllocation = TRUE;
  10597. }
  10598. if (RemainingCheckClusterCount <= CheckClusterCount) {
  10599. break;
  10600. }
  10601. RemainingCheckClusterCount -= CheckClusterCount;
  10602. CheckVcn += CheckClusterCount;
  10603. }
  10604. //
  10605. // Reload two gigabytes of allocation information at our Current Vcn.
  10606. //
  10607. if (ReloadAllocation) {
  10608. NtfsPreloadAllocation( IrpContext,
  10609. Scb,
  10610. CurrentVcn,
  10611. CurrentVcn + ThisClusterCount );
  10612. }
  10613. }
  10614. //
  10615. // Loop while we have more clusters to look for. We will load
  10616. // two gigabytes of allocation at a time into the Mcb.
  10617. //
  10618. UserMappedView = !(MmCanFileBeTruncated( &(Scb->NonpagedScb->SegmentObject), NULL ));
  10619. do {
  10620. LONGLONG CurrentClusterCount;
  10621. //
  10622. // Check to see if this range is allocated.
  10623. //
  10624. Allocated = NtfsIsRangeAllocated( Scb,
  10625. CurrentVcn,
  10626. CurrentVcn + ThisClusterCount,
  10627. TRUE,
  10628. &CurrentClusterCount );
  10629. //
  10630. // If we have an unallocated range then we need to trim it by any
  10631. // sparse units which have reservation. This is possible if it we haven't flushed because
  10632. // its never been mapped or its still being user mapped so our flush is unreliable.
  10633. // If the first unit has reservation then change the state of the range to 'Allocated'.
  10634. //
  10635. if ((UserMappedView || !FlagOn( Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE )) &&
  10636. !Allocated &&
  10637. NtfsCheckForReservedClusters( Scb, CurrentVcn, &CurrentClusterCount ) &&
  10638. (CurrentClusterCount < Vcb->SparseFileClusters)) {
  10639. Allocated = TRUE;
  10640. CurrentClusterCount = Vcb->SparseFileClusters;
  10641. }
  10642. //
  10643. // If allocated check and see whether to extend a previous
  10644. // run or start a new run.
  10645. //
  10646. if (Allocated) {
  10647. //
  10648. // Extend the previous run if contiguous.
  10649. //
  10650. AccessingUserBuffer = TRUE;
  10651. if (NextVcn == CurrentVcn) {
  10652. CurrentBuffer->Length.QuadPart += LlBytesFromClusters( Vcb, CurrentClusterCount );
  10653. //
  10654. // Otherwise use the next buffer location.
  10655. //
  10656. } else {
  10657. //
  10658. // Check that there is space.
  10659. //
  10660. if (RemainingBytes < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  10661. //
  10662. // We may already have some entries in the buffer. Return
  10663. // a different code if we were able to store at least one
  10664. // entry in the output buffer.
  10665. //
  10666. if (CurrentBuffer + 1 == OutputBuffer) {
  10667. Status = STATUS_BUFFER_TOO_SMALL;
  10668. } else {
  10669. Status = STATUS_BUFFER_OVERFLOW;
  10670. }
  10671. RemainingClusters = 0;
  10672. break;
  10673. }
  10674. RemainingBytes -= sizeof( FILE_ALLOCATED_RANGE_BUFFER );
  10675. //
  10676. // Move to the next position in the buffer and
  10677. // fill in the current position.
  10678. //
  10679. CurrentBuffer += 1;
  10680. CurrentBuffer->FileOffset.QuadPart = LlBytesFromClusters( Vcb, CurrentVcn );
  10681. CurrentBuffer->Length.QuadPart = LlBytesFromClusters( Vcb, CurrentClusterCount );
  10682. }
  10683. AccessingUserBuffer = FALSE;
  10684. CurrentVcn += CurrentClusterCount;
  10685. NextVcn = CurrentVcn;
  10686. //
  10687. // Otherwise move forward to the next range.
  10688. //
  10689. } else {
  10690. CurrentVcn += CurrentClusterCount;
  10691. }
  10692. //
  10693. // Break out of the loop if we have processed all of the user's
  10694. // clusters.
  10695. //
  10696. //
  10697. // Grab the FsRtl header lock to check if we are beyond
  10698. // file size. If so then trim the last entry in the
  10699. // output buffer to file size if necessary and break out.
  10700. //
  10701. NtfsAcquireFsrtlHeader( Scb );
  10702. if (((LONGLONG) LlBytesFromClusters( Vcb, CurrentVcn )) >= Scb->Header.FileSize.QuadPart) {
  10703. NtfsReleaseFsrtlHeader( Scb );
  10704. RemainingClusters = 0;
  10705. break;
  10706. }
  10707. NtfsReleaseFsrtlHeader( Scb );
  10708. ThisClusterCount -= CurrentClusterCount;
  10709. } while (ThisClusterCount > 0);
  10710. } while (RemainingClusters != 0);
  10711. //
  10712. // If we have at least one entry then check and see if we
  10713. // need to bias either the starting value or final
  10714. // length based on the user's input values.
  10715. //
  10716. if (CurrentBuffer != OutputBuffer - 1) {
  10717. AccessingUserBuffer = TRUE;
  10718. if (OutputBuffer->FileOffset.QuadPart < StartingOffset) {
  10719. OutputBuffer->Length.QuadPart -= (StartingOffset - OutputBuffer->FileOffset.QuadPart);
  10720. OutputBuffer->FileOffset.QuadPart = StartingOffset;
  10721. }
  10722. if ((CurrentBuffer->FileOffset.QuadPart + CurrentBuffer->Length.QuadPart) >
  10723. (StartingOffset + Length)) {
  10724. CurrentBuffer->Length.QuadPart = StartingOffset + Length - CurrentBuffer->FileOffset.QuadPart;
  10725. }
  10726. AccessingUserBuffer = FALSE;
  10727. }
  10728. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  10729. //
  10730. // Convert any unexpected error to INVALID_USER_BUFFER if we
  10731. // are writing in the user's buffer.
  10732. //
  10733. NtfsRaiseStatus( IrpContext,
  10734. STATUS_INVALID_USER_BUFFER,
  10735. NULL,
  10736. NULL );
  10737. }
  10738. //
  10739. // If we were successful then update the output information.
  10740. //
  10741. Irp->IoStatus.Information = PtrOffset( OutputBuffer, (CurrentBuffer + 1) );
  10742. } finally {
  10743. DebugUnwind( NtfsQueryAllocatedRanges );
  10744. //
  10745. // Release resources.
  10746. //
  10747. NtfsReleasePagingIo( IrpContext, Scb->Fcb );
  10748. if (AcquiredScb) {
  10749. NtfsReleaseScb( IrpContext, Scb );
  10750. }
  10751. //
  10752. // If nothing raised then complete the irp.
  10753. //
  10754. if (!AbnormalTermination()) {
  10755. NtfsCompleteRequest( IrpContext, Irp, Status );
  10756. }
  10757. }
  10758. return Status;
  10759. }
  10760. //
  10761. // Local support routine.
  10762. //
  10763. NTSTATUS
  10764. NtfsSetSparse (
  10765. IN PIRP_CONTEXT IrpContext,
  10766. IN PIRP Irp
  10767. )
  10768. /*++
  10769. Routine Description:
  10770. This routine is called to set the state of a stream to sparse. We only allow
  10771. this on user data streams. There is no input or output buffer needed for this call.
  10772. Arguments:
  10773. Irp - Request being serviced
  10774. Return Value:
  10775. NTSTATUS - The return status for the operation
  10776. --*/
  10777. {
  10778. NTSTATUS Status = STATUS_SUCCESS;
  10779. PVCB Vcb;
  10780. PFCB Fcb;
  10781. PSCB Scb;
  10782. PCCB Ccb;
  10783. PIO_STACK_LOCATION IrpSp;
  10784. BOOLEAN SetSparse = TRUE;
  10785. PAGED_CODE();
  10786. //
  10787. // Decode the file object, fail this request if not a user data stream.
  10788. // We check for dismount further below, so send FALSE to not raise here.
  10789. //
  10790. if (NtfsDecodeFileObject( IrpContext,
  10791. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10792. &Vcb,
  10793. &Fcb,
  10794. &Scb,
  10795. &Ccb,
  10796. FALSE ) != UserFileOpen) {
  10797. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10798. return STATUS_INVALID_PARAMETER;
  10799. }
  10800. //
  10801. // For now accept a zero length input buffer meaning set sparse
  10802. // remove this before shipping nt5
  10803. //
  10804. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  10805. if (IrpSp->Parameters.FileSystemControl.InputBufferLength != 0 &&
  10806. IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( FILE_SET_SPARSE_BUFFER )) {
  10807. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10808. return STATUS_INVALID_PARAMETER;
  10809. }
  10810. //
  10811. // Fsctrl is buffered so we don't need to probe etc. the input
  10812. //
  10813. if ((Irp->RequestorMode != KernelMode) && (IrpSp->Parameters.FileSystemControl.InputBufferLength != 0) ) {
  10814. SetSparse = ((PFILE_SET_SPARSE_BUFFER)Irp->AssociatedIrp.SystemBuffer)->SetSparse;
  10815. }
  10816. //
  10817. // For this release we don't support unsparsifying files
  10818. //
  10819. if (SetSparse == FALSE) {
  10820. NtfsCompleteRequest( IrpContext, Irp, STATUS_NOT_IMPLEMENTED );
  10821. return STATUS_NOT_IMPLEMENTED;
  10822. }
  10823. //
  10824. // Only upgraded volumes can have sparse files.
  10825. //
  10826. if (!NtfsVolumeVersionCheck( Vcb, NTFS_SPARSE_FILE_VERSION )) {
  10827. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  10828. return STATUS_VOLUME_NOT_UPGRADED;
  10829. }
  10830. //
  10831. // Readonly mount should be just that: read only.
  10832. //
  10833. if (NtfsIsVolumeReadOnly( Vcb )) {
  10834. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  10835. return STATUS_MEDIA_WRITE_PROTECTED;
  10836. }
  10837. //
  10838. // Remember the source info flags in the Ccb.
  10839. //
  10840. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  10841. //
  10842. // Acquire the paging Io resource. User data streams should always have
  10843. // a paging io resource.
  10844. //
  10845. ASSERT( Scb->Header.PagingIoResource != NULL );
  10846. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  10847. //
  10848. // Acquire the main resource as well.
  10849. //
  10850. NtfsAcquireExclusiveScb( IrpContext, Scb );
  10851. //
  10852. // Check that the volume is still mounted.
  10853. //
  10854. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  10855. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
  10856. return STATUS_VOLUME_DISMOUNTED;
  10857. }
  10858. //
  10859. // Make sure the caller has the appropriate access to this stream.
  10860. //
  10861. if (!(FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS )) &&
  10862. !IrpSp->FileObject->WriteAccess) {
  10863. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  10864. return STATUS_ACCESS_DENIED;
  10865. }
  10866. //
  10867. // Change the sparse state of the file.
  10868. //
  10869. NtfsSetSparseStream( IrpContext, NULL, Scb );
  10870. //
  10871. // There is no data returned in an output buffer for this.
  10872. //
  10873. Irp->IoStatus.Information = 0;
  10874. //
  10875. // Go ahead and complete the request.
  10876. //
  10877. NtfsCompleteRequest( IrpContext, Irp, Status );
  10878. return Status;
  10879. }
  10880. //
  10881. // Local support routine.
  10882. //
  10883. NTSTATUS
  10884. NtfsZeroRange (
  10885. IN PIRP_CONTEXT IrpContext,
  10886. IN PIRP Irp
  10887. )
  10888. /*++
  10889. Routine Description:
  10890. This routine is called to zero a range of a file. We will also deallocate any convenient
  10891. allocation on a sparse file.
  10892. Arguments:
  10893. Irp - Request being serviced
  10894. Return Value:
  10895. NTSTATUS - The return status for the operation
  10896. --*/
  10897. {
  10898. NTSTATUS Status = STATUS_SUCCESS;
  10899. PFILE_ZERO_DATA_INFORMATION ZeroRange;
  10900. PVCB Vcb;
  10901. PFCB Fcb;
  10902. PSCB Scb;
  10903. PCCB Ccb;
  10904. PAGED_CODE();
  10905. //
  10906. // Make sure the input buffer is large enough for the ZeroRange request.
  10907. //
  10908. if (IoGetCurrentIrpStackLocation( Irp )->Parameters.FileSystemControl.InputBufferLength < sizeof( FILE_ZERO_DATA_INFORMATION )) {
  10909. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10910. return STATUS_INVALID_PARAMETER;
  10911. }
  10912. //
  10913. // Verify the ZeroRange request is properly formed.
  10914. //
  10915. ZeroRange = (PFILE_ZERO_DATA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  10916. if ((ZeroRange->FileOffset.QuadPart < 0) ||
  10917. (ZeroRange->BeyondFinalZero.QuadPart < 0) ||
  10918. (ZeroRange->FileOffset.QuadPart > ZeroRange->BeyondFinalZero.QuadPart)) {
  10919. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10920. return STATUS_INVALID_PARAMETER;
  10921. }
  10922. //
  10923. // Decode the file object, fail this request if not a user data stream.
  10924. //
  10925. if (NtfsDecodeFileObject( IrpContext,
  10926. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10927. &Vcb,
  10928. &Fcb,
  10929. &Scb,
  10930. &Ccb,
  10931. TRUE ) != UserFileOpen) {
  10932. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  10933. return STATUS_INVALID_PARAMETER;
  10934. }
  10935. if (NtfsIsVolumeReadOnly( Vcb )) {
  10936. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  10937. return STATUS_MEDIA_WRITE_PROTECTED;
  10938. }
  10939. //
  10940. // Capture the source information.
  10941. //
  10942. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  10943. //
  10944. // Zero this range of the stream.
  10945. //
  10946. Status = NtfsZeroRangeInStream( IrpContext,
  10947. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10948. Scb,
  10949. &ZeroRange->FileOffset.QuadPart,
  10950. ZeroRange->BeyondFinalZero.QuadPart );
  10951. if (Status != STATUS_PENDING) {
  10952. //
  10953. // There is no data returned in an output buffer for this.
  10954. //
  10955. Irp->IoStatus.Information = 0;
  10956. //
  10957. // Go ahead and complete the request. Raise any error
  10958. // status to make sure to unwind any Usn reasons.
  10959. //
  10960. if (NT_SUCCESS( Status )) {
  10961. NtfsCompleteRequest( IrpContext, Irp, Status );
  10962. } else {
  10963. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  10964. }
  10965. }
  10966. return Status;
  10967. }
  10968. //
  10969. // Local support routine
  10970. //
  10971. NTSTATUS
  10972. NtfsEncryptionFsctl (
  10973. IN PIRP_CONTEXT IrpContext,
  10974. IN PIRP Irp
  10975. )
  10976. /*++
  10977. Routine Description:
  10978. This routine is called to pass the request through to the installed encryption
  10979. driver if present.
  10980. Arguments:
  10981. Irp - Request being serviced
  10982. Return Value:
  10983. NTSTATUS - The return status for the operation
  10984. --*/
  10985. {
  10986. NTSTATUS Status = STATUS_SUCCESS;
  10987. PVCB Vcb;
  10988. PFCB Fcb;
  10989. PSCB Scb;
  10990. PCCB Ccb;
  10991. TYPE_OF_OPEN TypeOfOpen;
  10992. PVOID InputBuffer;
  10993. ULONG InputBufferLength = 0;
  10994. PVOID OutputBuffer;
  10995. ULONG OutputBufferLength = 0;
  10996. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  10997. BOOLEAN ReleasePagingIo = FALSE;
  10998. BOOLEAN ReleaseScb = FALSE;
  10999. BOOLEAN ReleaseVcb = FALSE;
  11000. PAGED_CODE();
  11001. //
  11002. // This call should always be synchronous.
  11003. //
  11004. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  11005. //
  11006. // Decode the file object, fail this request if not a user data stream or directory.
  11007. // We check for dismount further below, so send FALSE to not raise here.
  11008. //
  11009. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  11010. IrpSp->FileObject,
  11011. &Vcb,
  11012. &Fcb,
  11013. &Scb,
  11014. &Ccb,
  11015. FALSE );
  11016. //
  11017. // This is only legal for files and directories, and not for anything
  11018. // that's compressed.
  11019. //
  11020. if (((TypeOfOpen != UserFileOpen) &&
  11021. (TypeOfOpen != UserDirectoryOpen)) ||
  11022. FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED )) {
  11023. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11024. return STATUS_INVALID_PARAMETER;
  11025. }
  11026. //
  11027. // This is also only supported on upgraded volumes.
  11028. //
  11029. if (!NtfsVolumeVersionCheck( Vcb, NTFS_ENCRYPTION_VERSION )) {
  11030. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  11031. return STATUS_VOLUME_NOT_UPGRADED;
  11032. }
  11033. OutputBuffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  11034. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  11035. InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  11036. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  11037. //
  11038. // Probe the user's buffers if necessary.
  11039. //
  11040. if (Irp->RequestorMode != KernelMode) {
  11041. try {
  11042. ProbeForRead( InputBuffer,
  11043. InputBufferLength,
  11044. sizeof(UCHAR) );
  11045. ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
  11046. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  11047. NtfsRaiseStatus( IrpContext,
  11048. STATUS_INVALID_USER_BUFFER,
  11049. NULL,
  11050. NULL );
  11051. }
  11052. }
  11053. //
  11054. // Use a try-finally to free the resource.
  11055. //
  11056. try {
  11057. //
  11058. // Acquire both resources if present on the file.
  11059. //
  11060. if (Fcb->PagingIoResource != NULL) {
  11061. NtfsAcquirePagingResourceExclusive( IrpContext, Fcb, TRUE );
  11062. ReleasePagingIo = TRUE;
  11063. }
  11064. NtfsAcquireExclusiveScb( IrpContext, Scb );
  11065. ReleaseScb = TRUE;
  11066. //
  11067. // Check that the volume is still mounted.
  11068. //
  11069. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  11070. Status = STATUS_VOLUME_DISMOUNTED;
  11071. leave;
  11072. }
  11073. //
  11074. // Call the EFS routine if specified.
  11075. //
  11076. if (NtfsData.EncryptionCallBackTable.FileSystemControl_2 != NULL) {
  11077. ULONG EncryptionFlag = 0;
  11078. if (IsEncrypted( &Fcb->Info )) {
  11079. SetFlag( EncryptionFlag, FILE_ENCRYPTED );
  11080. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11081. SetFlag( EncryptionFlag, STREAM_ENCRYPTED );
  11082. }
  11083. }
  11084. Status = NtfsData.EncryptionCallBackTable.FileSystemControl_2(
  11085. InputBuffer,
  11086. InputBufferLength,
  11087. OutputBuffer,
  11088. &OutputBufferLength,
  11089. EncryptionFlag,
  11090. Ccb->AccessFlags,
  11091. (NtfsIsVolumeReadOnly( Vcb )) ? READ_ONLY_VOLUME : 0,
  11092. IrpSp->Parameters.FileSystemControl.FsControlCode,
  11093. Fcb,
  11094. IrpContext,
  11095. (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ),
  11096. Scb,
  11097. &Scb->EncryptionContext,
  11098. &Scb->EncryptionContextLength);
  11099. Irp->IoStatus.Information = OutputBufferLength;
  11100. //
  11101. // There is no encryption driver present.
  11102. //
  11103. } else {
  11104. Status = STATUS_INVALID_DEVICE_REQUEST;
  11105. Irp->IoStatus.Information = 0;
  11106. }
  11107. NtfsCleanupTransaction( IrpContext, Status, TRUE );
  11108. } finally {
  11109. DebugUnwind( NtfsEncryptionPassThrough );
  11110. //
  11111. // Acquire both resources if present on the file.
  11112. //
  11113. if (ReleasePagingIo) {
  11114. NtfsReleasePagingResource( IrpContext, Fcb );
  11115. }
  11116. if (ReleaseScb) {
  11117. NtfsReleaseScb( IrpContext, Scb );
  11118. }
  11119. if (ReleaseVcb) {
  11120. NtfsReleaseVcb( IrpContext, Vcb );
  11121. }
  11122. }
  11123. //
  11124. // Go ahead and complete the request.
  11125. //
  11126. NtfsCompleteRequest( IrpContext, Irp, Status );
  11127. return Status;
  11128. }
  11129. //
  11130. // Local support routine
  11131. //
  11132. VOID
  11133. NtfsEncryptStream (
  11134. IN PIRP_CONTEXT IrpContext,
  11135. IN PFCB Fcb,
  11136. IN PSCB Scb OPTIONAL,
  11137. IN PATTRIBUTE_ENUMERATION_CONTEXT AttrContext
  11138. )
  11139. /*++
  11140. Routine Description:
  11141. This routine is called to mark a user data stream as encrypted. It sets
  11142. the encryption bit in the filerecord (handling logging, etc.) and in the
  11143. Scb if one is provided..
  11144. Arguments:
  11145. Fcb - The Fcb containing the stream to mark as encrypted.
  11146. Scb - The Scb (if one exists) to mark as ancrypted.
  11147. AttrContext - The attribute context that indicates where the stream is
  11148. within the file record.
  11149. Return Value:
  11150. None
  11151. --*/
  11152. {
  11153. ATTRIBUTE_RECORD_HEADER NewAttribute;
  11154. PATTRIBUTE_RECORD_HEADER Attribute;
  11155. NtfsPinMappedAttribute( IrpContext, Fcb->Vcb, AttrContext );
  11156. Attribute = NtfsFoundAttribute( AttrContext );
  11157. //
  11158. // We only need enough of the attribute to modify the bit.
  11159. //
  11160. RtlCopyMemory( &NewAttribute, Attribute, SIZEOF_RESIDENT_ATTRIBUTE_HEADER );
  11161. SetFlag( NewAttribute.Flags, ATTRIBUTE_FLAG_ENCRYPTED );
  11162. //
  11163. // Now, log the changed attribute.
  11164. //
  11165. (VOID)NtfsWriteLog( IrpContext,
  11166. Fcb->Vcb->MftScb,
  11167. NtfsFoundBcb( AttrContext ),
  11168. UpdateResidentValue,
  11169. &NewAttribute,
  11170. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11171. UpdateResidentValue,
  11172. Attribute,
  11173. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11174. NtfsMftOffset( AttrContext ),
  11175. PtrOffset(NtfsContainingFileRecord( AttrContext ), Attribute),
  11176. 0,
  11177. Fcb->Vcb->BytesPerFileRecordSegment );
  11178. //
  11179. // Change the attribute by calling the same routine called at restart.
  11180. //
  11181. NtfsRestartChangeValue( IrpContext,
  11182. NtfsContainingFileRecord( AttrContext ),
  11183. PtrOffset( NtfsContainingFileRecord( AttrContext ), Attribute ),
  11184. 0,
  11185. &NewAttribute,
  11186. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11187. FALSE );
  11188. if (ARGUMENT_PRESENT( Scb )) {
  11189. SetFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11190. }
  11191. //
  11192. // Now update the Fcb if this is the first of the streams.
  11193. //
  11194. if (!IsEncrypted( &Fcb->Info )) {
  11195. //
  11196. // Set the flag in the Fcb info field and let ourselves know to
  11197. // update the standard information.
  11198. //
  11199. ASSERTMSG( "conflict with flush",
  11200. NtfsIsSharedFcb( Fcb ) ||
  11201. (Fcb->PagingIoResource != NULL &&
  11202. NtfsIsSharedFcbPagingIo( Fcb )) );
  11203. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11204. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11205. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  11206. //
  11207. // If this is a directory, remember to set the appropriate bit in its Fcb.
  11208. //
  11209. if (IsDirectory( &Fcb->Info )) {
  11210. SetFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11211. }
  11212. }
  11213. }
  11214. //
  11215. // Local support routine
  11216. //
  11217. NTSTATUS
  11218. NtfsSetEncryption (
  11219. IN PIRP_CONTEXT IrpContext,
  11220. IN PIRP Irp
  11221. )
  11222. /*++
  11223. Routine Description:
  11224. This routine is called to initiate a set encryption operation. The input buffer specifies
  11225. whether we are accessing a file or a directory.
  11226. Arguments:
  11227. Irp - Request being serviced
  11228. Return Value:
  11229. NTSTATUS - The return status for the operation
  11230. --*/
  11231. {
  11232. NTSTATUS Status = STATUS_SUCCESS;
  11233. PVCB Vcb;
  11234. PFCB Fcb;
  11235. PSCB Scb;
  11236. PCCB Ccb;
  11237. PLCB Lcb;
  11238. PSCB ParentScb = NULL;
  11239. TYPE_OF_OPEN TypeOfOpen;
  11240. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  11241. BOOLEAN ReleasePagingIo = FALSE;
  11242. BOOLEAN ReleaseVcb = FALSE;
  11243. ULONG EncryptionFlag = 0;
  11244. ULONG EncryptionOperation;
  11245. ULONG InputBufferLength;
  11246. ULONG OutputBufferLength;
  11247. ULONG FilterMatch;
  11248. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  11249. BOOLEAN CleanupAttrContext = FALSE;
  11250. BOOLEAN FoundAttribute;
  11251. ATTRIBUTE_RECORD_HEADER NewAttribute;
  11252. PATTRIBUTE_RECORD_HEADER Attribute;
  11253. BOOLEAN UpdateCcbFlags = FALSE;
  11254. BOOLEAN ClearFcbUpdateFlag = FALSE;
  11255. BOOLEAN ClearFcbInfoFlags = FALSE;
  11256. BOOLEAN RestoreEncryptionFlag = FALSE;
  11257. BOOLEAN DirectoryFileEncrypted = FALSE;
  11258. PENCRYPTION_BUFFER EncryptionBuffer;
  11259. PDECRYPTION_STATUS_BUFFER DecryptionStatusBuffer;
  11260. PAGED_CODE();
  11261. //
  11262. // This call should always be synchronous.
  11263. //
  11264. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  11265. //
  11266. // Decode the file object, fail this request if not a user data stream or directory.
  11267. //
  11268. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  11269. IrpSp->FileObject,
  11270. &Vcb,
  11271. &Fcb,
  11272. &Scb,
  11273. &Ccb,
  11274. TRUE );
  11275. //
  11276. // This is only legal for files and directories.
  11277. //
  11278. if ((TypeOfOpen != UserFileOpen) &&
  11279. (TypeOfOpen != UserDirectoryOpen)) {
  11280. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11281. return STATUS_INVALID_PARAMETER;
  11282. }
  11283. //
  11284. // Readonly mount should be just that: read only.
  11285. //
  11286. if (NtfsIsVolumeReadOnly( Vcb )) {
  11287. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  11288. return STATUS_MEDIA_WRITE_PROTECTED;
  11289. }
  11290. //
  11291. // Get the input and output buffer lengths and pointers. Remember that the output
  11292. // buffer is optional.
  11293. //
  11294. EncryptionBuffer = (PENCRYPTION_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  11295. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  11296. DecryptionStatusBuffer = (PDECRYPTION_STATUS_BUFFER)NtfsMapUserBuffer( Irp, NormalPagePriority );
  11297. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  11298. //
  11299. // Check for a minimum length on the input and ouput buffers. The output buffer
  11300. // only needs to be a certain length if one was specified.
  11301. //
  11302. if ((InputBufferLength < sizeof(ENCRYPTION_BUFFER)) ||
  11303. ((DecryptionStatusBuffer != NULL) && (OutputBufferLength < sizeof(DECRYPTION_STATUS_BUFFER)))) {
  11304. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  11305. DebugTrace( -1, Dbg, ("NtfsSetEncryption -> %08lx\n", STATUS_BUFFER_TOO_SMALL) );
  11306. return STATUS_BUFFER_TOO_SMALL;
  11307. }
  11308. //
  11309. // Probe the user's buffers.
  11310. //
  11311. try {
  11312. if (Irp->RequestorMode != KernelMode) {
  11313. ProbeForRead( EncryptionBuffer, InputBufferLength, sizeof( UCHAR ) );
  11314. if (DecryptionStatusBuffer != NULL) ProbeForWrite( DecryptionStatusBuffer, OutputBufferLength, sizeof( UCHAR ) );
  11315. }
  11316. EncryptionOperation = EncryptionBuffer->EncryptionOperation;
  11317. Irp->IoStatus.Information = 0;
  11318. if (DecryptionStatusBuffer != NULL) {
  11319. DecryptionStatusBuffer->NoEncryptedStreams = FALSE;
  11320. }
  11321. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  11322. DebugTrace( -1, Dbg, ("NtfsSetEncryption -> %08lx\n", FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER) );
  11323. NtfsRaiseStatus( IrpContext,
  11324. STATUS_INVALID_USER_BUFFER,
  11325. NULL,
  11326. NULL );
  11327. }
  11328. //
  11329. // Verify that the user didn't specify any illegal flags.
  11330. //
  11331. if (EncryptionOperation > MAXIMUM_ENCRYPTION_VALUE) {
  11332. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11333. return STATUS_INVALID_PARAMETER;
  11334. }
  11335. //
  11336. // Capture the source information.
  11337. //
  11338. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  11339. //
  11340. // It's okay to mark the file encryption bit if this stream is compressed,
  11341. // but we do want to prevent setting the stream encrypted bit for a
  11342. // compressed stream. In some future release when we have a chance to
  11343. // test compression & encryption together (perhaps with some third-party
  11344. // encryption engine) we can relax/remove this restriction.
  11345. //
  11346. if ((EncryptionOperation == STREAM_SET_ENCRYPTION) &&
  11347. FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED )) {
  11348. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11349. return STATUS_INVALID_PARAMETER;
  11350. }
  11351. //
  11352. // This is also only supported on upgraded volumes.
  11353. //
  11354. if (!NtfsVolumeVersionCheck( Vcb, NTFS_ENCRYPTION_VERSION )) {
  11355. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  11356. return STATUS_VOLUME_NOT_UPGRADED;
  11357. }
  11358. //
  11359. // Use a try-finally to free the resource.
  11360. //
  11361. try {
  11362. //
  11363. // Acquire the Vcb shared in case we need to update the parent directory entry.
  11364. //
  11365. ReleaseVcb = NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  11366. //
  11367. // Acquire both resources if present on the file.
  11368. //
  11369. if (Fcb->PagingIoResource != NULL) {
  11370. NtfsAcquirePagingResourceExclusive( IrpContext, Fcb, TRUE );
  11371. ReleasePagingIo = TRUE;
  11372. }
  11373. NtfsAcquireExclusiveScb( IrpContext, Scb );
  11374. //
  11375. // Check that the volume is still mounted.
  11376. //
  11377. if ( !FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  11378. Status = STATUS_VOLUME_DISMOUNTED;
  11379. leave;
  11380. }
  11381. //
  11382. // We can't go on if there isn't an encryption driver loaded. We did our best
  11383. // to get it loaded above. If that didn't work, we need to leave now.
  11384. //
  11385. if (!FlagOn( NtfsData.Flags, NTFS_FLAGS_ENCRYPTION_DRIVER )) {
  11386. Status = STATUS_INVALID_DEVICE_REQUEST;
  11387. leave;
  11388. }
  11389. //
  11390. // Update the Scb from disk if necessary.
  11391. //
  11392. if (Scb->AttributeTypeCode == $INDEX_ALLOCATION) {
  11393. if (Scb->ScbType.Index.BytesPerIndexBuffer == 0) {
  11394. NtfsInitializeAttributeContext( &AttrContext );
  11395. CleanupAttrContext = TRUE;
  11396. if (!NtfsLookupAttributeByName( IrpContext,
  11397. Scb->Fcb,
  11398. &Scb->Fcb->FileReference,
  11399. $INDEX_ROOT,
  11400. &Scb->AttributeName,
  11401. NULL,
  11402. FALSE,
  11403. &AttrContext )) {
  11404. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb );
  11405. }
  11406. NtfsUpdateIndexScbFromAttribute( IrpContext,
  11407. Scb,
  11408. NtfsFoundAttribute( &AttrContext ),
  11409. FALSE );
  11410. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11411. }
  11412. } else if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  11413. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  11414. }
  11415. //
  11416. // Remember the starting encryption state for this operation.
  11417. //
  11418. if (IsEncrypted( &Fcb->Info )) {
  11419. SetFlag( EncryptionFlag, FILE_ENCRYPTED );
  11420. if (FlagOn( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED )) {
  11421. DirectoryFileEncrypted = TRUE;
  11422. }
  11423. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11424. SetFlag( EncryptionFlag, STREAM_ENCRYPTED );
  11425. }
  11426. }
  11427. RestoreEncryptionFlag = TRUE;
  11428. //
  11429. // If the caller wants to clear the encryption bit on the file then there should
  11430. // be no encrypted streams on the file.
  11431. //
  11432. if ((EncryptionOperation == FILE_CLEAR_ENCRYPTION) && IsEncrypted( &Fcb->Info )) {
  11433. NtfsInitializeAttributeContext( &AttrContext );
  11434. CleanupAttrContext = TRUE;
  11435. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  11436. Fcb,
  11437. &Fcb->FileReference,
  11438. $DATA,
  11439. &AttrContext );
  11440. while (FoundAttribute) {
  11441. //
  11442. // We only want to look at this attribute if it is resident or the
  11443. // first attribute header for a non-resident attribute.
  11444. //
  11445. Attribute = NtfsFoundAttribute( &AttrContext );
  11446. if (NtfsIsAttributeResident( Attribute ) ||
  11447. (Attribute->Form.Nonresident.LowestVcn == 0)) {
  11448. if (FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11449. break;
  11450. }
  11451. }
  11452. FoundAttribute = NtfsLookupNextAttributeByCode( IrpContext,
  11453. Fcb,
  11454. $DATA,
  11455. &AttrContext );
  11456. }
  11457. if (FoundAttribute) {
  11458. Status = STATUS_INVALID_DEVICE_REQUEST;
  11459. leave;
  11460. }
  11461. //
  11462. // If this is a directory then we need to check the index root as well.
  11463. //
  11464. if (IsDirectory( &Fcb->Info )) {
  11465. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11466. NtfsInitializeAttributeContext( &AttrContext );
  11467. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11468. Fcb,
  11469. &Fcb->FileReference,
  11470. $INDEX_ROOT,
  11471. &NtfsFileNameIndex,
  11472. NULL,
  11473. FALSE,
  11474. &AttrContext );
  11475. //
  11476. // We should always find this attribute in this case.
  11477. //
  11478. if (!FoundAttribute) {
  11479. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11480. }
  11481. Attribute = NtfsFoundAttribute( &AttrContext );
  11482. if (FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11483. Status = STATUS_INVALID_DEVICE_REQUEST;
  11484. leave;
  11485. }
  11486. }
  11487. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11488. CleanupAttrContext = FALSE;
  11489. }
  11490. //
  11491. // It's a pretty rare case that we'll decide we don't need to update
  11492. // the duplicate info below, so let's go ahead and prepare now. We
  11493. // can't wait until after the convert to nonresident, as that will
  11494. // acquire the quota resources before we've acquired the parent scb,
  11495. // resulting in a potential deadlock.
  11496. //
  11497. Lcb = Ccb->Lcb;
  11498. NtfsPrepareForUpdateDuplicate( IrpContext, Fcb, &Lcb, &ParentScb, TRUE );
  11499. //
  11500. // Now let's go ahead and modify the bit on the file/stream.
  11501. //
  11502. if (EncryptionOperation == FILE_SET_ENCRYPTION) {
  11503. if (!IsEncrypted( &Fcb->Info )) {
  11504. //
  11505. // Set the flag in the Fcb info field and let ourselves know to
  11506. // update the standard information.
  11507. //
  11508. ASSERTMSG( "conflict with flush",
  11509. NtfsIsSharedFcb( Fcb ) ||
  11510. (Fcb->PagingIoResource != NULL &&
  11511. NtfsIsSharedFcbPagingIo( Fcb )) );
  11512. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11513. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11514. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  11515. UpdateCcbFlags = TRUE;
  11516. }
  11517. } else if (EncryptionOperation == FILE_CLEAR_ENCRYPTION) {
  11518. if (IsEncrypted( &Fcb->Info )) {
  11519. //
  11520. // Clear the flag in the Fcb info field and let ourselves know to
  11521. // update the standard information. Also clear the directory
  11522. // encrypted bit, even though it may not even be set.
  11523. //
  11524. ASSERTMSG( "conflict with flush",
  11525. NtfsIsSharedFcb( Fcb ) ||
  11526. (Fcb->PagingIoResource != NULL &&
  11527. NtfsIsSharedFcbPagingIo( Fcb )) );
  11528. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11529. ClearFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11530. SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11531. SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  11532. UpdateCcbFlags = TRUE;
  11533. }
  11534. } else if (EncryptionOperation == STREAM_SET_ENCRYPTION) {
  11535. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11536. NtfsInitializeAttributeContext( &AttrContext );
  11537. CleanupAttrContext = TRUE;
  11538. //
  11539. // If we're being called to set the encyrption bit on a new named stream
  11540. // and we created the unnamed stream silently without calling out to the
  11541. // encryption engine, this is the best time to set the encryption bit on
  11542. // the unnamed stream and convert it to nonresident, too. Some encryption
  11543. // engines may not want this behavior, so we check the ImplementationFlags.
  11544. //
  11545. if (!FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
  11546. FlagOn( Fcb->FcbState, FCB_STATE_ENCRYPTION_PENDING) &&
  11547. FlagOn( NtfsData.EncryptionCallBackTable.ImplementationFlags, ENCRYPTION_ALL_STREAMS ) &&
  11548. NtfsIsTypeCodeUserData( Scb->AttributeTypeCode )) {
  11549. if (NtfsLookupAttributeByCode( IrpContext,
  11550. Fcb,
  11551. &Fcb->FileReference,
  11552. $DATA,
  11553. &AttrContext )) {
  11554. //
  11555. // If there is an the unnamed data attribute, it will be the
  11556. // first data attribute we find. There may be no unnamed data
  11557. // attribute in the case where we've been asked to encrypt a
  11558. // named data stream on a directory.
  11559. //
  11560. Attribute = NtfsFoundAttribute( &AttrContext );
  11561. if (Attribute->NameLength == 0) {
  11562. PSCB DefaultStreamScb = NULL;
  11563. ASSERT( NtfsIsAttributeResident( Attribute ) &&
  11564. Attribute->Form.Resident.ValueLength == 0 );
  11565. NtfsConvertToNonresident( IrpContext,
  11566. Fcb,
  11567. Attribute,
  11568. TRUE,
  11569. &AttrContext );
  11570. while (TRUE) {
  11571. DefaultStreamScb = NtfsGetNextChildScb( Fcb, DefaultStreamScb );
  11572. //
  11573. // If we've reached the end of the list of Scbs, or else
  11574. // found the unnamed data stream's Scb, we're done.
  11575. //
  11576. if ((DefaultStreamScb == NULL) ||
  11577. FlagOn( DefaultStreamScb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  11578. break;
  11579. }
  11580. }
  11581. NtfsEncryptStream( IrpContext, Fcb, DefaultStreamScb, &AttrContext );
  11582. }
  11583. }
  11584. //
  11585. // Get the AttrContext ready for reuse.
  11586. //
  11587. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11588. NtfsInitializeAttributeContext( &AttrContext );
  11589. }
  11590. //
  11591. // If the stream is a data stream we can look up the attribute
  11592. // from the Scb.
  11593. //
  11594. if (TypeOfOpen == UserFileOpen) {
  11595. NtfsLookupAttributeForScb( IrpContext,
  11596. Scb,
  11597. NULL,
  11598. &AttrContext );
  11599. //
  11600. // Convert to non-resident if necessary. It's entirely possible
  11601. // that our caller will not have read or write access to this
  11602. // file and won't have a key. Therefore we don't want to create
  11603. // a cache section for this stream during the convert, as we
  11604. // may not have a key with which to do flushes later.
  11605. //
  11606. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  11607. NtfsConvertToNonresident( IrpContext,
  11608. Fcb,
  11609. NtfsFoundAttribute( &AttrContext ),
  11610. TRUE,
  11611. &AttrContext );
  11612. }
  11613. } else {
  11614. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11615. Fcb,
  11616. &Fcb->FileReference,
  11617. $INDEX_ROOT,
  11618. &NtfsFileNameIndex,
  11619. NULL,
  11620. FALSE,
  11621. &AttrContext );
  11622. //
  11623. // We should always find this attribute in this case.
  11624. //
  11625. if (!FoundAttribute) {
  11626. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11627. }
  11628. }
  11629. NtfsEncryptStream( IrpContext, Fcb, Scb, &AttrContext );
  11630. UpdateCcbFlags = TRUE;
  11631. }
  11632. } else { // EncryptionOperation == STREAM_CLEAR_ENCRYPTION
  11633. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11634. NtfsInitializeAttributeContext( &AttrContext );
  11635. CleanupAttrContext = TRUE;
  11636. //
  11637. // If the stream is a data stream we can look up the attribute
  11638. // from the Scb.
  11639. //
  11640. if (TypeOfOpen == UserFileOpen) {
  11641. NtfsLookupAttributeForScb( IrpContext,
  11642. Scb,
  11643. NULL,
  11644. &AttrContext );
  11645. } else {
  11646. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11647. Fcb,
  11648. &Fcb->FileReference,
  11649. $INDEX_ROOT,
  11650. &NtfsFileNameIndex,
  11651. NULL,
  11652. FALSE,
  11653. &AttrContext );
  11654. //
  11655. // We should always find this attribute in this case.
  11656. //
  11657. if (!FoundAttribute) {
  11658. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11659. }
  11660. }
  11661. NtfsPinMappedAttribute( IrpContext, Vcb, &AttrContext );
  11662. Attribute = NtfsFoundAttribute( &AttrContext );
  11663. //
  11664. // We only need enough of the attribute to modify the bit.
  11665. //
  11666. RtlCopyMemory( &NewAttribute, Attribute, SIZEOF_RESIDENT_ATTRIBUTE_HEADER );
  11667. ClearFlag( NewAttribute.Flags, ATTRIBUTE_FLAG_ENCRYPTED );
  11668. //
  11669. // Now, log the changed attribute.
  11670. //
  11671. (VOID)NtfsWriteLog( IrpContext,
  11672. Vcb->MftScb,
  11673. NtfsFoundBcb( &AttrContext ),
  11674. UpdateResidentValue,
  11675. &NewAttribute,
  11676. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11677. UpdateResidentValue,
  11678. Attribute,
  11679. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11680. NtfsMftOffset( &AttrContext ),
  11681. PtrOffset(NtfsContainingFileRecord( &AttrContext ), Attribute),
  11682. 0,
  11683. Vcb->BytesPerFileRecordSegment );
  11684. //
  11685. // Change the attribute by calling the same routine called at restart.
  11686. //
  11687. NtfsRestartChangeValue( IrpContext,
  11688. NtfsContainingFileRecord( &AttrContext ),
  11689. PtrOffset( NtfsContainingFileRecord( &AttrContext ), Attribute ),
  11690. 0,
  11691. &NewAttribute,
  11692. SIZEOF_RESIDENT_ATTRIBUTE_HEADER,
  11693. FALSE );
  11694. ClearFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11695. //
  11696. // Now check if this is the last stream on the file with the encryption
  11697. // bit set.
  11698. //
  11699. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11700. NtfsInitializeAttributeContext( &AttrContext );
  11701. FoundAttribute = NtfsLookupAttributeByCode( IrpContext,
  11702. Fcb,
  11703. &Fcb->FileReference,
  11704. $DATA,
  11705. &AttrContext );
  11706. while (FoundAttribute) {
  11707. //
  11708. // We only want to look at this attribute if it is resident or the
  11709. // first attribute header for a non-resident attribute.
  11710. //
  11711. Attribute = NtfsFoundAttribute( &AttrContext );
  11712. if (NtfsIsAttributeResident( Attribute ) ||
  11713. (Attribute->Form.Nonresident.LowestVcn == 0)) {
  11714. if (FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11715. break;
  11716. }
  11717. }
  11718. FoundAttribute = NtfsLookupNextAttributeByCode( IrpContext,
  11719. Fcb,
  11720. $DATA,
  11721. &AttrContext );
  11722. }
  11723. //
  11724. // If this is a directory then we need to check the index root as well.
  11725. //
  11726. if (!FoundAttribute && IsDirectory( &Fcb->Info )) {
  11727. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11728. NtfsInitializeAttributeContext( &AttrContext );
  11729. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  11730. Fcb,
  11731. &Fcb->FileReference,
  11732. $INDEX_ROOT,
  11733. &NtfsFileNameIndex,
  11734. NULL,
  11735. FALSE,
  11736. &AttrContext );
  11737. //
  11738. // We should always find this attribute in this case.
  11739. //
  11740. if (!FoundAttribute) {
  11741. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11742. }
  11743. Attribute = NtfsFoundAttribute( &AttrContext );
  11744. if (!FlagOn( Attribute->Flags, ATTRIBUTE_FLAG_ENCRYPTED )) {
  11745. FoundAttribute = FALSE;
  11746. }
  11747. }
  11748. //
  11749. // If our caller is interested, let it know if we have decrypted the
  11750. // last encrypted stream. Since this is the only place we touch this
  11751. // buffer, we'll just wrap a little try/except around it here.
  11752. //
  11753. if (DecryptionStatusBuffer != NULL) {
  11754. try {
  11755. DecryptionStatusBuffer->NoEncryptedStreams = TRUE;
  11756. Irp->IoStatus.Information = sizeof(DECRYPTION_STATUS_BUFFER);
  11757. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  11758. DebugTrace( -1, Dbg, ("NtfsSetEncryption -> %08lx\n", FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER) );
  11759. NtfsRaiseStatus( IrpContext,
  11760. STATUS_INVALID_USER_BUFFER,
  11761. NULL,
  11762. NULL );
  11763. }
  11764. }
  11765. UpdateCcbFlags = TRUE;
  11766. }
  11767. }
  11768. //
  11769. // Now let's update the on-disk structures.
  11770. //
  11771. if (FlagOn( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  11772. NtfsUpdateStandardInformation( IrpContext, Fcb );
  11773. ClearFcbUpdateFlag = TRUE;
  11774. NtfsUpdateDuplicateInfo( IrpContext, Fcb, Lcb, ParentScb );
  11775. //
  11776. // Now perform the dir notify call if this is not an
  11777. // open by FileId.
  11778. //
  11779. if ((Vcb->NotifyCount != 0) &&
  11780. (ParentScb != NULL) &&
  11781. !FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_FILE_ID )) {
  11782. FilterMatch = NtfsBuildDirNotifyFilter( IrpContext,
  11783. Fcb->InfoFlags | Lcb->InfoFlags );
  11784. if (FilterMatch != 0) {
  11785. NtfsReportDirNotify( IrpContext,
  11786. Fcb->Vcb,
  11787. &Ccb->FullFileName,
  11788. Ccb->LastFileNameOffset,
  11789. NULL,
  11790. ((FlagOn( Ccb->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  11791. (Ccb->Lcb != NULL) &&
  11792. (Ccb->Lcb->Scb->ScbType.Index.NormalizedName.Length != 0)) ?
  11793. &Ccb->Lcb->Scb->ScbType.Index.NormalizedName :
  11794. NULL),
  11795. FilterMatch,
  11796. FILE_ACTION_MODIFIED,
  11797. ParentScb->Fcb );
  11798. }
  11799. }
  11800. NtfsUpdateLcbDuplicateInfo( Fcb, Lcb );
  11801. ClearFcbInfoFlags = TRUE;
  11802. }
  11803. //
  11804. // Call the EFS routine if specified.
  11805. //
  11806. if (NtfsData.EncryptionCallBackTable.FileSystemControl_1 != NULL) {
  11807. Status = NtfsData.EncryptionCallBackTable.FileSystemControl_1(
  11808. EncryptionBuffer,
  11809. InputBufferLength,
  11810. NULL,
  11811. NULL,
  11812. EncryptionFlag,
  11813. Ccb->AccessFlags,
  11814. (NtfsIsVolumeReadOnly( Vcb )) ? READ_ONLY_VOLUME : 0,
  11815. IrpSp->Parameters.FileSystemControl.FsControlCode,
  11816. Fcb,
  11817. IrpContext,
  11818. (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ),
  11819. Scb,
  11820. &Scb->EncryptionContext,
  11821. &Scb->EncryptionContextLength);
  11822. }
  11823. //
  11824. // Post the change to the Usn Journal (on errors change is backed out)
  11825. //
  11826. NtfsPostUsnChange( IrpContext, Scb, USN_REASON_ENCRYPTION_CHANGE );
  11827. NtfsCleanupTransaction( IrpContext, Status, TRUE );
  11828. ASSERT( NT_SUCCESS( Status ));
  11829. //
  11830. // Clear the flags in the Fcb if the update is complete.
  11831. //
  11832. if (ClearFcbUpdateFlag) {
  11833. ClearFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  11834. }
  11835. if (ClearFcbInfoFlags) {
  11836. Fcb->InfoFlags = 0;
  11837. }
  11838. if (UpdateCcbFlags) {
  11839. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE | CCB_FLAG_SET_ARCHIVE );
  11840. }
  11841. RestoreEncryptionFlag = FALSE;
  11842. } finally {
  11843. DebugUnwind( NtfsSetEncryption );
  11844. //
  11845. // In the error path we need to restore the correct encryption bit in
  11846. // the Fcb and Scb.
  11847. //
  11848. if (RestoreEncryptionFlag) {
  11849. DebugTrace( 0, Dbg, ("Error in NtfsSetEncryption, restoring encryption flags\n") );
  11850. if (FlagOn( EncryptionFlag, FILE_ENCRYPTED )) {
  11851. SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11852. if (DirectoryFileEncrypted) {
  11853. SetFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11854. }
  11855. } else {
  11856. ClearFlag( Fcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED );
  11857. ClearFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  11858. }
  11859. if (FlagOn( EncryptionFlag, STREAM_ENCRYPTED )) {
  11860. SetFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11861. } else {
  11862. ClearFlag( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  11863. }
  11864. }
  11865. //
  11866. // Acquire both resources if present on the file.
  11867. //
  11868. if (ReleasePagingIo) {
  11869. NtfsReleasePagingResource( IrpContext, Fcb );
  11870. }
  11871. if (ReleaseVcb) {
  11872. NtfsReleaseVcb( IrpContext, Vcb );
  11873. }
  11874. if (CleanupAttrContext) {
  11875. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  11876. }
  11877. }
  11878. //
  11879. // Go ahead and complete the request.
  11880. //
  11881. NtfsCompleteRequest( IrpContext, Irp, Status );
  11882. return Status;
  11883. }
  11884. //
  11885. // Local Support Routine
  11886. //
  11887. NTSTATUS
  11888. NtfsReadRawEncrypted (
  11889. IN PIRP_CONTEXT IrpContext,
  11890. IN PIRP Irp
  11891. )
  11892. /*++
  11893. Routine Description:
  11894. This routine performs a 'raw' read of encrypted data. By 'raw', we
  11895. mean without attempting to unencrypt. This is useful for backup
  11896. operations, and also for data recovery in the event the key stream
  11897. is somehow lost. Since this fsctrl works with any access, we have
  11898. to fail the request for unencrypted files. This routine is
  11899. responsible for either completing or enqueuing the input Irp.
  11900. Notes: DataUnit is the size of each peice written out in the buffer
  11901. ChunkUnit is the size of a compression chunk (not used yet)
  11902. For Sparse files DataUnit == CompressionUnit
  11903. Arguments:
  11904. Irp - Supplies the Irp to process
  11905. Return Value:
  11906. NTSTATUS - The return status for the operation
  11907. --*/
  11908. {
  11909. LONGLONG StartingVbo;
  11910. LONGLONG RequestedOffset;
  11911. LONGLONG RoundedFileSize;
  11912. ULONG TotalByteCount;
  11913. ULONG ByteCount;
  11914. ULONG BytesRead;
  11915. PIRP ReadIrp = NULL;
  11916. PDEVICE_OBJECT DeviceObject;
  11917. PFILE_OBJECT FileObject;
  11918. PVCB Vcb;
  11919. PFCB Fcb;
  11920. PSCB Scb;
  11921. PCCB Ccb;
  11922. PIO_STACK_LOCATION IrpSp;
  11923. PIO_STACK_LOCATION ReadIrpSp;
  11924. TYPE_OF_OPEN TypeOfOpen;
  11925. ULONG InputBufferLength;
  11926. ULONG OutputBufferLength;
  11927. ULONG ReadLength;
  11928. PREQUEST_RAW_ENCRYPTED_DATA RequestRawEncryptedData;
  11929. PENCRYPTED_DATA_INFO EncryptedDataInfo;
  11930. USHORT BlockIndex;
  11931. USHORT BlockCount = 0;
  11932. PUCHAR RawDataDestination;
  11933. NTFS_IO_CONTEXT LocalContext;
  11934. BOOLEAN LockedReadIrpPages = FALSE;
  11935. BOOLEAN SparseFile = FALSE;
  11936. BOOLEAN RangeAllocated = TRUE;
  11937. BOOLEAN AccessingUserBuffer = FALSE;
  11938. ULONG OutputBufferOffset;
  11939. ULONG BytesWithinValidDataLength = 0;
  11940. ULONG BytesWithinFileSize = 0;
  11941. ULONG i;
  11942. LONG BytesPerSectorMask;
  11943. NTSTATUS Status = STATUS_SUCCESS;
  11944. UCHAR TotalShift;
  11945. UCHAR DataUnitShift;
  11946. PAGED_CODE();
  11947. //
  11948. // Don't post this request, we can't lock both input and output buffers.
  11949. //
  11950. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  11951. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  11952. DebugTrace( +1, Dbg, ("NtfsReadRawEncrypted:\n") );
  11953. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  11954. FileObject = IrpSp->FileObject;
  11955. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  11956. FileObject,
  11957. &Vcb,
  11958. &Fcb,
  11959. &Scb,
  11960. &Ccb,
  11961. TRUE );
  11962. //
  11963. // This operation only applies to files, not indexes,
  11964. // or volumes.
  11965. //
  11966. if (TypeOfOpen != UserFileOpen) {
  11967. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  11968. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", STATUS_INVALID_PARAMETER) );
  11969. return STATUS_INVALID_PARAMETER;
  11970. }
  11971. //
  11972. // We can't allow reads of unencrypted data, as that would let any
  11973. // user read any file's contents..
  11974. //
  11975. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED ) ||
  11976. //
  11977. // Even for an encrypted file, we should only allow this if the
  11978. // user is a backup operator or has read access.
  11979. //
  11980. !FlagOn( Ccb->AccessFlags, BACKUP_ACCESS | READ_DATA_ACCESS )) {
  11981. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  11982. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", STATUS_ACCESS_DENIED) );
  11983. return STATUS_ACCESS_DENIED;
  11984. }
  11985. //
  11986. // Get the input and output buffer lengths and pointers.
  11987. // Initialize some variables.
  11988. //
  11989. RequestRawEncryptedData = (PREQUEST_RAW_ENCRYPTED_DATA)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  11990. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  11991. EncryptedDataInfo = (PENCRYPTED_DATA_INFO)NtfsMapUserBuffer( Irp, NormalPagePriority );
  11992. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  11993. //
  11994. // Check for a minimum length on the input and ouput buffers.
  11995. //
  11996. if ((InputBufferLength < sizeof(REQUEST_RAW_ENCRYPTED_DATA)) ||
  11997. (OutputBufferLength < sizeof(ENCRYPTED_DATA_INFO))) {
  11998. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  11999. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", STATUS_BUFFER_TOO_SMALL) );
  12000. return STATUS_BUFFER_TOO_SMALL;
  12001. }
  12002. //
  12003. // Probe the user's buffers.
  12004. //
  12005. try {
  12006. if (Irp->RequestorMode != KernelMode) {
  12007. ProbeForRead( RequestRawEncryptedData, InputBufferLength, sizeof( UCHAR ) );
  12008. ProbeForWrite( EncryptedDataInfo, OutputBufferLength, sizeof( UCHAR ) );
  12009. }
  12010. RequestedOffset = RequestRawEncryptedData->FileOffset;
  12011. ReadLength = RequestRawEncryptedData->Length;
  12012. //
  12013. // Zero the buffer.
  12014. //
  12015. RtlZeroMemory( EncryptedDataInfo, OutputBufferLength );
  12016. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), TRUE, &Status ) ) {
  12017. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER) );
  12018. NtfsRaiseStatus( IrpContext,
  12019. STATUS_INVALID_USER_BUFFER,
  12020. NULL,
  12021. NULL );
  12022. }
  12023. try {
  12024. //
  12025. // Get paging & main exclusively to keep eof from changing
  12026. // beneath us, and so we can safely flush the file and query the mapping info below.
  12027. //
  12028. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  12029. NtfsAcquireFcbWithPaging( IrpContext, Scb->Fcb, 0 );
  12030. //
  12031. // Make sure we aren't starting past the end of the file, in which case
  12032. // we would have nothing to return.
  12033. //
  12034. if ((RequestedOffset >= Scb->Header.FileSize.QuadPart) || (RequestedOffset >= Scb->Header.AllocationSize.QuadPart)) {
  12035. try_return( Status = STATUS_END_OF_FILE );
  12036. }
  12037. //
  12038. // Sanity check the read length.
  12039. //
  12040. if (0 == ReadLength) {
  12041. try_return( Status = STATUS_INVALID_PARAMETER );
  12042. }
  12043. RoundedFileSize = (Scb->Header.FileSize.QuadPart + Vcb->BytesPerSector) & ~((LONGLONG)Vcb->BytesPerSector);
  12044. if (RequestedOffset + ReadLength > RoundedFileSize) {
  12045. ReadLength = (ULONG)(RoundedFileSize - RequestedOffset);
  12046. }
  12047. try {
  12048. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  12049. //
  12050. // File is not compressed or sparse.
  12051. //
  12052. AccessingUserBuffer = TRUE;
  12053. EncryptedDataInfo->CompressionFormat = COMPRESSION_FORMAT_NONE;
  12054. AccessingUserBuffer = FALSE;
  12055. //
  12056. // For a simple uncompressed, nonsparse file, we can start on any
  12057. // cluster boundary. We like to start on a cluster boundary
  12058. // since the cluster size is always >= the size of a cipher block,
  12059. // and a recovery agent will always need to work with whole cipher
  12060. // blocks. Notice that the StartingVbo is rounded _down_ to the
  12061. // previous cluster boundary, while TotalByteCount is rounded _up_ to
  12062. // the next larger cluster multiple.
  12063. //
  12064. StartingVbo = RequestedOffset & Vcb->InverseClusterMask;
  12065. TotalByteCount = ClusterAlign( Vcb, ReadLength );
  12066. //
  12067. // We will do the transfer in one block for this simple case.
  12068. //
  12069. BlockCount = 1;
  12070. ByteCount = TotalByteCount;
  12071. //
  12072. // For an uncompressed file, we'll pick a data unit size so
  12073. // that it's some convenient power of two.
  12074. //
  12075. for (DataUnitShift = 0, i = TotalByteCount - 1;
  12076. i > 0;
  12077. i = i / 2) {
  12078. DataUnitShift += 1;
  12079. }
  12080. AccessingUserBuffer = TRUE;
  12081. EncryptedDataInfo->DataUnitShift = DataUnitShift;
  12082. EncryptedDataInfo->ChunkShift = DataUnitShift;
  12083. AccessingUserBuffer = FALSE;
  12084. } else if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  12085. //
  12086. // File is sparse and not compressed.
  12087. //
  12088. SparseFile = TRUE;
  12089. ASSERT( Vcb->ClusterShift + Scb->CompressionUnitShift <= MAXUCHAR );
  12090. TotalShift = (UCHAR)(Scb->CompressionUnitShift + Vcb->ClusterShift);
  12091. AccessingUserBuffer = TRUE;
  12092. EncryptedDataInfo->CompressionFormat = COMPRESSION_FORMAT_NONE;
  12093. EncryptedDataInfo->ChunkShift = TotalShift;
  12094. AccessingUserBuffer = FALSE;
  12095. //
  12096. // For a sparse file, we can start on any compression unit
  12097. // boundary. Notice that the StartingVbo is rounded _down_ to the
  12098. // previous compression unit boundary, while TotalByteCount is rounded
  12099. // _up_ to the next larger compression unit multiple.
  12100. //
  12101. StartingVbo = BlockAlignTruncate( RequestedOffset, (LONG)Scb->CompressionUnit );
  12102. TotalByteCount = BlockAlign( ReadLength, (LONG)Scb->CompressionUnit );
  12103. //
  12104. // BlockCount is the number of blocks needed to describe this range
  12105. // of the file. It is simply the number of bytes we're reading on
  12106. // this request divided by the size of a compression unit.
  12107. // (Literally, we're shifting, but semantically, we're dividing).
  12108. //
  12109. BlockCount = (USHORT) (TotalByteCount >> TotalShift);
  12110. //
  12111. // Since BlockCount is derived from a user-supplied value, we need
  12112. // to make sure we aren't about to divide by zero.
  12113. //
  12114. if (BlockCount == 0) {
  12115. Status = STATUS_INVALID_PARAMETER;
  12116. leave;
  12117. }
  12118. //
  12119. // ByteCount is the number of bytes to read per Irp, while TotalByteCount
  12120. // is how many bytes to try to read during this call into NtfsReadRawEncrypted.
  12121. //
  12122. ByteCount = TotalByteCount / BlockCount;
  12123. AccessingUserBuffer = TRUE;
  12124. EncryptedDataInfo->DataUnitShift = TotalShift;
  12125. AccessingUserBuffer = FALSE;
  12126. } else {
  12127. //
  12128. // We do not support compressed encrypted files yet.
  12129. //
  12130. Status = STATUS_NOT_IMPLEMENTED;
  12131. leave;
  12132. }
  12133. //
  12134. // The actual file contents will start after the fixed length part
  12135. // of the encrypted data info struct plus one ulong per block that
  12136. // specifies the length of that block. We also need to round
  12137. // OutputBufferOffset up so that the buffer we pass to the underlying
  12138. // driver(s) is sector aligned, since that is required for all
  12139. // unbuffered I/O.
  12140. //
  12141. BytesPerSectorMask = Vcb->BytesPerSector - 1;
  12142. OutputBufferOffset = sizeof(ENCRYPTED_DATA_INFO) + (BlockCount * sizeof(ULONG));
  12143. OutputBufferOffset = PtrOffset(EncryptedDataInfo,
  12144. (((UINT_PTR) EncryptedDataInfo + OutputBufferOffset + BytesPerSectorMask) & ~BytesPerSectorMask));
  12145. AccessingUserBuffer = TRUE;
  12146. EncryptedDataInfo->OutputBufferOffset = OutputBufferOffset;
  12147. EncryptedDataInfo->NumberOfDataBlocks = BlockCount;
  12148. AccessingUserBuffer = FALSE;
  12149. //
  12150. // Now that we know how much data we're going to try to read, and the
  12151. // offset into the user's buffer where we will start putting it, we
  12152. // can test one last time that the buffer is big enough.
  12153. //
  12154. if ((OutputBufferOffset + TotalByteCount) > OutputBufferLength) {
  12155. Status = STATUS_BUFFER_TOO_SMALL;
  12156. leave;
  12157. }
  12158. //
  12159. // While we have something acquired, let's take this opportunity to make sure
  12160. // that the volume hasn't been dismounted.
  12161. //
  12162. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  12163. Status = STATUS_VOLUME_DISMOUNTED;
  12164. leave;
  12165. }
  12166. #ifdef COMPRESS_ON_WIRE
  12167. if (Scb->Header.FileObjectC != NULL) {
  12168. PCOMPRESSION_SYNC CompressionSync = NULL;
  12169. //
  12170. // Use a try-finally to clean up the compression sync.
  12171. //
  12172. try {
  12173. NtfsSynchronizeUncompressedIo( Scb,
  12174. NULL,
  12175. 0,
  12176. TRUE,
  12177. &CompressionSync );
  12178. } finally {
  12179. NtfsReleaseCompressionSync( CompressionSync );
  12180. }
  12181. }
  12182. #endif
  12183. //
  12184. // Get any cached changes flushed to disk.
  12185. //
  12186. CcFlushCache( FileObject->SectionObjectPointer,
  12187. (PLARGE_INTEGER)&StartingVbo,
  12188. TotalByteCount,
  12189. &Irp->IoStatus );
  12190. //
  12191. // Check for errors in the flush.
  12192. //
  12193. NtfsNormalizeAndCleanupTransaction( IrpContext,
  12194. &Irp->IoStatus.Status,
  12195. TRUE,
  12196. STATUS_UNEXPECTED_IO_ERROR );
  12197. //
  12198. // Store where we really started in the file.
  12199. //
  12200. AccessingUserBuffer = TRUE;
  12201. EncryptedDataInfo->StartingFileOffset = StartingVbo;
  12202. EncryptedDataInfo->ClusterShift = (UCHAR) Vcb->ClusterShift;
  12203. EncryptedDataInfo->EncryptionFormat = ENCRYPTION_FORMAT_DEFAULT;
  12204. AccessingUserBuffer = FALSE;
  12205. //
  12206. // Begin by getting a pointer to the device object that the file resides
  12207. // on.
  12208. //
  12209. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  12210. //
  12211. // This IrpContext probably isn't ready to do noncached I/O yet,
  12212. // so let's set up its NtfsIoContext. We know we will be doing
  12213. // this operation synchronously, so it is safe to use the
  12214. // local context.
  12215. //
  12216. if (IrpContext->Union.NtfsIoContext == NULL) {
  12217. //
  12218. // Make sure the world knows we want this done synchronously.
  12219. //
  12220. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) );
  12221. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  12222. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_IO_CONTEXT ) );
  12223. NtfsInitializeIoContext( IrpContext, &LocalContext, FALSE );
  12224. }
  12225. //
  12226. // Now we just loop through for each block and do the actual read(s).
  12227. //
  12228. DebugTrace( 0, Dbg, ("BlockCount %08lx\n", BlockCount) );
  12229. DebugTrace( 0, Dbg, ("TotalByteCount %08lx\n", TotalByteCount) );
  12230. DebugTrace( 0, Dbg, ("ByteCount %08lx\n", ByteCount) );
  12231. for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
  12232. //
  12233. // Compute the address to which we will start copying raw data.
  12234. //
  12235. RawDataDestination = Add2Ptr( EncryptedDataInfo, OutputBufferOffset );
  12236. DebugTrace( 0, Dbg, ("RawDataDestination %p\n", (ULONG_PTR)RawDataDestination) );
  12237. //
  12238. // If this is a sparse file, we need to determine whether this compression
  12239. // unit is allocated.
  12240. //
  12241. if (SparseFile) {
  12242. VCN StartVcn = LlClustersFromBytes( Vcb, StartingVbo );
  12243. VCN FinalCluster = LlClustersFromBytes( Vcb, (StartingVbo + ByteCount) ) - 1;
  12244. LONGLONG ClusterCount;
  12245. DebugTrace( 0, Dbg, ("SparseFile block %08lx\n", BlockIndex) );
  12246. DebugTrace( 0, Dbg, (" StartingVbo %016I64x\n", StartingVbo) );
  12247. DebugTrace( 0, Dbg, (" StartVcn %016I64x\n", StartVcn) );
  12248. DebugTrace( 0, Dbg, (" FinalCluster %016I64x\n", FinalCluster) );
  12249. //
  12250. // We need to call NtfsPreloadAllocation to make sure all the
  12251. // ranges in this NtfsMcb are loaded.
  12252. //
  12253. NtfsPreloadAllocation( IrpContext,
  12254. Scb,
  12255. StartVcn,
  12256. FinalCluster );
  12257. RangeAllocated = NtfsIsRangeAllocated( Scb,
  12258. StartVcn,
  12259. FinalCluster,
  12260. FALSE,
  12261. &ClusterCount );
  12262. if (!RangeAllocated) { DebugTrace( 0, Dbg, ("Deallocated range at Vcn %016I64x\n", StartVcn) ); }
  12263. } else {
  12264. //
  12265. // If this isn't a sparse file, we can skip the potentially expensive
  12266. // mapping lookup.
  12267. //
  12268. ASSERT( BlockCount == 1 );
  12269. ASSERT( RangeAllocated );
  12270. }
  12271. if (RangeAllocated) {
  12272. //
  12273. // Allocate an I/O Request Packet (IRP) for this raw read operation.
  12274. //
  12275. AccessingUserBuffer = TRUE;
  12276. ReadIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ,
  12277. Vcb->Vpb->DeviceObject,
  12278. RawDataDestination,
  12279. ByteCount,
  12280. (PLARGE_INTEGER)&StartingVbo,
  12281. NULL );
  12282. AccessingUserBuffer = FALSE;
  12283. if (ReadIrp == NULL) {
  12284. Status = STATUS_INSUFFICIENT_RESOURCES;
  12285. leave;
  12286. }
  12287. //
  12288. // We now have an Irp, we want to make it look as though it is part of
  12289. // the current call. We need to adjust the Irp stack to update this.
  12290. //
  12291. ReadIrp->CurrentLocation--;
  12292. ReadIrpSp = IoGetNextIrpStackLocation( ReadIrp );
  12293. ReadIrp->Tail.Overlay.CurrentStackLocation = ReadIrpSp;
  12294. ReadIrpSp->DeviceObject = DeviceObject;
  12295. //
  12296. // Put our buffer in the Irp and lock it as well.
  12297. //
  12298. ReadIrp->UserBuffer = RawDataDestination;
  12299. AccessingUserBuffer = TRUE;
  12300. NtfsLockUserBuffer( IrpContext,
  12301. ReadIrp,
  12302. IoWriteAccess,
  12303. ByteCount );
  12304. LockedReadIrpPages = TRUE;
  12305. //
  12306. // Put the read code into the IrpContext.
  12307. //
  12308. IrpContext->MajorFunction = IRP_MJ_READ;
  12309. //
  12310. // Actually read the raw data from the disk.
  12311. //
  12312. // N.B. -- If the file is compressed, also pass the COMPRESSED_STREAM flag.
  12313. //
  12314. NtfsNonCachedIo( IrpContext,
  12315. ReadIrp,
  12316. Scb,
  12317. StartingVbo,
  12318. ByteCount,
  12319. ENCRYPTED_STREAM );
  12320. //
  12321. // Fill in how many bytes we actually read.
  12322. //
  12323. BytesRead = (ULONG) ReadIrp->IoStatus.Information;
  12324. ASSERT( OutputBufferLength >
  12325. ((BlockIndex * sizeof(ULONG)) + FIELD_OFFSET(ENCRYPTED_DATA_INFO, DataBlockSize)));
  12326. EncryptedDataInfo->DataBlockSize[BlockIndex] = BytesRead;
  12327. AccessingUserBuffer = FALSE;
  12328. OutputBufferOffset += BytesRead;
  12329. } else {
  12330. //
  12331. // We didn't really read anything, so we want to set the
  12332. // size of this block to 0, but we want to pretend we
  12333. // read a whole compression unit so that BytesWithinXXX
  12334. // get updated correctly.
  12335. //
  12336. ASSERT( ReadIrp == NULL );
  12337. AccessingUserBuffer = TRUE;
  12338. EncryptedDataInfo->DataBlockSize[BlockIndex] = 0;
  12339. AccessingUserBuffer = FALSE;
  12340. BytesRead = Scb->CompressionUnit;
  12341. }
  12342. //
  12343. // Fill in the fields that let our caller know whether any of
  12344. // the file size or valid data length boundaries occured in
  12345. // the range of this transfer.
  12346. //
  12347. if ((StartingVbo + BytesRead) > Scb->Header.FileSize.QuadPart) {
  12348. //
  12349. // Only increment if we start before filesize
  12350. //
  12351. if (StartingVbo < Scb->Header.FileSize.QuadPart) {
  12352. BytesWithinFileSize += (ULONG)(Scb->Header.FileSize.QuadPart -
  12353. StartingVbo);
  12354. }
  12355. //
  12356. // If we're at the end of the file, and it isn't compressed, we can save
  12357. // the user a ton of space on the tape if we truncate to the first 512 byte
  12358. // boundary beyond the end of the data.
  12359. // 512 is the maximum cipher block size an encryption engine can rely on the
  12360. // file system to allow..
  12361. //
  12362. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  12363. ASSERT( OutputBufferLength >
  12364. ((BlockIndex * sizeof(ULONG)) + FIELD_OFFSET(ENCRYPTED_DATA_INFO, DataBlockSize)));
  12365. AccessingUserBuffer = TRUE;
  12366. EncryptedDataInfo->DataBlockSize[BlockIndex] = ((BytesWithinFileSize + (ULONG)0x200) & (ULONG)(~0x1ff));
  12367. AccessingUserBuffer = FALSE;
  12368. }
  12369. } else {
  12370. BytesWithinFileSize += BytesRead;
  12371. }
  12372. if ((StartingVbo + BytesRead) > Scb->Header.ValidDataLength.QuadPart) {
  12373. //
  12374. // Make sure BytesWithinValidDataLength can't go negative.
  12375. //
  12376. if (Scb->Header.ValidDataLength.QuadPart > StartingVbo) {
  12377. BytesWithinValidDataLength += (ULONG)(Scb->Header.ValidDataLength.QuadPart -
  12378. StartingVbo);
  12379. }
  12380. } else {
  12381. BytesWithinValidDataLength += BytesRead;
  12382. }
  12383. StartingVbo += ByteCount;
  12384. //
  12385. // We need to clean up the irp before we go around again.
  12386. //
  12387. if (ReadIrp != NULL) {
  12388. //
  12389. // If there is an Mdl we free that first.
  12390. //
  12391. if (ReadIrp->MdlAddress != NULL) {
  12392. if (LockedReadIrpPages) {
  12393. MmUnlockPages( ReadIrp->MdlAddress );
  12394. LockedReadIrpPages = FALSE;
  12395. }
  12396. IoFreeMdl( ReadIrp->MdlAddress );
  12397. ReadIrp->MdlAddress = NULL;
  12398. }
  12399. IoFreeIrp( ReadIrp );
  12400. ReadIrp = NULL;
  12401. }
  12402. } // endfor
  12403. AccessingUserBuffer = TRUE;
  12404. EncryptedDataInfo->BytesWithinFileSize = BytesWithinFileSize;
  12405. EncryptedDataInfo->BytesWithinValidDataLength = BytesWithinValidDataLength;
  12406. AccessingUserBuffer = FALSE;
  12407. } except( NtfsFsctrlExceptionFilter( IrpContext, GetExceptionInformation(), AccessingUserBuffer, &Status ) ) {
  12408. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted raising %08lx\n", Status) );
  12409. NtfsRaiseStatus( IrpContext,
  12410. STATUS_INVALID_USER_BUFFER,
  12411. NULL,
  12412. NULL );
  12413. }
  12414. try_exit: NOTHING;
  12415. } finally {
  12416. if (ReadIrp != NULL) {
  12417. //
  12418. // If there is an Mdl we free that first.
  12419. //
  12420. if (ReadIrp->MdlAddress != NULL) {
  12421. if (LockedReadIrpPages) {
  12422. MmUnlockPages( ReadIrp->MdlAddress );
  12423. }
  12424. IoFreeMdl( ReadIrp->MdlAddress );
  12425. }
  12426. IoFreeIrp( ReadIrp );
  12427. }
  12428. }
  12429. NtfsCompleteRequest( IrpContext, Irp, Status );
  12430. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted -> %08lx\n", Status) );
  12431. return Status;
  12432. }
  12433. LONG
  12434. NtfsWriteRawExceptionFilter (
  12435. IN PIRP_CONTEXT IrpContext,
  12436. IN PEXCEPTION_POINTERS ExceptionPointer
  12437. )
  12438. /*++
  12439. Routine Description:
  12440. Exception filter for errors during cleanup. We want to raise if this is
  12441. a retryable condition or fatal error, plow on as best we can if not.
  12442. Arguments:
  12443. IrpContext - IrpContext
  12444. ExceptionPointer - Pointer to the exception context.
  12445. Status - Address to store the error status.
  12446. Return Value:
  12447. Exception status - EXCEPTION_CONTINUE_SEARCH if we want to raise to another handler,
  12448. EXCEPTION_EXECUTE_HANDLER if we plan to proceed on.
  12449. --*/
  12450. {
  12451. UNREFERENCED_PARAMETER( IrpContext );
  12452. UNREFERENCED_PARAMETER( ExceptionPointer );
  12453. ASSERT( FsRtlIsNtstatusExpected( ExceptionPointer->ExceptionRecord->ExceptionCode ) );
  12454. return EXCEPTION_EXECUTE_HANDLER;
  12455. }
  12456. NTSTATUS
  12457. NtfsWriteRawEncrypted (
  12458. IN PIRP_CONTEXT IrpContext,
  12459. IN PIRP Irp
  12460. )
  12461. /*++
  12462. Routine Description:
  12463. This routine performs a 'raw' write of encrypted data. By 'raw', we
  12464. mean without attempting to encrypt. This is useful for restore
  12465. operations, where the restore operator does not have a key with which
  12466. to read the plaintext. This routine is responsible for either
  12467. completing or enqueuing the input Irp.
  12468. NOTE: there is a strong assumption that the encrypted data info blocks
  12469. are ordered monotonically from the beginning to end of the file
  12470. Arguments:
  12471. Irp - Supplies the Irp to process
  12472. Return Value:
  12473. NTSTATUS - The return status for the operation
  12474. --*/
  12475. {
  12476. LONGLONG StartingVbo;
  12477. LONGLONG EndingVbo;
  12478. LONGLONG TotalBytesWritten = 0;
  12479. LONGLONG FirstZero;
  12480. LONGLONG OriginalStartingVbo;
  12481. ULONG ByteCount;
  12482. ULONG BytesWithinValidDataLength;
  12483. ULONG BytesWithinFileSize;
  12484. USHORT CompressionFormat;
  12485. PIRP WriteIrp = NULL;
  12486. PDEVICE_OBJECT DeviceObject;
  12487. PFILE_OBJECT FileObject;
  12488. PVCB Vcb;
  12489. PFCB Fcb;
  12490. PSCB Scb;
  12491. PCCB Ccb;
  12492. PIO_STACK_LOCATION IrpSp;
  12493. PIO_STACK_LOCATION WriteIrpSp;
  12494. TYPE_OF_OPEN TypeOfOpen;
  12495. ULONG InputBufferLength;
  12496. PENCRYPTED_DATA_INFO EncryptedDataInfo;
  12497. ULONG InputBufferOffset;
  12498. USHORT BlockIndex;
  12499. USHORT BlockCount;
  12500. PUCHAR RawDataSource;
  12501. BOOLEAN AccessingUserBuffer = FALSE;
  12502. UCHAR EncryptionFormat;
  12503. UCHAR ChunkShift;
  12504. KEVENT Event;
  12505. IO_STATUS_BLOCK Iosb;
  12506. NTSTATUS Status = STATUS_SUCCESS;
  12507. PAGED_CODE();
  12508. //
  12509. // Don't post this request, we can't lock both input and output buffers.
  12510. //
  12511. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  12512. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  12513. DebugTrace( +1, Dbg, ("NtfsWriteRawEncrypted:\n") );
  12514. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  12515. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  12516. FileObject = IrpSp->FileObject;
  12517. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  12518. FileObject,
  12519. &Vcb,
  12520. &Fcb,
  12521. &Scb,
  12522. &Ccb,
  12523. TRUE );
  12524. //
  12525. // This operation only applies to files, not indexes,
  12526. // or volumes.
  12527. //
  12528. if (TypeOfOpen != UserFileOpen) {
  12529. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12530. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted not a UserFileOpen -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12531. return STATUS_INVALID_PARAMETER;
  12532. }
  12533. //
  12534. // Readonly mount should be just that: read only.
  12535. //
  12536. if (NtfsIsVolumeReadOnly( Vcb )) {
  12537. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  12538. DebugTrace( -1, Dbg, ("SetCompression returning WRITE_PROTECTED\n") );
  12539. return STATUS_MEDIA_WRITE_PROTECTED;
  12540. }
  12541. //
  12542. // Remember the source info flags in the Ccb.
  12543. //
  12544. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  12545. //
  12546. // We can't allow writes to unencrypted files, as that could let any
  12547. // user write to any file..
  12548. //
  12549. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED ) ||
  12550. //
  12551. // Even for an encrypted file, we should only allow this if the
  12552. // user has write access.
  12553. //
  12554. (!(FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS )))) {
  12555. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  12556. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted -> %08lx\n", STATUS_ACCESS_DENIED) );
  12557. return STATUS_ACCESS_DENIED;
  12558. }
  12559. //
  12560. // Get the input buffer length and pointer.
  12561. //
  12562. EncryptedDataInfo = (PENCRYPTED_DATA_INFO)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  12563. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  12564. //
  12565. // Check for a minimum length on the input buffer.
  12566. //
  12567. if (InputBufferLength < sizeof(ENCRYPTED_DATA_INFO)) {
  12568. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  12569. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted -> %08lx\n", STATUS_BUFFER_TOO_SMALL) );
  12570. return STATUS_BUFFER_TOO_SMALL;
  12571. }
  12572. //
  12573. // Probe the user's buffer.
  12574. //
  12575. try {
  12576. if (Irp->RequestorMode != KernelMode) {
  12577. ProbeForRead( EncryptedDataInfo, InputBufferLength, sizeof( UCHAR ) );
  12578. }
  12579. InputBufferOffset = EncryptedDataInfo->OutputBufferOffset;
  12580. BytesWithinValidDataLength = EncryptedDataInfo->BytesWithinValidDataLength;
  12581. BytesWithinFileSize = EncryptedDataInfo->BytesWithinFileSize;
  12582. BlockCount = EncryptedDataInfo->NumberOfDataBlocks;
  12583. EncryptionFormat = EncryptedDataInfo->EncryptionFormat;
  12584. OriginalStartingVbo = StartingVbo = EncryptedDataInfo->StartingFileOffset;
  12585. ChunkShift = EncryptedDataInfo->ChunkShift;
  12586. CompressionFormat = EncryptedDataInfo->CompressionFormat;
  12587. } except( NtfsWriteRawExceptionFilter( IrpContext, GetExceptionInformation() ) ) {
  12588. Status = GetExceptionCode();
  12589. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted raising %08lx\n", Status) );
  12590. NtfsRaiseStatus( IrpContext,
  12591. FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER,
  12592. NULL,
  12593. NULL );
  12594. }
  12595. //
  12596. // See whether the data we're being given is valid.
  12597. //
  12598. if ((EncryptionFormat != ENCRYPTION_FORMAT_DEFAULT) ||
  12599. (BytesWithinValidDataLength > BytesWithinFileSize) ||
  12600. (CompressionFormat != COMPRESSION_FORMAT_NONE) ||
  12601. (BlockCount == 0) ||
  12602. (InputBufferOffset > InputBufferLength)) {
  12603. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12604. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted bad input data -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12605. return STATUS_INVALID_PARAMETER;
  12606. }
  12607. try {
  12608. //
  12609. // Serialize with anyone who might be changing file sizes. Acquire main directly
  12610. // because we call CommonWrite mult times and want to hold the resource across the calls
  12611. //
  12612. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  12613. NtfsAcquireExclusiveScb( IrpContext, Scb );
  12614. #ifdef COMPRESS_ON_WIRE
  12615. //
  12616. // Before we proceed, let's make sure this file is not cached.
  12617. //
  12618. if (Scb->Header.FileObjectC != NULL) {
  12619. PCOMPRESSION_SYNC CompressionSync = NULL;
  12620. //
  12621. // Use a try-finally to clean up the compression sync.
  12622. //
  12623. try {
  12624. NtfsSynchronizeUncompressedIo( Scb,
  12625. NULL,
  12626. 0,
  12627. TRUE,
  12628. &CompressionSync );
  12629. } finally {
  12630. NtfsReleaseCompressionSync( CompressionSync );
  12631. }
  12632. }
  12633. #endif
  12634. CcFlushCache( &Scb->NonpagedScb->SegmentObject, NULL, 0, &Irp->IoStatus );
  12635. NtfsNormalizeAndCleanupTransaction( IrpContext, &Irp->IoStatus.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  12636. if (!CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject, NULL, 0, FALSE )) {
  12637. DebugTrace( 0, Dbg, ("Can't purge cache section in write raw...aborting\n") );
  12638. Status = STATUS_UNABLE_TO_DELETE_SECTION;
  12639. leave;
  12640. }
  12641. // **** TIGHTEN THIS ASSERT ****
  12642. // ASSERT( Scb->NonpagedScb->SegmentObject.SharedCacheMap == NULL );
  12643. //
  12644. // Since we can't add zeroes in the middle of the file (since we may not
  12645. // have a key with which to encrypt them) it's illegal to try to write
  12646. // at some arbitrary offset beyond the current eof.
  12647. //
  12648. if (StartingVbo != Scb->Header.FileSize.QuadPart) {
  12649. DebugTrace( 0, Dbg, ("Attempting to begin a write raw beyond EOF...aborting\n") );
  12650. Status = STATUS_INVALID_PARAMETER;
  12651. leave;
  12652. }
  12653. //
  12654. // Add any allocation necc. to reach the new filesize
  12655. //
  12656. if (OriginalStartingVbo + BytesWithinFileSize > Scb->Header.AllocationSize.QuadPart) {
  12657. EndingVbo = OriginalStartingVbo + BytesWithinFileSize;
  12658. //
  12659. // Always add in compression units for sparse files
  12660. //
  12661. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  12662. EndingVbo = BlockAlign( EndingVbo, (LONG)Scb->CompressionUnit );
  12663. }
  12664. NtfsAddAllocation( IrpContext,
  12665. NULL,
  12666. Scb,
  12667. LlClustersFromBytes( Vcb,
  12668. Scb->Header.AllocationSize.QuadPart ),
  12669. LlClustersFromBytes( Vcb, EndingVbo - Scb->Header.AllocationSize.QuadPart ),
  12670. FALSE,
  12671. NULL );
  12672. }
  12673. //
  12674. // Now we just loop through for each block and do the actual write(s).
  12675. //
  12676. DebugTrace( 0, Dbg, ("BlockCount %08lx\n", BlockCount) );
  12677. for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
  12678. AccessingUserBuffer = TRUE;
  12679. ByteCount = EncryptedDataInfo->DataBlockSize[BlockIndex];
  12680. AccessingUserBuffer = FALSE;
  12681. EndingVbo = StartingVbo + ByteCount;
  12682. DebugTrace( 0, Dbg, ("BlockIndex %08lx\n", BlockIndex) );
  12683. DebugTrace( 0, Dbg, ("ByteCount %08lx\n", ByteCount) );
  12684. if (ByteCount != 0 && BytesWithinValidDataLength > 0) {
  12685. //
  12686. // Compute the address from which we will start copying raw data.
  12687. //
  12688. RawDataSource = Add2Ptr( EncryptedDataInfo, InputBufferOffset );
  12689. //
  12690. // Make sure we aren't about to touch memory beyond that part of the
  12691. // user's buffer that we probed above.
  12692. //
  12693. if ((InputBufferOffset + ByteCount) > InputBufferLength) {
  12694. DebugTrace( 0, Dbg, ("Going beyond InputBufferLength...aborting\n") );
  12695. Status = STATUS_INVALID_PARAMETER;
  12696. leave;
  12697. }
  12698. InputBufferOffset += ByteCount;
  12699. //
  12700. // Begin by getting a pointer to the device object that the file resides
  12701. // on.
  12702. //
  12703. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  12704. //
  12705. // Allocate an I/O Request Packet (IRP) for this raw write operation.
  12706. // It has to be synchronous so that it completes before we adjust
  12707. // filesize and valid data length.
  12708. //
  12709. AccessingUserBuffer = TRUE;
  12710. WriteIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE,
  12711. Vcb->Vpb->DeviceObject,
  12712. RawDataSource,
  12713. ByteCount,
  12714. (PLARGE_INTEGER)&StartingVbo,
  12715. &Event,
  12716. &Iosb );
  12717. AccessingUserBuffer = FALSE;
  12718. if (WriteIrp == NULL) {
  12719. Status = STATUS_INSUFFICIENT_RESOURCES;
  12720. leave;
  12721. }
  12722. //
  12723. // Put our buffer in the Irp and set some other irp fields.
  12724. //
  12725. WriteIrp->UserBuffer = RawDataSource;
  12726. SetFlag( WriteIrp->Flags, IRP_NOCACHE );
  12727. //
  12728. // We now have an Irp, we want to make it look as though it came from
  12729. // IoCallDriver and need to adjust the Irp stack to update this.
  12730. //
  12731. WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
  12732. WriteIrpSp->DeviceObject = DeviceObject;
  12733. WriteIrpSp->Parameters.Write.ByteOffset.QuadPart = StartingVbo;
  12734. WriteIrpSp->Parameters.Write.Length = ByteCount;
  12735. WriteIrpSp->FileObject = FileObject;
  12736. ASSERT( NtfsIsExclusiveScb( Scb ) );
  12737. //
  12738. // Callback directly into ourselfs - don't confuse filters with
  12739. // an extra write
  12740. //
  12741. Status = IoCallDriver( Vcb->Vpb->DeviceObject, WriteIrp );
  12742. if (Status == STATUS_PENDING) {
  12743. Status = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  12744. if (Status == STATUS_SUCCESS) {
  12745. Status = Iosb.Status;
  12746. }
  12747. }
  12748. //
  12749. // The write should always be done synchronously, we should still own
  12750. // the resource and all our cleanup structures and snapshots should be good
  12751. //
  12752. ASSERT(Status != STATUS_PENDING && Status != STATUS_CANT_WAIT);
  12753. ASSERT( NtfsIsExclusiveScb( Scb ) );
  12754. ASSERT( (IrpContext->CleanupStructure == Fcb) && (Scb->ScbSnapshot != NULL) );
  12755. NtfsNormalizeAndCleanupTransaction( IrpContext, &Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  12756. TotalBytesWritten += ByteCount;
  12757. } else if (ByteCount == 0) {
  12758. //
  12759. // This is a sparse hole, so there's nothing to actually write.
  12760. // We just need to make sure this stream is sparse, and zero this
  12761. // range. We can't ask our caller to mark the file as sparse,
  12762. // since they just opened the handle and don't have write
  12763. // access to this file.
  12764. //
  12765. DebugTrace( 0, Dbg, ("Deallocated range for block %x\n", BlockIndex) );
  12766. //
  12767. // Make sure our test of the attribute flag is safe.
  12768. //
  12769. ASSERT_SHARED_RESOURCE( Scb->Header.PagingIoResource );
  12770. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  12771. DebugTrace( 0, Dbg, ("Marking stream as sparse\n") );
  12772. NtfsSetSparseStream( IrpContext, NULL, Scb );
  12773. }
  12774. ByteCount = (1 << ChunkShift);
  12775. EndingVbo = StartingVbo + ByteCount;
  12776. //
  12777. // Add any allocation necc. to back this. Ie we have a sparse region
  12778. // beyond filesize
  12779. //
  12780. if (Scb->Header.AllocationSize.QuadPart < EndingVbo) {
  12781. //
  12782. // Round up to a compression unit
  12783. //
  12784. EndingVbo = BlockAlign( EndingVbo, (LONG)Scb->CompressionUnit );
  12785. NtfsAddAllocation( IrpContext,
  12786. NULL,
  12787. Scb,
  12788. LlClustersFromBytes( Vcb,
  12789. Scb->Header.AllocationSize.QuadPart ),
  12790. LlClustersFromBytes( Vcb,
  12791. EndingVbo - Scb->Header.AllocationSize.QuadPart ),
  12792. FALSE,
  12793. NULL );
  12794. }
  12795. DebugTrace( 0, Dbg, ("Zeroing range from %I64x\n", StartingVbo) );
  12796. DebugTrace( 0, Dbg, ("to %I64x\n", (StartingVbo + ByteCount - 1)) );
  12797. //
  12798. // We can't synthesize partial sparse holes, since our caller may
  12799. // not have a key with which to encrypt a buffer full of zeroes.
  12800. // Therefore, we can't do this restore if the volume we're restoring
  12801. // to requires sparse holes to be bigger than the hole we're
  12802. // trying to restore now.
  12803. //
  12804. if (ByteCount < Scb->CompressionUnit) {
  12805. DebugTrace( 0, Dbg, ("Can't synthesize partial sparse hole\n") );
  12806. Status = STATUS_INVALID_PARAMETER;
  12807. leave;
  12808. }
  12809. //
  12810. // Copy StartingVbo in case ZeroRangeInStream modifies it.
  12811. // NtfsZeroRangeInStream uses the cleanupstructure so always
  12812. // return it back to its original value afterwards
  12813. //
  12814. FirstZero = StartingVbo;
  12815. Status = NtfsZeroRangeInStream( IrpContext,
  12816. FileObject,
  12817. Scb,
  12818. &FirstZero,
  12819. (StartingVbo + ByteCount - 1) );
  12820. ASSERT( (PFCB)IrpContext->CleanupStructure == Fcb );
  12821. if (!NT_SUCCESS( Status )) {
  12822. leave;
  12823. }
  12824. //
  12825. // Let's move the filesize up now, just like NtfsCommonWrite does in
  12826. // the other half of this if statement.
  12827. //
  12828. {
  12829. LONGLONG NewFileSize = StartingVbo + ByteCount;
  12830. DebugTrace( 0, Dbg, ("Adjusting sparse file size to %I64x\n", NewFileSize) );
  12831. Scb->Header.FileSize.QuadPart = NewFileSize;
  12832. NtfsWriteFileSizes( IrpContext, Scb, &NewFileSize, FALSE, TRUE, TRUE );
  12833. if (Scb->FileObject != NULL) {
  12834. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  12835. }
  12836. }
  12837. TotalBytesWritten += ByteCount;
  12838. }
  12839. StartingVbo += ByteCount;
  12840. }
  12841. DebugTrace( 0, Dbg, ("TotalBytesWritten %I64x\n", TotalBytesWritten) );
  12842. //
  12843. // Only adjust the filesizes if the write succeeded. If the write failed
  12844. // the IrpContext has been freed already. Note: startyingvbo must be <= original eof
  12845. //
  12846. if (NT_SUCCESS( Status ) &&
  12847. ((LONGLONG)BytesWithinFileSize != TotalBytesWritten ||
  12848. (LONGLONG)BytesWithinValidDataLength < TotalBytesWritten)) {
  12849. LONGLONG NewValidDataLength = OriginalStartingVbo + BytesWithinValidDataLength;
  12850. Scb->Header.FileSize.QuadPart = OriginalStartingVbo + BytesWithinFileSize;
  12851. if (NewValidDataLength < Scb->Header.ValidDataLength.QuadPart) {
  12852. Scb->Header.ValidDataLength.QuadPart = NewValidDataLength;
  12853. }
  12854. //
  12855. // WriteFileSizes will only move the VDL back since we set AdvanceOnly to False
  12856. //
  12857. ASSERT( IrpContext->CleanupStructure != NULL );
  12858. NtfsWriteFileSizes( IrpContext, Scb, &NewValidDataLength, FALSE, TRUE, TRUE );
  12859. //
  12860. // Readjust VDD - for non compressed files this is a noop since vdd is not updated for them
  12861. //
  12862. if (Scb->ValidDataToDisk > Scb->Header.ValidDataLength.QuadPart) {
  12863. Scb->ValidDataToDisk = Scb->Header.ValidDataLength.QuadPart;
  12864. }
  12865. if (Scb->FileObject != NULL) {
  12866. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  12867. }
  12868. }
  12869. } except( NtfsWriteRawExceptionFilter( IrpContext, GetExceptionInformation() ) ) {
  12870. Status = GetExceptionCode();
  12871. DebugTrace( -1, Dbg, ("NtfsReadRawEncrypted raising %08lx\n", Status) );
  12872. NtfsRaiseStatus( IrpContext,
  12873. ((FsRtlIsNtstatusExpected(Status) || !AccessingUserBuffer) ? Status : STATUS_INVALID_USER_BUFFER),
  12874. NULL,
  12875. NULL );
  12876. }
  12877. NtfsCompleteRequest( IrpContext, Irp, Status );
  12878. DebugTrace( -1, Dbg, ("NtfsWriteRawEncrypted -> %08lx\n", Status) );
  12879. return Status;
  12880. }
  12881. //
  12882. // Local Support Routine
  12883. //
  12884. NTSTATUS
  12885. NtfsExtendVolume (
  12886. IN PIRP_CONTEXT IrpContext,
  12887. IN PIRP Irp
  12888. )
  12889. /*++
  12890. Routine Description:
  12891. This routine extends an Ntfs volume. We will take the number of sectors
  12892. passed to this routine and extend the volume provided that this will grow
  12893. the volume by at least one cluster.
  12894. Arguments:
  12895. Irp - Supplies the Irp to process
  12896. Return Value:
  12897. NTSTATUS - The return status for the operation
  12898. --*/
  12899. {
  12900. NTSTATUS Status = STATUS_SUCCESS;
  12901. PIO_STACK_LOCATION IrpSp;
  12902. TYPE_OF_OPEN TypeOfOpen;
  12903. PVCB Vcb;
  12904. PFCB Fcb;
  12905. PSCB Scb;
  12906. PCCB Ccb;
  12907. FILE_REFERENCE FileReference = { BOOT_FILE_NUMBER, 0, BOOT_FILE_NUMBER };
  12908. PSCB BootFileScb = NULL;
  12909. BOOLEAN RemovedBootFileFcb = FALSE;
  12910. BOOLEAN UnloadMcb = FALSE;
  12911. LONGLONG NewVolumeSize;
  12912. LONGLONG NewTotalClusters;
  12913. LONGLONG NewBitmapSize;
  12914. LONGLONG NewBitmapAllocation;
  12915. LONGLONG AddBytes;
  12916. LONGLONG AddClusters = 0;
  12917. LONGLONG PreviousBitmapAllocation;
  12918. LCN NewLcn;
  12919. LCN Lcn;
  12920. LONGLONG ClusterCount;
  12921. LONGLONG FileOffset;
  12922. LONGLONG BeyondBitsToModify;
  12923. LONGLONG NewSectors;
  12924. IO_STATUS_BLOCK Iosb;
  12925. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  12926. DISK_GEOMETRY DiskGeometry;
  12927. LONGLONG DiskBytes;
  12928. PBCB PrimaryBootBcb = NULL;
  12929. PBCB BackupBootBcb = NULL;
  12930. PPACKED_BOOT_SECTOR PrimaryBootSector;
  12931. PPACKED_BOOT_SECTOR BackupBootSector;
  12932. ASSERT_IRP_CONTEXT( IrpContext );
  12933. ASSERT_IRP( Irp );
  12934. PAGED_CODE();
  12935. DebugTrace( +1, Dbg, ("NtfsExtendVolume...\n") );
  12936. //
  12937. // Make sure the input parameters are valid.
  12938. //
  12939. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  12940. //
  12941. // The input buffer is a LONGLONG and it should not be zero.
  12942. //
  12943. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( LONGLONG )) {
  12944. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12945. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12946. return STATUS_INVALID_PARAMETER;
  12947. }
  12948. RtlCopyMemory( &NewSectors, Irp->AssociatedIrp.SystemBuffer, sizeof( LONGLONG ));
  12949. if (NewSectors <= 0) {
  12950. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  12951. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_INVALID_PARAMETER) );
  12952. return STATUS_INVALID_PARAMETER;
  12953. }
  12954. //
  12955. // Extract and decode the file object, and only permit user volume opens
  12956. //
  12957. TypeOfOpen = NtfsDecodeFileObject( IrpContext,
  12958. IrpSp->FileObject,
  12959. &Vcb,
  12960. &Fcb,
  12961. &Scb,
  12962. &Ccb,
  12963. TRUE );
  12964. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  12965. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  12966. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_ACCESS_DENIED) );
  12967. return STATUS_ACCESS_DENIED;
  12968. }
  12969. //
  12970. // Readonly mount should be just that: read only.
  12971. //
  12972. if (NtfsIsVolumeReadOnly( Vcb )) {
  12973. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  12974. DebugTrace( -1, Dbg, ("SetCompression returning WRITE_PROTECTED\n") );
  12975. return STATUS_MEDIA_WRITE_PROTECTED;
  12976. }
  12977. //
  12978. // We don't want to rewind back to a different value than what we currently have
  12979. //
  12980. ASSERT( Vcb->PreviousTotalClusters == Vcb->TotalClusters );
  12981. //
  12982. // Lets set the Scb to the volume bitmap scb at this point. We no longer care about
  12983. // the volume Dasd Scb from here on.
  12984. //
  12985. Scb = NULL;
  12986. //
  12987. // Compute the new volume size. Don't forget to allow one sector for the backup
  12988. // boot sector.
  12989. //
  12990. NewVolumeSize = (NewSectors - 1) * Vcb->BytesPerSector;
  12991. NewTotalClusters = LlClustersFromBytesTruncate( Vcb, NewVolumeSize );
  12992. //
  12993. // Make sure the volume size didn't wrap and that we don't have more than 2^32 - 2 clusters.
  12994. // We make this 2^32 - 2 so that we can generate a cluster for the backup boot sector in
  12995. // order to write it.
  12996. //
  12997. if ((NewVolumeSize < NewSectors) ||
  12998. (NewTotalClusters > (0x100000000 - 2))) {
  12999. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13000. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", STATUS_INVALID_PARAMETER) );
  13001. return STATUS_INVALID_PARAMETER;
  13002. }
  13003. //
  13004. // We hold the Vcb exclusively for this operation. Make sure the wait flag is
  13005. // set in the IrpContext.
  13006. //
  13007. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  13008. NtfsInitializeAttributeContext( &AttrContext );
  13009. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  13010. //
  13011. // Use a try-finally to facilitate cleanup.
  13012. //
  13013. try {
  13014. //
  13015. // Make sure the volume is mounted.
  13016. //
  13017. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  13018. Status = STATUS_VOLUME_DISMOUNTED;
  13019. leave;
  13020. }
  13021. //
  13022. // We only need the Mft and volume bitmap for this operation.
  13023. // Lets set the Scb to the volume bitmap scb at this point. We no longer care about
  13024. // the volume Dasd Scb from here on. We acquire it here solely to be able to
  13025. // update the size when we are done.
  13026. //
  13027. Scb = Vcb->BitmapScb;
  13028. NtfsAcquireExclusiveFcb( IrpContext, Vcb->VolumeDasdScb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  13029. NtfsAcquireExclusiveFcb( IrpContext, Vcb->MftScb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  13030. ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, TRUE );
  13031. NtfsAcquireExclusiveFcb( IrpContext, Scb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK | ACQUIRE_HOLD_BITMAP );
  13032. ASSERT( Scb->Fcb->ExclusiveFcbLinks.Flink != NULL );
  13033. //
  13034. // Make sure we are adding at least one cluster.
  13035. //
  13036. if ((Vcb->TotalClusters >= NewTotalClusters) &&
  13037. (NewTotalClusters >= 0)) {
  13038. Status = STATUS_INVALID_PARAMETER;
  13039. leave;
  13040. }
  13041. //
  13042. // Also check that the driver supports a drive of this size.
  13043. // Total size in use == NewVolumeSize + the last copy of the boot sector
  13044. // NewVolumeSize is already biased for the boot sector copy
  13045. //
  13046. NtfsGetDiskGeometry( IrpContext, Vcb->TargetDeviceObject, &DiskGeometry, &DiskBytes );
  13047. if ((Vcb->BytesPerSector != DiskGeometry.BytesPerSector) ||
  13048. (NewVolumeSize + Vcb->BytesPerSector > DiskBytes)) {
  13049. Status = STATUS_INVALID_PARAMETER;
  13050. leave;
  13051. }
  13052. //
  13053. // Go ahead and create an Fcb and Scb for the BootFile.
  13054. //
  13055. BootFileScb = NtfsCreatePrerestartScb( IrpContext, Vcb, &FileReference, $DATA, NULL, 0 );
  13056. //
  13057. // Acquire this Fcb exclusively but don't put it our exclusive lists or snapshot it.
  13058. //
  13059. NtfsAcquireResourceExclusive( IrpContext, BootFileScb, TRUE );
  13060. if (!FlagOn( BootFileScb->ScbState, SCB_STATE_FILE_SIZE_LOADED )) {
  13061. NtfsUpdateScbFromAttribute( IrpContext, BootFileScb, NULL );
  13062. }
  13063. //
  13064. // Lets flush and purge the volume bitmap. We want to make sure there are no
  13065. // partial pages at the end of the bitmap.
  13066. //
  13067. CcFlushCache( &Scb->NonpagedScb->SegmentObject,
  13068. NULL,
  13069. 0,
  13070. &Iosb );
  13071. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  13072. if (!CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject,
  13073. NULL,
  13074. 0,
  13075. FALSE )) {
  13076. NtfsRaiseStatus( IrpContext, STATUS_UNABLE_TO_DELETE_SECTION, NULL, NULL );
  13077. }
  13078. //
  13079. // We want to snapshot the volume bitmap.
  13080. //
  13081. NtfsSnapshotScb( IrpContext, Scb );
  13082. //
  13083. // Unload the Mcb in case of errors.
  13084. //
  13085. ASSERT( Scb->ScbSnapshot != NULL );
  13086. Scb->ScbSnapshot->LowestModifiedVcn = 0;
  13087. Scb->ScbSnapshot->HighestModifiedVcn = MAXLONGLONG;
  13088. //
  13089. // Round the bitmap size up to an 8 byte boundary.
  13090. //
  13091. NewBitmapSize = BlockAlign( Int64ShraMod32( NewTotalClusters + 7, 3 ), 8 );
  13092. NewBitmapAllocation = LlBytesFromClusters( Vcb, LlClustersFromBytes( Vcb, NewBitmapSize ));
  13093. PreviousBitmapAllocation = Scb->Header.AllocationSize.QuadPart;
  13094. //
  13095. // If we are growing the allocation for the volume bitmap then
  13096. // we want to make sure the entire new clusters are zeroed and
  13097. // then added to the volume bitmap.
  13098. //
  13099. if (NewBitmapAllocation > PreviousBitmapAllocation) {
  13100. AddBytes = NewBitmapAllocation - PreviousBitmapAllocation;
  13101. AddClusters = LlClustersFromBytesTruncate( Vcb, AddBytes );
  13102. //
  13103. // Add the entry to Mcb. We would prefer not to overwrite the existing
  13104. // backup boot sector if possible.
  13105. //
  13106. NewLcn = Vcb->PreviousTotalClusters + 1;
  13107. if (NewLcn + AddClusters > NewTotalClusters) {
  13108. NewLcn -= 1;
  13109. }
  13110. NtfsAddNtfsMcbEntry( &Scb->Mcb,
  13111. LlClustersFromBytesTruncate( Vcb, PreviousBitmapAllocation ),
  13112. NewLcn,
  13113. AddClusters,
  13114. FALSE );
  13115. //
  13116. // We may need to unload the Mcb by hand if we get a failure before the first log record.
  13117. //
  13118. UnloadMcb = TRUE;
  13119. //
  13120. // Now write zeroes into these clusters.
  13121. //
  13122. NtfsWriteClusters( IrpContext,
  13123. Vcb,
  13124. Scb,
  13125. PreviousBitmapAllocation,
  13126. NULL,
  13127. (ULONG)AddClusters);
  13128. //
  13129. // Store the new total clusters in the Vcb now. Several of our routines
  13130. // check that a cluster being used lies within the volume. We will temporarily round
  13131. // this up to an 8 byte boundary so we can set any unused bits in the tail of
  13132. // the bitmap.
  13133. //
  13134. Vcb->TotalClusters = Int64ShllMod32( NewBitmapSize, 3 );
  13135. //
  13136. // Go ahead and write the new mapping pairs for the larger allocation.
  13137. //
  13138. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &AttrContext );
  13139. NtfsAddAttributeAllocation( IrpContext, Scb, &AttrContext, NULL, NULL );
  13140. //
  13141. // Our transaction handling will deal with the Mcb now.
  13142. //
  13143. UnloadMcb = FALSE;
  13144. //
  13145. // Now tell the cache manager about the larger section.
  13146. //
  13147. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  13148. } else {
  13149. //
  13150. // Store the new total clusters in the Vcb now. Several of our routines
  13151. // check that a cluster being used lies within the volume. We will temporarily round
  13152. // this up to an 8 byte boundary so we can set any unused bits in the tail of
  13153. // the bitmap.
  13154. //
  13155. Vcb->TotalClusters = Int64ShllMod32( NewBitmapSize, 3 );
  13156. }
  13157. //
  13158. // We now have allocated enough space for the new clusters. The next step is to mark them
  13159. // allocated in the new volume bitmap. Start by updating the file size in the Scb and
  13160. // on disk for the new size. We can make the whole new range valid. We will explicitly
  13161. // update any bytes that may still be incorrect on disk.
  13162. //
  13163. Scb->Header.ValidDataLength.QuadPart =
  13164. Scb->Header.FileSize.QuadPart = NewBitmapSize;
  13165. Scb->TotalAllocated = Scb->Header.AllocationSize.QuadPart;
  13166. NtfsWriteFileSizes( IrpContext, Scb, &NewBitmapSize, TRUE, TRUE, TRUE );
  13167. CcSetFileSizes( Scb->FileObject, (PCC_FILE_SIZES) &Scb->Header.AllocationSize );
  13168. //
  13169. // The file size is now correct in the Scb and on disk. The next thing to do is
  13170. // to zero out any bits between the previous end of the bitmap and the end of the previous
  13171. // allocation (or the current total clusters, whichever is smaller).
  13172. //
  13173. BeyondBitsToModify = Int64ShllMod32( PreviousBitmapAllocation, 3 );
  13174. if (Vcb->TotalClusters < BeyondBitsToModify) {
  13175. BeyondBitsToModify = Vcb->TotalClusters;
  13176. }
  13177. if (BeyondBitsToModify != Vcb->PreviousTotalClusters) {
  13178. NtfsModifyBitsInBitmap( IrpContext,
  13179. Vcb,
  13180. Vcb->PreviousTotalClusters,
  13181. BeyondBitsToModify,
  13182. ClearBitsInNonresidentBitMap,
  13183. SetBitsInNonresidentBitMap );
  13184. }
  13185. //
  13186. // Now we need to set bits for all of the new clusters which are part of
  13187. // the extension of the volume bitmap.
  13188. //
  13189. if (AddClusters != 0) {
  13190. NtfsModifyBitsInBitmap( IrpContext,
  13191. Vcb,
  13192. NewLcn,
  13193. NewLcn + AddClusters,
  13194. SetBitsInNonresidentBitMap,
  13195. ClearBitsInNonresidentBitMap );
  13196. }
  13197. //
  13198. // Finally we need to set all of the bits in the new bitmap which lie beyond
  13199. // the end of the actual on-disk clusters.
  13200. //
  13201. BeyondBitsToModify = Int64ShllMod32( NewBitmapSize, 3 );
  13202. if (BeyondBitsToModify != NewTotalClusters) {
  13203. NtfsModifyBitsInBitmap( IrpContext,
  13204. Vcb,
  13205. NewTotalClusters,
  13206. BeyondBitsToModify,
  13207. SetBitsInNonresidentBitMap,
  13208. Noop );
  13209. }
  13210. //
  13211. // Now set to the exact clusters on the disk.
  13212. //
  13213. Vcb->TotalClusters = NewTotalClusters;
  13214. //
  13215. // Now it is time to modify the boot sectors for the volume. We want to:
  13216. //
  13217. // o Remove the allocation for the n/2 boot sector if present (3.51 format)
  13218. // o Copy the current boot sector to the end of the volume (with the new sector count)
  13219. // o Update the primary boot sector at the beginning of the volume.
  13220. //
  13221. // Start by purging the stream.
  13222. //
  13223. NtfsCreateInternalAttributeStream( IrpContext, BootFileScb, TRUE, NULL );
  13224. //
  13225. // Don't let the lazy writer touch this stream.
  13226. //
  13227. CcSetAdditionalCacheAttributes( BootFileScb->FileObject, TRUE, TRUE );
  13228. //
  13229. // Now look to see if the file has more than one run. If so we want to truncate
  13230. // it to the end of the first run.
  13231. //
  13232. if (NtfsLookupAllocation( IrpContext, BootFileScb, 0, &Lcn, &ClusterCount, NULL, NULL )) {
  13233. NtfsDeleteAllocation( IrpContext,
  13234. BootFileScb->FileObject,
  13235. BootFileScb,
  13236. ClusterCount,
  13237. MAXLONGLONG,
  13238. TRUE,
  13239. FALSE );
  13240. }
  13241. //
  13242. // Now create mapping for this stream where the first page (or cluster) will be used for the
  13243. // primary boot sector and we will have the additional sectors to be able to write to the
  13244. // last sector.
  13245. //
  13246. BootFileScb->Header.FileSize.QuadPart = PAGE_SIZE;
  13247. if (PAGE_SIZE < Vcb->BytesPerCluster) {
  13248. BootFileScb->Header.FileSize.QuadPart = Vcb->BytesPerCluster;
  13249. }
  13250. BootFileScb->Header.FileSize.QuadPart += (NewVolumeSize + Vcb->BytesPerSector) - LlBytesFromClusters( Vcb, NewTotalClusters );
  13251. BootFileScb->Header.ValidDataLength.QuadPart = BootFileScb->Header.FileSize.QuadPart;
  13252. BootFileScb->Header.AllocationSize.QuadPart = LlBytesFromClusters( Vcb, LlClustersFromBytes( Vcb, BootFileScb->Header.FileSize.QuadPart ));
  13253. CcSetFileSizes( BootFileScb->FileObject, (PCC_FILE_SIZES) &BootFileScb->Header.AllocationSize );
  13254. //
  13255. // Go ahead purge any existing data and empty the Mcb.
  13256. //
  13257. CcPurgeCacheSection( &BootFileScb->NonpagedScb->SegmentObject,
  13258. NULL,
  13259. 0,
  13260. FALSE );
  13261. NtfsUnloadNtfsMcbRange( &BootFileScb->Mcb,
  13262. 0,
  13263. MAXLONGLONG,
  13264. FALSE,
  13265. FALSE );
  13266. //
  13267. // Lets create the Mcb by hand for this.
  13268. //
  13269. NtfsAddNtfsMcbEntry( &BootFileScb->Mcb,
  13270. 0,
  13271. 0,
  13272. LlClustersFromBytes( Vcb, PAGE_SIZE ),
  13273. FALSE );
  13274. NtfsAddNtfsMcbEntry( &BootFileScb->Mcb,
  13275. LlClustersFromBytes( Vcb, PAGE_SIZE ),
  13276. NewTotalClusters,
  13277. 1,
  13278. FALSE );
  13279. //
  13280. // Now lets pin the two boot sectors.
  13281. //
  13282. FileOffset = 0;
  13283. NtfsPinStream( IrpContext,
  13284. BootFileScb,
  13285. 0,
  13286. Vcb->BytesPerSector,
  13287. &PrimaryBootBcb,
  13288. &PrimaryBootSector );
  13289. FileOffset = BootFileScb->Header.FileSize.QuadPart - Vcb->BytesPerSector;
  13290. NtfsPinStream( IrpContext,
  13291. BootFileScb,
  13292. FileOffset,
  13293. Vcb->BytesPerSector,
  13294. &BackupBootBcb,
  13295. &BackupBootSector );
  13296. //
  13297. // Remember thge new sector count is 1 less than what we were given
  13298. //
  13299. NewSectors -= 1;
  13300. //
  13301. // Copy the primary boot sector to the backup location.
  13302. //
  13303. RtlCopyMemory( BackupBootSector, PrimaryBootSector, Vcb->BytesPerSector );
  13304. //
  13305. // Now copy the sector count into the boot sectors and flush to disk.
  13306. // Use RtlCopy to avoid alignment faults.
  13307. //
  13308. RtlCopyMemory( &BackupBootSector->NumberSectors, &NewSectors, sizeof( LONGLONG ));
  13309. CcSetDirtyPinnedData( BackupBootBcb, NULL );
  13310. CcFlushCache( &BootFileScb->NonpagedScb->SegmentObject,
  13311. (PLARGE_INTEGER) &FileOffset,
  13312. Vcb->BytesPerSector,
  13313. &Iosb );
  13314. //
  13315. // Make sure the flush worked.
  13316. //
  13317. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  13318. //
  13319. // Now do the primary.
  13320. //
  13321. FileOffset = 0;
  13322. RtlCopyMemory( &PrimaryBootSector->NumberSectors, &NewSectors, sizeof( LONGLONG ));
  13323. CcSetDirtyPinnedData( PrimaryBootBcb, NULL );
  13324. CcFlushCache( &BootFileScb->NonpagedScb->SegmentObject,
  13325. (PLARGE_INTEGER) &FileOffset,
  13326. Vcb->BytesPerSector,
  13327. &Iosb );
  13328. //
  13329. // Make sure the flush worked.
  13330. //
  13331. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  13332. //
  13333. // Let's get rid of the pages for this stream now.
  13334. //
  13335. NtfsUnpinBcb( IrpContext, &PrimaryBootBcb );
  13336. NtfsUnpinBcb( IrpContext, &BackupBootBcb );
  13337. CcPurgeCacheSection( &BootFileScb->NonpagedScb->SegmentObject,
  13338. NULL,
  13339. 0,
  13340. FALSE );
  13341. NtfsCleanupTransaction( IrpContext, Status, TRUE );
  13342. //
  13343. // Commit the transaction now so we can update some of the in-memory structures.
  13344. //
  13345. NtfsCheckpointCurrentTransaction( IrpContext );
  13346. LfsFlushToLsn( Vcb->LogHandle, LiMax );
  13347. //
  13348. // We know this request has succeeded. Go ahead and remember the new total cluster count
  13349. // and sector count.
  13350. //
  13351. Vcb->PreviousTotalClusters = Vcb->TotalClusters;
  13352. Vcb->NumberSectors = NewSectors;
  13353. //
  13354. // Also update the volume dasd size.
  13355. //
  13356. Vcb->VolumeDasdScb->Header.ValidDataLength.QuadPart =
  13357. Vcb->VolumeDasdScb->Header.FileSize.QuadPart =
  13358. Vcb->VolumeDasdScb->Header.AllocationSize.QuadPart = LlBytesFromClusters( Vcb, Vcb->TotalClusters );
  13359. //
  13360. // Set the flag in the Vcb to cause a rescan of the bitmap for free clusters. This will also
  13361. // let the bitmap package use the larger blocks of available disk space.
  13362. //
  13363. SetFlag( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS );
  13364. } finally {
  13365. DebugUnwind( NtfsExtendVolume );
  13366. NtfsUnpinBcb( IrpContext, &PrimaryBootBcb );
  13367. NtfsUnpinBcb( IrpContext, &BackupBootBcb );
  13368. //
  13369. // Remove the boot file Fcb if we created it.
  13370. //
  13371. if (BootFileScb != NULL) {
  13372. //
  13373. // Let's know the sizes to zero and get rid of the pages.
  13374. //
  13375. BootFileScb->Header.AllocationSize.QuadPart =
  13376. BootFileScb->Header.FileSize.QuadPart =
  13377. BootFileScb->Header.ValidDataLength.QuadPart = 0;
  13378. ClearFlag( BootFileScb->ScbState, SCB_STATE_FILE_SIZE_LOADED );
  13379. NtfsUnloadNtfsMcbRange( &BootFileScb->Mcb,
  13380. 0,
  13381. MAXLONGLONG,
  13382. FALSE,
  13383. FALSE );
  13384. if (BootFileScb->FileObject != NULL) {
  13385. //
  13386. // Deleting the internal attribute stream should automatically
  13387. // trigger teardown since its the last ref count
  13388. //
  13389. CcSetFileSizes( BootFileScb->FileObject, (PCC_FILE_SIZES) &BootFileScb->Header.AllocationSize );
  13390. NtfsIncrementCloseCounts( BootFileScb, TRUE, FALSE );
  13391. NtfsDeleteInternalAttributeStream( BootFileScb, TRUE, FALSE );
  13392. NtfsDecrementCloseCounts( IrpContext, BootFileScb, NULL, TRUE, FALSE, TRUE, NULL );
  13393. }
  13394. NtfsTeardownStructures( IrpContext,
  13395. BootFileScb->Fcb,
  13396. NULL,
  13397. FALSE,
  13398. 0,
  13399. &RemovedBootFileFcb );
  13400. if (!RemovedBootFileFcb) {
  13401. NtfsReleaseResource( IrpContext, BootFileScb );
  13402. }
  13403. }
  13404. if (UnloadMcb) {
  13405. NtfsUnloadNtfsMcbRange( &Scb->Mcb,
  13406. 0,
  13407. MAXLONGLONG,
  13408. FALSE,
  13409. FALSE );
  13410. }
  13411. //
  13412. // Release the file resources if we hold them.
  13413. //
  13414. if (Scb != NULL) {
  13415. NtfsReleaseFcb( IrpContext, Scb->Fcb );
  13416. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  13417. NtfsReleaseFcb( IrpContext, Vcb->MftScb->Fcb );
  13418. NtfsReleaseFcb( IrpContext, Vcb->VolumeDasdScb->Fcb );
  13419. }
  13420. NtfsReleaseVcb( IrpContext, Vcb );
  13421. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  13422. DebugTrace( -1, Dbg, ("NtfsExtendVolume -> %08lx\n", Status) );
  13423. }
  13424. NtfsCompleteRequest( IrpContext, Irp, Status );
  13425. return Status;
  13426. }
  13427. //
  13428. // Local support routine
  13429. //
  13430. NTSTATUS
  13431. NtfsMarkHandle (
  13432. IN PIRP_CONTEXT IrpContext,
  13433. IN PIRP Irp
  13434. )
  13435. /*++
  13436. Routine Description:
  13437. This routine is used to attach special properties to a user handle.
  13438. Arguments:
  13439. Irp - Supplies the Irp to process
  13440. Return Value:
  13441. NTSTATUS - The return status for the operation
  13442. --*/
  13443. {
  13444. NTSTATUS Status = STATUS_SUCCESS;
  13445. PIO_STACK_LOCATION IrpSp;
  13446. PMARK_HANDLE_INFO HandleInfo;
  13447. TYPE_OF_OPEN TypeOfOpen;
  13448. PVCB Vcb;
  13449. PFILE_OBJECT DasdFileObject;
  13450. PFCB DasdFcb, Fcb;
  13451. PSCB DasdScb, Scb;
  13452. PCCB DasdCcb, Ccb;
  13453. BOOLEAN ReleaseScb = FALSE;
  13454. #if defined(_WIN64)
  13455. MARK_HANDLE_INFO LocalMarkHandleInfo;
  13456. #endif
  13457. extern POBJECT_TYPE *IoFileObjectType;
  13458. PAGED_CODE();
  13459. //
  13460. // Always make this synchronous.
  13461. //
  13462. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  13463. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  13464. //
  13465. // Get the current Irp stack location and save some references.
  13466. //
  13467. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  13468. //
  13469. // Extract and decode the file object and check for type of open.
  13470. //
  13471. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  13472. //
  13473. // We currently support this call for files and directories only.
  13474. //
  13475. if ((TypeOfOpen != UserFileOpen) &&
  13476. (TypeOfOpen != UserDirectoryOpen) &&
  13477. (TypeOfOpen != UserViewIndexOpen)) {
  13478. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13479. return STATUS_INVALID_PARAMETER;
  13480. }
  13481. #if defined(_WIN64)
  13482. //
  13483. // Win32/64 thunking code
  13484. //
  13485. if (IoIs32bitProcess( Irp )) {
  13486. PMARK_HANDLE_INFO32 MarkHandle32;
  13487. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO32 )) {
  13488. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13489. return STATUS_BUFFER_TOO_SMALL;
  13490. }
  13491. MarkHandle32 = (PMARK_HANDLE_INFO32) Irp->AssociatedIrp.SystemBuffer;
  13492. LocalMarkHandleInfo.HandleInfo = MarkHandle32->HandleInfo;
  13493. LocalMarkHandleInfo.UsnSourceInfo = MarkHandle32->UsnSourceInfo;
  13494. LocalMarkHandleInfo.VolumeHandle = (HANDLE)(ULONG_PTR)(LONG) MarkHandle32->VolumeHandle;
  13495. HandleInfo = &LocalMarkHandleInfo;
  13496. } else {
  13497. #endif
  13498. //
  13499. // Get the input buffer pointer and check its length.
  13500. //
  13501. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof( MARK_HANDLE_INFO )) {
  13502. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13503. return STATUS_BUFFER_TOO_SMALL;
  13504. }
  13505. HandleInfo = (PMARK_HANDLE_INFO) Irp->AssociatedIrp.SystemBuffer;
  13506. #if defined(_WIN64)
  13507. }
  13508. #endif
  13509. //
  13510. // Check that only legal bits are being set. We currently only support certain bits in the
  13511. // UsnSource reasons.
  13512. //
  13513. if (FlagOn( HandleInfo->HandleInfo, ~(MARK_HANDLE_PROTECT_CLUSTERS)) ||
  13514. FlagOn( HandleInfo->UsnSourceInfo,
  13515. ~(USN_SOURCE_DATA_MANAGEMENT |
  13516. USN_SOURCE_AUXILIARY_DATA |
  13517. USN_SOURCE_REPLICATION_MANAGEMENT) )) {
  13518. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13519. return STATUS_INVALID_PARAMETER;
  13520. }
  13521. //
  13522. // Check that the user has a valid volume handle or the manage volume
  13523. // privilege or is a kerbel mode caller
  13524. //
  13525. //
  13526. // NOTE: the kernel mode check is only valid because the rdr doesn't support this
  13527. // FSCTL
  13528. //
  13529. if ((Irp->RequestorMode != KernelMode) && !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13530. if (HandleInfo->VolumeHandle == 0) {
  13531. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13532. return STATUS_ACCESS_DENIED;
  13533. }
  13534. Status = ObReferenceObjectByHandle( HandleInfo->VolumeHandle,
  13535. 0,
  13536. *IoFileObjectType,
  13537. Irp->RequestorMode,
  13538. &DasdFileObject,
  13539. NULL );
  13540. if (!NT_SUCCESS(Status)) {
  13541. NtfsCompleteRequest( IrpContext, Irp, Status );
  13542. return Status;
  13543. }
  13544. // Check that this file object is opened on the same volume as the
  13545. // handle used to call this routine.
  13546. //
  13547. if (DasdFileObject->Vpb != Vcb->Vpb) {
  13548. ObDereferenceObject( DasdFileObject );
  13549. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13550. return STATUS_INVALID_PARAMETER;
  13551. }
  13552. //
  13553. // Now decode this FileObject and verify it is a volume handle.
  13554. // We don't care to raise on dismounts here because
  13555. // we check for that further down anyway. So send FALSE.
  13556. //
  13557. TypeOfOpen = NtfsDecodeFileObject( IrpContext, DasdFileObject, &Vcb, &DasdFcb, &DasdScb, &DasdCcb, FALSE );
  13558. ObDereferenceObject( DasdFileObject );
  13559. if ((DasdCcb == NULL) || !FlagOn( DasdCcb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13560. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13561. return STATUS_ACCESS_DENIED;
  13562. }
  13563. }
  13564. //
  13565. // Acquire the paging io resource exclusively if present.
  13566. //
  13567. if (Scb->Header.PagingIoResource != NULL) {
  13568. NtfsAcquirePagingResourceExclusive( IrpContext, Scb, TRUE );
  13569. }
  13570. try {
  13571. //
  13572. // Acquire the file exclusively to serialize changes to the Ccb.
  13573. //
  13574. NtfsAcquireExclusiveScb( IrpContext, Scb );
  13575. ReleaseScb = TRUE;
  13576. //
  13577. // Verify the volume is still mounted.
  13578. //
  13579. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  13580. Status = STATUS_VOLUME_DISMOUNTED;
  13581. leave;
  13582. }
  13583. //
  13584. // Set these new bits in the Ccb.
  13585. //
  13586. if (FlagOn( HandleInfo->HandleInfo, MARK_HANDLE_PROTECT_CLUSTERS )) {
  13587. //
  13588. // We can't deny defrag if anyone else already has
  13589. //
  13590. if (FlagOn( Scb->ScbPersist, SCB_PERSIST_DENY_DEFRAG )) {
  13591. Status = STATUS_ACCESS_DENIED;
  13592. leave;
  13593. }
  13594. SetFlag( Ccb->Flags, CCB_FLAG_DENY_DEFRAG );
  13595. SetFlag( Scb->ScbPersist, SCB_PERSIST_DENY_DEFRAG );
  13596. }
  13597. SetFlag( Ccb->UsnSourceInfo, HandleInfo->UsnSourceInfo );
  13598. } finally {
  13599. DebugUnwind( NtfsMarkHandle );
  13600. //
  13601. // Release the Scb.
  13602. //
  13603. if (ReleaseScb) {
  13604. NtfsReleaseScb( IrpContext, Scb );
  13605. }
  13606. if (Scb->Header.PagingIoResource != NULL) {
  13607. NtfsReleasePagingResource( IrpContext, Scb );
  13608. }
  13609. }
  13610. NtfsCompleteRequest( IrpContext, Irp, Status );
  13611. return Status;
  13612. }
  13613. //
  13614. // Local Support routine
  13615. //
  13616. NTSTATUS
  13617. NtfsPrefetchFile (
  13618. IN PIRP_CONTEXT IrpContext,
  13619. IN PIRP Irp
  13620. )
  13621. /*++
  13622. Routine Description:
  13623. This routine is called to perform the requested prefetch on a system file.
  13624. Arguments:
  13625. Irp - Supplies the Irp to process
  13626. Return Value:
  13627. NTSTATUS - The return status for the operation
  13628. --*/
  13629. {
  13630. NTSTATUS Status = STATUS_SUCCESS;
  13631. NTSTATUS MmStatus = STATUS_SUCCESS;
  13632. PIO_STACK_LOCATION IrpSp;
  13633. PFILE_PREFETCH FilePrefetch;
  13634. PREAD_LIST ReadList = NULL;
  13635. PULONGLONG NextFileId;
  13636. ULONG Count;
  13637. ULONGLONG FileOffset;
  13638. TYPE_OF_OPEN TypeOfOpen;
  13639. PVCB Vcb;
  13640. PFCB Fcb;
  13641. PSCB Scb;
  13642. PCCB Ccb;
  13643. BOOLEAN ReleaseMft = FALSE;
  13644. PAGED_CODE();
  13645. //
  13646. // Always make this synchronous. There isn't much advantage to posting this work to a
  13647. // worker thread.
  13648. //
  13649. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  13650. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ));
  13651. //
  13652. // Get the current Irp stack location and save some references.
  13653. //
  13654. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  13655. //
  13656. // Extract and decode the file object and check for type of open.
  13657. //
  13658. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  13659. //
  13660. // We currently support this call only for the Mft (accessed through a volume handle).
  13661. //
  13662. if ((Ccb == NULL) || !FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS )) {
  13663. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  13664. return STATUS_ACCESS_DENIED;
  13665. }
  13666. //
  13667. // Get the input buffer pointer and check its length. It needs to be sufficient to
  13668. // contain the fixed portion of structure plus whatever optional fields passed in.
  13669. //
  13670. FilePrefetch = (PFILE_PREFETCH) Irp->AssociatedIrp.SystemBuffer;
  13671. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < FIELD_OFFSET( FILE_PREFETCH, Prefetch )) {
  13672. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13673. return STATUS_BUFFER_TOO_SMALL;
  13674. }
  13675. //
  13676. // Make sure the type and cound fields are valid.
  13677. //
  13678. if ((FilePrefetch->Type != FILE_PREFETCH_TYPE_FOR_CREATE) ||
  13679. (FilePrefetch->Count > 0x300)) {
  13680. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  13681. return STATUS_INVALID_PARAMETER;
  13682. }
  13683. //
  13684. // Finally verify that the variable length data is of valid length.
  13685. //
  13686. if (IrpSp->Parameters.FileSystemControl.InputBufferLength <
  13687. (FIELD_OFFSET( FILE_PREFETCH, Prefetch ) + (sizeof( ULONGLONG ) * FilePrefetch->Count))) {
  13688. NtfsCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
  13689. return STATUS_BUFFER_TOO_SMALL;
  13690. }
  13691. //
  13692. // If the user didn't specify any entries we are done.
  13693. //
  13694. if (FilePrefetch->Count == 0) {
  13695. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  13696. return STATUS_SUCCESS;
  13697. }
  13698. //
  13699. // Acquire the volume dasd file shared to do this.
  13700. //
  13701. NtfsAcquireSharedScb( IrpContext, Scb );
  13702. try {
  13703. //
  13704. // Verify the volume is still mounted.
  13705. //
  13706. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  13707. Status = STATUS_VOLUME_DISMOUNTED;
  13708. leave;
  13709. }
  13710. //
  13711. // Allocate the necessary pool to pass to MM.
  13712. //
  13713. ReadList = NtfsAllocatePool( PagedPool,
  13714. FIELD_OFFSET( READ_LIST, List ) + (FilePrefetch->Count * sizeof( FILE_SEGMENT_ELEMENT )));
  13715. //
  13716. // Initialize the read list.
  13717. //
  13718. ReadList->FileObject = Vcb->MftScb->FileObject;
  13719. ASSERT( Vcb->MftScb->FileObject != NULL );
  13720. ReadList->NumberOfEntries = 0;
  13721. ReadList->IsImage = FALSE;
  13722. //
  13723. // Walk through and load the list. We won't bother to check sequence numbers
  13724. // as they don't really change the correctness of this call. We do check for the
  13725. // valid length of the Mft though.
  13726. //
  13727. NtfsAcquireSharedScb( IrpContext, Vcb->MftScb );
  13728. ReleaseMft = TRUE;
  13729. NextFileId = &FilePrefetch->Prefetch[0];
  13730. Count = FilePrefetch->Count;
  13731. while (Count > 0) {
  13732. FileOffset = NtfsFullSegmentNumber( NextFileId );
  13733. FileOffset = LlBytesFromFileRecords( Vcb, FileOffset );
  13734. //
  13735. // Round down to page boundary. This will reduce the number of entries
  13736. // passed to MM.
  13737. //
  13738. FileOffset = BlockAlignTruncate( FileOffset, PAGE_SIZE );
  13739. //
  13740. // Check if we are beyond the end of the Mft. Treat this as a ULONGLONG
  13741. // so we can catch the case where the ID generates a negative number.
  13742. //
  13743. if (FileOffset >= (ULONGLONG) Vcb->MftScb->Header.ValidDataLength.QuadPart) {
  13744. Status = STATUS_END_OF_FILE;
  13745. //
  13746. // If not then add to the buffer to pass to mm.
  13747. //
  13748. } else {
  13749. ULONG Index;
  13750. //
  13751. // Position ourselves in the output array. Look in reverse
  13752. // order in case our caller has already sorted this.
  13753. //
  13754. Index = ReadList->NumberOfEntries;
  13755. while (Index != 0) {
  13756. //
  13757. // If the prior entry is less than the current entry we are done.
  13758. //
  13759. if (ReadList->List[Index - 1].Alignment < FileOffset) {
  13760. break;
  13761. }
  13762. //
  13763. // If the prior entry equals the current entry then skip it.
  13764. //
  13765. if (ReadList->List[Index - 1].Alignment == FileOffset) {
  13766. Index = MAXULONG;
  13767. break;
  13768. }
  13769. //
  13770. // Move backwards to the previous entry.
  13771. //
  13772. Index -= 1;
  13773. }
  13774. //
  13775. // Index now points to the insert point, except if MAXULONG. Insert the entry
  13776. // and shift any existing entries necessary if we are doing the insert.
  13777. //
  13778. if (Index != MAXULONG) {
  13779. if (Index != ReadList->NumberOfEntries) {
  13780. RtlMoveMemory( &ReadList->List[Index + 1],
  13781. &ReadList->List[Index],
  13782. sizeof( LONGLONG ) * (ReadList->NumberOfEntries - Index) );
  13783. }
  13784. ReadList->NumberOfEntries += 1;
  13785. ReadList->List[Index].Alignment = FileOffset;
  13786. }
  13787. }
  13788. //
  13789. // Move to the next entry.
  13790. //
  13791. Count -= 1;
  13792. NextFileId += 1;
  13793. }
  13794. //
  13795. // We're done with the Mft. If we ever support shrinking the Mft we will have to close
  13796. // the hole here.
  13797. //
  13798. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  13799. ReleaseMft = FALSE;
  13800. //
  13801. // Now call mm to do the IO.
  13802. //
  13803. if (ReadList->NumberOfEntries != 0) {
  13804. MmStatus = MmPrefetchPages( 1, &ReadList );
  13805. //
  13806. // Use the Mm status if we don't already have one.
  13807. //
  13808. if (Status == STATUS_SUCCESS) {
  13809. Status = MmStatus;
  13810. }
  13811. }
  13812. } finally {
  13813. DebugUnwind( NtfsPrefetchFile );
  13814. //
  13815. // Free the read list if allocated.
  13816. //
  13817. if (ReadList != NULL) {
  13818. NtfsFreePool( ReadList );
  13819. }
  13820. //
  13821. // Release any Scb acquired.
  13822. //
  13823. if (ReleaseMft) {
  13824. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  13825. }
  13826. NtfsReleaseScb( IrpContext, Scb );
  13827. }
  13828. NtfsCompleteRequest( IrpContext, Irp, Status );
  13829. return Status;
  13830. }
  13831. //
  13832. // Local Support routine
  13833. //
  13834. LONG
  13835. NtfsFsctrlExceptionFilter (
  13836. IN PIRP_CONTEXT IrpContext,
  13837. IN PEXCEPTION_POINTERS ExceptionPointer,
  13838. IN BOOLEAN AccessingUserData,
  13839. OUT PNTSTATUS Status
  13840. )
  13841. /*++
  13842. Routine Description:
  13843. Generic Exception filter for errors during fsctrl processing. Raise invalid user buffer
  13844. directly or let it filter on to the top level try-except
  13845. Arguments:
  13846. IrpContext - IrpContext
  13847. ExceptionPointer - Pointer to the exception context.
  13848. AccessingUserData - if false always let the exception filter up
  13849. Status - Address to store the error status.
  13850. Return Value:
  13851. Exception status - EXCEPTION_CONTINUE_SEARCH if we want to raise to another handler,
  13852. EXCEPTION_EXECUTE_HANDLER if we plan to proceed on.
  13853. --*/
  13854. {
  13855. *Status = ExceptionPointer->ExceptionRecord->ExceptionCode;
  13856. if (!FsRtlIsNtstatusExpected( *Status ) && AccessingUserData) {
  13857. NtfsMinimumExceptionProcessing( IrpContext );
  13858. return EXCEPTION_EXECUTE_HANDLER;
  13859. } else {
  13860. return EXCEPTION_CONTINUE_SEARCH;
  13861. }
  13862. }
  13863. #ifdef SYSCACHE_DEBUG
  13864. //
  13865. // Local support routine
  13866. //
  13867. VOID
  13868. NtfsInitializeSyscacheLogFile (
  13869. IN PIRP_CONTEXT IrpContext,
  13870. IN PVCB Vcb
  13871. )
  13872. /*++
  13873. Routine Description:
  13874. This routine creates the syscache logfile in the root directory.
  13875. Arguments:
  13876. Vcb - Pointer to the Vcb for the volume
  13877. Return Value:
  13878. None.
  13879. --*/
  13880. {
  13881. UNICODE_STRING AttrName;
  13882. struct {
  13883. FILE_NAME FileName;
  13884. WCHAR FileNameChars[10];
  13885. } FileNameAttr;
  13886. FILE_REFERENCE FileReference;
  13887. LONGLONG FileRecordOffset;
  13888. PINDEX_ENTRY IndexEntry;
  13889. PBCB FileRecordBcb = NULL;
  13890. PBCB IndexEntryBcb = NULL;
  13891. PBCB ParentSecurityBcb = NULL;
  13892. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  13893. UCHAR FileNameFlags;
  13894. BOOLEAN FoundEntry;
  13895. PFCB Fcb = NULL;
  13896. BOOLEAN AcquiredFcbTable = FALSE;
  13897. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  13898. ULONG DesiredAccess = GENERIC_READ | GENERIC_WRITE;
  13899. NTSTATUS Status = STATUS_SUCCESS;
  13900. NtfsAcquireExclusiveScb( IrpContext, Vcb->RootIndexScb );
  13901. //
  13902. // Initialize the FileName.
  13903. //
  13904. RtlZeroMemory( &FileNameAttr, sizeof(FileNameAttr) );
  13905. FileNameAttr.FileName.ParentDirectory = Vcb->RootIndexScb->Fcb->FileReference;
  13906. FileNameAttr.FileName.FileNameLength = (UCHAR)(9); // 9 unicode characters long
  13907. RtlCopyMemory( FileNameAttr.FileName.FileName, L"$ntfs.log", 9 * sizeof( WCHAR ) );
  13908. NtfsInitializeAttributeContext( &Context );
  13909. try {
  13910. //
  13911. // Does the file already exist?
  13912. //
  13913. FoundEntry = NtfsFindIndexEntry( IrpContext,
  13914. Vcb->RootIndexScb,
  13915. &FileNameAttr,
  13916. FALSE,
  13917. NULL,
  13918. &IndexEntryBcb,
  13919. &IndexEntry,
  13920. NULL );
  13921. //
  13922. // If we did not find it, then start creating the file.
  13923. //
  13924. if (!FoundEntry) {
  13925. //
  13926. // We will now try to do all of the on-disk operations. This means first
  13927. // allocating and initializing an Mft record. After that we create
  13928. // an Fcb to use to access this record.
  13929. //
  13930. FileReference = NtfsAllocateMftRecord( IrpContext, Vcb, FALSE );
  13931. //
  13932. // Pin the file record we need.
  13933. //
  13934. NtfsPinMftRecord( IrpContext,
  13935. Vcb,
  13936. &FileReference,
  13937. TRUE,
  13938. &FileRecordBcb,
  13939. &FileRecord,
  13940. &FileRecordOffset );
  13941. //
  13942. // Initialize the file record header.
  13943. //
  13944. NtfsInitializeMftRecord( IrpContext,
  13945. Vcb,
  13946. &FileReference,
  13947. FileRecord,
  13948. FileRecordBcb,
  13949. FALSE );
  13950. //
  13951. // If we found the file, then just get its FileReference out of the
  13952. // IndexEntry.
  13953. //
  13954. } else {
  13955. FileReference = IndexEntry->FileReference;
  13956. }
  13957. //
  13958. // Now that we know the FileReference, we can create the Fcb.
  13959. //
  13960. NtfsAcquireFcbTable( IrpContext, Vcb );
  13961. AcquiredFcbTable = TRUE;
  13962. Fcb = NtfsCreateFcb( IrpContext,
  13963. Vcb,
  13964. FileReference,
  13965. FALSE,
  13966. FALSE,
  13967. NULL );
  13968. //
  13969. // Reference the Fcb so it doesn't go away.
  13970. //
  13971. Fcb->ReferenceCount += 1;
  13972. NtfsReleaseFcbTable( IrpContext, Vcb );
  13973. AcquiredFcbTable = FALSE;
  13974. //
  13975. // Acquire the main resource
  13976. //
  13977. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  13978. NtfsAcquireFcbTable( IrpContext, Vcb );
  13979. Fcb->ReferenceCount -= 1;
  13980. NtfsReleaseFcbTable( IrpContext, Vcb );
  13981. //
  13982. // If we are creating this file, then carry on.
  13983. //
  13984. if (!FoundEntry) {
  13985. BOOLEAN LogIt = FALSE;
  13986. //
  13987. // Just copy the Security Id from the parent. (Load it first if necc.)
  13988. //
  13989. if (Vcb->RootIndexScb->Fcb->SharedSecurity == NULL) {
  13990. NtfsLoadSecurityDescriptor( IrpContext, Vcb->RootIndexScb->Fcb );
  13991. }
  13992. NtfsAcquireFcbSecurity( Fcb->Vcb );
  13993. Fcb->SecurityId = Vcb->RootIndexScb->Fcb->SecurityId;
  13994. ASSERT( Fcb->SharedSecurity == NULL );
  13995. Fcb->SharedSecurity = Vcb->RootIndexScb->Fcb->SharedSecurity;
  13996. Fcb->SharedSecurity->ReferenceCount++;
  13997. NtfsReleaseFcbSecurity( Fcb->Vcb );
  13998. //
  13999. // The changes to make on disk are first to create a standard information
  14000. // attribute. We start by filling the Fcb with the information we
  14001. // know and creating the attribute on disk.
  14002. //
  14003. NtfsInitializeFcbAndStdInfo( IrpContext,
  14004. Fcb,
  14005. FALSE,
  14006. FALSE,
  14007. FALSE,
  14008. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  14009. NULL );
  14010. //
  14011. // Now link the file into the $Extend directory.
  14012. //
  14013. NtfsAddLink( IrpContext,
  14014. TRUE,
  14015. Vcb->RootIndexScb,
  14016. Fcb,
  14017. (PFILE_NAME)&FileNameAttr,
  14018. &LogIt,
  14019. &FileNameFlags,
  14020. NULL,
  14021. NULL,
  14022. NULL );
  14023. /*
  14024. //
  14025. // Set this flag to indicate that the file is to be locked via the Scb
  14026. // pointers in the Vcb.
  14027. //
  14028. SetFlag( FileRecord->Flags, FILE_SYSTEM_FILE );
  14029. */
  14030. //
  14031. // Log the file record.
  14032. //
  14033. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  14034. Vcb->MftScb,
  14035. FileRecordBcb,
  14036. InitializeFileRecordSegment,
  14037. FileRecord,
  14038. FileRecord->FirstFreeByte,
  14039. Noop,
  14040. NULL,
  14041. 0,
  14042. FileRecordOffset,
  14043. 0,
  14044. 0,
  14045. Vcb->BytesPerFileRecordSegment );
  14046. //
  14047. // Verify that the file record for this file is valid.
  14048. //
  14049. } else {
  14050. ULONG CorruptHint;
  14051. if (!NtfsLookupAttributeByCode( IrpContext,
  14052. Fcb,
  14053. &Fcb->FileReference,
  14054. $STANDARD_INFORMATION,
  14055. &Context ) ||
  14056. !NtfsCheckFileRecord( Vcb, NtfsContainingFileRecord( &Context ), &Fcb->FileReference, &CorruptHint )) {
  14057. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, &Fcb->FileReference, NULL );
  14058. }
  14059. }
  14060. //
  14061. // Update Fcb fields from disk.
  14062. //
  14063. SetFlag( Fcb->FcbState, FCB_STATE_SYSTEM_FILE );
  14064. NtfsUpdateFcbInfoFromDisk( IrpContext, TRUE, Fcb, NULL );
  14065. //
  14066. // Open/Create the data stream
  14067. //
  14068. memset( &AttrName, 0, sizeof( AttrName ) );
  14069. NtOfsCreateAttribute( IrpContext,
  14070. Fcb,
  14071. AttrName,
  14072. CREATE_OR_OPEN,
  14073. FALSE,
  14074. &Vcb->SyscacheScb );
  14075. RtlMapGenericMask( &DesiredAccess, IoGetFileObjectGenericMapping() );
  14076. IoSetShareAccess( DesiredAccess, FILE_SHARE_READ, Vcb->SyscacheScb->FileObject, &Vcb->SyscacheScb->ShareAccess );
  14077. do {
  14078. if (STATUS_LOG_FILE_FULL == Status) {
  14079. NtfsCleanCheckpoint( IrpContext->Vcb );
  14080. Status = STATUS_SUCCESS;
  14081. }
  14082. try {
  14083. LONGLONG Length = PAGE_SIZE * 0x1d00; // approx 30mb
  14084. NtOfsSetLength( IrpContext, Vcb->SyscacheScb, Length );
  14085. //
  14086. // Make this look like it came from a write so ioateof is not done
  14087. // we must do a writefilesizes to update VDL by hand
  14088. //
  14089. SetFlag( IrpContext->TopLevelIrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_SEEN );
  14090. NtfsZeroData( IrpContext, Vcb->SyscacheScb, Vcb->SyscacheScb->FileObject, 0, Length, NULL );
  14091. NtfsWriteFileSizes( IrpContext, Vcb->SyscacheScb, &Vcb->SyscacheScb->Header.ValidDataLength.QuadPart, TRUE, TRUE, TRUE );
  14092. } except( EXCEPTION_EXECUTE_HANDLER ) {
  14093. Status = GetExceptionCode();
  14094. ASSERT( Status == STATUS_DISK_FULL || Status == STATUS_LOG_FILE_FULL );
  14095. NtfsMinimumExceptionProcessing( IrpContext );
  14096. IrpContext->ExceptionStatus = 0;
  14097. }
  14098. ClearFlag(IrpContext->TopLevelIrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_SEEN);
  14099. NtfsReleaseScb( IrpContext, Vcb->SyscacheScb );
  14100. } while ( STATUS_LOG_FILE_FULL == Status );
  14101. //
  14102. // Increment cleanup counts to enforce the sharing we set up
  14103. //
  14104. NtfsIncrementCleanupCounts( Vcb->SyscacheScb, NULL, FALSE );
  14105. } finally {
  14106. NtfsCleanupAttributeContext( IrpContext, &Context );
  14107. NtfsUnpinBcb( IrpContext, &FileRecordBcb );
  14108. NtfsUnpinBcb( IrpContext, &IndexEntryBcb );
  14109. NtfsUnpinBcb( IrpContext, &ParentSecurityBcb );
  14110. //
  14111. // On any kind of error, nuke the Fcb.
  14112. //
  14113. if (AbnormalTermination()) {
  14114. //
  14115. // If some error caused us to abort, then delete
  14116. // the Fcb, because we are the only ones who will.
  14117. //
  14118. if (Fcb) {
  14119. if (!AcquiredFcbTable) {
  14120. NtfsAcquireFcbTable( IrpContext, Vcb );
  14121. AcquiredFcbTable = TRUE;
  14122. }
  14123. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  14124. ASSERT(!AcquiredFcbTable);
  14125. }
  14126. if (AcquiredFcbTable) {
  14127. NtfsReleaseFcbTable( IrpContext, Vcb );
  14128. }
  14129. }
  14130. }
  14131. }
  14132. #endif