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.

1725 lines
43 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. VolInfo.c
  5. Abstract:
  6. This module implements the set and query volume information routines for
  7. Ntfs called by the dispatch driver.
  8. Author:
  9. Your Name [Email] dd-Mon-Year
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. //
  14. // The local debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_VOLINFO)
  17. //
  18. // Local procedure prototypes
  19. //
  20. NTSTATUS
  21. NtfsQueryFsVolumeInfo (
  22. IN PIRP_CONTEXT IrpContext,
  23. IN PVCB Vcb,
  24. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  25. IN OUT PULONG Length
  26. );
  27. NTSTATUS
  28. NtfsQueryFsSizeInfo (
  29. IN PIRP_CONTEXT IrpContext,
  30. IN PVCB Vcb,
  31. IN PFILE_FS_SIZE_INFORMATION Buffer,
  32. IN OUT PULONG Length
  33. );
  34. NTSTATUS
  35. NtfsQueryFsDeviceInfo (
  36. IN PIRP_CONTEXT IrpContext,
  37. IN PVCB Vcb,
  38. IN PFILE_FS_DEVICE_INFORMATION Buffer,
  39. IN OUT PULONG Length
  40. );
  41. NTSTATUS
  42. NtfsQueryFsAttributeInfo (
  43. IN PIRP_CONTEXT IrpContext,
  44. IN PVCB Vcb,
  45. IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
  46. IN OUT PULONG Length
  47. );
  48. NTSTATUS
  49. NtfsQueryFsControlInfo (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PVCB Vcb,
  52. IN PFILE_FS_CONTROL_INFORMATION Buffer,
  53. IN OUT PULONG Length
  54. );
  55. NTSTATUS
  56. NtfsQueryFsFullSizeInfo (
  57. IN PIRP_CONTEXT IrpContext,
  58. IN PVCB Vcb,
  59. IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
  60. IN OUT PULONG Length
  61. );
  62. NTSTATUS
  63. NtfsQueryFsVolumeObjectIdInfo (
  64. IN PIRP_CONTEXT IrpContext,
  65. IN PVCB Vcb,
  66. IN PFILE_FS_OBJECTID_INFORMATION Buffer,
  67. IN OUT PULONG Length
  68. );
  69. NTSTATUS
  70. NtfsSetFsLabelInfo (
  71. IN PIRP_CONTEXT IrpContext,
  72. IN PVCB Vcb,
  73. IN PFILE_FS_LABEL_INFORMATION Buffer
  74. );
  75. NTSTATUS
  76. NtfsSetFsControlInfo (
  77. IN PIRP_CONTEXT IrpContext,
  78. IN PVCB Vcb,
  79. IN PFILE_FS_CONTROL_INFORMATION Buffer
  80. );
  81. NTSTATUS
  82. NtfsSetFsVolumeObjectIdInfo (
  83. IN PIRP_CONTEXT IrpContext,
  84. IN PVCB Vcb,
  85. IN PFILE_FS_OBJECTID_INFORMATION Buffer
  86. );
  87. #ifdef ALLOC_PRAGMA
  88. #pragma alloc_text(PAGE, NtfsCommonQueryVolumeInfo)
  89. #pragma alloc_text(PAGE, NtfsCommonSetVolumeInfo)
  90. #pragma alloc_text(PAGE, NtfsQueryFsAttributeInfo)
  91. #pragma alloc_text(PAGE, NtfsQueryFsDeviceInfo)
  92. #pragma alloc_text(PAGE, NtfsQueryFsSizeInfo)
  93. #pragma alloc_text(PAGE, NtfsQueryFsVolumeInfo)
  94. #pragma alloc_text(PAGE, NtfsQueryFsControlInfo)
  95. #pragma alloc_text(PAGE, NtfsQueryFsFullSizeInfo)
  96. #pragma alloc_text(PAGE, NtfsQueryFsVolumeObjectIdInfo)
  97. #pragma alloc_text(PAGE, NtfsSetFsLabelInfo)
  98. #pragma alloc_text(PAGE, NtfsSetFsControlInfo)
  99. #pragma alloc_text(PAGE, NtfsSetFsVolumeObjectIdInfo)
  100. #endif
  101. NTSTATUS
  102. NtfsCommonQueryVolumeInfo (
  103. IN PIRP_CONTEXT IrpContext,
  104. IN PIRP Irp
  105. )
  106. /*++
  107. Routine Description:
  108. This is the common routine for query Volume Information called by both the
  109. fsd and fsp threads.
  110. Arguments:
  111. Irp - Supplies the Irp to process
  112. Return Value:
  113. NTSTATUS - The return status for the operation
  114. --*/
  115. {
  116. NTSTATUS Status;
  117. PIO_STACK_LOCATION IrpSp;
  118. PFILE_OBJECT FileObject;
  119. TYPE_OF_OPEN TypeOfOpen;
  120. PVCB Vcb;
  121. PFCB Fcb;
  122. PSCB Scb;
  123. PCCB Ccb;
  124. ULONG Length;
  125. FS_INFORMATION_CLASS FsInformationClass;
  126. PVOID Buffer;
  127. BOOLEAN AcquiredVcb = FALSE;
  128. ASSERT_IRP_CONTEXT( IrpContext );
  129. ASSERT_IRP( Irp );
  130. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  131. PAGED_CODE();
  132. //
  133. // Get the current stack location
  134. //
  135. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  136. DebugTrace( +1, Dbg, ("NtfsCommonQueryVolumeInfo...\n") );
  137. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  138. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  139. DebugTrace( 0, Dbg, ("Length = %08lx\n", IrpSp->Parameters.QueryVolume.Length) );
  140. DebugTrace( 0, Dbg, ("FsInformationClass = %08lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass) );
  141. DebugTrace( 0, Dbg, ("Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer) );
  142. //
  143. // Reference our input parameters to make things easier
  144. //
  145. Length = IrpSp->Parameters.QueryVolume.Length;
  146. FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
  147. Buffer = Irp->AssociatedIrp.SystemBuffer;
  148. //
  149. // Extract and decode the file object to get the Vcb, we don't really
  150. // care what the type of open is.
  151. //
  152. FileObject = IrpSp->FileObject;
  153. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  154. //
  155. // Let's kill invalid vol. query requests.
  156. //
  157. if (UnopenedFileObject == TypeOfOpen) {
  158. DebugTrace( 0, Dbg, ("Invalid file object for write\n") );
  159. DebugTrace( -1, Dbg, ("NtfsCommonQueryVolume: Exit -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST) );
  160. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  161. return STATUS_INVALID_DEVICE_REQUEST;
  162. }
  163. //
  164. // Get the Vcb shared and raise if we can't wait for the resource.
  165. // We're only using $Volume Scb for the query size calls because the info
  166. // it gets is static and we only need to protect against dismount
  167. // Doing this prevents a deadlock with commit extensions from mm which use
  168. // this call. However for system files like the mft we always need the vcb to avoid deadlock
  169. //
  170. if ((FsInformationClass != FileFsSizeInformation) ||
  171. (FlagOn( Scb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE ))) {
  172. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  173. AcquiredVcb = TRUE;
  174. } else {
  175. NtfsAcquireSharedScb( IrpContext, Scb );
  176. }
  177. try {
  178. //
  179. // Make sure the volume is mounted.
  180. //
  181. if ((AcquiredVcb && !FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) ||
  182. (!AcquiredVcb && FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED))) {
  183. Irp->IoStatus.Information = 0;
  184. Status = STATUS_VOLUME_DISMOUNTED;
  185. leave;
  186. }
  187. //
  188. // Based on the information class we'll do different actions. Each
  189. // of the procedures that we're calling fills up the output buffer
  190. // if possible and returns true if it successfully filled the buffer
  191. // and false if it couldn't wait for any I/O to complete.
  192. //
  193. switch (FsInformationClass) {
  194. case FileFsVolumeInformation:
  195. Status = NtfsQueryFsVolumeInfo( IrpContext, Vcb, Buffer, &Length );
  196. break;
  197. case FileFsSizeInformation:
  198. Status = NtfsQueryFsSizeInfo( IrpContext, Vcb, Buffer, &Length );
  199. break;
  200. case FileFsDeviceInformation:
  201. Status = NtfsQueryFsDeviceInfo( IrpContext, Vcb, Buffer, &Length );
  202. break;
  203. case FileFsAttributeInformation:
  204. Status = NtfsQueryFsAttributeInfo( IrpContext, Vcb, Buffer, &Length );
  205. break;
  206. case FileFsControlInformation:
  207. Status = NtfsQueryFsControlInfo( IrpContext, Vcb, Buffer, &Length );
  208. break;
  209. case FileFsFullSizeInformation:
  210. Status = NtfsQueryFsFullSizeInfo( IrpContext, Vcb, Buffer, &Length );
  211. break;
  212. case FileFsObjectIdInformation:
  213. Status = NtfsQueryFsVolumeObjectIdInfo( IrpContext, Vcb, Buffer, &Length );
  214. break;
  215. default:
  216. Status = STATUS_INVALID_PARAMETER;
  217. break;
  218. }
  219. //
  220. // Set the information field to the number of bytes actually filled in
  221. //
  222. Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
  223. //
  224. // Abort transaction on error by raising.
  225. //
  226. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  227. } finally {
  228. DebugUnwind( NtfsCommonQueryVolumeInfo );
  229. if (AcquiredVcb) {
  230. NtfsReleaseVcb( IrpContext, Vcb );
  231. } else {
  232. NtfsReleaseScb( IrpContext, Scb );
  233. }
  234. DebugTrace( -1, Dbg, ("NtfsCommonQueryVolumeInfo -> %08lx\n", Status) );
  235. }
  236. NtfsCompleteRequest( IrpContext, Irp, Status );
  237. return Status;
  238. }
  239. NTSTATUS
  240. NtfsCommonSetVolumeInfo (
  241. IN PIRP_CONTEXT IrpContext,
  242. IN PIRP Irp
  243. )
  244. /*++
  245. Routine Description:
  246. This is the common routine for set Volume Information called by both the
  247. fsd and fsp threads.
  248. Arguments:
  249. Irp - Supplies the Irp to process
  250. Return Value:
  251. NTSTATUS - The return status for the operation
  252. --*/
  253. {
  254. NTSTATUS Status;
  255. PIO_STACK_LOCATION IrpSp;
  256. PFILE_OBJECT FileObject;
  257. TYPE_OF_OPEN TypeOfOpen;
  258. PVCB Vcb;
  259. PFCB Fcb;
  260. PSCB Scb;
  261. PCCB Ccb;
  262. ULONG Length;
  263. FS_INFORMATION_CLASS FsInformationClass;
  264. PVOID Buffer;
  265. ASSERT_IRP_CONTEXT( IrpContext );
  266. ASSERT_IRP( Irp );
  267. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  268. PAGED_CODE();
  269. //
  270. // Get the current Irp stack location
  271. //
  272. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  273. DebugTrace( +1, Dbg, ("NtfsCommonSetVolumeInfo\n") );
  274. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  275. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  276. DebugTrace( 0, Dbg, ("Length = %08lx\n", IrpSp->Parameters.SetVolume.Length) );
  277. DebugTrace( 0, Dbg, ("FsInformationClass = %08lx\n", IrpSp->Parameters.SetVolume.FsInformationClass) );
  278. DebugTrace( 0, Dbg, ("Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer) );
  279. //
  280. // Reference our input parameters to make things easier
  281. //
  282. Length = IrpSp->Parameters.SetVolume.Length;
  283. FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
  284. Buffer = Irp->AssociatedIrp.SystemBuffer;
  285. //
  286. // Extract and decode the file object to get the Vcb, we don't really
  287. // care what the type of open is.
  288. //
  289. FileObject = IrpSp->FileObject;
  290. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  291. if (TypeOfOpen != UserVolumeOpen &&
  292. (TypeOfOpen != UserViewIndexOpen ||
  293. FsInformationClass != FileFsControlInformation ||
  294. Fcb != Vcb->QuotaTableScb->Fcb)) {
  295. NtfsCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  296. DebugTrace( -1, Dbg, ("NtfsCommonSetVolumeInfo -> STATUS_ACCESS_DENIED\n") );
  297. return STATUS_ACCESS_DENIED;
  298. }
  299. //
  300. // The volume must be writable.
  301. //
  302. if (NtfsIsVolumeReadOnly( Vcb )) {
  303. Status = STATUS_MEDIA_WRITE_PROTECTED;
  304. NtfsCompleteRequest( IrpContext, Irp, Status );
  305. DebugTrace( -1, Dbg, ("NtfsCommonSetVolumeInfo -> %08lx\n", Status) );
  306. return Status;
  307. }
  308. //
  309. // Acquire exclusive access to the Vcb
  310. //
  311. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  312. try {
  313. //
  314. // Proceed only if the volume is mounted.
  315. //
  316. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  317. //
  318. // Based on the information class we'll do different actions. Each
  319. // of the procedures that we're calling performs the action if
  320. // possible and returns true if it successful and false if it couldn't
  321. // wait for any I/O to complete.
  322. //
  323. switch (FsInformationClass) {
  324. case FileFsLabelInformation:
  325. Status = NtfsSetFsLabelInfo( IrpContext, Vcb, Buffer );
  326. break;
  327. case FileFsControlInformation:
  328. Status = NtfsSetFsControlInfo( IrpContext, Vcb, Buffer );
  329. break;
  330. case FileFsObjectIdInformation:
  331. Status = NtfsSetFsVolumeObjectIdInfo( IrpContext, Vcb, Buffer );
  332. break;
  333. default:
  334. Status = STATUS_INVALID_PARAMETER;
  335. break;
  336. }
  337. } else {
  338. Status = STATUS_FILE_INVALID;
  339. }
  340. //
  341. // Abort transaction on error by raising.
  342. //
  343. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  344. } finally {
  345. DebugUnwind( NtfsCommonSetVolumeInfo );
  346. NtfsReleaseVcb( IrpContext, Vcb );
  347. DebugTrace( -1, Dbg, ("NtfsCommonSetVolumeInfo -> %08lx\n", Status) );
  348. }
  349. NtfsCompleteRequest( IrpContext, Irp, Status );
  350. return Status;
  351. }
  352. //
  353. // Internal Support Routine
  354. //
  355. NTSTATUS
  356. NtfsQueryFsVolumeInfo (
  357. IN PIRP_CONTEXT IrpContext,
  358. IN PVCB Vcb,
  359. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  360. IN OUT PULONG Length
  361. )
  362. /*++
  363. Routine Description:
  364. This routine implements the query volume info call
  365. Arguments:
  366. Vcb - Supplies the Vcb being queried
  367. Buffer - Supplies a pointer to the output buffer where the information
  368. is to be returned
  369. Length - Supplies the length of the buffer in byte. This variable
  370. upon return recieves the remaining bytes free in the buffer
  371. Return Value:
  372. NTSTATUS - Returns the status for the query
  373. --*/
  374. {
  375. NTSTATUS Status;
  376. ULONG BytesToCopy;
  377. ASSERT_IRP_CONTEXT( IrpContext );
  378. ASSERT_VCB( Vcb );
  379. PAGED_CODE();
  380. DebugTrace( 0, Dbg, ("NtfsQueryFsVolumeInfo...\n") );
  381. //
  382. // Get the volume creation time from the Vcb.
  383. //
  384. Buffer->VolumeCreationTime.QuadPart = Vcb->VolumeCreationTime;
  385. //
  386. // Fill in the serial number and indicate that we support objects
  387. //
  388. Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
  389. Buffer->SupportsObjects = TRUE;
  390. Buffer->VolumeLabelLength = Vcb->Vpb->VolumeLabelLength;
  391. //
  392. // Update the length field with how much we have filled in so far.
  393. //
  394. *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
  395. //
  396. // See how many bytes of volume label we can copy
  397. //
  398. if (*Length >= (ULONG)Vcb->Vpb->VolumeLabelLength) {
  399. Status = STATUS_SUCCESS;
  400. BytesToCopy = Vcb->Vpb->VolumeLabelLength;
  401. } else {
  402. Status = STATUS_BUFFER_OVERFLOW;
  403. BytesToCopy = *Length;
  404. }
  405. //
  406. // Copy over the volume label (if there is one).
  407. //
  408. RtlCopyMemory( &Buffer->VolumeLabel[0],
  409. &Vcb->Vpb->VolumeLabel[0],
  410. BytesToCopy);
  411. //
  412. // Update the buffer length by the amount we copied.
  413. //
  414. *Length -= BytesToCopy;
  415. return Status;
  416. }
  417. //
  418. // Internal Support Routine
  419. //
  420. NTSTATUS
  421. NtfsQueryFsSizeInfo (
  422. IN PIRP_CONTEXT IrpContext,
  423. IN PVCB Vcb,
  424. IN PFILE_FS_SIZE_INFORMATION Buffer,
  425. IN OUT PULONG Length
  426. )
  427. /*++
  428. Routine Description:
  429. This routine implements the query size information call
  430. Arguments:
  431. Vcb - Supplies the Vcb being queried
  432. Buffer - Supplies a pointer to the output buffer where the information
  433. is to be returned
  434. Length - Supplies the length of the buffer in byte. This variable
  435. upon return recieves the remaining bytes free in the buffer
  436. Return Value:
  437. NTSTATUS - Returns the status for the query
  438. --*/
  439. {
  440. ASSERT_IRP_CONTEXT( IrpContext );
  441. ASSERT_VCB( Vcb );
  442. PAGED_CODE();
  443. DebugTrace( 0, Dbg, ("NtfsQueryFsSizeInfo...\n") );
  444. //
  445. // Make sure the buffer is large enough and zero it out
  446. //
  447. if (*Length < sizeof(FILE_FS_SIZE_INFORMATION)) {
  448. return STATUS_BUFFER_OVERFLOW;
  449. }
  450. RtlZeroMemory( Buffer, sizeof(FILE_FS_SIZE_INFORMATION) );
  451. //
  452. // Check if we need to rescan the bitmap. Don't try this
  453. // if we have started to teardown the volume.
  454. //
  455. if (FlagOn( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS ) &&
  456. FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  457. //
  458. // Acquire the volume bitmap shared to rescan the bitmap.
  459. //
  460. NtfsAcquireExclusiveScb( IrpContext, Vcb->BitmapScb );
  461. try {
  462. NtfsScanEntireBitmap( IrpContext, Vcb, FALSE );
  463. } finally {
  464. NtfsReleaseScb( IrpContext, Vcb->BitmapScb );
  465. }
  466. }
  467. //
  468. // Set the output buffer
  469. //
  470. Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalClusters;
  471. Buffer->AvailableAllocationUnits.QuadPart = Vcb->FreeClusters - Vcb->TotalReserved;
  472. Buffer->SectorsPerAllocationUnit = Vcb->BytesPerCluster / Vcb->BytesPerSector;
  473. Buffer->BytesPerSector = Vcb->BytesPerSector;
  474. if (Buffer->AvailableAllocationUnits.QuadPart < 0) {
  475. Buffer->AvailableAllocationUnits.QuadPart = 0;
  476. }
  477. //
  478. // If quota enforcement is enabled then the available allocation
  479. // units. must be reduced by the available quota.
  480. //
  481. if (FlagOn( Vcb->QuotaFlags, QUOTA_FLAG_ENFORCEMENT_ENABLED )) {
  482. PCCB Ccb;
  483. ULONGLONG Quota;
  484. ULONGLONG QuotaLimit;
  485. //
  486. // Go grab the ccb out of the Irp.
  487. //
  488. Ccb = (PCCB) (IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->
  489. FileObject->FsContext2);
  490. if (Ccb != NULL && Ccb->OwnerId != 0) {
  491. NtfsGetRemainingQuota( IrpContext, Ccb->OwnerId, &Quota, &QuotaLimit, NULL );
  492. } else {
  493. NtfsGetRemainingQuota( IrpContext,
  494. NtfsGetCallersUserId( IrpContext ),
  495. &Quota,
  496. &QuotaLimit,
  497. NULL );
  498. }
  499. //
  500. // Do not use LlClustersFromBytesTruncate it is signed and this must be
  501. // an unsigned operation.
  502. //
  503. Quota = Int64ShrlMod32( Quota, Vcb->ClusterShift );
  504. QuotaLimit = Int64ShrlMod32( QuotaLimit, Vcb->ClusterShift );
  505. if (Quota < (ULONGLONG) Buffer->AvailableAllocationUnits.QuadPart) {
  506. Buffer->AvailableAllocationUnits.QuadPart = Quota;
  507. DebugTrace( 0, Dbg, (" QQQQQ AvailableAllocation is quota limited to %I64x\n", Quota) );
  508. }
  509. if (QuotaLimit < (ULONGLONG) Vcb->TotalClusters) {
  510. Buffer->TotalAllocationUnits.QuadPart = QuotaLimit;
  511. DebugTrace( 0, Dbg, (" QQQQQ TotalAllocation is quota limited to %I64x\n", QuotaLimit) );
  512. }
  513. }
  514. //
  515. // Adjust the length variable
  516. //
  517. DebugTrace( 0, Dbg, ("AvailableAllocation is %I64x\n", Buffer->AvailableAllocationUnits.QuadPart) );
  518. DebugTrace( 0, Dbg, ("TotalAllocation is %I64x\n", Buffer->TotalAllocationUnits.QuadPart) );
  519. *Length -= sizeof(FILE_FS_SIZE_INFORMATION);
  520. return STATUS_SUCCESS;
  521. }
  522. //
  523. // Internal Support Routine
  524. //
  525. NTSTATUS
  526. NtfsQueryFsDeviceInfo (
  527. IN PIRP_CONTEXT IrpContext,
  528. IN PVCB Vcb,
  529. IN PFILE_FS_DEVICE_INFORMATION Buffer,
  530. IN OUT PULONG Length
  531. )
  532. /*++
  533. Routine Description:
  534. This routine implements the query device information call
  535. Arguments:
  536. Vcb - Supplies the Vcb being queried
  537. Buffer - Supplies a pointer to the output buffer where the information
  538. is to be returned
  539. Length - Supplies the length of the buffer in byte. This variable
  540. upon return recieves the remaining bytes free in the buffer
  541. Return Value:
  542. NTSTATUS - Returns the status for the query
  543. --*/
  544. {
  545. ASSERT_IRP_CONTEXT( IrpContext );
  546. ASSERT_VCB( Vcb );
  547. PAGED_CODE();
  548. DebugTrace( 0, Dbg, ("NtfsQueryFsDeviceInfo...\n") );
  549. //
  550. // Make sure the buffer is large enough and zero it out
  551. //
  552. if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION)) {
  553. return STATUS_BUFFER_OVERFLOW;
  554. }
  555. RtlZeroMemory( Buffer, sizeof(FILE_FS_DEVICE_INFORMATION) );
  556. //
  557. // Set the output buffer
  558. //
  559. Buffer->DeviceType = FILE_DEVICE_DISK;
  560. Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
  561. //
  562. // Adjust the length variable
  563. //
  564. *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
  565. return STATUS_SUCCESS;
  566. }
  567. //
  568. // Internal Support Routine
  569. //
  570. NTSTATUS
  571. NtfsQueryFsAttributeInfo (
  572. IN PIRP_CONTEXT IrpContext,
  573. IN PVCB Vcb,
  574. IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
  575. IN OUT PULONG Length
  576. )
  577. /*++
  578. Routine Description:
  579. This routine implements the query attribute information call
  580. Arguments:
  581. Vcb - Supplies the Vcb being queried
  582. Buffer - Supplies a pointer to the output buffer where the information
  583. is to be returned
  584. Length - Supplies the length of the buffer in byte. This variable
  585. upon return recieves the remaining bytes free in the buffer
  586. Return Value:
  587. NTSTATUS - Returns the status for the query
  588. --*/
  589. {
  590. NTSTATUS Status;
  591. ULONG BytesToCopy;
  592. ASSERT_IRP_CONTEXT( IrpContext );
  593. ASSERT_VCB( Vcb );
  594. PAGED_CODE();
  595. DebugTrace( 0, Dbg, ("NtfsQueryFsAttributeInfo...\n") );
  596. //
  597. // See how many bytes of the name we can copy.
  598. //
  599. *Length -= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0]);
  600. if ( *Length >= 8 ) {
  601. Status = STATUS_SUCCESS;
  602. BytesToCopy = 8;
  603. } else {
  604. Status = STATUS_BUFFER_OVERFLOW;
  605. BytesToCopy = *Length;
  606. }
  607. //
  608. // Set the output buffer
  609. //
  610. Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH |
  611. FILE_CASE_PRESERVED_NAMES |
  612. FILE_UNICODE_ON_DISK |
  613. FILE_FILE_COMPRESSION |
  614. FILE_PERSISTENT_ACLS |
  615. FILE_NAMED_STREAMS;
  616. //
  617. // This may be a version 1.x volume that has not been upgraded yet.
  618. // It may also be an upgraded volume where we somehow failed to
  619. // open the quota index. In either case, we should only tell the
  620. // quota ui that this volume supports quotas if it really does.
  621. //
  622. if (Vcb->QuotaTableScb != NULL) {
  623. SetFlag( Buffer->FileSystemAttributes, FILE_VOLUME_QUOTAS );
  624. }
  625. //
  626. // Ditto for object ids.
  627. //
  628. if (Vcb->ObjectIdTableScb != NULL) {
  629. SetFlag( Buffer->FileSystemAttributes, FILE_SUPPORTS_OBJECT_IDS );
  630. }
  631. //
  632. // Encryption is trickier than quotas and object ids. It requires an
  633. // upgraded volume as well as a registered encryption driver.
  634. //
  635. if (NtfsVolumeVersionCheck( Vcb, NTFS_ENCRYPTION_VERSION ) &&
  636. FlagOn( NtfsData.Flags, NTFS_FLAGS_ENCRYPTION_DRIVER )) {
  637. SetFlag( Buffer->FileSystemAttributes, FILE_SUPPORTS_ENCRYPTION );
  638. }
  639. //
  640. // Reparse points and sparse files are supported in 5.0 volumes.
  641. //
  642. // For reparse points we verify whether the Vcb->ReparsePointTableScb has
  643. // been initialized or not.
  644. //
  645. if (Vcb->ReparsePointTableScb != NULL) {
  646. SetFlag( Buffer->FileSystemAttributes, FILE_SUPPORTS_REPARSE_POINTS );
  647. }
  648. if (NtfsVolumeVersionCheck( Vcb, NTFS_SPARSE_FILE_VERSION )) {
  649. SetFlag( Buffer->FileSystemAttributes, FILE_SUPPORTS_SPARSE_FILES );
  650. }
  651. //
  652. // Clear the compression flag if we don't allow compression on this drive
  653. // (i.e. large clusters)
  654. //
  655. if (!FlagOn( Vcb->AttributeFlagsMask, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  656. ClearFlag( Buffer->FileSystemAttributes, FILE_FILE_COMPRESSION );
  657. }
  658. if (NtfsIsVolumeReadOnly( Vcb )) {
  659. SetFlag( Buffer->FileSystemAttributes, FILE_READ_ONLY_VOLUME );
  660. }
  661. Buffer->MaximumComponentNameLength = 255;
  662. Buffer->FileSystemNameLength = BytesToCopy;;
  663. RtlCopyMemory( &Buffer->FileSystemName[0], L"NTFS", BytesToCopy );
  664. //
  665. // Adjust the length variable
  666. //
  667. *Length -= BytesToCopy;
  668. return Status;
  669. }
  670. //
  671. // Internal Support Routine
  672. //
  673. NTSTATUS
  674. NtfsQueryFsControlInfo (
  675. IN PIRP_CONTEXT IrpContext,
  676. IN PVCB Vcb,
  677. IN PFILE_FS_CONTROL_INFORMATION Buffer,
  678. IN OUT PULONG Length
  679. )
  680. /*++
  681. Routine Description:
  682. This routine implements the query control information call
  683. Arguments:
  684. Vcb - Supplies the Vcb being queried
  685. Buffer - Supplies a pointer to the output buffer where the information
  686. is to be returned
  687. Length - Supplies the length of the buffer in byte. This variable
  688. upon return recieves the remaining bytes free in the buffer
  689. Return Value:
  690. NTSTATUS - Returns the status for the query
  691. --*/
  692. {
  693. INDEX_ROW IndexRow;
  694. INDEX_KEY IndexKey;
  695. QUOTA_USER_DATA QuotaBuffer;
  696. PQUOTA_USER_DATA UserData;
  697. ULONG OwnerId;
  698. ULONG Count = 1;
  699. PREAD_CONTEXT ReadContext = NULL;
  700. NTSTATUS Status = STATUS_SUCCESS;
  701. ASSERT_IRP_CONTEXT( IrpContext );
  702. ASSERT_VCB( Vcb );
  703. PAGED_CODE();
  704. DebugTrace( 0, Dbg, ("NtfsQueryFsControlInfo...\n") );
  705. RtlZeroMemory( Buffer, sizeof( FILE_FS_CONTROL_INFORMATION ));
  706. PAGED_CODE();
  707. try {
  708. //
  709. // Fill in the quota information if quotas are running.
  710. //
  711. if (Vcb->QuotaTableScb != NULL) {
  712. OwnerId = QUOTA_DEFAULTS_ID;
  713. IndexKey.KeyLength = sizeof( OwnerId );
  714. IndexKey.Key = &OwnerId;
  715. Status = NtOfsReadRecords( IrpContext,
  716. Vcb->QuotaTableScb,
  717. &ReadContext,
  718. &IndexKey,
  719. NtOfsMatchUlongExact,
  720. &IndexKey,
  721. &Count,
  722. &IndexRow,
  723. sizeof( QuotaBuffer ),
  724. &QuotaBuffer );
  725. if (NT_SUCCESS( Status )) {
  726. UserData = IndexRow.DataPart.Data;
  727. Buffer->DefaultQuotaThreshold.QuadPart =
  728. UserData->QuotaThreshold;
  729. Buffer->DefaultQuotaLimit.QuadPart =
  730. UserData->QuotaLimit;
  731. //
  732. // If the quota info is corrupt or has not been rebuilt
  733. // yet then indicate the information is incomplete.
  734. //
  735. if (FlagOn( Vcb->QuotaFlags, QUOTA_FLAG_OUT_OF_DATE |
  736. QUOTA_FLAG_CORRUPT )) {
  737. SetFlag( Buffer->FileSystemControlFlags,
  738. FILE_VC_QUOTAS_INCOMPLETE );
  739. }
  740. if ((Vcb->QuotaState & VCB_QUOTA_REPAIR_RUNNING) >
  741. VCB_QUOTA_REPAIR_POSTED ) {
  742. SetFlag( Buffer->FileSystemControlFlags,
  743. FILE_VC_QUOTAS_REBUILDING );
  744. }
  745. //
  746. // Set the quota information basied on where we want
  747. // to be rather than where we are.
  748. //
  749. if (FlagOn( UserData->QuotaFlags,
  750. QUOTA_FLAG_ENFORCEMENT_ENABLED )) {
  751. SetFlag( Buffer->FileSystemControlFlags,
  752. FILE_VC_QUOTA_ENFORCE );
  753. } else if (FlagOn( UserData->QuotaFlags,
  754. QUOTA_FLAG_TRACKING_REQUESTED )) {
  755. SetFlag( Buffer->FileSystemControlFlags,
  756. FILE_VC_QUOTA_TRACK );
  757. }
  758. if (FlagOn( UserData->QuotaFlags, QUOTA_FLAG_LOG_LIMIT)) {
  759. SetFlag( Buffer->FileSystemControlFlags,
  760. FILE_VC_LOG_QUOTA_LIMIT );
  761. }
  762. if (FlagOn( UserData->QuotaFlags, QUOTA_FLAG_LOG_THRESHOLD)) {
  763. SetFlag( Buffer->FileSystemControlFlags,
  764. FILE_VC_LOG_QUOTA_THRESHOLD );
  765. }
  766. }
  767. }
  768. } finally {
  769. if (ReadContext != NULL) {
  770. NtOfsFreeReadContext( ReadContext );
  771. }
  772. }
  773. //
  774. // Adjust the length variable
  775. //
  776. *Length -= sizeof( FILE_FS_CONTROL_INFORMATION );
  777. return Status;
  778. }
  779. //
  780. // Internal Support Routine
  781. //
  782. NTSTATUS
  783. NtfsQueryFsFullSizeInfo (
  784. IN PIRP_CONTEXT IrpContext,
  785. IN PVCB Vcb,
  786. IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
  787. IN OUT PULONG Length
  788. )
  789. /*++
  790. Routine Description:
  791. This routine implements the query full size information call
  792. Arguments:
  793. Vcb - Supplies the Vcb being queried
  794. Buffer - Supplies a pointer to the output buffer where the information
  795. is to be returned
  796. Length - Supplies the length of the buffer in byte. This variable
  797. upon return recieves the remaining bytes free in the buffer
  798. Return Value:
  799. NTSTATUS - Returns the status for the query
  800. --*/
  801. {
  802. ASSERT_IRP_CONTEXT( IrpContext );
  803. ASSERT_VCB( Vcb );
  804. PAGED_CODE();
  805. DebugTrace( 0, Dbg, ("NtfsQueryFsFullSizeInfo...\n") );
  806. //
  807. // Make sure the buffer is large enough and zero it out
  808. //
  809. if (*Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) {
  810. return STATUS_BUFFER_OVERFLOW;
  811. }
  812. RtlZeroMemory( Buffer, sizeof(FILE_FS_FULL_SIZE_INFORMATION) );
  813. //
  814. // Check if we need to rescan the bitmap. Don't try this
  815. // if we have started to teardown the volume.
  816. //
  817. if (FlagOn( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS ) &&
  818. FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  819. //
  820. // Acquire the volume bitmap shared to rescan the bitmap.
  821. //
  822. NtfsAcquireExclusiveScb( IrpContext, Vcb->BitmapScb );
  823. try {
  824. NtfsScanEntireBitmap( IrpContext, Vcb, FALSE );
  825. } finally {
  826. NtfsReleaseScb( IrpContext, Vcb->BitmapScb );
  827. }
  828. }
  829. //
  830. // Set the output buffer
  831. //
  832. Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalClusters;
  833. Buffer->CallerAvailableAllocationUnits.QuadPart = Vcb->FreeClusters - Vcb->TotalReserved;
  834. Buffer->ActualAvailableAllocationUnits.QuadPart = Vcb->FreeClusters - Vcb->TotalReserved;
  835. Buffer->SectorsPerAllocationUnit = Vcb->BytesPerCluster / Vcb->BytesPerSector;
  836. Buffer->BytesPerSector = Vcb->BytesPerSector;
  837. if (Buffer->CallerAvailableAllocationUnits.QuadPart < 0) {
  838. Buffer->CallerAvailableAllocationUnits.QuadPart = 0;
  839. }
  840. if (Buffer->ActualAvailableAllocationUnits.QuadPart < 0) {
  841. Buffer->ActualAvailableAllocationUnits.QuadPart = 0;
  842. }
  843. //
  844. // If quota enforcement is enabled then the available allocation
  845. // units. must be reduced by the available quota.
  846. //
  847. if (FlagOn(Vcb->QuotaFlags, QUOTA_FLAG_ENFORCEMENT_ENABLED)) {
  848. ULONGLONG Quota;
  849. ULONGLONG QuotaLimit;
  850. PCCB Ccb;
  851. //
  852. // Go grab the ccb out of the Irp.
  853. //
  854. Ccb = (PCCB) (IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->
  855. FileObject->FsContext2);
  856. if (Ccb != NULL && Ccb->OwnerId != 0) {
  857. NtfsGetRemainingQuota( IrpContext, Ccb->OwnerId, &Quota, &QuotaLimit, NULL );
  858. } else {
  859. NtfsGetRemainingQuota( IrpContext,
  860. NtfsGetCallersUserId( IrpContext ),
  861. &Quota,
  862. &QuotaLimit,
  863. NULL );
  864. }
  865. //
  866. // Do not use LlClustersFromBytesTruncate it is signed and this must be
  867. // an unsigned operation.
  868. //
  869. Quota = Int64ShrlMod32( Quota, Vcb->ClusterShift );
  870. QuotaLimit = Int64ShrlMod32( QuotaLimit, Vcb->ClusterShift );
  871. if (Quota < (ULONGLONG) Buffer->CallerAvailableAllocationUnits.QuadPart) {
  872. Buffer->CallerAvailableAllocationUnits.QuadPart = Quota;
  873. }
  874. if (QuotaLimit < (ULONGLONG) Vcb->TotalClusters) {
  875. Buffer->TotalAllocationUnits.QuadPart = QuotaLimit;
  876. }
  877. }
  878. //
  879. // Adjust the length variable
  880. //
  881. *Length -= sizeof(FILE_FS_FULL_SIZE_INFORMATION);
  882. return STATUS_SUCCESS;
  883. }
  884. //
  885. // Internal Support Routine
  886. //
  887. NTSTATUS
  888. NtfsQueryFsVolumeObjectIdInfo (
  889. IN PIRP_CONTEXT IrpContext,
  890. IN PVCB Vcb,
  891. IN PFILE_FS_OBJECTID_INFORMATION Buffer,
  892. IN OUT PULONG Length
  893. )
  894. /*++
  895. Routine Description:
  896. This routine implements the query volume object id information call
  897. Arguments:
  898. Vcb - Supplies the Vcb being queried
  899. Buffer - Supplies a pointer to the output buffer where the information
  900. is to be returned
  901. Length - Supplies the length of the buffer in byte. This variable
  902. upon return recieves the remaining bytes free in the buffer
  903. Return Value:
  904. NTSTATUS - Returns the status for the query
  905. --*/
  906. {
  907. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  908. NTSTATUS Status;
  909. ASSERT_IRP_CONTEXT( IrpContext );
  910. ASSERT_VCB( Vcb );
  911. PAGED_CODE();
  912. //
  913. // The Vcb should be held so a dismount can't sneak in.
  914. //
  915. ASSERT_SHARED_RESOURCE( &(Vcb->Resource) );
  916. //
  917. // Fail for version 1.x volumes.
  918. //
  919. if (Vcb->ObjectIdTableScb == NULL) {
  920. return STATUS_VOLUME_NOT_UPGRADED;
  921. }
  922. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  923. //
  924. // Only try this if the volume has an object id.
  925. //
  926. if (!FlagOn( Vcb->VcbState, VCB_STATE_VALID_OBJECT_ID )) {
  927. return STATUS_OBJECT_NAME_NOT_FOUND;
  928. }
  929. //
  930. // Get the object id extended info for the $Volume file. We
  931. // can cheat a little because we have the key part of the object
  932. // id stored in the Vcb.
  933. //
  934. Status = NtfsGetObjectIdExtendedInfo( IrpContext,
  935. Vcb,
  936. Vcb->VolumeObjectId,
  937. ObjectIdBuffer.ExtendedInfo );
  938. //
  939. // Copy both the indexed part and the extended info part out to the
  940. // user's buffer.
  941. //
  942. if (Status == STATUS_SUCCESS) {
  943. RtlCopyMemory( Buffer->ObjectId,
  944. Vcb->VolumeObjectId,
  945. OBJECT_ID_KEY_LENGTH );
  946. RtlCopyMemory( Buffer->ExtendedInfo,
  947. ObjectIdBuffer.ExtendedInfo,
  948. OBJECT_ID_EXT_INFO_LENGTH );
  949. *Length -= (OBJECT_ID_EXT_INFO_LENGTH + OBJECT_ID_KEY_LENGTH);
  950. }
  951. } else {
  952. Status = STATUS_VOLUME_DISMOUNTED;
  953. }
  954. return Status;
  955. }
  956. //
  957. // Internal Support Routine
  958. //
  959. NTSTATUS
  960. NtfsSetFsLabelInfo (
  961. IN PIRP_CONTEXT IrpContext,
  962. IN PVCB Vcb,
  963. IN PFILE_FS_LABEL_INFORMATION Buffer
  964. )
  965. /*++
  966. Routine Description:
  967. This routine implements the set label call
  968. Arguments:
  969. Vcb - Supplies the Vcb being altered
  970. Buffer - Supplies a pointer to the input buffer containing the new label
  971. Return Value:
  972. NTSTATUS - Returns the status for the operation
  973. --*/
  974. {
  975. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  976. ASSERT_IRP_CONTEXT( IrpContext );
  977. ASSERT_VCB( Vcb );
  978. PAGED_CODE();
  979. DebugTrace( 0, Dbg, ("NtfsSetFsLabelInfo...\n") );
  980. //
  981. // Check that the volume label length is supported by the system.
  982. //
  983. if (Buffer->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH) {
  984. return STATUS_INVALID_VOLUME_LABEL;
  985. }
  986. try {
  987. //
  988. // Initialize the attribute context and then lookup the volume name
  989. // attribute for on the volume dasd file
  990. //
  991. NtfsInitializeAttributeContext( &AttributeContext );
  992. if (NtfsLookupAttributeByCode( IrpContext,
  993. Vcb->VolumeDasdScb->Fcb,
  994. &Vcb->VolumeDasdScb->Fcb->FileReference,
  995. $VOLUME_NAME,
  996. &AttributeContext )) {
  997. //
  998. // We found the volume name so now simply update the label
  999. //
  1000. NtfsChangeAttributeValue( IrpContext,
  1001. Vcb->VolumeDasdScb->Fcb,
  1002. 0,
  1003. &Buffer->VolumeLabel[0],
  1004. Buffer->VolumeLabelLength,
  1005. TRUE,
  1006. FALSE,
  1007. FALSE,
  1008. FALSE,
  1009. &AttributeContext );
  1010. } else {
  1011. //
  1012. // We didn't find the volume name so now create a new label
  1013. //
  1014. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  1015. NtfsInitializeAttributeContext( &AttributeContext );
  1016. NtfsCreateAttributeWithValue( IrpContext,
  1017. Vcb->VolumeDasdScb->Fcb,
  1018. $VOLUME_NAME,
  1019. NULL,
  1020. &Buffer->VolumeLabel[0],
  1021. Buffer->VolumeLabelLength,
  1022. 0, // Attributeflags
  1023. NULL,
  1024. TRUE,
  1025. &AttributeContext );
  1026. }
  1027. Vcb->Vpb->VolumeLabelLength = (USHORT)Buffer->VolumeLabelLength;
  1028. if ( Vcb->Vpb->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH) {
  1029. Vcb->Vpb->VolumeLabelLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  1030. }
  1031. RtlCopyMemory( &Vcb->Vpb->VolumeLabel[0],
  1032. &Buffer->VolumeLabel[0],
  1033. Vcb->Vpb->VolumeLabelLength );
  1034. } finally {
  1035. DebugUnwind( NtfsSetFsLabelInfo );
  1036. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  1037. }
  1038. //
  1039. // and return to our caller
  1040. //
  1041. return STATUS_SUCCESS;
  1042. }
  1043. //
  1044. // Internal Support Routine
  1045. //
  1046. NTSTATUS
  1047. NtfsSetFsControlInfo (
  1048. IN PIRP_CONTEXT IrpContext,
  1049. IN PVCB Vcb,
  1050. IN PFILE_FS_CONTROL_INFORMATION Buffer
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. This routine implements the set volume quota control info call
  1055. Arguments:
  1056. Vcb - Supplies the Vcb being altered
  1057. Buffer - Supplies a pointer to the input buffer containing the new label
  1058. Return Value:
  1059. NTSTATUS - Returns the status for the operation
  1060. --*/
  1061. {
  1062. ASSERT_IRP_CONTEXT( IrpContext );
  1063. ASSERT_VCB( Vcb );
  1064. PAGED_CODE();
  1065. if (Vcb->QuotaTableScb == NULL) {
  1066. return( STATUS_INVALID_PARAMETER );
  1067. }
  1068. //
  1069. // Process the quota part of the control structure.
  1070. //
  1071. NtfsUpdateQuotaDefaults( IrpContext, Vcb, Buffer );
  1072. return STATUS_SUCCESS;
  1073. }
  1074. //
  1075. // Internal Support Routine
  1076. //
  1077. NTSTATUS
  1078. NtfsSetFsVolumeObjectIdInfo (
  1079. IN PIRP_CONTEXT IrpContext,
  1080. IN PVCB Vcb,
  1081. IN PFILE_FS_OBJECTID_INFORMATION Buffer
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. This routine implements the set volume object id call.
  1086. Arguments:
  1087. Vcb - Supplies the Vcb being altered
  1088. Buffer - Supplies a pointer to the input buffer containing the new label
  1089. Return Value:
  1090. NTSTATUS - Returns the status for the operation
  1091. --*/
  1092. {
  1093. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  1094. FILE_OBJECTID_BUFFER OldObjectIdBuffer;
  1095. NTSTATUS Status = STATUS_SUCCESS;
  1096. PFCB DasdFcb;
  1097. ASSERT_IRP_CONTEXT( IrpContext );
  1098. ASSERT_VCB( Vcb );
  1099. PAGED_CODE();
  1100. //
  1101. // The Vcb should be held so a dismount can't sneak in.
  1102. //
  1103. ASSERT_EXCLUSIVE_RESOURCE( &(Vcb->Resource) );
  1104. ASSERT( FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ));
  1105. //
  1106. // Every mounted volume should have the dasd scb open.
  1107. //
  1108. ASSERT( Vcb->VolumeDasdScb != NULL );
  1109. //
  1110. // Fail for version 1.x volumes.
  1111. //
  1112. if (Vcb->ObjectIdTableScb == NULL) {
  1113. return STATUS_VOLUME_NOT_UPGRADED;
  1114. }
  1115. DasdFcb = Vcb->VolumeDasdScb->Fcb;
  1116. //
  1117. // Make sure the volume doesn't already have an object id.
  1118. //
  1119. Status = NtfsGetObjectIdInternal( IrpContext, DasdFcb, FALSE, &OldObjectIdBuffer );
  1120. if (NT_SUCCESS( Status )) {
  1121. //
  1122. // This volume apparently has an object id, so we need to delete it.
  1123. //
  1124. Status = NtfsDeleteObjectIdInternal( IrpContext, DasdFcb, Vcb, TRUE );
  1125. //
  1126. // The volume currently has no object id, so update the in-memory object id.
  1127. //
  1128. if (NT_SUCCESS( Status )) {
  1129. RtlZeroMemory( Vcb->VolumeObjectId,
  1130. OBJECT_ID_KEY_LENGTH );
  1131. ClearFlag( Vcb->VcbState, VCB_STATE_VALID_OBJECT_ID );
  1132. }
  1133. } else if ((Status == STATUS_OBJECTID_NOT_FOUND) ||
  1134. (Status == STATUS_OBJECT_NAME_NOT_FOUND)) {
  1135. //
  1136. // This volume does not have an object id, but nothing else went wrong
  1137. // while we were checking, so let's proceed normally.
  1138. //
  1139. Status = STATUS_SUCCESS;
  1140. } else {
  1141. //
  1142. // The object id lookup failed for some unexpected reason.
  1143. // Let's get out of here and return that status to our caller.
  1144. //
  1145. return Status;
  1146. }
  1147. //
  1148. // If we either didn't find an object id, or successfully deleted one,
  1149. // let's set the new object id.
  1150. //
  1151. if (NT_SUCCESS( Status )) {
  1152. //
  1153. // I'd rather do one copy for the entire structure than one for
  1154. // the indexed part, and another for the extended info. I'd
  1155. // like to assert that the strucutres are still the same and I
  1156. // can safely do that.
  1157. //
  1158. ASSERT( sizeof( ObjectIdBuffer ) == sizeof( *Buffer ) );
  1159. RtlCopyMemory( &ObjectIdBuffer,
  1160. Buffer,
  1161. sizeof( ObjectIdBuffer ) );
  1162. //
  1163. // Set this object id for the $Volume file.
  1164. //
  1165. Status = NtfsSetObjectIdInternal( IrpContext,
  1166. DasdFcb,
  1167. Vcb,
  1168. &ObjectIdBuffer );
  1169. //
  1170. // If all went well, update the in-memory object id.
  1171. //
  1172. if (NT_SUCCESS( Status )) {
  1173. RtlCopyMemory( Vcb->VolumeObjectId,
  1174. &ObjectIdBuffer.ObjectId,
  1175. OBJECT_ID_KEY_LENGTH );
  1176. SetFlag( Vcb->VcbState, VCB_STATE_VALID_OBJECT_ID );
  1177. }
  1178. }
  1179. return Status;
  1180. }