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.

1837 lines
53 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. VAttrSup.c
  5. Abstract:
  6. This module implements the attribute routines for NtOfs
  7. Author:
  8. Tom Miller [TomM] 10-Apr-1996
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. //
  13. // Define a tag for general pool allocations from this module
  14. //
  15. #undef MODULE_POOL_TAG
  16. #define MODULE_POOL_TAG ('vFtN')
  17. #undef NtOfsMapAttribute
  18. NTFSAPI
  19. VOID
  20. NtOfsMapAttribute (
  21. IN PIRP_CONTEXT IrpContext,
  22. IN PSCB Scb,
  23. IN LONGLONG Offset,
  24. IN ULONG Length,
  25. OUT PVOID *Buffer,
  26. OUT PMAP_HANDLE MapHandle
  27. );
  28. #undef NtOfsPreparePinWrite
  29. NTFSAPI
  30. VOID
  31. NtOfsPreparePinWrite (
  32. IN PIRP_CONTEXT IrpContext,
  33. IN PSCB Scb,
  34. IN LONGLONG Offset,
  35. IN ULONG Length,
  36. OUT PVOID *Buffer,
  37. OUT PMAP_HANDLE MapHandle
  38. );
  39. #undef NtOfsPinRead
  40. NTFSAPI
  41. VOID
  42. NtOfsPinRead(
  43. IN PIRP_CONTEXT IrpContext,
  44. IN PSCB Scb,
  45. IN LONGLONG Offset,
  46. IN ULONG Length,
  47. OUT PMAP_HANDLE MapHandle
  48. );
  49. #undef NtOfsReleaseMap
  50. NTFSAPI
  51. VOID
  52. NtOfsReleaseMap (
  53. IN PIRP_CONTEXT IrpContext,
  54. IN PMAP_HANDLE MapHandle
  55. );
  56. #ifdef ALLOC_PRAGMA
  57. #pragma alloc_text(PAGE, NtOfsCreateAttribute)
  58. #pragma alloc_text(PAGE, NtOfsCreateAttributeEx)
  59. #pragma alloc_text(PAGE, NtOfsCloseAttribute)
  60. #pragma alloc_text(PAGE, NtOfsDeleteAttribute)
  61. #pragma alloc_text(PAGE, NtOfsQueryLength)
  62. #pragma alloc_text(PAGE, NtOfsSetLength)
  63. #pragma alloc_text(PAGE, NtfsHoldIrpForNewLength)
  64. #pragma alloc_text(PAGE, NtOfsPostNewLength)
  65. #pragma alloc_text(PAGE, NtOfsFlushAttribute)
  66. #pragma alloc_text(PAGE, NtOfsPutData)
  67. #pragma alloc_text(PAGE, NtOfsMapAttribute)
  68. #pragma alloc_text(PAGE, NtOfsReleaseMap)
  69. #endif
  70. NTFSAPI
  71. NTSTATUS
  72. NtOfsCreateAttribute (
  73. IN PIRP_CONTEXT IrpContext,
  74. IN PFCB Fcb,
  75. IN UNICODE_STRING Name,
  76. IN CREATE_OPTIONS CreateOptions,
  77. IN ULONG LogNonresidentToo,
  78. OUT PSCB *ReturnScb
  79. )
  80. /*++
  81. Routine Description:
  82. This routine may be called to create / open a named data attribute
  83. within a given file, which may or may not be recoverable.
  84. Arguments:
  85. Fcb - File in which the attribute is to be created. It is acquired exclusive
  86. Name - Name of the attribute for all related Scbs and attributes on disk.
  87. CreateOptions - Standard create flags.
  88. LogNonresidentToo - Supplies nonzero if updates to the attribute should
  89. be logged.
  90. ReturnScb - Returns an Scb as handle for the attribute.
  91. Return Value:
  92. STATUS_OBJECT_NAME_COLLISION -- if CreateNew and attribute already exists
  93. STATUS_OBJECT_NAME_NOT_FOUND -- if OpenExisting and attribute does not exist
  94. --*/
  95. {
  96. return NtOfsCreateAttributeEx( IrpContext,
  97. Fcb,
  98. Name,
  99. $DATA,
  100. CreateOptions,
  101. LogNonresidentToo,
  102. ReturnScb );
  103. }
  104. NTFSAPI
  105. NTSTATUS
  106. NtOfsCreateAttributeEx (
  107. IN PIRP_CONTEXT IrpContext,
  108. IN PFCB Fcb,
  109. IN UNICODE_STRING Name,
  110. IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
  111. IN CREATE_OPTIONS CreateOptions,
  112. IN ULONG LogNonresidentToo,
  113. OUT PSCB *ReturnScb
  114. )
  115. /*++
  116. Routine Description:
  117. This routine may be called to create / open a named data attribute
  118. within a given file, which may or may not be recoverable.
  119. Arguments:
  120. Fcb - File in which the attribute is to be created. It is acquired exclusive
  121. Name - Name of the attribute for all related Scbs and attributes on disk.
  122. CreateOptions - Standard create flags.
  123. LogNonresidentToo - Supplies nonzero if updates to the attribute should
  124. be logged.
  125. ReturnScb - Returns an Scb as handle for the attribute.
  126. Return Value:
  127. STATUS_OBJECT_NAME_COLLISION -- if CreateNew and attribute already exists
  128. STATUS_OBJECT_NAME_NOT_FOUND -- if OpenExisting and attribute does not exist
  129. --*/
  130. {
  131. ATTRIBUTE_ENUMERATION_CONTEXT LocalContext;
  132. BOOLEAN FoundAttribute;
  133. NTSTATUS Status = STATUS_SUCCESS;
  134. PSCB Scb = NULL;
  135. ASSERT_IRP_CONTEXT( IrpContext );
  136. ASSERT( NtfsIsExclusiveFcb( Fcb ));
  137. PAGED_CODE();
  138. if (AttributeTypeCode != $DATA &&
  139. AttributeTypeCode != $LOGGED_UTILITY_STREAM) {
  140. ASSERTMSG( "Invalid attribute type code in NtOfsCreateAttributeEx", FALSE );
  141. *ReturnScb = NULL;
  142. return STATUS_INVALID_PARAMETER;
  143. }
  144. //
  145. // Now, just create the Data Attribute.
  146. //
  147. NtfsInitializeAttributeContext( &LocalContext );
  148. try {
  149. //
  150. // First see if the attribute already exists, by searching for the root
  151. // attribute.
  152. //
  153. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  154. Fcb,
  155. &Fcb->FileReference,
  156. AttributeTypeCode,
  157. &Name,
  158. NULL,
  159. TRUE,
  160. &LocalContext );
  161. //
  162. // If it is not there, and the CreateOptions allow, then let's create
  163. // the attribute root now. (First cleaning up the attribute context from
  164. // the lookup).
  165. //
  166. if (!FoundAttribute && (CreateOptions <= CREATE_OR_OPEN)) {
  167. //
  168. // Make sure we acquire the quota resource before creating the stream. Just
  169. // in case we need the Mft during the create.
  170. //
  171. if (NtfsIsTypeCodeSubjectToQuota( AttributeTypeCode ) &&
  172. NtfsPerformQuotaOperation( Fcb )) {
  173. //
  174. // The quota index must be acquired before the mft scb is acquired.
  175. //
  176. ASSERT( !NtfsIsExclusiveScb( Fcb->Vcb->MftScb ) ||
  177. NtfsIsSharedScb( Fcb->Vcb->QuotaTableScb ) );
  178. NtfsAcquireQuotaControl( IrpContext, Fcb->QuotaControl );
  179. }
  180. NtfsCleanupAttributeContext( IrpContext, &LocalContext );
  181. NtfsCreateAttributeWithValue( IrpContext,
  182. Fcb,
  183. AttributeTypeCode,
  184. &Name,
  185. NULL,
  186. 0,
  187. 0,
  188. NULL,
  189. TRUE,
  190. &LocalContext );
  191. //
  192. // If the attribute is already there, and we were asked to create it, then
  193. // return an error.
  194. //
  195. } else if (FoundAttribute && (CreateOptions == CREATE_NEW)) {
  196. Status = STATUS_OBJECT_NAME_COLLISION;
  197. leave;
  198. //
  199. // If the attribute is not there, and we were supposed to open existing, then
  200. // return an error.
  201. //
  202. } else if (!FoundAttribute) {
  203. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  204. leave;
  205. }
  206. //
  207. // Otherwise create/find the Scb and reference it.
  208. //
  209. Scb = NtfsCreateScb( IrpContext, Fcb, AttributeTypeCode, &Name, FALSE, &FoundAttribute );
  210. //
  211. // Make sure things are correctly reference counted
  212. //
  213. NtfsIncrementCloseCounts( Scb, TRUE, FALSE );
  214. //
  215. // If we created the Scb, then get the no modified write set correctly.
  216. //
  217. ASSERT( !FoundAttribute ||
  218. (LogNonresidentToo == BooleanFlagOn(Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE)) );
  219. if (!FoundAttribute && LogNonresidentToo) {
  220. SetFlag( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE );
  221. Scb->Header.ValidDataLength.QuadPart = MAXLONGLONG;
  222. }
  223. //
  224. // Make sure the stream can be mapped internally. Defer this for the Usn journal
  225. // until we set up the journal bias.
  226. //
  227. if ((Scb->FileObject == NULL) && !FlagOn( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL )) {
  228. NtfsCreateInternalAttributeStream( IrpContext, Scb, TRUE, NULL );
  229. }
  230. NtfsUpdateScbFromAttribute( IrpContext, Scb, NtfsFoundAttribute(&LocalContext) );
  231. } finally {
  232. if (AbnormalTermination( )) {
  233. if (Scb != NULL) {
  234. NtOfsCloseAttribute( IrpContext, Scb );
  235. }
  236. }
  237. NtfsCleanupAttributeContext( IrpContext, &LocalContext );
  238. }
  239. *ReturnScb = Scb;
  240. return Status;
  241. }
  242. NTFSAPI
  243. VOID
  244. NtOfsCloseAttribute (
  245. IN PIRP_CONTEXT IrpContext,
  246. IN PSCB Scb
  247. )
  248. /*++
  249. Routine Description:
  250. This routine may be called to close a previously returned handle on an attribute.
  251. Arguments:
  252. Scb - Supplies an Scb as the previously returned handle for this attribute.
  253. Return Value:
  254. None.
  255. --*/
  256. {
  257. ASSERT( NtfsIsExclusiveFcb( Scb->Fcb ));
  258. PAGED_CODE();
  259. //
  260. // We either need the caller to empty this list before closing (as assumed here),
  261. // or possibly empty it here. At this point it seems better to assume that the
  262. // caller must take action to insure any waiting threads will shutdown and not
  263. // touch the stream anymore, then call NtOfsPostNewLength to flush the queue.
  264. // If the queue is nonempty here, maybe the caller didn't think this through!
  265. //
  266. ASSERT( IsListEmpty( &Scb->ScbType.Data.WaitForNewLength ) ||
  267. (Scb->CloseCount > 1) );
  268. NtfsDecrementCloseCounts( IrpContext, Scb, NULL, TRUE, FALSE, TRUE, NULL );
  269. }
  270. NTFSAPI
  271. VOID
  272. NtOfsDeleteAttribute (
  273. IN PIRP_CONTEXT IrpContext,
  274. IN PFCB Fcb,
  275. IN PSCB Scb
  276. )
  277. /*++
  278. Routine Description:
  279. This routine may be called to delete an attribute with type code
  280. $LOGGED_UTILITY_STREAM.
  281. Arguments:
  282. Fcb - Supplies an Fcb as the previously returned object handle for the file
  283. Scb - Supplies an Scb as the previously returned handle for this attribute.
  284. Return Value:
  285. None (Deleting a nonexistant index is benign).
  286. --*/
  287. {
  288. ATTRIBUTE_ENUMERATION_CONTEXT LocalContext;
  289. BOOLEAN FoundAttribute;
  290. ASSERT_IRP_CONTEXT( IrpContext );
  291. PAGED_CODE();
  292. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  293. try {
  294. //
  295. // Make sure we aren't deleting a data stream. We do this after
  296. // initializing the attribute context to make the finally clause simpler.
  297. // This test can be removed if some trusted component using the NtOfs
  298. // API has a legitimate need to delete other types of attributes.
  299. //
  300. NtfsInitializeAttributeContext( &LocalContext );
  301. if (Scb->AttributeTypeCode != $LOGGED_UTILITY_STREAM) {
  302. leave;
  303. }
  304. //
  305. // First see if there is some attribute allocation, and if so truncate it
  306. // away allowing this operation to be broken up.
  307. //
  308. if (NtfsLookupAttributeByName( IrpContext,
  309. Fcb,
  310. &Fcb->FileReference,
  311. Scb->AttributeTypeCode,
  312. &Scb->AttributeName,
  313. NULL,
  314. FALSE,
  315. &LocalContext )
  316. &&
  317. !NtfsIsAttributeResident( NtfsFoundAttribute( &LocalContext ))) {
  318. ASSERT( Scb->FileObject != NULL );
  319. NtfsDeleteAllocation( IrpContext, NULL, Scb, 0, MAXLONGLONG, TRUE, TRUE );
  320. }
  321. NtfsCleanupAttributeContext( IrpContext, &LocalContext );
  322. //
  323. // Initialize the attribute context on each trip through the loop.
  324. //
  325. NtfsInitializeAttributeContext( &LocalContext );
  326. //
  327. // Now there should be a single attribute record, so look it up and delete it.
  328. //
  329. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  330. Fcb,
  331. &Fcb->FileReference,
  332. Scb->AttributeTypeCode,
  333. &Scb->AttributeName,
  334. NULL,
  335. TRUE,
  336. &LocalContext );
  337. //
  338. // If this stream is subject to quota, make sure the quota has been enlarged.
  339. //
  340. NtfsDeleteAttributeRecord( IrpContext,
  341. Fcb,
  342. (DELETE_LOG_OPERATION |
  343. DELETE_RELEASE_FILE_RECORD |
  344. DELETE_RELEASE_ALLOCATION),
  345. &LocalContext );
  346. SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  347. } finally {
  348. NtfsReleaseFcb( IrpContext, Fcb );
  349. NtfsCleanupAttributeContext( IrpContext, &LocalContext );
  350. }
  351. return;
  352. }
  353. NTFSAPI
  354. LONGLONG
  355. NtOfsQueryLength (
  356. IN PSCB Scb
  357. )
  358. /*++
  359. Routine Description:
  360. This routine may be called to query the Length (FileSize) of an attribute.
  361. Arguments:
  362. Scb - Supplies an Scb as the previously returned handle for this attribute.
  363. Length - Returns the current Length of the attribute.
  364. Return Value:
  365. None (Deleting a nonexistant index is benign).
  366. --*/
  367. {
  368. LONGLONG Length;
  369. PAGED_CODE();
  370. NtfsAcquireFsrtlHeader( Scb );
  371. Length = Scb->Header.FileSize.QuadPart;
  372. NtfsReleaseFsrtlHeader( Scb );
  373. return Length;
  374. }
  375. NTFSAPI
  376. VOID
  377. NtOfsSetLength (
  378. IN PIRP_CONTEXT IrpContext,
  379. IN PSCB Scb,
  380. IN LONGLONG Length
  381. )
  382. /*++
  383. Routine Description:
  384. This routine may be called to set the Length (FileSize) of an attribute.
  385. Arguments:
  386. Scb - Supplies an Scb as the previously returned handle for this attribute.
  387. Length - Supplies the new Length for the attribute.
  388. Return Value:
  389. None (Deleting a nonexistant index is benign).
  390. --*/
  391. {
  392. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  393. PFILE_OBJECT FileObject = Scb->FileObject;
  394. PFCB Fcb = Scb->Fcb;
  395. PVCB Vcb = Scb->Vcb;
  396. BOOLEAN DoingIoAtEof = FALSE;
  397. BOOLEAN Truncating = FALSE;
  398. BOOLEAN CleanupAttrContext = FALSE;
  399. ASSERT_IRP_CONTEXT( IrpContext );
  400. ASSERT_SCB( Scb );
  401. ASSERT( NtfsIsExclusiveScb( Scb ));
  402. ASSERT(FileObject != NULL);
  403. PAGED_CODE();
  404. try {
  405. //
  406. // If this is a resident attribute we will try to keep it resident.
  407. //
  408. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  409. //
  410. // If the new file size is larger than a file record then convert
  411. // to non-resident and use the non-resident code below. Otherwise
  412. // call ChangeAttributeValue which may also convert to nonresident.
  413. //
  414. NtfsInitializeAttributeContext( &AttrContext );
  415. CleanupAttrContext = TRUE;
  416. NtfsLookupAttributeForScb( IrpContext,
  417. Scb,
  418. NULL,
  419. &AttrContext );
  420. //
  421. // Either convert or change the attribute value.
  422. //
  423. if (Length >= Scb->Vcb->BytesPerFileRecordSegment) {
  424. NtfsConvertToNonresident( IrpContext,
  425. Fcb,
  426. NtfsFoundAttribute( &AttrContext ),
  427. FALSE,
  428. &AttrContext );
  429. } else {
  430. ULONG AttributeOffset;
  431. //
  432. // We are sometimes called by MM during a create section, so
  433. // for right now the best way we have of detecting a create
  434. // section is whether or not the requestor mode is kernel.
  435. //
  436. if ((ULONG)Length > Scb->Header.FileSize.LowPart) {
  437. AttributeOffset = Scb->Header.FileSize.LowPart;
  438. } else {
  439. AttributeOffset = (ULONG) Length;
  440. }
  441. //
  442. // ****TEMP Ideally we would do this simple case by hand.
  443. //
  444. NtfsChangeAttributeValue( IrpContext,
  445. Fcb,
  446. AttributeOffset,
  447. NULL,
  448. (ULONG)Length - AttributeOffset,
  449. TRUE,
  450. FALSE,
  451. FALSE,
  452. FALSE,
  453. &AttrContext );
  454. NtfsAcquireFsrtlHeader( Scb );
  455. Scb->Header.FileSize.QuadPart = Length;
  456. //
  457. // If the file went non-resident, then the allocation size in
  458. // the Scb is correct. Otherwise we quad-align the new file size.
  459. //
  460. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  461. Scb->Header.AllocationSize.LowPart = QuadAlign( Scb->Header.FileSize.LowPart );
  462. if (Scb->Header.ValidDataLength.QuadPart != MAXLONGLONG) {
  463. Scb->Header.ValidDataLength.QuadPart = Length;
  464. }
  465. Scb->TotalAllocated = Scb->Header.AllocationSize.QuadPart;
  466. } else {
  467. SetFlag( Scb->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
  468. }
  469. NtfsReleaseFsrtlHeader( Scb );
  470. //
  471. // Now update Cc.
  472. //
  473. CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Scb->Header.AllocationSize );
  474. //
  475. // ****TEMP**** This hack is awaiting our actually doing this change
  476. // in CcSetFileSizes.
  477. //
  478. *((PLONGLONG)(Scb->NonpagedScb->SegmentObject.SharedCacheMap) + 5) = Length;
  479. leave;
  480. }
  481. }
  482. //
  483. // Nonresident path
  484. //
  485. // Now determine where the new file size lines up with the
  486. // current file layout. The two cases we need to consider are
  487. // where the new file size is less than the current file size and
  488. // valid data length, in which case we need to shrink them.
  489. // Or we new file size is greater than the current allocation,
  490. // in which case we need to extend the allocation to match the
  491. // new file size.
  492. //
  493. if (Length > Scb->Header.AllocationSize.QuadPart) {
  494. LONGLONG NewAllocationSize = Length;
  495. BOOLEAN AskForMore = TRUE;
  496. //
  497. // See if this is the Usn Journal to enforce allocation granularity.
  498. //
  499. // **** Temporary - this support should be generalized with an Scb field
  500. // settable by all callers.
  501. //
  502. if (Scb == Vcb->UsnJournal) {
  503. LONGLONG MaxAllocation;
  504. //
  505. // Limit ourselves to 128 runs. We don't want to commit in the
  506. // middle of the allocation.
  507. //
  508. NewAllocationSize = MAXIMUM_RUNS_AT_ONCE * Vcb->BytesPerCluster;
  509. //
  510. // Don't use more than 1/4 of the free space on the volume.
  511. //
  512. MaxAllocation = Int64ShllMod32( Vcb->FreeClusters, Vcb->ClusterShift - 2 );
  513. if (NewAllocationSize > MaxAllocation) {
  514. //
  515. // Round down to the Max. Don't worry if there is nothing, our code
  516. // below will catch this case and the allocation package always rounds
  517. // to a compression unit boundary.
  518. //
  519. NewAllocationSize = MaxAllocation;
  520. }
  521. //
  522. // Don't grow by more than the Usn delta.
  523. //
  524. if (NewAllocationSize > (LONGLONG) Vcb->UsnJournalInstance.AllocationDelta) {
  525. NewAllocationSize = (LONGLONG) Vcb->UsnJournalInstance.AllocationDelta;
  526. }
  527. NewAllocationSize += (LONGLONG) Scb->Header.AllocationSize.QuadPart;
  528. //
  529. // Handle possible weird case.
  530. //
  531. if (NewAllocationSize < Length) {
  532. NewAllocationSize = Length;
  533. }
  534. //
  535. // Always pad the allocation to a compression unit boundary.
  536. //
  537. ASSERT( Scb->CompressionUnit != 0 );
  538. NewAllocationSize = BlockAlign( NewAllocationSize, (LONG)Scb->CompressionUnit );
  539. AskForMore = FALSE;
  540. } else if (Scb->Header.PagingIoResource == NULL) {
  541. //
  542. // If the file is sparse then make sure we allocate a full compression unit.
  543. // Otherwise we can end up with a partially allocated chunk in the Usn
  544. // Journal.
  545. //
  546. if (Scb->CompressionUnit != 0) {
  547. NewAllocationSize = BlockAlign( NewAllocationSize, (LONG)Scb->CompressionUnit );
  548. }
  549. AskForMore = FALSE;
  550. }
  551. //
  552. // Add the allocation. Never ask for extra for logged streams.
  553. //
  554. NtfsAddAllocation( IrpContext,
  555. FileObject,
  556. Scb,
  557. LlClustersFromBytes( Scb->Vcb, Scb->Header.AllocationSize.QuadPart ),
  558. LlClustersFromBytes(Scb->Vcb, (NewAllocationSize - Scb->Header.AllocationSize.QuadPart)),
  559. AskForMore,
  560. NULL );
  561. NtfsAcquireFsrtlHeader( Scb );
  562. //
  563. // Otherwise see if we have to knock these numbers down...
  564. //
  565. } else {
  566. NtfsAcquireFsrtlHeader( Scb );
  567. if ((Length < Scb->Header.ValidDataLength.QuadPart) &&
  568. (Scb->Header.ValidDataLength.QuadPart != MAXLONGLONG)) {
  569. Scb->Header.ValidDataLength.QuadPart = Length;
  570. }
  571. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK ) &&
  572. (Length < Scb->ValidDataToDisk)) {
  573. Scb->ValidDataToDisk = Length;
  574. }
  575. }
  576. //
  577. // Now put the new size in the Scb.
  578. //
  579. Scb->Header.FileSize.QuadPart = Length;
  580. NtfsReleaseFsrtlHeader( Scb );
  581. //
  582. // Call our common routine to modify the file sizes. We are now
  583. // done with Length and NewValidDataLength, and we have
  584. // PagingIo + main exclusive (so no one can be working on this Scb).
  585. // NtfsWriteFileSizes uses the sizes in the Scb, and this is the
  586. // one place where in Ntfs where we wish to use a different value
  587. // for ValidDataLength. Therefore, we save the current ValidData
  588. // and plug it with our desired value and restore on return.
  589. //
  590. NtfsWriteFileSizes( IrpContext,
  591. Scb,
  592. &Scb->Header.ValidDataLength.QuadPart,
  593. FALSE,
  594. TRUE,
  595. TRUE );
  596. //
  597. // Now update Cc.
  598. //
  599. NtfsSetCcFileSizes( FileObject, Scb, (PCC_FILE_SIZES)&Scb->Header.AllocationSize );
  600. } finally {
  601. if (CleanupAttrContext) {
  602. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  603. }
  604. }
  605. }
  606. NTFSAPI
  607. NTSTATUS
  608. NtfsHoldIrpForNewLength (
  609. IN PIRP_CONTEXT IrpContext,
  610. IN PSCB Scb,
  611. IN PIRP Irp,
  612. IN LONGLONG Length,
  613. IN PDRIVER_CANCEL CancelRoutine,
  614. IN PVOID CapturedData OPTIONAL,
  615. OUT PVOID *CopyCapturedData OPTIONAL,
  616. IN ULONG CapturedDataLength
  617. )
  618. /*++
  619. RoutineDescription:
  620. This routine may be called to wait until the designated stream exceeds the specified
  621. length.
  622. Arguments:
  623. Scb - Supplies the stream to wait on.
  624. Irp - Supplies the address of the Irp to hold
  625. Length - Supplies the length to be exceeded. To wait for any file extend, supply the last seen
  626. FileSize. To wait for N new bytes wait for last seen FileSize + N.
  627. CancelRoutine - Routine to register as the cancel routine.
  628. CapturedData - Specified if caller wishes to have auxillary data captured to pool.
  629. CopyCapturedData - Address to store copy of the captured data.
  630. CapturedDataLength - Length of the auxillary data to capture. Must be 0 if CapturedData not
  631. specified.
  632. Return value:
  633. NTSTATUS - Status of posting this request. STATUS_CANCELLED if the irp has been cancelled
  634. before we could register a callback, STATUS_PENDING if the request was posted without
  635. problem. Any other error indicates the irp wasn't posted and our caller needs to
  636. clean it up.
  637. --*/
  638. {
  639. PWAIT_FOR_NEW_LENGTH WaitForNewLength;
  640. NTSTATUS Status = STATUS_PENDING;
  641. PAGED_CODE();
  642. //
  643. // Allocate and initialize a wait block.
  644. //
  645. WaitForNewLength = NtfsAllocatePool( NonPagedPool, QuadAlign(sizeof(WAIT_FOR_NEW_LENGTH)) + CapturedDataLength );
  646. RtlZeroMemory( WaitForNewLength, sizeof(WAIT_FOR_NEW_LENGTH) );
  647. if (ARGUMENT_PRESENT(CapturedData)) {
  648. RtlCopyMemory( Add2Ptr(WaitForNewLength, QuadAlign(sizeof(WAIT_FOR_NEW_LENGTH))),
  649. CapturedData,
  650. CapturedDataLength );
  651. CapturedData = Add2Ptr(WaitForNewLength, QuadAlign(sizeof(WAIT_FOR_NEW_LENGTH)));
  652. *CopyCapturedData = CapturedData;
  653. }
  654. WaitForNewLength->Irp = Irp;
  655. WaitForNewLength->Length = Length;
  656. WaitForNewLength->Stream = Scb;
  657. WaitForNewLength->Status = STATUS_SUCCESS;
  658. WaitForNewLength->Flags = NTFS_WAIT_FLAG_ASYNC;
  659. //
  660. // Prepare the Irp for hanging around. Only make this call once per Irp. We occasionally
  661. // wake up a waiting Irp and then find we don't have enough data to return. In that
  662. // case we don't want to clean up the 'borrowed' IrpContext and the Irp has already
  663. // been prepared. Note: we don't mark the irp pending in prepostinternal and wait until
  664. // we've set the cancel routine to do so
  665. //
  666. if (IrpContext->OriginatingIrp == Irp) {
  667. NtfsPrePostIrpInternal( IrpContext, Irp, FALSE, FALSE );
  668. }
  669. //
  670. // Synchronize to queue and set cancel routine and initialize the wait block.
  671. //
  672. NtfsAcquireFsrtlHeader( Scb );
  673. if (NtfsSetCancelRoutine( Irp, CancelRoutine, (ULONG_PTR) WaitForNewLength, TRUE )) {
  674. InsertTailList( &Scb->ScbType.Data.WaitForNewLength, &WaitForNewLength->WaitList );
  675. } else {
  676. //
  677. // The irp has already been marked for cancel.
  678. //
  679. Status = STATUS_CANCELLED;
  680. NtfsFreePool( WaitForNewLength );
  681. }
  682. NtfsReleaseFsrtlHeader( Scb );
  683. return Status;
  684. }
  685. NTFSAPI
  686. NTSTATUS
  687. NtOfsWaitForNewLength (
  688. IN PSCB Scb,
  689. IN LONGLONG Length,
  690. IN ULONG Async,
  691. IN PIRP Irp,
  692. IN PDRIVER_CANCEL CancelRoutine,
  693. IN PLARGE_INTEGER Timeout OPTIONAL
  694. )
  695. /*++
  696. RoutineDescription:
  697. This routine may be called to wait until the designated stream exceeds the specified
  698. length.
  699. Arguments:
  700. Scb - Supplies the stream to wait on.
  701. Length - Supplies the length to be exceeded. To wait for any file extend, supply the last seen
  702. FileSize. To wait for N new bytes wait for last seen FileSize + N.
  703. Async - Indicates if we want to complete this request in another thread in
  704. the case of cancel.
  705. Irp - Supplies Irp of current request, so that wait can be skipped if Irp has been cancelled.
  706. CancelRoutine - This is the cancel routine to store in the Irp.
  707. TimeOut - Supplies an standard optional timeout spec, in case the caller wants to set
  708. a max time to wait.
  709. Return value:
  710. NTSTATUS - Status to proceed with the request. It may be STATUS_SUCCESS, STATUS_TIMEOUT or
  711. STATUS_CANCELLED. It may also be some other error specific to this type of request.
  712. In general the caller may wish to ignore the status code since they own the Irp now
  713. and are responsible for completing it.
  714. --*/
  715. {
  716. PWAIT_FOR_NEW_LENGTH WaitForNewLength;
  717. LONGLONG OriginalLength = Scb->Header.FileSize.QuadPart;
  718. NTSTATUS Status = STATUS_SUCCESS;
  719. PAGED_CODE();
  720. //
  721. // Allocate and initialize a wait block.
  722. //
  723. WaitForNewLength = NtfsAllocatePool( NonPagedPool, sizeof( WAIT_FOR_NEW_LENGTH ));
  724. WaitForNewLength->Irp = Irp;
  725. WaitForNewLength->Length = Length;
  726. WaitForNewLength->Stream = Scb;
  727. WaitForNewLength->Status = STATUS_SUCCESS;
  728. //
  729. // Take different action if this is async or sync.
  730. //
  731. if (Async) {
  732. WaitForNewLength->Flags = NTFS_WAIT_FLAG_ASYNC;
  733. } else {
  734. WaitForNewLength->Flags = 0;
  735. KeInitializeEvent( &WaitForNewLength->Event, NotificationEvent, FALSE );
  736. }
  737. //
  738. // Test if we need to wait at all.
  739. //
  740. NtfsAcquireFsrtlHeader( Scb );
  741. //
  742. // Has the length already changed? If not we must wait.
  743. //
  744. if (Scb->Header.FileSize.QuadPart <= Length) {
  745. //
  746. // Now set up the cancel routine. Return cancel if the user has
  747. // already cancelled this. Otherwise set up to wait.
  748. //
  749. if (NtfsSetCancelRoutine( Irp, CancelRoutine, (ULONG_PTR) WaitForNewLength, Async )) {
  750. InsertTailList( &Scb->ScbType.Data.WaitForNewLength, &WaitForNewLength->WaitList );
  751. NtfsReleaseFsrtlHeader( Scb );
  752. //
  753. // Now wait for someone to signal the length change.
  754. //
  755. if (!Async) {
  756. do {
  757. Status = KeWaitForSingleObject( &WaitForNewLength->Event,
  758. Executive,
  759. (KPROCESSOR_MODE)(ARGUMENT_PRESENT(Irp) ?
  760. Irp->RequestorMode :
  761. KernelMode),
  762. TRUE,
  763. Timeout );
  764. //
  765. // If the system timed out but there was no change in the file length then
  766. // we want to wait for the first change of the file. Wait again but without
  767. // a timeout and a length of the current size + 1. This satisfies the timeout
  768. // semantics which are don't wait for the full user length request to be satisfied
  769. // if it doesn't occur within the timeout period. Return either what has changed
  770. // in that time or the first change which occurs if nothing changed within the
  771. // timeout period.
  772. //
  773. if ((Status == STATUS_TIMEOUT) &&
  774. ARGUMENT_PRESENT( Timeout ) &&
  775. (Scb->Header.FileSize.QuadPart == OriginalLength)) {
  776. Timeout = NULL;
  777. WaitForNewLength->Length = OriginalLength + 1;
  778. //
  779. // Set the status to STATUS_KERNEL_APC so we will retry.
  780. //
  781. Status = STATUS_KERNEL_APC;
  782. continue;
  783. }
  784. } while (Status == STATUS_KERNEL_APC);
  785. //
  786. // Make sure to clear the cancel routine. We don't care if
  787. // a cancel is underway here.
  788. //
  789. NtfsAcquireFsrtlHeader( Scb );
  790. //
  791. // Make a timeout look like STATUS_SUCCESS. Otherwise return the error.
  792. //
  793. if (Status == STATUS_TIMEOUT) {
  794. Status = STATUS_SUCCESS;
  795. //
  796. // Clear the cancel routine.
  797. //
  798. NtfsClearCancelRoutine( WaitForNewLength->Irp );
  799. } else {
  800. //
  801. // If the wait completed with success then check for the error
  802. // in the wait block.
  803. //
  804. if (Status == STATUS_SUCCESS) {
  805. Status = WaitForNewLength->Status;
  806. //
  807. // Clear the cancel routine.
  808. //
  809. } else {
  810. NtfsClearCancelRoutine( WaitForNewLength->Irp );
  811. }
  812. }
  813. RemoveEntryList( &WaitForNewLength->WaitList );
  814. NtfsReleaseFsrtlHeader( Scb );
  815. NtfsFreePool( WaitForNewLength );
  816. //
  817. // The current thread is finished with the Irp.
  818. //
  819. } else {
  820. Status = STATUS_PENDING;
  821. }
  822. //
  823. // The irp has already been marked for cancel.
  824. //
  825. } else {
  826. NtfsReleaseFsrtlHeader( Scb );
  827. NtfsFreePool( WaitForNewLength );
  828. Status = STATUS_CANCELLED;
  829. }
  830. } else {
  831. NtfsReleaseFsrtlHeader( Scb );
  832. NtfsFreePool( WaitForNewLength );
  833. }
  834. return Status;
  835. }
  836. VOID
  837. NtOfsPostNewLength (
  838. IN PIRP_CONTEXT IrpContext OPTIONAL,
  839. IN PSCB Scb,
  840. IN BOOLEAN WakeAll
  841. )
  842. /*++
  843. RoutineDescription:
  844. This routine may be called to wake one or more waiters based on the desired FileSize change,
  845. or to unconditionally wake all waiters (such as for a shutdown condition).
  846. NOTE: The caller must have the FsRtl header mutex acquired when calling this routine.
  847. Arguments:
  848. Scb - Supplies the stream to act on.
  849. WakeAll - Supplies TRUE if all waiters should be unconditionally woken.
  850. Return value:
  851. None.
  852. --*/
  853. {
  854. PWAIT_FOR_NEW_LENGTH WaitForNewLength, WaiterToWake;
  855. ASSERT(FIELD_OFFSET(WAIT_FOR_NEW_LENGTH, WaitList) == 0);
  856. PAGED_CODE();
  857. NtfsAcquireFsrtlHeader( Scb );
  858. WaitForNewLength = (PWAIT_FOR_NEW_LENGTH)Scb->ScbType.Data.WaitForNewLength.Flink;
  859. while (WaitForNewLength != (PWAIT_FOR_NEW_LENGTH)&Scb->ScbType.Data.WaitForNewLength) {
  860. //
  861. // If we are supposed to wake this guy, then move our pointer to the next guy
  862. // first, then wake him, setting his event after removing him from the list,
  863. // since setting the event will cause him to eventually reuse the stack space
  864. // containing the wait block.
  865. //
  866. if ((Scb->Header.FileSize.QuadPart > WaitForNewLength->Length) || WakeAll) {
  867. WaiterToWake = WaitForNewLength;
  868. WaitForNewLength = (PWAIT_FOR_NEW_LENGTH)WaitForNewLength->WaitList.Flink;
  869. //
  870. // If this is for an asynchronous Irp, then remove him from the list and
  871. // drop the mutex to do further processing. We only do further processing
  872. // if there is not currently a cancel thread active for this Irp.
  873. //
  874. // NOTE: This code currently relies on the fact that there is just one
  875. // caller to the routine to hold an Irp. If more such caller's
  876. // surface, then the routine address would have to be stored in
  877. // the wait context.
  878. //
  879. // If cancel is active then we will skip over this Irp.
  880. //
  881. if (NtfsClearCancelRoutine( WaiterToWake->Irp )) {
  882. if (FlagOn( WaiterToWake->Flags, NTFS_WAIT_FLAG_ASYNC )) {
  883. //
  884. // Make sure we decrement the reference count in the Scb.
  885. //
  886. InterlockedDecrement( &Scb->CloseCount );
  887. RemoveEntryList( &WaiterToWake->WaitList );
  888. NtfsReleaseFsrtlHeader( Scb );
  889. //
  890. // Nothing really should go wrong, unless we get an I/O error,
  891. // none the less, we want to stop any exceptions and complete
  892. // the request ourselves rather than impact our caller.
  893. //
  894. if (ARGUMENT_PRESENT( IrpContext )) {
  895. try {
  896. NtfsReadUsnJournal( IrpContext,
  897. WaiterToWake->Irp,
  898. FALSE );
  899. } except(NtfsExceptionFilter( NULL, GetExceptionInformation())) {
  900. NtfsCompleteRequest( NULL, WaiterToWake->Irp, GetExceptionCode() );
  901. }
  902. //
  903. // Assume the only caller with no IrpContext is cancelling the request.
  904. //
  905. } else {
  906. NtfsCompleteRequest( NULL, WaiterToWake->Irp, STATUS_CANCELLED );
  907. }
  908. //
  909. // Free the wait block and go back to the beginning of the list.
  910. // Is it possible that we can into a continuous loop here? We may
  911. // need a strategy to recognize which entries we have visited
  912. // in this loop.
  913. //
  914. NtfsFreePool( WaiterToWake );
  915. NtfsAcquireFsrtlHeader( Scb );
  916. WaitForNewLength = (PWAIT_FOR_NEW_LENGTH)Scb->ScbType.Data.WaitForNewLength.Flink;
  917. } else {
  918. KeSetEvent( &WaiterToWake->Event, 0, FALSE );
  919. }
  920. }
  921. } else {
  922. WaitForNewLength = (PWAIT_FOR_NEW_LENGTH)WaitForNewLength->WaitList.Flink;
  923. }
  924. }
  925. NtfsReleaseFsrtlHeader( Scb );
  926. }
  927. NTFSAPI
  928. VOID
  929. NtOfsFlushAttribute (
  930. IN PIRP_CONTEXT IrpContext,
  931. IN PSCB Scb,
  932. IN ULONG Purge
  933. )
  934. /*++
  935. Routine Description:
  936. This routine flushes the specified attribute, and optionally purges it from the cache.
  937. Arguments:
  938. Scb - Supplies an Scb as the previously returned handle for this attribute.
  939. Purge - Supplies TRUE if the attribute is to be purged.
  940. Return Value:
  941. None (Deleting a nonexistant index is benign).
  942. --*/
  943. {
  944. PAGED_CODE();
  945. if (Purge) {
  946. NtfsFlushAndPurgeScb( IrpContext, Scb, NULL );
  947. } else {
  948. NtfsFlushUserStream( IrpContext, Scb, NULL, 0 );
  949. }
  950. }
  951. NTFSAPI
  952. VOID
  953. NtOfsPutData (
  954. IN PIRP_CONTEXT IrpContext,
  955. IN PSCB Scb,
  956. IN LONGLONG Offset,
  957. IN ULONG Length,
  958. IN PVOID Data OPTIONAL
  959. )
  960. /*++
  961. Routine Description:
  962. This routine is called to update a range of a recoverable stream. Note this
  963. update cannot extend the filesize unless its a write to eof put (Offset = -1)
  964. Arguments:
  965. Scb - Scb for the stream to zero.
  966. Offset - Offset in stream to update.
  967. Length - Length of stream to update in bytes.
  968. Data - Data to update stream with if specified, else range should be zeroed.
  969. Return Value:
  970. None.
  971. --*/
  972. {
  973. ULONG OriginalLength = Length;
  974. BOOLEAN WriteToEof = FALSE;
  975. BOOLEAN MovingBackwards = TRUE;
  976. PAGED_CODE();
  977. ASSERT( FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) );
  978. //
  979. // Handle Put to end of file.
  980. //
  981. if (Offset < 0) {
  982. WriteToEof = TRUE;
  983. Offset = Scb->Header.FileSize.QuadPart;
  984. NtOfsSetLength( IrpContext, Scb, Offset + Length );
  985. }
  986. ASSERT((Offset + Length) <= Scb->Header.FileSize.QuadPart);
  987. //
  988. // First handle the resident case.
  989. //
  990. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  991. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  992. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  993. PATTRIBUTE_RECORD_HEADER Attribute;
  994. ULONG RecordOffset, AttributeOffset;
  995. PVCB Vcb = Scb->Vcb;
  996. NtfsInitializeAttributeContext( &Context );
  997. try {
  998. //
  999. // Lookup and pin the attribute.
  1000. //
  1001. NtfsLookupAttributeForScb( IrpContext, Scb, NULL, &Context );
  1002. NtfsPinMappedAttribute( IrpContext, Vcb, &Context );
  1003. //
  1004. // Extract the relevant pointers and calculate offsets.
  1005. //
  1006. FileRecord = NtfsContainingFileRecord(&Context);
  1007. Attribute = NtfsFoundAttribute(&Context);
  1008. RecordOffset = PtrOffset(FileRecord, Attribute);
  1009. AttributeOffset = Attribute->Form.Resident.ValueOffset + (ULONG)Offset;
  1010. //
  1011. // Log the change while we still have the old data.
  1012. //
  1013. FileRecord->Lsn =
  1014. NtfsWriteLog( IrpContext,
  1015. Vcb->MftScb,
  1016. NtfsFoundBcb( &Context ),
  1017. UpdateResidentValue,
  1018. Data,
  1019. Length,
  1020. UpdateResidentValue,
  1021. Add2Ptr(Attribute, Attribute->Form.Resident.ValueOffset + (ULONG)Offset),
  1022. Length,
  1023. NtfsMftOffset(&Context),
  1024. RecordOffset,
  1025. AttributeOffset,
  1026. Vcb->BytesPerFileRecordSegment );
  1027. //
  1028. // Now update this data by calling the same routine as restart.
  1029. //
  1030. NtfsRestartChangeValue( IrpContext,
  1031. FileRecord,
  1032. RecordOffset,
  1033. AttributeOffset,
  1034. Data,
  1035. Length,
  1036. FALSE );
  1037. //
  1038. // If there is a stream for this attribute, then we must update it in the
  1039. // cache, copying from the attribute itself in order to handle the zeroing
  1040. // (Data == NULL) case.
  1041. //
  1042. if (Scb->FileObject != NULL) {
  1043. CcCopyWrite( Scb->FileObject,
  1044. (PLARGE_INTEGER)&Offset,
  1045. Length,
  1046. TRUE,
  1047. Add2Ptr(Attribute, AttributeOffset) );
  1048. }
  1049. //
  1050. // Optionally update ValidDataLength
  1051. //
  1052. Offset += Length;
  1053. if (Offset > Scb->Header.ValidDataLength.QuadPart) {
  1054. Scb->Header.ValidDataLength.QuadPart = Offset;
  1055. }
  1056. } finally {
  1057. NtfsCleanupAttributeContext( IrpContext, &Context );
  1058. }
  1059. //
  1060. // Now handle the nonresident case.
  1061. //
  1062. } else {
  1063. PVOID Buffer;
  1064. PVOID SubData = NULL;
  1065. LONGLONG NewValidDataLength = Offset + Length;
  1066. PBCB Bcb = NULL;
  1067. ULONG PageOffset = (ULONG)Offset & (PAGE_SIZE - 1);
  1068. ULONGLONG SubOffset;
  1069. ULONG SubLength;
  1070. ASSERT(Scb->FileObject != NULL);
  1071. //
  1072. // If we are starting beyond ValidDataLength, then recurse to
  1073. // zero what we need.
  1074. //
  1075. if (Offset > Scb->Header.FileSize.QuadPart) {
  1076. ASSERT((Offset - Scb->Header.FileSize.QuadPart) <= MAXULONG);
  1077. NtOfsPutData( IrpContext,
  1078. Scb,
  1079. Scb->Header.FileSize.QuadPart,
  1080. (ULONG)(Offset - Scb->Header.FileSize.QuadPart),
  1081. NULL );
  1082. }
  1083. try {
  1084. //
  1085. // Now loop until there are no more pages with new data
  1086. // to log. We'll start assuming a backwards copy
  1087. //
  1088. while (Length != 0) {
  1089. if (MovingBackwards) {
  1090. //
  1091. // Calculate the last page of the transfer - if its the 1st page start at offset
  1092. //
  1093. SubOffset = max( Offset, BlockAlignTruncate( Offset + Length - 1, PAGE_SIZE ) );
  1094. SubLength = (ULONG)(Offset + Length - SubOffset);
  1095. //
  1096. // This guarantees we can truncate to a 32 bit value
  1097. //
  1098. ASSERT( Offset + Length - SubOffset <= PAGE_SIZE );
  1099. } else {
  1100. SubOffset = Offset + OriginalLength - Length;
  1101. SubLength = min( PAGE_SIZE - ((ULONG)SubOffset & (PAGE_SIZE - 1)), Length );
  1102. }
  1103. if (Data != NULL) {
  1104. SubData = Add2Ptr( Data, SubOffset - Offset );
  1105. }
  1106. //
  1107. // Pin the page
  1108. //
  1109. NtfsPinStream( IrpContext,
  1110. Scb,
  1111. SubOffset,
  1112. SubLength,
  1113. &Bcb,
  1114. &Buffer );
  1115. //
  1116. // Doublecheck the direction of copy based on the relative position of the
  1117. // source (data) and destination (buffer). We don't care if the source is null
  1118. // We'll only switch once from backwards to forwards
  1119. //
  1120. if (MovingBackwards &&
  1121. ((PCHAR)Buffer < (PCHAR)SubData) &&
  1122. (Data != NULL)) {
  1123. //
  1124. // Start over with the opposite direction
  1125. //
  1126. MovingBackwards = FALSE;
  1127. NtfsUnpinBcb( IrpContext, &Bcb );
  1128. continue;
  1129. }
  1130. //
  1131. // Now log the changes to this page.
  1132. //
  1133. (VOID)
  1134. NtfsWriteLog( IrpContext,
  1135. Scb,
  1136. Bcb,
  1137. UpdateNonresidentValue,
  1138. SubData,
  1139. SubLength,
  1140. WriteToEof ? Noop : UpdateNonresidentValue,
  1141. WriteToEof ? NULL : Buffer,
  1142. WriteToEof ? 0 : SubLength,
  1143. BlockAlignTruncate( SubOffset, PAGE_SIZE ),
  1144. (ULONG)(SubOffset & (PAGE_SIZE - 1)),
  1145. 0,
  1146. (ULONG)(SubOffset & (PAGE_SIZE - 1)) + SubLength );
  1147. //
  1148. // Move the data into place.
  1149. //
  1150. if (Data != NULL) {
  1151. RtlMoveMemory( Buffer, SubData, SubLength );
  1152. } else {
  1153. RtlZeroMemory( Buffer, SubLength );
  1154. }
  1155. //
  1156. // Unpin the page and decrement the length
  1157. //
  1158. NtfsUnpinBcb( IrpContext, &Bcb );
  1159. Length -= SubLength;
  1160. }
  1161. //
  1162. // Optionally update ValidDataLength
  1163. //
  1164. if (NewValidDataLength > Scb->Header.ValidDataLength.QuadPart) {
  1165. Scb->Header.ValidDataLength.QuadPart = NewValidDataLength;
  1166. NtfsWriteFileSizes( IrpContext, Scb, &NewValidDataLength, TRUE, TRUE, TRUE );
  1167. //
  1168. // See if we have to wake anyone.
  1169. //
  1170. if (!IsListEmpty( &Scb->ScbType.Data.WaitForNewLength )) {
  1171. NtfsPostToNewLengthQueue( IrpContext, Scb );
  1172. }
  1173. }
  1174. } finally {
  1175. NtfsUnpinBcb( IrpContext, &Bcb );
  1176. }
  1177. }
  1178. }
  1179. //
  1180. // The following prototypes are here only for someone external to Ntfs (such as EFS)
  1181. // trying to link to Ntfs using ntfsexp.h.
  1182. //
  1183. NTFSAPI
  1184. VOID
  1185. NtOfsMapAttribute (
  1186. IN PIRP_CONTEXT IrpContext,
  1187. IN PSCB Scb,
  1188. IN LONGLONG Offset,
  1189. IN ULONG Length,
  1190. OUT PVOID *Buffer,
  1191. OUT PMAP_HANDLE MapHandle
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. NtOfsMapAttribute maps the given region of an Scb. Its a thin wrapper
  1196. around CcMapData.
  1197. Arguments:
  1198. IrpContext - Supplies the irpcontext associated with the current operation
  1199. Scb - Scb to map data from
  1200. Offset - offset into data
  1201. Length - length of region to be pinned
  1202. Buffer - returned buffer with pinned data virtual address
  1203. MapHandle - returned map handle used to manage the pinned region.
  1204. Return Value:
  1205. None
  1206. --*/
  1207. {
  1208. PAGED_CODE( );
  1209. UNREFERENCED_PARAMETER( IrpContext );
  1210. CcMapData( Scb->FileObject, (PLARGE_INTEGER)&Offset, Length, TRUE, &MapHandle->Bcb, Buffer );
  1211. #ifdef MAPCOUNT_DBG
  1212. IrpContext->MapCount++;
  1213. #endif
  1214. MapHandle->Buffer = *(PVOID *)Buffer;
  1215. }
  1216. NTFSAPI
  1217. VOID
  1218. NtOfsPreparePinWrite (
  1219. IN PIRP_CONTEXT IrpContext,
  1220. IN PSCB Scb,
  1221. IN LONGLONG Offset,
  1222. IN ULONG Length,
  1223. OUT PVOID *Buffer,
  1224. OUT PMAP_HANDLE MapHandle
  1225. )
  1226. /*++
  1227. Routine Description:
  1228. NtOfsPreparePinWrite maps and pins a portion of the specified attribute and
  1229. returns a pointer to the memory. This is equivalent to doing a NtOfsMapAttribute
  1230. followed by NtOfsPinRead and NtOfsDirty but is more efficient.
  1231. Arguments:
  1232. IrpContext - Supplies the irpcontext associated with the current operation
  1233. Scb - Scb to pin in preparation for a write
  1234. Offset - offset into data
  1235. Length - length of region to be pinned
  1236. Buffer - returned buffer with pinned data virtual address
  1237. MapHandle - returned map handle used to manage the pinned region.
  1238. Return Value:
  1239. None
  1240. --*/
  1241. {
  1242. UNREFERENCED_PARAMETER( IrpContext );
  1243. if ((Offset + Length) > Scb->Header.AllocationSize.QuadPart) {
  1244. ExRaiseStatus(STATUS_END_OF_FILE);
  1245. }
  1246. CcPreparePinWrite( Scb->FileObject, (PLARGE_INTEGER)&Offset, Length, FALSE, TRUE, &MapHandle->Bcb, Buffer );
  1247. #ifdef MAPCOUNT_DBG
  1248. IrpContext->MapCount++;
  1249. #endif
  1250. MapHandle->Buffer = Buffer;
  1251. }
  1252. NTFSAPI
  1253. VOID
  1254. NtOfsPinRead(
  1255. IN PIRP_CONTEXT IrpContext,
  1256. IN PSCB Scb,
  1257. IN LONGLONG Offset,
  1258. IN ULONG Length,
  1259. OUT PMAP_HANDLE MapHandle
  1260. )
  1261. /*++
  1262. Routine Description:
  1263. NtOfsPinRead pins a section of a map and read in all pages from the mapped
  1264. attribute. Offset and Length must describe a byte range which is equal to
  1265. or included by the original mapped range.
  1266. Arguments:
  1267. IrpContext - Supplies the irpcontext associated with the current operation
  1268. Scb - Scb to pin data for reads in
  1269. Offset - offset into data
  1270. Length - length of region to be pinned
  1271. MapHandle - returned map handle used to manage the pinned region.
  1272. Return Value:
  1273. None
  1274. --*/
  1275. {
  1276. UNREFERENCED_PARAMETER( IrpContext );
  1277. ASSERT( MapHandle->Bcb != NULL );
  1278. CcPinMappedData( Scb->FileObject, (PLARGE_INTEGER)&Offset, Length, TRUE, &MapHandle->Bcb );
  1279. }
  1280. NTFSAPI
  1281. VOID
  1282. NtOfsReleaseMap (
  1283. IN PIRP_CONTEXT IrpContext,
  1284. IN PMAP_HANDLE MapHandle
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine unmaps/unpins a mapped portion of an attribute.
  1289. Arguments:
  1290. IrpContext - Supplies the irpcontext associated with the current operation
  1291. MapHandle - Supplies map handle containing the bcb to be released.
  1292. Return Value:
  1293. None
  1294. --*/
  1295. {
  1296. UNREFERENCED_PARAMETER( IrpContext );
  1297. if (MapHandle->Bcb != NULL) {
  1298. CcUnpinData( MapHandle->Bcb );
  1299. #ifdef MAPCOUNT_DBG
  1300. IrpContext->MapCount--;
  1301. #endif
  1302. MapHandle->Bcb = NULL;
  1303. }
  1304. }