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

2365 lines
77 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. FstIoSup.c
  5. Abstract:
  6. This module implements the fast I/O routines for Ntfs.
  7. Author:
  8. Tom Miller [TomM] 16-May-96
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, NtfsCopyReadA)
  14. #pragma alloc_text(PAGE, NtfsCopyWriteA)
  15. #pragma alloc_text(PAGE, NtfsMdlReadA)
  16. #pragma alloc_text(PAGE, NtfsPrepareMdlWriteA)
  17. #pragma alloc_text(PAGE, NtfsWaitForIoAtEof)
  18. #pragma alloc_text(PAGE, NtfsFinishIoAtEof)
  19. #endif
  20. #ifdef NTFS_RWC_DEBUG
  21. PRWC_HISTORY_ENTRY
  22. NtfsGetHistoryEntry (
  23. IN PSCB Scb
  24. );
  25. #endif
  26. BOOLEAN
  27. NtfsCopyReadA (
  28. IN PFILE_OBJECT FileObject,
  29. IN PLARGE_INTEGER FileOffset,
  30. IN ULONG Length,
  31. IN BOOLEAN Wait,
  32. IN ULONG LockKey,
  33. OUT PVOID Buffer,
  34. OUT PIO_STATUS_BLOCK IoStatus,
  35. IN PDEVICE_OBJECT DeviceObject
  36. )
  37. /*++
  38. Routine Description:
  39. This routine does a fast cached read bypassing the usual file system
  40. entry routine (i.e., without the Irp). It is used to do a copy read
  41. of a cached file object. For a complete description of the arguments
  42. see CcCopyRead.
  43. Arguments:
  44. FileObject - Pointer to the file object being read.
  45. FileOffset - Byte offset in file for desired data.
  46. Length - Length of desired data in bytes.
  47. Wait - FALSE if caller may not block, TRUE otherwise
  48. Buffer - Pointer to output buffer to which data should be copied.
  49. IoStatus - Pointer to standard I/O status block to receive the status
  50. for the transfer.
  51. Return Value:
  52. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  53. if there is an I/O error.
  54. TRUE - if the data is being delivered
  55. --*/
  56. {
  57. PNTFS_ADVANCED_FCB_HEADER Header;
  58. LARGE_INTEGER BeyondLastByte;
  59. PDEVICE_OBJECT targetVdo;
  60. #ifdef COMPRESS_ON_WIRE
  61. PCOMPRESSION_SYNC CompressionSync = NULL;
  62. #endif
  63. BOOLEAN WasDataRead = TRUE;
  64. ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES( FileOffset->QuadPart, Length );
  65. BOOLEAN DoingIoAtEof = FALSE;
  66. UNREFERENCED_PARAMETER( DeviceObject );
  67. PAGED_CODE();
  68. #ifdef NTFS_NO_FASTIO
  69. UNREFERENCED_PARAMETER( FileObject );
  70. UNREFERENCED_PARAMETER( FileOffset );
  71. UNREFERENCED_PARAMETER( Length );
  72. UNREFERENCED_PARAMETER( Wait );
  73. UNREFERENCED_PARAMETER( LockKey );
  74. UNREFERENCED_PARAMETER( Buffer );
  75. UNREFERENCED_PARAMETER( IoStatus );
  76. return FALSE;
  77. #endif
  78. //
  79. // Don't take the fast io path if someone is already active in this thread.
  80. //
  81. if (IoGetTopLevelIrp() != NULL) {
  82. return FALSE;
  83. }
  84. //
  85. // Special case a read of zero length
  86. //
  87. if (Length != 0) {
  88. //
  89. // Get a real pointer to the common fcb header. Check for overflow.
  90. //
  91. if (MAXLONGLONG - FileOffset->QuadPart < (LONGLONG)Length) {
  92. return FALSE;
  93. }
  94. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  95. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  96. //
  97. // Enter the file system
  98. //
  99. FsRtlEnterFileSystem();
  100. //
  101. // Make our best guess on whether we need the file exclusive
  102. // or shared. Note that we do not check FileOffset->HighPart
  103. // until below.
  104. //
  105. if (Wait) {
  106. FsRtlIncrementCcFastReadWait();
  107. } else {
  108. FsRtlIncrementCcFastReadNoWait();
  109. }
  110. if ((Header->PagingIoResource == NULL) ||
  111. !ExAcquireResourceSharedLite(Header->PagingIoResource, Wait)) {
  112. FsRtlIncrementCcFastReadResourceMiss();
  113. WasDataRead = FALSE;
  114. goto Done2;
  115. }
  116. //
  117. // Now synchronize with the FsRtl Header
  118. //
  119. NtfsAcquireFsrtlHeader( (PSCB)Header );
  120. //
  121. // Now see if we are reading beyond ValidDataLength. We have to
  122. // do it now so that our reads are not nooped.
  123. //
  124. if (BeyondLastByte.QuadPart > Header->ValidDataLength.QuadPart) {
  125. //
  126. // We must serialize with anyone else doing I/O at beyond
  127. // ValidDataLength, and then remember if we need to declare
  128. // when we are done.
  129. //
  130. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  131. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  132. //
  133. // Set the Flag if we are in fact beyond ValidDataLength.
  134. //
  135. if (DoingIoAtEof) {
  136. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  137. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  138. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  139. } else {
  140. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  141. #endif
  142. }
  143. }
  144. NtfsReleaseFsrtlHeader( (PSCB)Header );
  145. //
  146. // Now that the File is acquired shared, we can safely test if it
  147. // is really cached and if we can do fast i/o and if not, then
  148. // release the fcb and return.
  149. //
  150. if ((FileObject->PrivateCacheMap == NULL) ||
  151. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  152. FsRtlIncrementCcFastReadNotPossible();
  153. WasDataRead = FALSE;
  154. goto Done;
  155. }
  156. //
  157. // Check if fast I/O is questionable and if so then go ask the
  158. // file system the answer
  159. //
  160. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  161. PFAST_IO_DISPATCH FastIoDispatch;
  162. targetVdo = IoGetRelatedDeviceObject( FileObject );
  163. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  164. //
  165. // All file systems that set "Is Questionable" had better support
  166. // fast I/O
  167. //
  168. ASSERT(FastIoDispatch != NULL);
  169. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  170. //
  171. // Call the file system to check for fast I/O. If the answer is
  172. // anything other than GoForIt then we cannot take the fast I/O
  173. // path.
  174. //
  175. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  176. FileOffset,
  177. Length,
  178. Wait,
  179. LockKey,
  180. TRUE, // read operation
  181. IoStatus,
  182. targetVdo )) {
  183. //
  184. // Fast I/O is not possible so release the Fcb and return.
  185. //
  186. FsRtlIncrementCcFastReadNotPossible();
  187. WasDataRead = FALSE;
  188. goto Done;
  189. }
  190. }
  191. //
  192. // Check for read past file size.
  193. //
  194. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  195. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  196. IoStatus->Status = STATUS_END_OF_FILE;
  197. IoStatus->Information = 0;
  198. goto Done;
  199. }
  200. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  201. }
  202. //
  203. // We can do fast i/o so call the cc routine to do the work and then
  204. // release the fcb when we've done. If for whatever reason the
  205. // copy read fails, then return FALSE to our caller.
  206. //
  207. // Also mark this as the top level "Irp" so that lower file system
  208. // levels will not attempt a pop-up
  209. //
  210. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  211. try {
  212. //
  213. // If there is a compressed section, then synchronize with that cache.
  214. //
  215. IoStatus->Status = STATUS_SUCCESS;
  216. #ifdef COMPRESS_ON_WIRE
  217. //
  218. // If there is a compressed section, then we have to synchronize with
  219. // the data out there. Note the FileObjectC better also be there, or else
  220. // we would have made the fast I/O not possible.
  221. //
  222. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  223. LONGLONG LocalOffset = FileOffset->QuadPart;
  224. ULONG LocalLength;
  225. ULONG LengthLeft = Length;
  226. ASSERT(Header->FileObjectC != NULL);
  227. //
  228. // If we are doing DoingIoAtEof then take the long path. Otherwise a recursive
  229. // flush will try to reacquire DoingIoAtEof and deadlock.
  230. //
  231. if (DoingIoAtEof) {
  232. WasDataRead = FALSE;
  233. } else {
  234. do {
  235. ULONG ViewOffset;
  236. //
  237. // Calculate length left in view.
  238. //
  239. ViewOffset = ((ULONG) LocalOffset & (VACB_MAPPING_GRANULARITY - 1));
  240. LocalLength = LengthLeft;
  241. if (LocalLength > VACB_MAPPING_GRANULARITY - ViewOffset) {
  242. LocalLength = VACB_MAPPING_GRANULARITY - ViewOffset;
  243. }
  244. //
  245. // Trim the read so we don't inadvertently go beyond the end of the
  246. // view because of the MM read ahead.
  247. //
  248. PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(((PVOID)(ULONG_PTR)((ULONG)LocalOffset)), LocalLength);
  249. if (LocalLength > (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset)) {
  250. #ifdef NTFS_RWC_DEBUG
  251. {
  252. PRWC_HISTORY_ENTRY NextBuffer;
  253. NextBuffer = NtfsGetHistoryEntry( (PSCB) Header );
  254. NextBuffer->Operation = TrimCopyRead;
  255. NextBuffer->Information = PageCount;
  256. NextBuffer->FileOffset = (ULONG) LocalOffset;
  257. NextBuffer->Length = (ULONG) LocalLength;
  258. }
  259. #endif
  260. LocalLength = (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset);
  261. PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(((PVOID)(ULONG_PTR)((ULONG)LocalOffset)), LocalLength);
  262. ASSERT( LocalLength <= (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset) );
  263. }
  264. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  265. &LocalOffset,
  266. LocalLength,
  267. FALSE,
  268. &CompressionSync );
  269. if (NT_SUCCESS(IoStatus->Status)) {
  270. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  271. CcFastCopyRead( FileObject,
  272. (ULONG)LocalOffset,
  273. LocalLength,
  274. PageCount,
  275. Buffer,
  276. IoStatus );
  277. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  278. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  279. } else {
  280. WasDataRead = CcCopyRead( FileObject,
  281. (PLARGE_INTEGER)&LocalOffset,
  282. LocalLength,
  283. Wait,
  284. Buffer,
  285. IoStatus );
  286. ASSERT( !WasDataRead || (IoStatus->Status == STATUS_END_OF_FILE) ||
  287. ((LocalOffset + (LONG_PTR) IoStatus->Information) <= Header->FileSize.QuadPart));
  288. }
  289. LocalOffset += LocalLength;
  290. LengthLeft -= LocalLength;
  291. Buffer = Add2Ptr( Buffer, LocalLength );
  292. }
  293. } while ((LengthLeft != 0) && WasDataRead && NT_SUCCESS(IoStatus->Status));
  294. //
  295. // Remember the full amount of the read.
  296. //
  297. if (WasDataRead) {
  298. IoStatus->Information = Length;
  299. }
  300. }
  301. } else {
  302. #endif
  303. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  304. CcFastCopyRead( FileObject,
  305. FileOffset->LowPart,
  306. Length,
  307. PageCount,
  308. Buffer,
  309. IoStatus );
  310. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  311. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  312. } else {
  313. WasDataRead = CcCopyRead( FileObject,
  314. FileOffset,
  315. Length,
  316. Wait,
  317. Buffer,
  318. IoStatus );
  319. ASSERT( !WasDataRead || (IoStatus->Status == STATUS_END_OF_FILE) ||
  320. ((FileOffset->QuadPart + (LONG_PTR) IoStatus->Information) <= Header->FileSize.QuadPart));
  321. }
  322. #ifdef COMPRESS_ON_WIRE
  323. }
  324. #endif
  325. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  326. if (WasDataRead) {
  327. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
  328. }
  329. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  330. ? EXCEPTION_EXECUTE_HANDLER
  331. : EXCEPTION_CONTINUE_SEARCH ) {
  332. WasDataRead = FALSE;
  333. }
  334. IoSetTopLevelIrp( NULL );
  335. #ifdef COMPRESS_ON_WIRE
  336. if (CompressionSync != NULL) {
  337. NtfsReleaseCompressionSync( CompressionSync );
  338. }
  339. #endif
  340. Done:
  341. if (DoingIoAtEof) {
  342. FsRtlUnlockFsRtlHeader( Header );
  343. }
  344. ExReleaseResourceLite( Header->PagingIoResource );
  345. Done2:
  346. FsRtlExitFileSystem();
  347. } else {
  348. //
  349. // A zero length transfer was requested.
  350. //
  351. IoStatus->Status = STATUS_SUCCESS;
  352. IoStatus->Information = 0;
  353. }
  354. return WasDataRead;
  355. }
  356. BOOLEAN
  357. NtfsCopyWriteA (
  358. IN PFILE_OBJECT FileObject,
  359. IN PLARGE_INTEGER FileOffset,
  360. IN ULONG Length,
  361. IN BOOLEAN Wait,
  362. IN ULONG LockKey,
  363. IN PVOID Buffer,
  364. OUT PIO_STATUS_BLOCK IoStatus,
  365. IN PDEVICE_OBJECT DeviceObject
  366. )
  367. /*++
  368. Routine Description:
  369. This routine does a fast cached write bypassing the usual file system
  370. entry routine (i.e., without the Irp). It is used to do a copy write
  371. of a cached file object. For a complete description of the arguments
  372. see CcCopyWrite.
  373. Arguments:
  374. FileObject - Pointer to the file object being write.
  375. FileOffset - Byte offset in file for desired data.
  376. Length - Length of desired data in bytes.
  377. Wait - FALSE if caller may not block, TRUE otherwise
  378. Buffer - Pointer to output buffer to which data should be copied.
  379. IoStatus - Pointer to standard I/O status block to receive the status
  380. for the transfer.
  381. Return Value:
  382. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  383. if there is an I/O error.
  384. TRUE - if the data is being delivered
  385. --*/
  386. {
  387. PNTFS_ADVANCED_FCB_HEADER Header;
  388. LARGE_INTEGER Offset;
  389. LARGE_INTEGER NewFileSize;
  390. LARGE_INTEGER OldFileSize;
  391. #ifdef COMPRESS_ON_WIRE
  392. PCOMPRESSION_SYNC CompressionSync = NULL;
  393. #endif
  394. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  395. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  396. ULONG DoingIoAtEof = FALSE;
  397. BOOLEAN WasDataWritten = TRUE;
  398. #ifdef SYSCACHE_DEBUG
  399. PSCB Scb = (PSCB) FileObject->FsContext;
  400. #endif
  401. UNREFERENCED_PARAMETER( DeviceObject );
  402. PAGED_CODE();
  403. #ifdef NTFS_NO_FASTIO
  404. UNREFERENCED_PARAMETER( FileObject );
  405. UNREFERENCED_PARAMETER( FileOffset );
  406. UNREFERENCED_PARAMETER( Length );
  407. UNREFERENCED_PARAMETER( Wait );
  408. UNREFERENCED_PARAMETER( LockKey );
  409. UNREFERENCED_PARAMETER( Buffer );
  410. UNREFERENCED_PARAMETER( IoStatus );
  411. return FALSE;
  412. #endif
  413. //
  414. // Don't take the fast io path if someone is already active in this thread.
  415. //
  416. if (IoGetTopLevelIrp() != NULL) {
  417. return FALSE;
  418. }
  419. //
  420. // Get a real pointer to the common fcb header
  421. //
  422. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  423. //
  424. // Do we need to verify the volume? If so, we must go to the file
  425. // system. Also return FALSE if FileObject is write through, the
  426. // File System must do that.
  427. //
  428. if (!FlagOn( FileObject->Flags, FO_WRITE_THROUGH ) &&
  429. CcCanIWrite( FileObject, Length, Wait, FALSE ) &&
  430. CcCopyWriteWontFlush( FileObject, FileOffset, Length ) &&
  431. (Header->PagingIoResource != NULL)) {
  432. //
  433. // Assume our transfer will work
  434. //
  435. IoStatus->Status = STATUS_SUCCESS;
  436. IoStatus->Information = Length;
  437. //
  438. // Special case the zero byte length
  439. //
  440. if (Length != 0) {
  441. //
  442. // Enter the file system
  443. //
  444. FsRtlEnterFileSystem();
  445. //
  446. // Split into separate paths for increased performance. First
  447. // we have the faster path which only supports Wait == TRUE and
  448. // 32 bits. We will make an unsafe test on whether the fast path
  449. // is ok, then just return FALSE later if we were wrong. This
  450. // should virtually never happen.
  451. //
  452. // IMPORTANT NOTE: It is very important that any changes mad to
  453. // this path also be applied to the 64-bit path
  454. // which is the else of this test!
  455. //
  456. NewFileSize.QuadPart = FileOffset->QuadPart + Length;
  457. Offset = *FileOffset;
  458. if (Wait && (Header->AllocationSize.HighPart == 0)) {
  459. //
  460. // Prevent truncates by acquiring paging I/O
  461. //
  462. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  463. //
  464. // Now synchronize with the FsRtl Header
  465. //
  466. NtfsAcquireFsrtlHeader( (PSCB) Header );
  467. //
  468. // Now see if we will change FileSize. We have to do it now
  469. // so that our reads are not nooped.
  470. //
  471. if ((FileOffset->HighPart < 0) || (NewFileSize.LowPart > Header->ValidDataLength.LowPart)) {
  472. //
  473. // We can change FileSize and ValidDataLength if either, no one
  474. // else is now, or we are still extending after waiting.
  475. //
  476. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  477. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  478. //
  479. // Set the Flag if we are changing FileSize or ValidDataLength,
  480. // and save current values.
  481. //
  482. if (DoingIoAtEof) {
  483. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  484. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  485. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  486. #endif
  487. //
  488. // Now that we are synchronized for end of file cases,
  489. // we can calculate the real offset for this transfer and
  490. // the new file size (if we succeed).
  491. //
  492. if ((FileOffset->HighPart < 0)) {
  493. Offset = Header->FileSize;
  494. }
  495. //
  496. // Above we allowed any negative .HighPart for the 32-bit path,
  497. // but now we are counting on the I/O system to have thrown
  498. // any negative number other than write to end of file.
  499. //
  500. ASSERT(Offset.HighPart >= 0);
  501. //
  502. // Now calculate the new FileSize and see if we wrapped the
  503. // 32-bit boundary.
  504. //
  505. NewFileSize.QuadPart = Offset.QuadPart + Length;
  506. //
  507. // Update Filesize now so that we do not truncate reads.
  508. //
  509. OldFileSize.QuadPart = Header->FileSize.QuadPart;
  510. if (NewFileSize.QuadPart > Header->FileSize.QuadPart) {
  511. //
  512. // If we are beyond AllocationSize, make sure we will
  513. // ErrOut below, and don't modify FileSize now!
  514. //
  515. if (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) {
  516. NewFileSize.QuadPart = (LONGLONG)0x7FFFFFFFFFFFFFFF;
  517. } else {
  518. Header->FileSize.QuadPart = NewFileSize.QuadPart;
  519. }
  520. }
  521. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  522. } else {
  523. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  524. #endif
  525. }
  526. }
  527. NtfsReleaseFsrtlHeader( (PSCB) Header );
  528. //
  529. // Now that the File is acquired shared, we can safely test
  530. // if it is really cached and if we can do fast i/o and we
  531. // do not have to extend. If not then release the fcb and
  532. // return.
  533. //
  534. // Get out if we have too much to zero. This case is not important
  535. // for performance, and a file system supporting sparseness may have
  536. // a way to do this more efficiently.
  537. //
  538. // If there is a compressed stream and we are DoingIoAtEof, then get
  539. // out because we could deadlock on a recursive flush from the synchronize.
  540. //
  541. if ((FileObject->PrivateCacheMap == NULL) ||
  542. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  543. /* Remove? */ (NewFileSize.LowPart > Header->AllocationSize.QuadPart) ||
  544. (Offset.LowPart >= (Header->ValidDataLength.LowPart + 0x2000)) ||
  545. (NewFileSize.HighPart != 0) ||
  546. #ifdef COMPRESS_ON_WIRE
  547. ((((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) &&
  548. DoingIoAtEof)
  549. #else
  550. FALSE
  551. #endif
  552. ) {
  553. goto ErrOut;
  554. }
  555. //
  556. // Check if fast I/O is questionable and if so then go ask
  557. // the file system the answer
  558. //
  559. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  560. targetVdo = IoGetRelatedDeviceObject( FileObject );
  561. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  562. //
  563. // All file system then set "Is Questionable" had better
  564. // support fast I/O
  565. //
  566. ASSERT(FastIoDispatch != NULL);
  567. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  568. //
  569. // Call the file system to check for fast I/O. If the
  570. // answer is anything other than GoForIt then we cannot
  571. // take the fast I/O path.
  572. //
  573. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  574. &Offset,
  575. Length,
  576. TRUE,
  577. LockKey,
  578. FALSE, // write operation
  579. IoStatus,
  580. targetVdo )) {
  581. //
  582. // Fast I/O is not possible so cleanup and return.
  583. //
  584. goto ErrOut;
  585. }
  586. }
  587. //
  588. // Update both caches with EOF.
  589. //
  590. if (DoingIoAtEof) {
  591. NtfsSetBothCacheSizes( FileObject,
  592. (PCC_FILE_SIZES)&Header->AllocationSize,
  593. (PSCB)Header );
  594. }
  595. //
  596. // We can do fast i/o so call the cc routine to do the work
  597. // and then release the fcb when we've done. If for whatever
  598. // reason the copy write fails, then return FALSE to our
  599. // caller.
  600. //
  601. // Also mark this as the top level "Irp" so that lower file
  602. // system levels will not attempt a pop-up
  603. //
  604. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  605. try {
  606. //
  607. // See if we have to do some zeroing
  608. //
  609. if (Offset.LowPart > Header->ValidDataLength.LowPart) {
  610. CcZeroData( FileObject,
  611. &Header->ValidDataLength,
  612. &Offset,
  613. TRUE );
  614. #ifdef SYSCACHE_DEBUG
  615. if (ScbIsBeingLogged( Scb )) {
  616. FsRtlLogSyscacheEvent( Scb, SCE_ZERO_FST, 0, Header->ValidDataLength.QuadPart, Offset.QuadPart - Header->ValidDataLength.QuadPart, 0 );
  617. }
  618. #endif
  619. }
  620. #ifdef COMPRESS_ON_WIRE
  621. //
  622. // If there is a compressed section, update its FileSize here
  623. //
  624. if ((Header->FileObjectC != NULL) && DoingIoAtEof) {
  625. CcSetFileSizes( Header->FileObjectC, (PCC_FILE_SIZES)&Header->AllocationSize );
  626. }
  627. #endif
  628. //
  629. // If there is a compressed section, then synchronize with that cache.
  630. //
  631. IoStatus->Status = STATUS_SUCCESS;
  632. //
  633. // If there is a compressed section, then we have to synchronize with
  634. // the data out there. Note the FileObjectC better also be there, or else
  635. // we would have made the fast I/O not possible.
  636. //
  637. WasDataWritten = FALSE;
  638. #ifdef COMPRESS_ON_WIRE
  639. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  640. LONGLONG LocalOffset = Offset.QuadPart;
  641. ULONG LocalLength;
  642. ULONG LengthLeft = Length;
  643. ASSERT( Header->FileObjectC != NULL );
  644. do {
  645. //
  646. // Calculate length left in view.
  647. //
  648. LocalLength = LengthLeft;
  649. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  650. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  651. }
  652. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  653. &LocalOffset,
  654. LocalLength,
  655. TRUE,
  656. &CompressionSync );
  657. if (NT_SUCCESS(IoStatus->Status)) {
  658. WasDataWritten = TRUE;
  659. CcFastCopyWrite( FileObject,
  660. (ULONG)LocalOffset,
  661. LocalLength,
  662. Buffer );
  663. LocalOffset += LocalLength;
  664. LengthLeft -= LocalLength;
  665. Buffer = Add2Ptr( Buffer, LocalLength );
  666. }
  667. } while ((LengthLeft != 0) && NT_SUCCESS( IoStatus->Status ));
  668. } else {
  669. #endif
  670. CcFastCopyWrite( FileObject,
  671. Offset.LowPart,
  672. Length,
  673. Buffer );
  674. WasDataWritten = TRUE;
  675. #ifdef COMPRESS_ON_WIRE
  676. }
  677. #endif
  678. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  679. ? EXCEPTION_EXECUTE_HANDLER
  680. : EXCEPTION_CONTINUE_SEARCH ) {
  681. WasDataWritten = FALSE;
  682. }
  683. IoSetTopLevelIrp( NULL );
  684. #ifdef COMPRESS_ON_WIRE
  685. if (CompressionSync != NULL) {
  686. NtfsReleaseCompressionSync( CompressionSync );
  687. }
  688. #endif
  689. //
  690. // If we succeeded, see if we have to update FileSize or
  691. // ValidDataLength.
  692. //
  693. if (WasDataWritten) {
  694. //
  695. // Set this handle as having modified the file and update
  696. // the current file position pointer
  697. //
  698. FileObject->Flags |= FO_FILE_MODIFIED;
  699. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  700. if (DoingIoAtEof) {
  701. CC_FILE_SIZES CcFileSizes;
  702. //
  703. // Make sure Cc knows the current FileSize, as set above,
  704. // (we may not have changed it). Update ValidDataLength
  705. // and finish EOF.
  706. //
  707. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  708. NtfsAcquireFsrtlHeader( (PSCB) Header );
  709. CcGetFileSizePointer(FileObject)->LowPart = Header->FileSize.LowPart;
  710. Header->ValidDataLength = NewFileSize;
  711. #ifdef SYSCACHE_DEBUG
  712. if (ScbIsBeingLogged( Scb )) {
  713. FsRtlLogSyscacheEvent( Scb, SCE_VDL_CHANGE, SCE_FLAG_WRITE | SCE_FLAG_FASTIO, 0, 0, NewFileSize.QuadPart );
  714. }
  715. #endif
  716. CcFileSizes = *(PCC_FILE_SIZES)&Header->AllocationSize;
  717. NtfsVerifySizes( Header );
  718. NtfsFinishIoAtEof( Header );
  719. NtfsReleaseFsrtlHeader( (PSCB) Header );
  720. #ifdef COMPRESS_ON_WIRE
  721. //
  722. // Update the CompressedCache with ValidDataLength.
  723. //
  724. if (Header->FileObjectC != NULL) {
  725. CcSetFileSizes( Header->FileObjectC, &CcFileSizes );
  726. }
  727. #endif
  728. }
  729. goto Done1;
  730. }
  731. //
  732. // Here is the 64-bit or no-wait path.
  733. //
  734. } else {
  735. //
  736. // Prevent truncates by acquiring paging I/O
  737. //
  738. WasDataWritten = ExAcquireResourceSharedLite( Header->PagingIoResource, Wait );
  739. if (!WasDataWritten) {
  740. goto Done2;
  741. }
  742. //
  743. // Now synchronize with the FsRtl Header
  744. //
  745. NtfsAcquireFsrtlHeader( (PSCB) Header );
  746. //
  747. // Now see if we will change FileSize. We have to do it now
  748. // so that our reads are not nooped.
  749. //
  750. if ((FileOffset->QuadPart < 0) || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  751. //
  752. // We can change FileSize and ValidDataLength if either, no one
  753. // else is now, or we are still extending after waiting.
  754. //
  755. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  756. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  757. //
  758. // Set the Flag if we are changing FileSize or ValidDataLength,
  759. // and save current values.
  760. //
  761. if (DoingIoAtEof) {
  762. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  763. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  764. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  765. #endif
  766. //
  767. // Now that we are synchronized for end of file cases,
  768. // we can calculate the real offset for this transfer and
  769. // the new file size (if we succeed).
  770. //
  771. if ((FileOffset->QuadPart < 0)) {
  772. Offset = Header->FileSize;
  773. }
  774. //
  775. // Now calculate the new FileSize and see if we wrapped the
  776. // 32-bit boundary.
  777. //
  778. NewFileSize.QuadPart = Offset.QuadPart + Length;
  779. //
  780. // Update Filesize now so that we do not truncate reads.
  781. //
  782. OldFileSize.QuadPart = Header->FileSize.QuadPart;
  783. if (NewFileSize.QuadPart > Header->FileSize.QuadPart) {
  784. //
  785. // If we are beyond AllocationSize, make sure we will
  786. // ErrOut below, and don't modify FileSize now!
  787. //
  788. if (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) {
  789. NewFileSize.QuadPart = (LONGLONG)0x7FFFFFFFFFFFFFFF;
  790. } else {
  791. Header->FileSize.QuadPart = NewFileSize.QuadPart;
  792. }
  793. }
  794. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  795. } else {
  796. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  797. #endif
  798. }
  799. }
  800. NtfsReleaseFsrtlHeader( (PSCB) Header );
  801. //
  802. // Now that the File is acquired shared, we can safely test
  803. // if it is really cached and if we can do fast i/o and we
  804. // do not have to extend. If not then release the fcb and
  805. // return.
  806. //
  807. // Get out if we are about to zero too much as well, as commented above.
  808. //
  809. // If there is a compressed stream and we are DoingIoAtEof, then get
  810. // out because we could deadlock on a recursive flush from the synchronize.
  811. //
  812. if ((FileObject->PrivateCacheMap == NULL) ||
  813. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  814. /* Remove? */ (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ||
  815. (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000)) ||
  816. #ifdef COMPRESS_ON_WIRE
  817. ((((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) &&
  818. DoingIoAtEof)
  819. #else
  820. FALSE
  821. #endif
  822. ) {
  823. goto ErrOut;
  824. }
  825. //
  826. // Check if fast I/O is questionable and if so then go ask
  827. // the file system the answer
  828. //
  829. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  830. targetVdo = IoGetRelatedDeviceObject( FileObject );
  831. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  832. //
  833. // All file system then set "Is Questionable" had better
  834. // support fast I/O
  835. //
  836. ASSERT(FastIoDispatch != NULL);
  837. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  838. //
  839. // Call the file system to check for fast I/O. If the
  840. // answer is anything other than GoForIt then we cannot
  841. // take the fast I/O path.
  842. //
  843. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  844. &Offset,
  845. Length,
  846. Wait,
  847. LockKey,
  848. FALSE, // write operation
  849. IoStatus,
  850. targetVdo )) {
  851. //
  852. // Fast I/O is not possible so cleanup and return.
  853. //
  854. goto ErrOut;
  855. }
  856. }
  857. //
  858. // Update both caches with EOF.
  859. //
  860. if (DoingIoAtEof) {
  861. NtfsSetBothCacheSizes( FileObject,
  862. (PCC_FILE_SIZES)&Header->AllocationSize,
  863. (PSCB)Header );
  864. }
  865. //
  866. // We can do fast i/o so call the cc routine to do the work
  867. // and then release the fcb when we've done. If for whatever
  868. // reason the copy write fails, then return FALSE to our
  869. // caller.
  870. //
  871. // Also mark this as the top level "Irp" so that lower file
  872. // system levels will not attempt a pop-up
  873. //
  874. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  875. try {
  876. //
  877. // See if we have to do some zeroing
  878. //
  879. if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {
  880. #ifdef SYSCACHE_DEBUG
  881. if (ScbIsBeingLogged( Scb )) {
  882. FsRtlLogSyscacheEvent( Scb, SCE_ZERO_FST, SCE_FLAG_ASYNC, Header->ValidDataLength.QuadPart, Offset.QuadPart, 0 );
  883. }
  884. #endif
  885. WasDataWritten = CcZeroData( FileObject,
  886. &Header->ValidDataLength,
  887. &Offset,
  888. Wait );
  889. }
  890. if (WasDataWritten) {
  891. //
  892. // If there is a compressed section, update its FileSize here
  893. //
  894. #ifdef COMPRESS_ON_WIRE
  895. if ((Header->FileObjectC != NULL) && DoingIoAtEof) {
  896. CcSetFileSizes( Header->FileObjectC, (PCC_FILE_SIZES)&Header->AllocationSize );
  897. }
  898. #endif
  899. //
  900. // If there is a compressed section, then synchronize with that cache.
  901. //
  902. IoStatus->Status = STATUS_SUCCESS;
  903. //
  904. // If there is a compressed section, then we have to synchronize with
  905. // the data out there. Note the FileObjectC better also be there, or else
  906. // we would have made the fast I/O not possible.
  907. //
  908. WasDataWritten = FALSE;
  909. #ifdef COMPRESS_ON_WIRE
  910. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  911. LONGLONG LocalOffset = Offset.QuadPart;
  912. ULONG LocalLength;
  913. ULONG LengthLeft = Length;
  914. ASSERT(Header->FileObjectC != NULL);
  915. do {
  916. //
  917. // Calculate length left in view.
  918. //
  919. LocalLength = LengthLeft;
  920. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  921. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  922. }
  923. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  924. &LocalOffset,
  925. LocalLength,
  926. TRUE,
  927. &CompressionSync );
  928. if (NT_SUCCESS(IoStatus->Status)) {
  929. WasDataWritten = CcCopyWrite( FileObject,
  930. (PLARGE_INTEGER)&LocalOffset,
  931. LocalLength,
  932. Wait,
  933. Buffer );
  934. LocalOffset += LocalLength;
  935. LengthLeft -= LocalLength;
  936. Buffer = Add2Ptr( Buffer, LocalLength );
  937. }
  938. } while ((LengthLeft != 0) && WasDataWritten && NT_SUCCESS(IoStatus->Status));
  939. } else {
  940. #endif
  941. WasDataWritten = CcCopyWrite( FileObject,
  942. &Offset,
  943. Length,
  944. Wait,
  945. Buffer );
  946. }
  947. #ifdef COMPRESS_ON_WIRE
  948. }
  949. #endif
  950. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  951. ? EXCEPTION_EXECUTE_HANDLER
  952. : EXCEPTION_CONTINUE_SEARCH ) {
  953. WasDataWritten = FALSE;
  954. }
  955. IoSetTopLevelIrp( NULL );
  956. #ifdef COMPRESS_ON_WIRE
  957. if (CompressionSync != NULL) {
  958. NtfsReleaseCompressionSync( CompressionSync );
  959. }
  960. #endif
  961. //
  962. // If we succeeded, see if we have to update FileSize ValidDataLength.
  963. //
  964. if (WasDataWritten) {
  965. //
  966. // Set this handle as having modified the file and update
  967. // the current file position pointer
  968. //
  969. FileObject->Flags |= FO_FILE_MODIFIED;
  970. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  971. if (DoingIoAtEof) {
  972. CC_FILE_SIZES CcFileSizes;
  973. //
  974. // Make sure Cc knows the current FileSize, as set above,
  975. // (we may not have changed it). Update ValidDataLength
  976. // and finish EOF.
  977. //
  978. NtfsAcquireFsrtlHeader( (PSCB) Header );
  979. CcGetFileSizePointer(FileObject)->QuadPart = Header->FileSize.QuadPart;
  980. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  981. Header->ValidDataLength = NewFileSize;
  982. CcFileSizes = *(PCC_FILE_SIZES)&Header->AllocationSize;
  983. NtfsVerifySizes( Header );
  984. NtfsFinishIoAtEof( Header );
  985. NtfsReleaseFsrtlHeader( (PSCB) Header );
  986. #ifdef COMPRESS_ON_WIRE
  987. //
  988. // Update the CompressedCache with ValidDataLength.
  989. //
  990. if (Header->FileObjectC != NULL) {
  991. CcSetFileSizes( Header->FileObjectC, &CcFileSizes );
  992. }
  993. #endif
  994. }
  995. goto Done1;
  996. }
  997. }
  998. ErrOut:
  999. WasDataWritten = FALSE;
  1000. if (DoingIoAtEof) {
  1001. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1002. #ifdef COMPRESS_ON_WIRE
  1003. if (Header->FileObjectC != NULL) {
  1004. *CcGetFileSizePointer(Header->FileObjectC) = OldFileSize;
  1005. }
  1006. #endif
  1007. Header->FileSize = OldFileSize;
  1008. NtfsFinishIoAtEof( Header );
  1009. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1010. }
  1011. Done1:
  1012. ExReleaseResourceLite( Header->PagingIoResource );
  1013. Done2:
  1014. FsRtlExitFileSystem();
  1015. }
  1016. } else {
  1017. //
  1018. // We could not do the I/O now.
  1019. //
  1020. WasDataWritten = FALSE;
  1021. }
  1022. return WasDataWritten;
  1023. }
  1024. BOOLEAN
  1025. NtfsMdlReadA (
  1026. IN PFILE_OBJECT FileObject,
  1027. IN PLARGE_INTEGER FileOffset,
  1028. IN ULONG Length,
  1029. IN ULONG LockKey,
  1030. OUT PMDL *MdlChain,
  1031. OUT PIO_STATUS_BLOCK IoStatus,
  1032. IN PDEVICE_OBJECT DeviceObject
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. This routine does a fast cached mdl read bypassing the usual file system
  1037. entry routine (i.e., without the Irp). It is used to do a copy read
  1038. of a cached file object. For a complete description of the arguments
  1039. see CcMdlRead.
  1040. Arguments:
  1041. FileObject - Pointer to the file object being read.
  1042. FileOffset - Byte offset in file for desired data.
  1043. Length - Length of desired data in bytes.
  1044. MdlChain - On output it returns a pointer to an MDL chain describing
  1045. the desired data.
  1046. IoStatus - Pointer to standard I/O status block to receive the status
  1047. for the transfer.
  1048. Return Value:
  1049. FALSE - if the data was not delivered, or if there is an I/O error.
  1050. TRUE - if the data is being delivered
  1051. --*/
  1052. {
  1053. PNTFS_ADVANCED_FCB_HEADER Header;
  1054. #ifdef COMPRESS_ON_WIRE
  1055. PCOMPRESSION_SYNC CompressionSync = NULL;
  1056. #endif
  1057. BOOLEAN DoingIoAtEof = FALSE;
  1058. BOOLEAN WasDataRead = TRUE;
  1059. LARGE_INTEGER BeyondLastByte;
  1060. UNREFERENCED_PARAMETER( DeviceObject );
  1061. PAGED_CODE();
  1062. //
  1063. // Special case a read of zero length
  1064. //
  1065. if (Length == 0) {
  1066. IoStatus->Status = STATUS_SUCCESS;
  1067. IoStatus->Information = 0;
  1068. //
  1069. // Get a real pointer to the common fcb header
  1070. //
  1071. } else {
  1072. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  1073. //
  1074. // Overflows should've been handled by the caller.
  1075. //
  1076. ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length);
  1077. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  1078. //
  1079. // Enter the file system
  1080. //
  1081. FsRtlEnterFileSystem();
  1082. #ifdef _WIN64
  1083. //
  1084. // The following should work for either 64 or 32 bits.
  1085. // Remove the 32 bit-only version in the #else clause
  1086. // after NT2K ships.
  1087. //
  1088. **((PULONG *)&CcFastMdlReadWait) += 1;
  1089. #else
  1090. *(PULONG)CcFastMdlReadWait += 1;
  1091. #endif
  1092. //
  1093. // Acquired shared on the common fcb header
  1094. //
  1095. if (Header->PagingIoResource == NULL) {
  1096. WasDataRead = FALSE;
  1097. goto Done2;
  1098. }
  1099. (VOID)ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  1100. //
  1101. // Now synchronize with the FsRtl Header
  1102. //
  1103. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1104. //
  1105. // Now see if we are reading beyond ValidDataLength. We have to
  1106. // do it now so that our reads are not nooped.
  1107. //
  1108. if (BeyondLastByte.QuadPart > Header->ValidDataLength.QuadPart) {
  1109. //
  1110. // We must serialize with anyone else doing I/O at beyond
  1111. // ValidDataLength, and then remember if we need to declare
  1112. // when we are done.
  1113. //
  1114. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  1115. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  1116. //
  1117. // Set the Flag if we are in fact beyond ValidDataLength.
  1118. //
  1119. if (DoingIoAtEof) {
  1120. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  1121. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1122. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  1123. } else {
  1124. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  1125. #endif
  1126. }
  1127. }
  1128. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1129. //
  1130. // Now that the File is acquired shared, we can safely test if it is
  1131. // really cached and if we can do fast i/o and if not
  1132. // then release the fcb and return.
  1133. //
  1134. if ((FileObject->PrivateCacheMap == NULL) ||
  1135. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  1136. WasDataRead = FALSE;
  1137. goto Done;
  1138. }
  1139. //
  1140. // Check if fast I/O is questionable and if so then go ask the file system
  1141. // the answer
  1142. //
  1143. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  1144. PFAST_IO_DISPATCH FastIoDispatch;
  1145. FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  1146. //
  1147. // All file system then set "Is Questionable" had better support fast I/O
  1148. //
  1149. ASSERT(FastIoDispatch != NULL);
  1150. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  1151. //
  1152. // Call the file system to check for fast I/O. If the answer is anything
  1153. // other than GoForIt then we cannot take the fast I/O path.
  1154. //
  1155. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  1156. FileOffset,
  1157. Length,
  1158. TRUE,
  1159. LockKey,
  1160. TRUE, // read operation
  1161. IoStatus,
  1162. IoGetRelatedDeviceObject( FileObject ) )) {
  1163. //
  1164. // Fast I/O is not possible so release the Fcb and return.
  1165. //
  1166. WasDataRead = FALSE;
  1167. goto Done;
  1168. }
  1169. }
  1170. //
  1171. // Check for read past file size.
  1172. //
  1173. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  1174. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  1175. IoStatus->Status = STATUS_END_OF_FILE;
  1176. IoStatus->Information = 0;
  1177. goto Done;
  1178. }
  1179. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  1180. }
  1181. //
  1182. // We can do fast i/o so call the cc routine to do the work and then
  1183. // release the fcb when we've done. If for whatever reason the
  1184. // mdl read fails, then return FALSE to our caller.
  1185. //
  1186. //
  1187. // Also mark this as the top level "Irp" so that lower file system levels
  1188. // will not attempt a pop-up
  1189. //
  1190. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  1191. try {
  1192. //
  1193. // If there is a compressed section, then synchronize with that cache.
  1194. //
  1195. IoStatus->Status = STATUS_SUCCESS;
  1196. //
  1197. // If there is a compressed section, then we have to synchronize with
  1198. // the data out there. Note the FileObjectC better also be there, or else
  1199. // we would have made the fast I/O not possible.
  1200. //
  1201. WasDataRead = FALSE;
  1202. #ifdef COMPRESS_ON_WIRE
  1203. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  1204. LONGLONG LocalOffset = FileOffset->QuadPart;
  1205. ULONG LengthRemaining = Length;
  1206. ULONG LocalLength;
  1207. ASSERT(Header->FileObjectC != NULL);
  1208. //
  1209. // If we are doing DoingIoAtEof then take the long path. Otherwise a recursive
  1210. // flush will try to reacquire DoingIoAtEof and deadlock.
  1211. //
  1212. if (DoingIoAtEof) {
  1213. WasDataRead = FALSE;
  1214. } else {
  1215. do {
  1216. //
  1217. // Calculate length left in view.
  1218. //
  1219. LocalLength = LengthRemaining;
  1220. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  1221. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  1222. }
  1223. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  1224. &LocalOffset,
  1225. LocalLength,
  1226. FALSE,
  1227. &CompressionSync );
  1228. if (NT_SUCCESS(IoStatus->Status)) {
  1229. #ifdef NTFS_RWCMP_TRACE
  1230. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1231. DbgPrint("CcMdlRead(F): FO = %08lx, Len = %08lx\n", (ULONG)LocalOffset, LocalLength );
  1232. }
  1233. #endif
  1234. CcMdlRead( FileObject,
  1235. (PLARGE_INTEGER)&LocalOffset,
  1236. LocalLength,
  1237. MdlChain,
  1238. IoStatus );
  1239. LocalOffset += LocalLength;
  1240. LengthRemaining -= LocalLength;
  1241. }
  1242. } while ((LengthRemaining != 0) && NT_SUCCESS(IoStatus->Status));
  1243. //
  1244. // Store final return byte count.
  1245. //
  1246. if (NT_SUCCESS( IoStatus->Status )) {
  1247. IoStatus->Information = Length;
  1248. }
  1249. }
  1250. } else {
  1251. #endif
  1252. #ifdef NTFS_RWCMP_TRACE
  1253. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1254. DbgPrint("CcMdlRead(F): FO = %08lx, Len = %08lx\n", FileOffset->LowPart, Length );
  1255. }
  1256. #endif
  1257. CcMdlRead( FileObject, FileOffset, Length, MdlChain, IoStatus );
  1258. WasDataRead = TRUE;
  1259. #ifdef COMPRESS_ON_WIRE
  1260. }
  1261. #endif
  1262. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  1263. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  1264. ? EXCEPTION_EXECUTE_HANDLER
  1265. : EXCEPTION_CONTINUE_SEARCH ) {
  1266. WasDataRead = FALSE;
  1267. }
  1268. IoSetTopLevelIrp( NULL );
  1269. #ifdef COMPRESS_ON_WIRE
  1270. if (CompressionSync != NULL) {
  1271. NtfsReleaseCompressionSync( CompressionSync );
  1272. }
  1273. #endif
  1274. Done: NOTHING;
  1275. if (DoingIoAtEof) {
  1276. FsRtlUnlockFsRtlHeader( Header );
  1277. }
  1278. ExReleaseResourceLite( Header->PagingIoResource );
  1279. Done2: NOTHING;
  1280. FsRtlExitFileSystem();
  1281. }
  1282. return WasDataRead;
  1283. }
  1284. BOOLEAN
  1285. NtfsPrepareMdlWriteA (
  1286. IN PFILE_OBJECT FileObject,
  1287. IN PLARGE_INTEGER FileOffset,
  1288. IN ULONG Length,
  1289. IN ULONG LockKey,
  1290. OUT PMDL *MdlChain,
  1291. OUT PIO_STATUS_BLOCK IoStatus,
  1292. IN PDEVICE_OBJECT DeviceObject
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. This routine does a fast cached mdl read bypassing the usual file system
  1297. entry routine (i.e., without the Irp). It is used to do a copy read
  1298. of a cached file object. For a complete description of the arguments
  1299. see CcMdlRead.
  1300. Arguments:
  1301. FileObject - Pointer to the file object being read.
  1302. FileOffset - Byte offset in file for desired data.
  1303. Length - Length of desired data in bytes.
  1304. MdlChain - On output it returns a pointer to an MDL chain describing
  1305. the desired data.
  1306. IoStatus - Pointer to standard I/O status block to receive the status
  1307. for the transfer.
  1308. Return Value:
  1309. FALSE - if the data was not written, or if there is an I/O error.
  1310. TRUE - if the data is being written
  1311. --*/
  1312. {
  1313. PNTFS_ADVANCED_FCB_HEADER Header;
  1314. LARGE_INTEGER Offset, NewFileSize;
  1315. LARGE_INTEGER OldFileSize;
  1316. #ifdef COMPRESS_ON_WIRE
  1317. PCOMPRESSION_SYNC CompressionSync = NULL;
  1318. #endif
  1319. ULONG DoingIoAtEof = FALSE;
  1320. BOOLEAN WasDataWritten = TRUE;
  1321. UNREFERENCED_PARAMETER( DeviceObject );
  1322. PAGED_CODE();
  1323. //
  1324. // Get a real pointer to the common fcb header
  1325. //
  1326. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  1327. //
  1328. // Do we need to verify the volume? If so, we must go to the file
  1329. // system. Also return FALSE if FileObject is write through, the
  1330. // File System must do that.
  1331. //
  1332. if (CcCanIWrite( FileObject, Length, TRUE, FALSE ) &&
  1333. !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) &&
  1334. CcCopyWriteWontFlush(FileObject, FileOffset, Length) &&
  1335. (Header->PagingIoResource != NULL)) {
  1336. //
  1337. // Assume our transfer will work
  1338. //
  1339. IoStatus->Status = STATUS_SUCCESS;
  1340. //
  1341. // Special case the zero byte length
  1342. //
  1343. if (Length != 0) {
  1344. //
  1345. // Enter the file system
  1346. //
  1347. FsRtlEnterFileSystem();
  1348. //
  1349. // Make our best guess on whether we need the file exclusive or
  1350. // shared.
  1351. //
  1352. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  1353. Offset = *FileOffset;
  1354. //
  1355. // Prevent truncates by acquiring paging I/O
  1356. //
  1357. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  1358. //
  1359. // Now synchronize with the FsRtl Header
  1360. //
  1361. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1362. //
  1363. // Now see if we will change FileSize. We have to do it now
  1364. // so that our reads are not nooped.
  1365. //
  1366. if ((FileOffset->QuadPart < 0) || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  1367. //
  1368. // We can change FileSize and ValidDataLength if either, no one
  1369. // else is now, or we are still extending after waiting.
  1370. //
  1371. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  1372. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  1373. //
  1374. // Set the Flag if we are changing FileSize or ValidDataLength,
  1375. // and save current values.
  1376. //
  1377. if (DoingIoAtEof) {
  1378. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  1379. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1380. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  1381. #endif
  1382. //
  1383. // Now that we are synchronized for end of file cases,
  1384. // we can calculate the real offset for this transfer and
  1385. // the new file size (if we succeed).
  1386. //
  1387. if ((FileOffset->QuadPart < 0)) {
  1388. Offset = Header->FileSize;
  1389. }
  1390. //
  1391. // Now calculate the new FileSize and see if we wrapped the
  1392. // 32-bit boundary.
  1393. //
  1394. NewFileSize.QuadPart = Offset.QuadPart + Length;
  1395. //
  1396. // Update Filesize now so that we do not truncate reads.
  1397. //
  1398. OldFileSize.QuadPart = Header->FileSize.QuadPart;
  1399. if (NewFileSize.QuadPart > Header->FileSize.QuadPart) {
  1400. //
  1401. // If we are beyond AllocationSize, make sure we will
  1402. // ErrOut below, and don't modify FileSize now!
  1403. //
  1404. if (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) {
  1405. NewFileSize.QuadPart = (LONGLONG)0x7FFFFFFFFFFFFFFF;
  1406. } else {
  1407. Header->FileSize.QuadPart = NewFileSize.QuadPart;
  1408. }
  1409. }
  1410. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1411. } else {
  1412. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  1413. #endif
  1414. }
  1415. }
  1416. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1417. //
  1418. // Now that the File is acquired shared, we can safely test
  1419. // if it is really cached and if we can do fast i/o and we
  1420. // do not have to extend. If not then release the fcb and
  1421. // return.
  1422. //
  1423. // Get out if we are about to zero too much as well, as commented above.
  1424. //
  1425. if ((FileObject->PrivateCacheMap == NULL) ||
  1426. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  1427. /* Remove? */ (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ||
  1428. (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000))) {
  1429. goto ErrOut;
  1430. }
  1431. //
  1432. // Check if fast I/O is questionable and if so then go ask the file system
  1433. // the answer
  1434. //
  1435. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  1436. PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  1437. //
  1438. // All file system then set "Is Questionable" had better support fast I/O
  1439. //
  1440. ASSERT(FastIoDispatch != NULL);
  1441. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  1442. //
  1443. // Call the file system to check for fast I/O. If the answer is anything
  1444. // other than GoForIt then we cannot take the fast I/O path.
  1445. //
  1446. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  1447. &Offset,
  1448. Length,
  1449. TRUE,
  1450. LockKey,
  1451. FALSE, // write operation
  1452. IoStatus,
  1453. IoGetRelatedDeviceObject( FileObject ) )) {
  1454. //
  1455. // Fast I/O is not possible so release the Fcb and return.
  1456. //
  1457. goto ErrOut;
  1458. }
  1459. }
  1460. //
  1461. // Update both caches with EOF.
  1462. //
  1463. if (DoingIoAtEof) {
  1464. NtfsSetBothCacheSizes( FileObject,
  1465. (PCC_FILE_SIZES)&Header->AllocationSize,
  1466. (PSCB)Header );
  1467. }
  1468. //
  1469. // We can do fast i/o so call the cc routine to do the work and then
  1470. // release the fcb when we've done. If for whatever reason the
  1471. // copy write fails, then return FALSE to our caller.
  1472. //
  1473. //
  1474. // Also mark this as the top level "Irp" so that lower file system levels
  1475. // will not attempt a pop-up
  1476. //
  1477. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  1478. try {
  1479. //
  1480. // See if we have to do some zeroing
  1481. //
  1482. if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {
  1483. WasDataWritten = CcZeroData( FileObject,
  1484. &Header->ValidDataLength,
  1485. &Offset,
  1486. TRUE );
  1487. }
  1488. if (WasDataWritten) {
  1489. #ifdef COMPRESS_ON_WIRE
  1490. //
  1491. // If there is a compressed section, update its FileSize here
  1492. //
  1493. if ((Header->FileObjectC != NULL) && DoingIoAtEof) {
  1494. CcSetFileSizes( Header->FileObjectC, (PCC_FILE_SIZES)&Header->AllocationSize );
  1495. }
  1496. #endif
  1497. //
  1498. // If there is a compressed section, then synchronize with that cache.
  1499. //
  1500. IoStatus->Status = STATUS_SUCCESS;
  1501. //
  1502. // If there is a compressed section, then we have to synchronize with
  1503. // the data out there. Note the FileObjectC better also be there, or else
  1504. // we would have made the fast I/O not possible.
  1505. //
  1506. #ifdef COMPRESS_ON_WIRE
  1507. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  1508. LONGLONG LocalOffset = Offset.QuadPart;
  1509. ULONG LocalLength;
  1510. ULONG LengthLeft = Length;
  1511. ASSERT(Header->FileObjectC != NULL);
  1512. //
  1513. // If we are doing DoingIoAtEof then take the long path. Otherwise a recursive
  1514. // flush will try to reacquire DoingIoAtEof and deadlock.
  1515. //
  1516. if (DoingIoAtEof) {
  1517. WasDataWritten = FALSE;
  1518. } else {
  1519. do {
  1520. //
  1521. // Calculate length left in view.
  1522. //
  1523. LocalLength = LengthLeft;
  1524. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  1525. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  1526. }
  1527. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  1528. &LocalOffset,
  1529. LocalLength,
  1530. TRUE,
  1531. &CompressionSync );
  1532. if (NT_SUCCESS(IoStatus->Status)) {
  1533. #ifdef NTFS_RWCMP_TRACE
  1534. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1535. DbgPrint("CcMdlWrite(F): FO = %08lx, Len = %08lx\n", (ULONG)LocalOffset, LocalLength );
  1536. }
  1537. #endif
  1538. CcPrepareMdlWrite( FileObject,
  1539. (PLARGE_INTEGER)&LocalOffset,
  1540. LocalLength,
  1541. MdlChain,
  1542. IoStatus );
  1543. LocalOffset += LocalLength;
  1544. LengthLeft -= LocalLength;
  1545. }
  1546. } while ((LengthLeft != 0) && NT_SUCCESS(IoStatus->Status));
  1547. WasDataWritten = TRUE;
  1548. }
  1549. } else {
  1550. #endif
  1551. #ifdef NTFS_RWCMP_TRACE
  1552. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1553. DbgPrint("CcMdlWrite(F): FO = %08lx, Len = %08lx\n", Offset.LowPart, Length );
  1554. }
  1555. #endif
  1556. CcPrepareMdlWrite( FileObject, &Offset, Length, MdlChain, IoStatus );
  1557. WasDataWritten = TRUE;
  1558. }
  1559. #ifdef COMPRESS_ON_WIRE
  1560. }
  1561. #endif
  1562. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  1563. ? EXCEPTION_EXECUTE_HANDLER
  1564. : EXCEPTION_CONTINUE_SEARCH ) {
  1565. WasDataWritten = FALSE;
  1566. }
  1567. IoSetTopLevelIrp( NULL );
  1568. #ifdef COMPRESS_ON_WIRE
  1569. if (CompressionSync != NULL) {
  1570. NtfsReleaseCompressionSync( CompressionSync );
  1571. }
  1572. #endif
  1573. //
  1574. // If we succeeded, see if we have to update FileSize ValidDataLength.
  1575. //
  1576. if (WasDataWritten) {
  1577. //
  1578. // Set this handle as having modified the file
  1579. //
  1580. FileObject->Flags |= FO_FILE_MODIFIED;
  1581. IoStatus->Information = Length;
  1582. if (DoingIoAtEof) {
  1583. CC_FILE_SIZES CcFileSizes;
  1584. //
  1585. // Make sure Cc knows the current FileSize, as set above,
  1586. // (we may not have changed it). Update ValidDataLength
  1587. // and finish EOF.
  1588. //
  1589. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1590. CcGetFileSizePointer(FileObject)->QuadPart = Header->FileSize.QuadPart;
  1591. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  1592. Header->ValidDataLength = NewFileSize;
  1593. CcFileSizes = *(PCC_FILE_SIZES)&Header->AllocationSize;
  1594. NtfsVerifySizes( Header );
  1595. NtfsFinishIoAtEof( Header );
  1596. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1597. #ifdef COMPRESS_ON_WIRE
  1598. //
  1599. // Update the CompressedCache with ValidDataLength.
  1600. //
  1601. if (Header->FileObjectC != NULL) {
  1602. CcSetFileSizes( Header->FileObjectC, &CcFileSizes );
  1603. }
  1604. #endif
  1605. }
  1606. goto Done1;
  1607. }
  1608. ErrOut: NOTHING;
  1609. WasDataWritten = FALSE;
  1610. if (DoingIoAtEof) {
  1611. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1612. #ifdef COMPRESS_ON_WIRE
  1613. if (Header->FileObjectC != NULL) {
  1614. *CcGetFileSizePointer(Header->FileObjectC) = OldFileSize;
  1615. }
  1616. #endif
  1617. Header->FileSize = OldFileSize;
  1618. NtfsFinishIoAtEof( Header );
  1619. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1620. }
  1621. Done1: ExReleaseResourceLite( Header->PagingIoResource );
  1622. FsRtlExitFileSystem();
  1623. }
  1624. } else {
  1625. //
  1626. // We could not do the I/O now.
  1627. //
  1628. WasDataWritten = FALSE;
  1629. }
  1630. return WasDataWritten;
  1631. }
  1632. BOOLEAN
  1633. NtfsWaitForIoAtEof (
  1634. IN PNTFS_ADVANCED_FCB_HEADER Header,
  1635. IN OUT PLARGE_INTEGER FileOffset,
  1636. IN ULONG Length
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. This routine may be called while synchronized for cached write, to
  1641. test for a possible Eof update, and return with a status if Eof is
  1642. being updated and with the previous FileSize to restore on error.
  1643. All updates to Eof are serialized by waiting in this routine. If
  1644. this routine returns TRUE, then NtfsFinishIoAtEof must be called.
  1645. This routine must be called while synchronized with the FsRtl header.
  1646. Arguments:
  1647. Header - Pointer to the FsRtl header for the file
  1648. FileOffset - Pointer to FileOffset for the intended write
  1649. Length - Length for the intended write
  1650. EofWaitBlock - Uninitialized structure used only to serialize Eof updates
  1651. Return Value:
  1652. FALSE - If the write does not extend Eof (OldFileSize not returned)
  1653. TRUE - If the write does extend Eof OldFileSize returned and caller
  1654. must eventually call NtfsFinishIoAtEof
  1655. --*/
  1656. {
  1657. EOF_WAIT_BLOCK EofWaitBlock;
  1658. PAGED_CODE();
  1659. ASSERT( Header->FileSize.QuadPart >= Header->ValidDataLength.QuadPart );
  1660. //
  1661. // Initialize the event and queue our block
  1662. //
  1663. KeInitializeEvent( &EofWaitBlock.Event, NotificationEvent, FALSE );
  1664. InsertTailList( Header->PendingEofAdvances, &EofWaitBlock.EofWaitLinks );
  1665. //
  1666. // Free the mutex and wait
  1667. //
  1668. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1669. KeWaitForSingleObject( &EofWaitBlock.Event,
  1670. Executive,
  1671. KernelMode,
  1672. FALSE,
  1673. (PLARGE_INTEGER)NULL);
  1674. //
  1675. // Now, resynchronize and get on with it.
  1676. //
  1677. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1678. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1679. ASSERT( ((PSCB) Header)->IoAtEofThread == NULL );
  1680. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  1681. #endif
  1682. //
  1683. // Now we have to check again, and actually catch the case
  1684. // where we are no longer extending!
  1685. //
  1686. if ((FileOffset->QuadPart >= 0) &&
  1687. ((FileOffset->QuadPart + Length) <= Header->ValidDataLength.QuadPart)) {
  1688. NtfsFinishIoAtEof( Header );
  1689. return FALSE;
  1690. }
  1691. return TRUE;
  1692. }
  1693. VOID
  1694. NtfsFinishIoAtEof (
  1695. IN PNTFS_ADVANCED_FCB_HEADER Header
  1696. )
  1697. /*++
  1698. Routine Description:
  1699. This routine must be called if NtfsWaitForIoAtEof returned
  1700. TRUE, or we otherwise set EOF_ADVANCE_ACTIVE.
  1701. This routine must be called while synchronized with the FsRtl header.
  1702. Arguments:
  1703. Header - Pointer to the FsRtl header for the file
  1704. Return Value:
  1705. None
  1706. --*/
  1707. {
  1708. PEOF_WAIT_BLOCK EofWaitBlock;
  1709. PAGED_CODE();
  1710. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1711. ((PSCB) Header)->IoAtEofThread = NULL;
  1712. #endif
  1713. //
  1714. // If anyone is waiting, just let them go.
  1715. //
  1716. if (!IsListEmpty(Header->PendingEofAdvances)) {
  1717. EofWaitBlock = (PEOF_WAIT_BLOCK)RemoveHeadList( Header-> PendingEofAdvances );
  1718. KeSetEvent( &EofWaitBlock->Event, 0, FALSE );
  1719. //
  1720. // Otherwise, show there is no active extender now.
  1721. //
  1722. } else {
  1723. ClearFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  1724. }
  1725. }