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.

2211 lines
64 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. ObjIdSup.c
  5. Abstract:
  6. This module implements the object id support routines for Ntfs
  7. Author:
  8. Keith Kaplan [KeithKa] 27-Jun-1996
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. //
  13. // The local debug trace level
  14. //
  15. #define Dbg (DEBUG_TRACE_OBJIDSUP)
  16. //
  17. // Define a tag for general pool allocations from this module
  18. //
  19. #undef MODULE_POOL_TAG
  20. #define MODULE_POOL_TAG ('OFtN')
  21. //
  22. // Local define for number of times to attempt to generate a unique object id.
  23. //
  24. #define NTFS_MAX_OBJID_RETRIES 16
  25. NTSTATUS
  26. NtfsSetObjectIdExtendedInfoInternal (
  27. IN PIRP_CONTEXT IrpContext,
  28. IN PFCB Fcb,
  29. IN PVCB Vcb,
  30. IN PUCHAR ExtendedInfoBuffer
  31. );
  32. VOID
  33. NtfsGetIdFromGenerator (
  34. OUT PFILE_OBJECTID_BUFFER ObjectId
  35. );
  36. NTSTATUS
  37. NtfsSetObjectIdInternal (
  38. IN PIRP_CONTEXT IrpContext,
  39. IN PFCB Fcb,
  40. IN PVCB Vcb,
  41. IN PFILE_OBJECTID_BUFFER ObjectIdBuffer
  42. );
  43. NTSTATUS
  44. NtfsDeleteObjectIdInternal (
  45. IN PIRP_CONTEXT IrpContext,
  46. IN PFCB Fcb,
  47. IN PVCB Vcb,
  48. IN BOOLEAN DeleteFileAttribute
  49. );
  50. VOID
  51. NtfsGetIdFromGenerator (
  52. OUT PFILE_OBJECTID_BUFFER ObjectId
  53. );
  54. #ifdef ALLOC_PRAGMA
  55. #pragma alloc_text(PAGE, NtfsCreateOrGetObjectId)
  56. #pragma alloc_text(PAGE, NtfsDeleteObjectId)
  57. #pragma alloc_text(PAGE, NtfsDeleteObjectIdInternal)
  58. #pragma alloc_text(PAGE, NtfsGetIdFromGenerator)
  59. #pragma alloc_text(PAGE, NtfsGetObjectId)
  60. #pragma alloc_text(PAGE, NtfsGetObjectIdExtendedInfo)
  61. #pragma alloc_text(PAGE, NtfsGetObjectIdInternal)
  62. #pragma alloc_text(PAGE, NtfsInitializeObjectIdIndex)
  63. #pragma alloc_text(PAGE, NtfsSetObjectId)
  64. #pragma alloc_text(PAGE, NtfsSetObjectIdExtendedInfo)
  65. #pragma alloc_text(PAGE, NtfsSetObjectIdExtendedInfoInternal)
  66. #pragma alloc_text(PAGE, NtfsSetObjectIdInternal)
  67. #endif
  68. VOID
  69. NtfsInitializeObjectIdIndex (
  70. IN PIRP_CONTEXT IrpContext,
  71. IN PFCB Fcb,
  72. IN PVCB Vcb
  73. )
  74. /*++
  75. Routine Description:
  76. This routine opens the object id index for the volume. If the index does not
  77. exist it is created and initialized. We also look up the volume's object id,
  78. if any, in this routine.
  79. Arguments:
  80. Fcb - Pointer to Fcb for the object id file.
  81. Vcb - Volume control block for volume being mounted.
  82. Return Value:
  83. None
  84. --*/
  85. {
  86. NTSTATUS Status;
  87. UNICODE_STRING IndexName = CONSTANT_UNICODE_STRING( L"$O" );
  88. FILE_OBJECTID_BUFFER ObjectId;
  89. PAGED_CODE();
  90. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  91. try {
  92. Status = NtOfsCreateIndex( IrpContext,
  93. Fcb,
  94. IndexName,
  95. CREATE_OR_OPEN,
  96. 0,
  97. COLLATION_NTOFS_ULONGS,
  98. NtOfsCollateUlongs,
  99. NULL,
  100. &Vcb->ObjectIdTableScb );
  101. if (NT_SUCCESS( Status )) {
  102. //
  103. // We were able to create the index, now let's see if the volume has an object id.
  104. //
  105. Status = NtfsGetObjectIdInternal( IrpContext,
  106. Vcb->VolumeDasdScb->Fcb,
  107. FALSE,
  108. &ObjectId );
  109. if (NT_SUCCESS( Status )) {
  110. //
  111. // The volume does indeed have an object id, so copy it into the Vcb
  112. // and set the appropriate flag.
  113. //
  114. RtlCopyMemory( Vcb->VolumeObjectId,
  115. &ObjectId.ObjectId,
  116. OBJECT_ID_KEY_LENGTH );
  117. SetFlag( Vcb->VcbState, VCB_STATE_VALID_OBJECT_ID );
  118. }
  119. }
  120. } finally {
  121. NtfsReleaseFcb( IrpContext, Fcb );
  122. }
  123. }
  124. NTSTATUS
  125. NtfsSetObjectId (
  126. IN PIRP_CONTEXT IrpContext,
  127. IN PIRP Irp
  128. )
  129. /*++
  130. Routine Description:
  131. This routine associates an object id with a file. If the object id is already
  132. in use on the volume we return STATUS_DUPLICATE_NAME. If the file already has
  133. an object id, we return STATUS_OBJECT_NAME_COLLISION.
  134. Arguments:
  135. Irp - Supplies the Irp to process.
  136. Return Value:
  137. NTSTATUS - The return status for the operation.
  138. --*/
  139. {
  140. NTSTATUS Status = STATUS_OBJECT_NAME_INVALID;
  141. PIO_STACK_LOCATION IrpSp;
  142. TYPE_OF_OPEN TypeOfOpen;
  143. PVCB Vcb;
  144. PFCB Fcb;
  145. PSCB Scb;
  146. PCCB Ccb;
  147. PAGED_CODE();
  148. //
  149. // Get the current Irp stack location and save some references.
  150. //
  151. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  152. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  153. if (!(((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) &&
  154. (IrpSp->Parameters.FileSystemControl.InputBufferLength == sizeof( FILE_OBJECTID_BUFFER )))) {
  155. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  156. return STATUS_INVALID_PARAMETER;
  157. }
  158. //
  159. // Read only volumes stay read only.
  160. //
  161. if (NtfsIsVolumeReadOnly( Vcb )) {
  162. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  163. return STATUS_MEDIA_WRITE_PROTECTED;
  164. }
  165. //
  166. // Cleanly exit for volumes without oid indices, such as non-upgraded
  167. // version 1.x volumes.
  168. //
  169. if (Vcb->ObjectIdTableScb == NULL) {
  170. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  171. return STATUS_VOLUME_NOT_UPGRADED;
  172. }
  173. //
  174. // Capture the source information.
  175. //
  176. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  177. try {
  178. //
  179. // Only a restore operator or the I/O system (using its private irp minor code)
  180. // is allowed to set an arbitrary object id.
  181. //
  182. if (FlagOn( Ccb->AccessFlags, RESTORE_ACCESS ) ||
  183. (IrpSp->MinorFunction == IRP_MN_KERNEL_CALL)) {
  184. Status = NtfsSetObjectIdInternal( IrpContext,
  185. Fcb,
  186. Vcb,
  187. (PFILE_OBJECTID_BUFFER) Irp->AssociatedIrp.SystemBuffer );
  188. //
  189. // Remember to update the timestamps.
  190. //
  191. if (NT_SUCCESS( Status )) {
  192. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  193. }
  194. } else {
  195. Status = STATUS_ACCESS_DENIED;
  196. }
  197. } finally {
  198. if (!AbnormalTermination()) {
  199. NtfsCompleteRequest( IrpContext, Irp, Status );
  200. }
  201. }
  202. return Status;
  203. }
  204. NTSTATUS
  205. NtfsSetObjectIdExtendedInfo (
  206. IN PIRP_CONTEXT IrpContext,
  207. IN PIRP Irp
  208. )
  209. /*++
  210. Routine Description:
  211. This routine sets the extended info for a file which already has an object
  212. id. If the file does not yet have an object id, we return a status other
  213. than STATUS_SUCCESS.
  214. Arguments:
  215. Irp - Supplies the Irp to process.
  216. Return Value:
  217. NTSTATUS - The return status for the operation.
  218. --*/
  219. {
  220. NTSTATUS Status = STATUS_OBJECT_NAME_INVALID;
  221. PIO_STACK_LOCATION IrpSp;
  222. TYPE_OF_OPEN TypeOfOpen;
  223. PVCB Vcb;
  224. PFCB Fcb;
  225. PSCB Scb;
  226. PCCB Ccb;
  227. //
  228. // Get the current Irp stack location and save some references.
  229. //
  230. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  231. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  232. if (!(((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) &&
  233. (IrpSp->Parameters.FileSystemControl.InputBufferLength == OBJECT_ID_EXT_INFO_LENGTH))) {
  234. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  235. return STATUS_INVALID_PARAMETER;
  236. }
  237. //
  238. // Read only volumes stay read only.
  239. //
  240. if (NtfsIsVolumeReadOnly( Vcb )) {
  241. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  242. return STATUS_MEDIA_WRITE_PROTECTED;
  243. }
  244. //
  245. // Cleanly exit for volumes without oid indices, such as non-upgraded
  246. // version 1.x volumes.
  247. //
  248. if (Vcb->ObjectIdTableScb == NULL) {
  249. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  250. return STATUS_VOLUME_NOT_UPGRADED;
  251. }
  252. //
  253. // Capture the source information.
  254. //
  255. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  256. try {
  257. //
  258. // Setting extended info requires either write access or else it has
  259. // to be the I/O system using its private irp minor code.
  260. //
  261. if ((FlagOn( Ccb->AccessFlags, WRITE_DATA_ACCESS | WRITE_ATTRIBUTES_ACCESS )) ||
  262. (IrpSp->MinorFunction == IRP_MN_KERNEL_CALL)) {
  263. Status = NtfsSetObjectIdExtendedInfoInternal( IrpContext,
  264. Fcb,
  265. Vcb,
  266. (PUCHAR) Irp->AssociatedIrp.SystemBuffer );
  267. //
  268. // Remember to update the timestamps.
  269. //
  270. if (NT_SUCCESS( Status )) {
  271. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  272. }
  273. } else {
  274. Status = STATUS_ACCESS_DENIED;
  275. }
  276. } finally {
  277. if (!AbnormalTermination()) {
  278. NtfsCompleteRequest( IrpContext, Irp, Status );
  279. }
  280. }
  281. return Status;
  282. }
  283. NTSTATUS
  284. NtfsSetObjectIdInternal (
  285. IN PIRP_CONTEXT IrpContext,
  286. IN PFCB Fcb,
  287. IN PVCB Vcb,
  288. IN PFILE_OBJECTID_BUFFER ObjectIdBuffer
  289. )
  290. /*++
  291. Routine Description:
  292. This routine associates an object id with a file. If the object id is already
  293. in use on the volume we return STATUS_DUPLICATE_NAME. If the file already has
  294. an object id, we return STATUS_OBJECT_NAME_COLLISION.
  295. Arguments:
  296. Fcb - The file to associate with the object id.
  297. Vcb - The volume whose object id index the entry should be added to.
  298. ObjectIdBuffer - Supplies both the object id and the extended info.
  299. Return Value:
  300. NTSTATUS - The return status for the operation.
  301. --*/
  302. {
  303. NTSTATUS Status = STATUS_OBJECT_NAME_INVALID;
  304. NTFS_OBJECTID_INFORMATION ObjectIdInfo;
  305. FILE_OBJECTID_INFORMATION FileObjectIdInfo;
  306. INDEX_KEY IndexKey;
  307. INDEX_ROW IndexRow;
  308. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  309. BOOLEAN InitializedAttributeContext = FALSE;
  310. BOOLEAN AcquiredPaging = FALSE;
  311. try {
  312. RtlZeroMemory( &ObjectIdInfo,
  313. sizeof( NTFS_OBJECTID_INFORMATION ) );
  314. RtlCopyMemory( &ObjectIdInfo.FileSystemReference,
  315. &Fcb->FileReference,
  316. sizeof( FILE_REFERENCE ) );
  317. RtlCopyMemory( ObjectIdInfo.ExtendedInfo,
  318. ObjectIdBuffer->ExtendedInfo,
  319. OBJECT_ID_EXT_INFO_LENGTH );
  320. } except(EXCEPTION_EXECUTE_HANDLER) {
  321. return STATUS_INVALID_ADDRESS;
  322. }
  323. //
  324. // Acquire the file we're setting the object id on. Main blocks
  325. // anybody else from deleting the file or setting another object
  326. // id behind our backs. Paging blocks collided flushes if we have to convert
  327. // another (data) attribute to be non-resident.
  328. //
  329. // Don't use AcquireFcbWithPaging because
  330. // it can't recursively acquire paging and we come in often with it
  331. // preacquired
  332. //
  333. if (Fcb->PagingIoResource != NULL) {
  334. ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, TRUE );
  335. AcquiredPaging = TRUE;
  336. }
  337. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  338. try {
  339. //
  340. // if there is now a paging resource release main and grab both
  341. // This is the case for a named data stream in a directory created between our
  342. // unsafe test and owning the main
  343. // Note: if we already owned main before entrance this could never happen. So we can just drop
  344. // and not worry about still owning main and taking paging
  345. //
  346. if (!AcquiredPaging && (Fcb->PagingIoResource != NULL)) {
  347. NtfsReleaseFcb( IrpContext, Fcb );
  348. ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, TRUE );
  349. AcquiredPaging = TRUE;
  350. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  351. }
  352. if (!IsListEmpty( &Fcb->ScbQueue )) {
  353. PSCB Scb;
  354. Scb = CONTAINING_RECORD( Fcb->ScbQueue.Flink, SCB, FcbLinks );
  355. ASSERT( Scb->Header.Resource == Fcb->Resource );
  356. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  357. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  358. }
  359. }
  360. //
  361. // Post the change to the Usn Journal (on errors change is backed out).
  362. // We dont' want to do this if we've been called because create is
  363. // trying to set an object id from the tunnel cache, since we can't
  364. // call the Usn package yet, since the file record doesn't have a file
  365. // name yet.
  366. //
  367. if (IrpContext->MajorFunction != IRP_MJ_CREATE) {
  368. NtfsPostUsnChange( IrpContext, Fcb, USN_REASON_OBJECT_ID_CHANGE );
  369. }
  370. //
  371. // Make sure the file doesn't already have an object id.
  372. //
  373. NtfsInitializeAttributeContext( &AttributeContext );
  374. InitializedAttributeContext = TRUE;
  375. if (NtfsLookupAttributeByCode( IrpContext,
  376. Fcb,
  377. &Fcb->FileReference,
  378. $OBJECT_ID,
  379. &AttributeContext )) {
  380. try_return( Status = STATUS_OBJECT_NAME_COLLISION );
  381. }
  382. //
  383. // Add ObjectId to the index, associate it with this file.
  384. //
  385. IndexKey.Key = ObjectIdBuffer->ObjectId;
  386. IndexKey.KeyLength = OBJECT_ID_KEY_LENGTH;
  387. IndexRow.KeyPart = IndexKey;
  388. IndexRow.DataPart.DataLength = sizeof( ObjectIdInfo );
  389. IndexRow.DataPart.Data = &ObjectIdInfo;
  390. //
  391. // NtOfsAddRecords may raise if the object id isn't unique.
  392. //
  393. NtOfsAddRecords( IrpContext,
  394. Vcb->ObjectIdTableScb,
  395. 1, // adding one record to the index
  396. &IndexRow,
  397. FALSE ); // sequential insert
  398. //
  399. // Now add the objectid attribute to the file. Notice that
  400. // we do _not_ log this operation if we're within a create
  401. // operation, i.e. if we're restoring an object id from the
  402. // tunnel cache. The create path has its own logging scheme
  403. // that we don't want to interfere with.
  404. //
  405. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  406. NtfsCreateAttributeWithValue( IrpContext,
  407. Fcb,
  408. $OBJECT_ID,
  409. NULL,
  410. ObjectIdBuffer->ObjectId,
  411. OBJECT_ID_KEY_LENGTH,
  412. 0,
  413. NULL,
  414. (BOOLEAN)(IrpContext->MajorFunction != IRP_MJ_CREATE),
  415. &AttributeContext );
  416. ASSERT( IrpContext->TransactionId != 0 );
  417. //
  418. // Notify anybody who's interested.
  419. //
  420. if (Vcb->ViewIndexNotifyCount != 0) {
  421. //
  422. // The FRS field is only populated for the notification of a failed
  423. // object id restore from the tunnel cache.
  424. //
  425. FileObjectIdInfo.FileReference = 0L;
  426. RtlCopyMemory( FileObjectIdInfo.ObjectId,
  427. ObjectIdBuffer->ObjectId,
  428. OBJECT_ID_KEY_LENGTH );
  429. RtlCopyMemory( FileObjectIdInfo.ExtendedInfo,
  430. ObjectIdBuffer->ExtendedInfo,
  431. OBJECT_ID_EXT_INFO_LENGTH );
  432. NtfsReportViewIndexNotify( Vcb,
  433. Vcb->ObjectIdTableScb->Fcb,
  434. FILE_NOTIFY_CHANGE_FILE_NAME,
  435. FILE_ACTION_ADDED,
  436. &FileObjectIdInfo,
  437. sizeof(FILE_OBJECTID_INFORMATION) );
  438. }
  439. //
  440. // If we made it this far and didn't have to jump into the
  441. // finally clause yet, all must have gone well.
  442. //
  443. Status = STATUS_SUCCESS;
  444. try_exit: NOTHING;
  445. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  446. } finally {
  447. if (AcquiredPaging) {
  448. ExReleaseResourceLite( Fcb->PagingIoResource );
  449. }
  450. NtfsReleaseFcb( IrpContext, Fcb );
  451. if (InitializedAttributeContext) {
  452. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  453. }
  454. }
  455. return Status;
  456. }
  457. NTSTATUS
  458. NtfsCreateOrGetObjectId (
  459. IN PIRP_CONTEXT IrpContext,
  460. IN PIRP Irp
  461. )
  462. /*++
  463. Routine Description:
  464. This routine generates a new object id, if possible, for a given file. It is
  465. different from NtfsSetObjectId in that it does not take an object id as an
  466. input, rather it calls a routine to generate one. If the file already has
  467. an object id, that existing object id is returned.
  468. Arguments:
  469. Irp - Supplies the Irp to process.
  470. Return Value:
  471. NTSTATUS - The return status for the operation.
  472. STATUS_DUPLICATE_NAME if we are unable to generate a unique id
  473. in NTFS_MAX_OBJID_RETRIES retries.
  474. --*/
  475. {
  476. NTSTATUS Status;
  477. PIO_STACK_LOCATION IrpSp;
  478. TYPE_OF_OPEN TypeOfOpen;
  479. PVCB Vcb;
  480. PFCB Fcb;
  481. PSCB Scb;
  482. PCCB Ccb;
  483. FILE_OBJECTID_BUFFER ObjectId;
  484. FILE_OBJECTID_BUFFER *OutputBuffer;
  485. ULONG RetryCount = 0;
  486. //
  487. // Get the current Irp stack location and save some references.
  488. //
  489. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  490. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  491. //
  492. // This only works for files and directories.
  493. //
  494. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  495. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  496. return STATUS_INVALID_PARAMETER;
  497. }
  498. //
  499. // Cleanly exit for volumes without oid indices, such as non-upgraded
  500. // version 1.x volumes.
  501. //
  502. if (Vcb->ObjectIdTableScb == NULL) {
  503. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  504. return STATUS_VOLUME_NOT_UPGRADED;
  505. }
  506. //
  507. // Get a pointer to the output buffer. Look at the system buffer field in the
  508. // irp first, then the Irp Mdl.
  509. //
  510. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  511. OutputBuffer = (FILE_OBJECTID_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
  512. } else if (Irp->MdlAddress != NULL) {
  513. OutputBuffer = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  514. if (OutputBuffer == NULL) {
  515. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  516. return STATUS_INSUFFICIENT_RESOURCES;
  517. }
  518. } else {
  519. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  520. return STATUS_INVALID_USER_BUFFER;
  521. }
  522. //
  523. // Make sure the output buffer is large enough.
  524. //
  525. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ObjectId)) {
  526. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  527. return STATUS_INVALID_PARAMETER;
  528. }
  529. //
  530. // Capture the source information.
  531. //
  532. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  533. try {
  534. //
  535. // Get this file exlusively so we know nobody else is trying
  536. // to do this at the same time. At this point the irpcontext flag
  537. // is not set so paging is not acquired.
  538. //
  539. NtfsAcquireFcbWithPaging( IrpContext, Fcb, 0 );
  540. //
  541. // Let's make sure the volume is still mounted.
  542. //
  543. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  544. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  545. }
  546. DebugTrace( +1, Dbg, ("NtfsCreateOrGetObjectId\n") );
  547. //
  548. // If this file already has an object id, let's return it. Doing this
  549. // first saves a (possibly expensive) call to NtfsGetIdFromGenerator.
  550. //
  551. Status = NtfsGetObjectIdInternal( IrpContext, Fcb, TRUE, OutputBuffer );
  552. if (Status == STATUS_OBJECTID_NOT_FOUND) {
  553. DebugTrace( 0, Dbg, ("File has no oid, we have to generate one\n") );
  554. //
  555. // We want to keep retrying if the object id generator returns a
  556. // duplicate name. If we have success, or any other error, we
  557. // should stop trying. For instance, if we fail because the file
  558. // already has an object id, retrying is just a waste of time.
  559. // We also need some sane limit on the number of times we retry
  560. // this operation.
  561. //
  562. do {
  563. RetryCount += 1;
  564. //
  565. // Drop this file so we don't deadlock in the guid generator.
  566. //
  567. ASSERT( 0 == IrpContext->TransactionId );
  568. NtfsReleaseFcbWithPaging( IrpContext, Fcb );
  569. DebugTrace( 0, Dbg, ("Calling oid generator\n") );
  570. NtfsGetIdFromGenerator( &ObjectId );
  571. //
  572. // Reacquire the file so we know nobody else is trying to do
  573. // this at the same time. SetObjIdInternal acquires both so we need to
  574. // do the same
  575. //
  576. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  577. NtfsAcquireFcbWithPaging( IrpContext, Fcb, 0 );
  578. //
  579. // Make sure we didn't miss a dismount.
  580. //
  581. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  582. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  583. }
  584. //
  585. // Let's make sure this file didn't get an object id assigned to it
  586. // while we weren't holding the Fcb above.
  587. //
  588. Status = NtfsGetObjectIdInternal( IrpContext, Fcb, TRUE, OutputBuffer );
  589. if (Status == STATUS_OBJECTID_NOT_FOUND) {
  590. if (NtfsIsVolumeReadOnly( Vcb )) {
  591. try_return( Status = STATUS_MEDIA_WRITE_PROTECTED );
  592. }
  593. DebugTrace( 0, Dbg, ("File still has no oid, attempting to set generated one\n") );
  594. //
  595. // The object id generator only generates the indexed part, so
  596. // we need to fill in the rest of the 'birth id' now. Note that if
  597. // the volume has no object id, we're relying on the Vcb creation
  598. // code to zero init the Vcb->VolumeObjectId for us. The net result
  599. // is right -- we get zeroes in the volume id part of the extended
  600. // info if the volume has no object id.
  601. //
  602. RtlCopyMemory( &ObjectId.BirthVolumeId,
  603. Vcb->VolumeObjectId,
  604. OBJECT_ID_KEY_LENGTH );
  605. RtlCopyMemory( &ObjectId.BirthObjectId,
  606. &ObjectId.ObjectId,
  607. OBJECT_ID_KEY_LENGTH );
  608. RtlZeroMemory( &ObjectId.DomainId,
  609. OBJECT_ID_KEY_LENGTH );
  610. Status = NtfsSetObjectIdInternal( IrpContext,
  611. Fcb,
  612. Vcb,
  613. &ObjectId );
  614. if (Status == STATUS_SUCCESS) {
  615. DebugTrace( 0, Dbg, ("Successfully set generated oid\n") );
  616. //
  617. // We have successfully generated and set an object id for this
  618. // file, so we need to tell our caller what that id is.
  619. //
  620. RtlCopyMemory( OutputBuffer,
  621. &ObjectId,
  622. sizeof(ObjectId) );
  623. //
  624. // Let's also remember to update the timestamps.
  625. //
  626. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  627. }
  628. }
  629. } while ((Status == STATUS_DUPLICATE_NAME) &&
  630. (RetryCount <= NTFS_MAX_OBJID_RETRIES));
  631. } else if (Status == STATUS_SUCCESS) {
  632. //
  633. // If we found an ID, make sure it isn't a partially formed id with
  634. // an all zero extended info. If it's partially formed, we'll generate
  635. // extended info now.
  636. //
  637. if (RtlCompareMemory( (PUCHAR)&OutputBuffer->ExtendedInfo, &NtfsZeroExtendedInfo, sizeof(ObjectId.ExtendedInfo)) == sizeof(ObjectId.ExtendedInfo)) {
  638. RtlCopyMemory( &OutputBuffer->BirthVolumeId,
  639. Vcb->VolumeObjectId,
  640. OBJECT_ID_KEY_LENGTH );
  641. RtlCopyMemory( &OutputBuffer->BirthObjectId,
  642. &OutputBuffer->ObjectId,
  643. OBJECT_ID_KEY_LENGTH );
  644. Status = NtfsSetObjectIdExtendedInfoInternal( IrpContext,
  645. Fcb,
  646. Vcb,
  647. (PUCHAR) &OutputBuffer->ExtendedInfo );
  648. }
  649. }
  650. if (Status == STATUS_SUCCESS) {
  651. //
  652. // If we found an existing id for the file, or managed to generate one
  653. // ourselves, we need to set the size in the information field so the
  654. // rdr can handle this operation correctly.
  655. //
  656. IrpContext->OriginatingIrp->IoStatus.Information = sizeof( ObjectId );
  657. }
  658. try_exit: NOTHING;
  659. } finally {
  660. }
  661. NtfsCompleteRequest( IrpContext, Irp, Status );
  662. DebugTrace( -1, Dbg, ("NtfsCreateOrGetObjectId -> %08lx\n", Status) );
  663. return Status;
  664. }
  665. NTSTATUS
  666. NtfsGetObjectId (
  667. IN PIRP_CONTEXT IrpContext,
  668. IN PIRP Irp
  669. )
  670. /*++
  671. Routine Description:
  672. This routine finds the object id, if any, for a given file.
  673. Arguments:
  674. Irp - Supplies the Irp to process.
  675. Return Value:
  676. NTSTATUS - The return status for the operation.
  677. --*/
  678. {
  679. NTSTATUS Status = STATUS_SUCCESS;
  680. PIO_STACK_LOCATION IrpSp;
  681. TYPE_OF_OPEN TypeOfOpen;
  682. PVCB Vcb;
  683. PFCB Fcb;
  684. PSCB Scb;
  685. PCCB Ccb;
  686. FILE_OBJECTID_BUFFER *OutputBuffer;
  687. //
  688. // Get the current Irp stack location and save some references.
  689. //
  690. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  691. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  692. //
  693. // This only works for files and directories.
  694. //
  695. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  696. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  697. return STATUS_INVALID_PARAMETER;
  698. }
  699. //
  700. // Cleanly exit for volumes without oid indices, such as non-upgraded
  701. // version 1.x volumes.
  702. //
  703. if (Vcb->ObjectIdTableScb == NULL) {
  704. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  705. return STATUS_VOLUME_NOT_UPGRADED;
  706. }
  707. //
  708. // Get a pointer to the output buffer. Look at the system buffer field in the
  709. // irp first, then the Irp Mdl.
  710. //
  711. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  712. OutputBuffer = (FILE_OBJECTID_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
  713. } else if (Irp->MdlAddress != NULL) {
  714. OutputBuffer = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  715. if (OutputBuffer == NULL) {
  716. NtfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  717. return STATUS_INSUFFICIENT_RESOURCES;
  718. }
  719. } else {
  720. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
  721. return STATUS_INVALID_USER_BUFFER;
  722. }
  723. //
  724. // Make sure the output buffer is large enough.
  725. //
  726. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(FILE_OBJECTID_BUFFER)) {
  727. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  728. return STATUS_INVALID_PARAMETER;
  729. }
  730. try {
  731. //
  732. // Call the function that does the real work.
  733. //
  734. Status = NtfsGetObjectIdInternal( IrpContext, Fcb, TRUE, OutputBuffer );
  735. if (NT_SUCCESS( Status )) {
  736. //
  737. // And set the size in the information field so the rdr
  738. // can handle this correctly.
  739. //
  740. IrpContext->OriginatingIrp->IoStatus.Information = sizeof( FILE_OBJECTID_BUFFER );
  741. }
  742. } finally {
  743. if (!AbnormalTermination()) {
  744. NtfsCompleteRequest( IrpContext, Irp, Status );
  745. }
  746. }
  747. return Status;
  748. }
  749. NTSTATUS
  750. NtfsGetObjectIdInternal (
  751. IN PIRP_CONTEXT IrpContext,
  752. IN PFCB Fcb,
  753. IN BOOLEAN GetExtendedInfo,
  754. OUT FILE_OBJECTID_BUFFER *OutputBuffer
  755. )
  756. /*++
  757. Routine Description:
  758. Internal function to find the object id, if any, for a given file. Called
  759. in response to the user's ioctl and by NtfsDeleteObjectIdInternal.
  760. Arguments:
  761. Fcb - The file whose object id we need to look up.
  762. GetExtendedInfo - If TRUE, we also copy the object id's extended information
  763. to the OutputBuffer, otherwise we only copy the object id
  764. itself. For instance, NtfsDeleteObjectIdInternal is not
  765. interested in the extended info -- it only needs to know
  766. which object id to delete from the index.
  767. OutputBuffer - Where to store the object id (and optionally, extended info)
  768. if an object id is found.
  769. Return Value:
  770. NTSTATUS - The return status for the operation.
  771. STATUS_OBJECT_NAME_NOT_FOUND if the file does not have an object id.
  772. --*/
  773. {
  774. NTSTATUS Status = STATUS_SUCCESS;
  775. UCHAR *ObjectId;
  776. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  777. BOOLEAN InitializedAttributeContext = FALSE;
  778. if ((OutputBuffer == NULL) ||
  779. (OutputBuffer->ObjectId == NULL)) {
  780. return STATUS_INVALID_PARAMETER;
  781. }
  782. //
  783. // Acquire the file we're getting the object id for. We don't
  784. // want anybody else deleting the file or setting an object
  785. // id behind our backs.
  786. //
  787. NtfsAcquireSharedFcb( IrpContext, Fcb, NULL, 0 );
  788. try {
  789. if (!IsListEmpty( &Fcb->ScbQueue )) {
  790. PSCB Scb;
  791. Scb = CONTAINING_RECORD( Fcb->ScbQueue.Flink, SCB, FcbLinks );
  792. ASSERT( Scb->Header.Resource == Fcb->Resource );
  793. if (FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  794. Status = STATUS_VOLUME_DISMOUNTED;
  795. leave;
  796. }
  797. }
  798. //
  799. // Make sure the file has an object id.
  800. //
  801. NtfsInitializeAttributeContext( &AttributeContext );
  802. InitializedAttributeContext = TRUE;
  803. if (NtfsLookupAttributeByCode( IrpContext,
  804. Fcb,
  805. &Fcb->FileReference,
  806. $OBJECT_ID,
  807. &AttributeContext )) {
  808. //
  809. // Prepare the object id to be returned
  810. //
  811. ObjectId = (UCHAR *) NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  812. RtlCopyMemory( &OutputBuffer->ObjectId,
  813. ObjectId,
  814. OBJECT_ID_KEY_LENGTH );
  815. if (GetExtendedInfo) {
  816. Status = NtfsGetObjectIdExtendedInfo( IrpContext,
  817. Fcb->Vcb,
  818. ObjectId,
  819. OutputBuffer->ExtendedInfo );
  820. }
  821. } else {
  822. //
  823. // This file has no object id.
  824. //
  825. Status = STATUS_OBJECTID_NOT_FOUND;
  826. }
  827. } finally {
  828. NtfsReleaseFcb( IrpContext, Fcb );
  829. if (InitializedAttributeContext) {
  830. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  831. }
  832. }
  833. return Status;
  834. }
  835. NTSTATUS
  836. NtfsGetObjectIdExtendedInfo (
  837. IN PIRP_CONTEXT IrpContext,
  838. IN PVCB Vcb,
  839. IN UCHAR *ObjectId,
  840. IN OUT UCHAR *ExtendedInfo
  841. )
  842. /*++
  843. Routine Description:
  844. This routine finds the extended info stored with a given object id.
  845. Arguments:
  846. Vcb - Supplies the volume whose object id index should be searched.
  847. ObjectId - Supplies the object id to lookup in the index.
  848. ExtendedInfo - Where to store the extended info. Must be a buffer with
  849. room for OBJECT_ID_EXT_INFO_LENGTH UCHARs.
  850. Return Value:
  851. NTSTATUS - The return status for the operation.
  852. --*/
  853. {
  854. NTSTATUS Status = STATUS_SUCCESS;
  855. INDEX_KEY IndexKey;
  856. INDEX_ROW IndexRow;
  857. MAP_HANDLE MapHandle;
  858. BOOLEAN InitializedMapHandle = FALSE;
  859. BOOLEAN IndexAcquired = FALSE;
  860. try {
  861. //
  862. // Now look for object id in the index so we can return the
  863. // extended info.
  864. //
  865. IndexKey.Key = ObjectId;
  866. IndexKey.KeyLength = OBJECT_ID_KEY_LENGTH;
  867. NtOfsInitializeMapHandle( &MapHandle );
  868. InitializedMapHandle = TRUE;
  869. //
  870. // Acquire the object id index before doing the lookup.
  871. // We need to make sure the file is acquired first to prevent
  872. // a possible deadlock.
  873. //
  874. // **** ASSERT_EXCLUSIVE_FCB( Fcb ); ****
  875. //
  876. // We shouldn't try to get the object id index while holding the Mft.
  877. //
  878. ASSERT( !NtfsIsExclusiveScb( Vcb->MftScb ) ||
  879. NtfsIsSharedScb( Vcb->ObjectIdTableScb ) );
  880. NtfsAcquireSharedScb( IrpContext, Vcb->ObjectIdTableScb );
  881. IndexAcquired = TRUE;
  882. if ( NtOfsFindRecord( IrpContext,
  883. Vcb->ObjectIdTableScb,
  884. &IndexKey,
  885. &IndexRow,
  886. &MapHandle,
  887. NULL) != STATUS_SUCCESS ) {
  888. //
  889. // If the object id attribute exists for the file,
  890. // but it isn't in the index, the object id index
  891. // for this volume is corrupt.
  892. //
  893. SetFlag( Vcb->ObjectIdState, VCB_OBJECT_ID_CORRUPT );
  894. try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
  895. }
  896. RtlCopyMemory( ExtendedInfo,
  897. ((NTFS_OBJECTID_INFORMATION *)IndexRow.DataPart.Data)->ExtendedInfo,
  898. OBJECT_ID_EXT_INFO_LENGTH );
  899. try_exit: NOTHING;
  900. } finally {
  901. if (IndexAcquired) {
  902. NtfsReleaseScb( IrpContext, Vcb->ObjectIdTableScb );
  903. }
  904. if (InitializedMapHandle) {
  905. NtOfsReleaseMap( IrpContext, &MapHandle );
  906. }
  907. }
  908. return Status;
  909. }
  910. NTSTATUS
  911. NtfsDeleteObjectId (
  912. IN PIRP_CONTEXT IrpContext,
  913. IN PIRP Irp
  914. )
  915. /*++
  916. Routine Description:
  917. This routine deletes the object id attribute from a file
  918. and removes that object id from the index.
  919. Arguments:
  920. Irp - Supplies the Irp to process
  921. Return Value:
  922. NTSTATUS - The return status for the operation.
  923. --*/
  924. {
  925. NTSTATUS Status = STATUS_SUCCESS;
  926. PIO_STACK_LOCATION IrpSp;
  927. TYPE_OF_OPEN TypeOfOpen;
  928. PVCB Vcb;
  929. PFCB Fcb;
  930. PSCB Scb;
  931. PCCB Ccb;
  932. //
  933. // Get the current Irp stack location and save some references.
  934. //
  935. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  936. TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  937. //
  938. // This only works for files and directories.
  939. //
  940. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  941. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  942. return STATUS_INVALID_PARAMETER;
  943. }
  944. //
  945. // Read only volumes stay read only.
  946. //
  947. if (NtfsIsVolumeReadOnly( Vcb )) {
  948. NtfsCompleteRequest( IrpContext, Irp, STATUS_MEDIA_WRITE_PROTECTED );
  949. return STATUS_MEDIA_WRITE_PROTECTED;
  950. }
  951. //
  952. // Cleanly exit for volumes without oid indices, such as non-upgraded
  953. // version 1.x volumes.
  954. //
  955. if (Vcb->ObjectIdTableScb == NULL) {
  956. NtfsCompleteRequest( IrpContext, Irp, STATUS_VOLUME_NOT_UPGRADED );
  957. return STATUS_VOLUME_NOT_UPGRADED;
  958. }
  959. //
  960. // Capture the source information.
  961. //
  962. IrpContext->SourceInfo = Ccb->UsnSourceInfo;
  963. try {
  964. //
  965. // Only a restore operator or the I/O system (using its private irp minor code)
  966. // is allowed to delete an object id.
  967. //
  968. if (FlagOn( Ccb->AccessFlags, RESTORE_ACCESS | WRITE_DATA_ACCESS) ||
  969. (IrpSp->MinorFunction == IRP_MN_KERNEL_CALL)) {
  970. Status = NtfsDeleteObjectIdInternal( IrpContext,
  971. Fcb,
  972. Vcb,
  973. TRUE );
  974. } else {
  975. Status = STATUS_ACCESS_DENIED;
  976. }
  977. } finally {
  978. //
  979. // Update the last change timestamp
  980. //
  981. if (NT_SUCCESS( Status )) {
  982. SetFlag( Ccb->Flags, CCB_FLAG_UPDATE_LAST_CHANGE );
  983. }
  984. //
  985. // If there was no object id - just return success
  986. //
  987. if (STATUS_OBJECTID_NOT_FOUND == Status) {
  988. Status = STATUS_SUCCESS;
  989. }
  990. if (!AbnormalTermination()) {
  991. NtfsCompleteRequest( IrpContext, Irp, Status );
  992. }
  993. }
  994. return Status;
  995. }
  996. NTSTATUS
  997. NtfsDeleteObjectIdInternal (
  998. IN PIRP_CONTEXT IrpContext,
  999. IN PFCB Fcb,
  1000. IN PVCB Vcb,
  1001. IN BOOLEAN DeleteFileAttribute
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. Internal function to (optionally) delete the object id attribute from
  1006. a file and remove that object id from the index.
  1007. Arguments:
  1008. Fcb - The file from which to delete the object id.
  1009. Vcb - The volume whose object id index the object id should be removed from.
  1010. DeleteFileAttribute - Specifies whether to delete the object id file attribute
  1011. from the file in addition to removing the id from the index.
  1012. Return Value:
  1013. NTSTATUS - The return status for the operation.
  1014. --*/
  1015. {
  1016. NTSTATUS Status = STATUS_SUCCESS;
  1017. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  1018. FILE_OBJECTID_INFORMATION FileObjectIdInfo;
  1019. INDEX_KEY IndexKey;
  1020. INDEX_ROW IndexRow;
  1021. MAP_HANDLE MapHandle;
  1022. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  1023. BOOLEAN InitializedAttributeContext = FALSE;
  1024. BOOLEAN InitializedMapHandle = FALSE;
  1025. BOOLEAN IndexAcquired = FALSE;
  1026. //
  1027. // Cleanly exit for volumes without oid indices, such as non-upgraded
  1028. // version 1.x volumes.
  1029. //
  1030. if (Vcb->ObjectIdTableScb == NULL) {
  1031. return STATUS_VOLUME_NOT_UPGRADED;
  1032. }
  1033. //
  1034. // Acquire the file we're deleting the object id from. We don't
  1035. // want anybody else deleting the file or object id behind
  1036. // our backs.
  1037. //
  1038. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  1039. try {
  1040. //
  1041. // We need to look up the object id. It's quite possible that
  1042. // this file has no object id, so we'll treat that as success.
  1043. //
  1044. Status = NtfsGetObjectIdInternal( IrpContext,
  1045. Fcb,
  1046. FALSE,
  1047. &ObjectIdBuffer );
  1048. if (Status != STATUS_SUCCESS) {
  1049. try_return( NOTHING );
  1050. }
  1051. //
  1052. // Look for object id in the index.
  1053. //
  1054. IndexKey.Key = ObjectIdBuffer.ObjectId;
  1055. IndexKey.KeyLength = sizeof( ObjectIdBuffer.ObjectId );
  1056. NtOfsInitializeMapHandle( &MapHandle );
  1057. InitializedMapHandle = TRUE;
  1058. //
  1059. // Acquire the object id index before doing the lookup.
  1060. // We need to make sure the file is acquired first to prevent
  1061. // a possible deadlock.
  1062. //
  1063. ASSERT_EXCLUSIVE_FCB( Fcb );
  1064. NtfsAcquireExclusiveScb( IrpContext, Vcb->ObjectIdTableScb );
  1065. IndexAcquired = TRUE;
  1066. if ( NtOfsFindRecord( IrpContext,
  1067. Vcb->ObjectIdTableScb,
  1068. &IndexKey,
  1069. &IndexRow,
  1070. &MapHandle,
  1071. NULL) != STATUS_SUCCESS ) {
  1072. try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
  1073. }
  1074. ASSERT( IndexRow.DataPart.DataLength == sizeof( NTFS_OBJECTID_INFORMATION ) );
  1075. //
  1076. // Copy objectid info into the correct buffer if we need it for the notify
  1077. // below.
  1078. //
  1079. if ((Vcb->ViewIndexNotifyCount != 0) &&
  1080. (IndexRow.DataPart.DataLength == sizeof( NTFS_OBJECTID_INFORMATION ))) {
  1081. //
  1082. // The FRS field is only populated for the notification of a failed
  1083. // object id restore from the tunnel cache.
  1084. //
  1085. FileObjectIdInfo.FileReference = 0L;
  1086. RtlCopyMemory( &FileObjectIdInfo.ObjectId,
  1087. ObjectIdBuffer.ObjectId,
  1088. OBJECT_ID_KEY_LENGTH );
  1089. RtlCopyMemory( &FileObjectIdInfo.ExtendedInfo,
  1090. ((NTFS_OBJECTID_INFORMATION *)IndexRow.DataPart.Data)->ExtendedInfo,
  1091. OBJECT_ID_EXT_INFO_LENGTH );
  1092. }
  1093. //
  1094. // Remove ObjectId from the index.
  1095. //
  1096. NtOfsDeleteRecords( IrpContext,
  1097. Vcb->ObjectIdTableScb,
  1098. 1, // deleting one record from the index
  1099. &IndexKey );
  1100. //
  1101. // Notify anybody who's interested. We use a different action if the
  1102. // object id is being deleted by the fsctl versus a delete file.
  1103. //
  1104. if (Vcb->ViewIndexNotifyCount != 0) {
  1105. NtfsReportViewIndexNotify( Vcb,
  1106. Vcb->ObjectIdTableScb->Fcb,
  1107. FILE_NOTIFY_CHANGE_FILE_NAME,
  1108. (DeleteFileAttribute ?
  1109. FILE_ACTION_REMOVED :
  1110. FILE_ACTION_REMOVED_BY_DELETE),
  1111. &FileObjectIdInfo,
  1112. sizeof(FILE_OBJECTID_INFORMATION) );
  1113. }
  1114. if (DeleteFileAttribute) {
  1115. //
  1116. // Post the change to the Usn Journal (on errors change is backed out)
  1117. //
  1118. NtfsPostUsnChange( IrpContext, Fcb, USN_REASON_OBJECT_ID_CHANGE );
  1119. //
  1120. // Now remove the object id attribute from the file.
  1121. //
  1122. NtfsInitializeAttributeContext( &AttributeContext );
  1123. InitializedAttributeContext = TRUE;
  1124. if (NtfsLookupAttributeByCode( IrpContext,
  1125. Fcb,
  1126. &Fcb->FileReference,
  1127. $OBJECT_ID,
  1128. &AttributeContext )) {
  1129. NtfsDeleteAttributeRecord( IrpContext,
  1130. Fcb,
  1131. DELETE_LOG_OPERATION |
  1132. DELETE_RELEASE_FILE_RECORD |
  1133. DELETE_RELEASE_ALLOCATION,
  1134. &AttributeContext );
  1135. } else {
  1136. //
  1137. // If the object id was in the index, but the attribute
  1138. // isn't on the file, then the object id index for this
  1139. // volume is corrupt. We can repair this corruption in
  1140. // the background, so let's start doing that now.
  1141. //
  1142. NtfsPostSpecial( IrpContext, Vcb, NtfsRepairObjectId, NULL );
  1143. }
  1144. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  1145. }
  1146. try_exit: NOTHING;
  1147. } finally {
  1148. if (InitializedMapHandle) {
  1149. NtOfsReleaseMap( IrpContext, &MapHandle );
  1150. }
  1151. if (InitializedAttributeContext) {
  1152. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  1153. }
  1154. }
  1155. return Status;
  1156. }
  1157. VOID
  1158. NtfsRepairObjectId (
  1159. IN PIRP_CONTEXT IrpContext,
  1160. IN PVOID Context
  1161. )
  1162. /*++
  1163. Routine Description:
  1164. This routine is called to repair the object Id index. This is called when
  1165. the system detects that the object Id index may be out of date. For example
  1166. after the volume was mounted on 4.0.
  1167. Arguments:
  1168. IrpContext - context of the call
  1169. Context - NULL
  1170. Return Value:
  1171. None
  1172. --*/
  1173. {
  1174. NTSTATUS Status = STATUS_SUCCESS;
  1175. BOOLEAN AcquiredVcb = FALSE;
  1176. BOOLEAN SetRepairFlag = FALSE;
  1177. BOOLEAN IncrementedCloseCounts = FALSE;
  1178. PBCB Bcb = NULL;
  1179. PVCB Vcb = IrpContext->Vcb;
  1180. PSCB ObjectIdScb;
  1181. PREAD_CONTEXT ReadContext = NULL;
  1182. PINDEX_ROW IndexRow = NULL;
  1183. PINDEX_ROW ObjectIdRow;
  1184. INDEX_KEY IndexKey;
  1185. MAP_HANDLE MapHandle;
  1186. PNTFS_OBJECTID_INFORMATION ObjectIdInfo;
  1187. PVOID RowBuffer = NULL;
  1188. ULONG Count;
  1189. ULONG i;
  1190. BOOLEAN IndexAcquired = FALSE;
  1191. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  1192. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  1193. LONGLONG MftOffset;
  1194. PAGED_CODE();
  1195. UNREFERENCED_PARAMETER( Context );
  1196. ASSERT( Vcb->MajorVersion >= NTFS_OBJECT_ID_VERSION );
  1197. //
  1198. // Use a try-except to catch errors.
  1199. //
  1200. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  1201. AcquiredVcb = TRUE;
  1202. try {
  1203. //
  1204. // Now that we're holding the Vcb, we can safely test for the presence
  1205. // of the ObjectId index, as well as whether the volume is mounted.
  1206. //
  1207. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  1208. (Vcb->ObjectIdTableScb != NULL) &&
  1209. (!FlagOn( Vcb->ObjectIdTableScb->ScbState, SCB_STATE_VOLUME_DISMOUNTED ))) {
  1210. ObjectIdScb = Vcb->ObjectIdTableScb;
  1211. NtfsAcquireExclusiveScb( IrpContext, ObjectIdScb );
  1212. IndexAcquired = TRUE;
  1213. //
  1214. // Since we'll be dropping the ObjectIdScb periodically, and we're
  1215. // not holding anything else, there's a chance that a dismount could
  1216. // happen, and make it unsafe for us to reacquire the ObjectIdScb.
  1217. // By incrementing the close counts, we keep it around as long as
  1218. // we need it.
  1219. //
  1220. NtfsIncrementCloseCounts( ObjectIdScb, TRUE, FALSE );
  1221. IncrementedCloseCounts = TRUE;
  1222. NtfsReleaseVcb( IrpContext, Vcb );
  1223. AcquiredVcb = FALSE;
  1224. } else {
  1225. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  1226. }
  1227. //
  1228. // The volume could've gotten write-protected by now.
  1229. //
  1230. if (NtfsIsVolumeReadOnly( Vcb )) {
  1231. NtfsRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED, NULL, NULL );
  1232. }
  1233. if (!FlagOn( Vcb->ObjectIdState, VCB_OBJECT_ID_REPAIR_RUNNING )) {
  1234. SetFlag( Vcb->ObjectIdState, VCB_OBJECT_ID_REPAIR_RUNNING );
  1235. SetRepairFlag = TRUE;
  1236. //
  1237. // Check the object id index. Periodically release all resources.
  1238. // See NtfsClearAndVerifyQuotaIndex
  1239. //
  1240. NtOfsInitializeMapHandle( &MapHandle );
  1241. //
  1242. // Allocate a buffer large enough for several rows.
  1243. //
  1244. RowBuffer = NtfsAllocatePool( PagedPool, PAGE_SIZE );
  1245. try {
  1246. //
  1247. // Allocate a bunch of index row entries.
  1248. //
  1249. Count = PAGE_SIZE / sizeof( NTFS_OBJECTID_INFORMATION );
  1250. IndexRow = NtfsAllocatePool( PagedPool,
  1251. Count * sizeof( INDEX_ROW ) );
  1252. //
  1253. // Iterate through the object id entries. Start at the beginning.
  1254. //
  1255. RtlZeroMemory( &ObjectIdBuffer, sizeof(ObjectIdBuffer) );
  1256. IndexKey.Key = ObjectIdBuffer.ObjectId;
  1257. IndexKey.KeyLength = sizeof( ObjectIdBuffer.ObjectId );
  1258. Status = NtOfsReadRecords( IrpContext,
  1259. ObjectIdScb,
  1260. &ReadContext,
  1261. &IndexKey,
  1262. NtOfsMatchAll,
  1263. NULL,
  1264. &Count,
  1265. IndexRow,
  1266. PAGE_SIZE,
  1267. RowBuffer );
  1268. while (NT_SUCCESS( Status )) {
  1269. //
  1270. // Acquire the VCB shared and check whether we should
  1271. // continue.
  1272. //
  1273. if (!NtfsIsVcbAvailable( Vcb )) {
  1274. //
  1275. // The volume is going away, bail out.
  1276. //
  1277. Status = STATUS_VOLUME_DISMOUNTED;
  1278. leave;
  1279. }
  1280. ObjectIdRow = IndexRow;
  1281. for (i = 0; i < Count; i++, ObjectIdRow++) {
  1282. ObjectIdInfo = ObjectIdRow->DataPart.Data;
  1283. //
  1284. // Make sure the mft record referenced in the index
  1285. // row still exists and hasn't been deleted, etc.
  1286. //
  1287. // We start by reading the disk and checking that the file record
  1288. // sequence number matches and that the file record is in use. If
  1289. // we find an invalid entry, we will simply delete it from the
  1290. // object id index.
  1291. //
  1292. MftOffset = NtfsFullSegmentNumber( &ObjectIdInfo->FileSystemReference );
  1293. MftOffset = Int64ShllMod32(MftOffset, Vcb->MftShift);
  1294. if (MftOffset >= Vcb->MftScb->Header.FileSize.QuadPart) {
  1295. DebugTrace( 0, Dbg, ("File Id doesn't lie within Mft FRS %04x:%08lx\n",
  1296. ObjectIdInfo->FileSystemReference.SequenceNumber,
  1297. ObjectIdInfo->FileSystemReference.SegmentNumberLowPart) );
  1298. NtOfsDeleteRecords( IrpContext,
  1299. ObjectIdScb,
  1300. 1, // deleting one record from the index
  1301. &ObjectIdRow->KeyPart );
  1302. } else {
  1303. NtfsReadMftRecord( IrpContext,
  1304. Vcb,
  1305. &ObjectIdInfo->FileSystemReference,
  1306. FALSE,
  1307. &Bcb,
  1308. &FileRecord,
  1309. NULL );
  1310. //
  1311. // This file record better be in use, have a matching sequence number and
  1312. // be the primary file record for this file.
  1313. //
  1314. if ((*((PULONG) FileRecord->MultiSectorHeader.Signature) != *((PULONG) FileSignature)) ||
  1315. !FlagOn( FileRecord->Flags, FILE_RECORD_SEGMENT_IN_USE ) ||
  1316. (FileRecord->SequenceNumber != ObjectIdInfo->FileSystemReference.SequenceNumber) ||
  1317. (*((PLONGLONG) &FileRecord->BaseFileRecordSegment) != 0)) {
  1318. DebugTrace( 0, Dbg, ("RepairOID removing an orphaned OID\n") );
  1319. NtOfsDeleteRecords( IrpContext,
  1320. ObjectIdScb,
  1321. 1, // deleting one record from the index
  1322. &ObjectIdRow->KeyPart );
  1323. } else {
  1324. DebugTrace( 0, Dbg, ("RepairOID happy with OID %08lx on FRS %04x:%08lx\n",
  1325. *((PULONG) ObjectIdRow->KeyPart.Key),
  1326. ObjectIdInfo->FileSystemReference.SequenceNumber,
  1327. ObjectIdInfo->FileSystemReference.SegmentNumberLowPart) );
  1328. }
  1329. NtfsUnpinBcb( IrpContext, &Bcb );
  1330. }
  1331. }
  1332. //
  1333. // Release the index and commit what has been done so far.
  1334. //
  1335. ASSERT( IndexAcquired );
  1336. NtfsReleaseScb( IrpContext, ObjectIdScb );
  1337. IndexAcquired = FALSE;
  1338. //
  1339. // Complete the request which commits the pending
  1340. // transaction if there is one and releases of the
  1341. // acquired resources. The IrpContext will not
  1342. // be deleted because the no delete flag is set.
  1343. //
  1344. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE | IRP_CONTEXT_FLAG_RETAIN_FLAGS );
  1345. NtfsCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
  1346. //
  1347. // Remember how far we got so we can restart correctly. **** ??? ****
  1348. //
  1349. // Vcb->QuotaFileReference.SegmentNumberLowPart =
  1350. // *((PULONG) IndexRow[Count - 1].KeyPart.Key);
  1351. //
  1352. // Reacquire the object id index for the next pass.
  1353. //
  1354. NtfsAcquireExclusiveScb( IrpContext, ObjectIdScb );
  1355. IndexAcquired = TRUE;
  1356. //
  1357. // Make sure a dismount didn't occur while we weren't holding any
  1358. // resources.
  1359. //
  1360. if (FlagOn( ObjectIdScb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  1361. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  1362. }
  1363. //
  1364. // Look up the next set of entries in the object id index.
  1365. //
  1366. Count = PAGE_SIZE / sizeof( NTFS_OBJECTID_INFORMATION );
  1367. Status = NtOfsReadRecords( IrpContext,
  1368. ObjectIdScb,
  1369. &ReadContext,
  1370. NULL,
  1371. NtOfsMatchAll,
  1372. NULL,
  1373. &Count,
  1374. IndexRow,
  1375. PAGE_SIZE,
  1376. RowBuffer );
  1377. }
  1378. ASSERT( (Status == STATUS_NO_MORE_MATCHES) ||
  1379. (Status == STATUS_NO_MATCH) );
  1380. } finally {
  1381. NtfsUnpinBcb( IrpContext, &Bcb );
  1382. NtfsFreePool( RowBuffer );
  1383. NtOfsReleaseMap( IrpContext, &MapHandle );
  1384. if (IndexAcquired) {
  1385. NtfsReleaseScb( IrpContext, ObjectIdScb );
  1386. IndexAcquired = FALSE;
  1387. }
  1388. if (IndexRow != NULL) {
  1389. NtfsFreePool( IndexRow );
  1390. }
  1391. if (ReadContext != NULL) {
  1392. NtOfsFreeReadContext( ReadContext );
  1393. }
  1394. }
  1395. //
  1396. // Acquire the Vcb to clear the object ID flag on disk. Since we got the
  1397. // Vcb shared before, we better not still be holding it when we try to
  1398. // get it exclusively now or else we'll have a one thread deadlock.
  1399. //
  1400. ASSERT( !AcquiredVcb );
  1401. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  1402. AcquiredVcb = TRUE;
  1403. if (!NtfsIsVcbAvailable( Vcb )) {
  1404. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  1405. }
  1406. //
  1407. // Clear the on-disk flag indicating the repair is underway.
  1408. //
  1409. NtfsSetVolumeInfoFlagState( IrpContext,
  1410. Vcb,
  1411. VOLUME_REPAIR_OBJECT_ID,
  1412. FALSE,
  1413. TRUE );
  1414. //
  1415. // Make sure we don't own any resources at this point.
  1416. //
  1417. NtfsPurgeFileRecordCache( IrpContext );
  1418. NtfsCheckpointCurrentTransaction( IrpContext );
  1419. }
  1420. } except( NtfsExceptionFilter( IrpContext, GetExceptionInformation())) {
  1421. Status = IrpContext->TopLevelIrpContext->ExceptionStatus;
  1422. }
  1423. //
  1424. // Clear the repair_running flag if we're the ones who set it, making sure
  1425. // to only change the ObjectIdState bits while holding the ObjectId index.
  1426. //
  1427. if (SetRepairFlag) {
  1428. if (!IndexAcquired) {
  1429. NtfsAcquireExclusiveScb( IrpContext, ObjectIdScb );
  1430. IndexAcquired = TRUE;
  1431. }
  1432. ClearFlag( Vcb->ObjectIdState, VCB_OBJECT_ID_REPAIR_RUNNING );
  1433. }
  1434. if (IncrementedCloseCounts) {
  1435. if (!IndexAcquired) {
  1436. NtfsAcquireExclusiveScb( IrpContext, ObjectIdScb );
  1437. IndexAcquired = TRUE;
  1438. }
  1439. NtfsDecrementCloseCounts( IrpContext, ObjectIdScb, NULL, TRUE, FALSE, FALSE, NULL );
  1440. }
  1441. //
  1442. // Drop the index and the Vcb.
  1443. //
  1444. if (IndexAcquired) {
  1445. NtfsReleaseScb( IrpContext, ObjectIdScb );
  1446. }
  1447. if (AcquiredVcb) {
  1448. NtfsReleaseVcb( IrpContext, Vcb );
  1449. }
  1450. //
  1451. // If this is a fatal failure then do any final cleanup.
  1452. //
  1453. if (!NT_SUCCESS( Status )) {
  1454. //
  1455. // If we will not be called back then clear the running state bits.
  1456. //
  1457. if ((Status != STATUS_CANT_WAIT) && (Status != STATUS_LOG_FILE_FULL)) {
  1458. //
  1459. // Do we want to log this error? Some may be expected (i.e. STATUS_VOLUME_DISMOUNTED ).
  1460. //
  1461. // NtfsLogEvent( IrpContext, NULL, IO_FILE_OBJECTID_REPAIR_FAILED, Status );
  1462. }
  1463. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  1464. }
  1465. }
  1466. //
  1467. // Local support routine
  1468. //
  1469. NTSTATUS
  1470. NtfsSetObjectIdExtendedInfoInternal (
  1471. IN PIRP_CONTEXT IrpContext,
  1472. IN PFCB Fcb,
  1473. IN PVCB Vcb,
  1474. IN PUCHAR ExtendedInfoBuffer
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. This routine sets the extended info for a file which already has an object
  1479. id. If the file does not yet have an object id, we return a status other
  1480. than STATUS_SUCCESS.
  1481. Arguments:
  1482. Fcb - The file whose extended info is to be set.
  1483. Vcb - The volume whose object id index the entry should be modified in.
  1484. ExtendedInfoBuffer - Supplies the new extended info.
  1485. Return Value:
  1486. NTSTATUS - The return status for the operation.
  1487. --*/
  1488. {
  1489. NTSTATUS Status;
  1490. NTFS_OBJECTID_INFORMATION ObjectIdInfo;
  1491. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  1492. INDEX_ROW IndexRow;
  1493. PAGED_CODE();
  1494. Status = NtfsGetObjectIdInternal( IrpContext,
  1495. Fcb,
  1496. FALSE, // GetExtendedInfo
  1497. &ObjectIdBuffer );
  1498. if (Status != STATUS_SUCCESS) {
  1499. //
  1500. // This file may not have an object id yet.
  1501. //
  1502. return Status;
  1503. }
  1504. //
  1505. // Setup the index row for updating. Since part of the data
  1506. // is passed into this function (the new extended info) and
  1507. // the rest can be determined easily (the file reference), we
  1508. // don't need to look up any of the existing data before
  1509. // proceeding. If the NTFS_OBJECTID_INFORMATION structure
  1510. // ever changes, this code may have to be changed to include
  1511. // a lookup of the data currently in the object id index.
  1512. //
  1513. RtlCopyMemory( &ObjectIdInfo.FileSystemReference,
  1514. &Fcb->FileReference,
  1515. sizeof( ObjectIdInfo.FileSystemReference ) );
  1516. RtlCopyMemory( &ObjectIdInfo.ExtendedInfo,
  1517. ExtendedInfoBuffer,
  1518. OBJECT_ID_EXT_INFO_LENGTH );
  1519. IndexRow.DataPart.Data = &ObjectIdInfo;
  1520. IndexRow.DataPart.DataLength = sizeof( NTFS_OBJECTID_INFORMATION );
  1521. IndexRow.KeyPart.Key = &ObjectIdBuffer;
  1522. IndexRow.KeyPart.KeyLength = OBJECT_ID_KEY_LENGTH;
  1523. //
  1524. // Acquire the file and the object id index before doing the modification.
  1525. //
  1526. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  1527. NtfsAcquireExclusiveScb( IrpContext, Vcb->ObjectIdTableScb );
  1528. //
  1529. // Post the change to the Usn Journal (on errors change is backed out)
  1530. //
  1531. NtfsPostUsnChange( IrpContext, Fcb, USN_REASON_OBJECT_ID_CHANGE );
  1532. //
  1533. // Update the ObjectId index record's data in place.
  1534. //
  1535. NtOfsUpdateRecord( IrpContext,
  1536. Vcb->ObjectIdTableScb,
  1537. 1, // Count
  1538. &IndexRow,
  1539. NULL, // QuickIndexHint
  1540. NULL ); // MapHandle
  1541. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  1542. return Status;
  1543. }
  1544. //
  1545. // Local support routine
  1546. //
  1547. VOID
  1548. NtfsGetIdFromGenerator (
  1549. OUT PFILE_OBJECTID_BUFFER ObjectId
  1550. )
  1551. /*++
  1552. Routine Description:
  1553. This function conjures up a random object id.
  1554. Arguments:
  1555. ObjectId - The location where the generated object id will be stored.
  1556. Return Value:
  1557. None.
  1558. --*/
  1559. {
  1560. PAGED_CODE( );
  1561. //
  1562. // Cal the id generator.
  1563. //
  1564. ExUuidCreate( (UUID *)ObjectId->ObjectId );
  1565. }