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.

1062 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FastIo2.c
  5. Abstract:
  6. This module REimplements the fsrtl copy read/write routines.
  7. Author:
  8. Joe Linn [JoeLinn] 9-Nov-1994
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifndef FlagOn
  14. //
  15. // This macro returns TRUE if a flag in a set of flags is on and FALSE
  16. // otherwise
  17. //
  18. #define FlagOn(Flags,SingleFlag) ((Flags) & (SingleFlag))
  19. #endif
  20. BOOLEAN
  21. FsRtlCopyRead2 (
  22. IN PFILE_OBJECT FileObject,
  23. IN PLARGE_INTEGER FileOffset,
  24. IN ULONG Length,
  25. IN BOOLEAN Wait,
  26. IN ULONG LockKey,
  27. OUT PVOID Buffer,
  28. OUT PIO_STATUS_BLOCK IoStatus,
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN ULONG_PTR TopLevelIrpValue
  31. );
  32. BOOLEAN
  33. FsRtlCopyWrite2 (
  34. IN PFILE_OBJECT FileObject,
  35. IN PLARGE_INTEGER FileOffset,
  36. IN ULONG Length,
  37. IN BOOLEAN Wait,
  38. IN ULONG LockKey,
  39. IN PVOID Buffer,
  40. OUT PIO_STATUS_BLOCK IoStatus,
  41. IN PDEVICE_OBJECT DeviceObject,
  42. IN ULONG_PTR TopLevelIrpValue
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(PAGE, FsRtlCopyRead2)
  46. #pragma alloc_text(PAGE, FsRtlCopyWrite2)
  47. #endif
  48. BOOLEAN
  49. FsRtlCopyRead2 (
  50. IN PFILE_OBJECT FileObject,
  51. IN PLARGE_INTEGER FileOffset,
  52. IN ULONG Length,
  53. IN BOOLEAN Wait,
  54. IN ULONG LockKey,
  55. OUT PVOID Buffer,
  56. OUT PIO_STATUS_BLOCK IoStatus,
  57. IN PDEVICE_OBJECT DeviceObject,
  58. IN ULONG_PTR TopLevelIrpValue
  59. )
  60. /*++
  61. Routine Description:
  62. This routine does a fast cached read bypassing the usual file system
  63. entry routine (i.e., without the Irp). It is used to do a copy read
  64. of a cached file object. For a complete description of the arguments
  65. see CcCopyRead.
  66. Arguments:
  67. FileObject - Pointer to the file object being read.
  68. FileOffset - Byte offset in file for desired data.
  69. Length - Length of desired data in bytes.
  70. Wait - FALSE if caller may not block, TRUE otherwise
  71. Buffer - Pointer to output buffer to which data should be copied.
  72. IoStatus - Pointer to standard I/O status block to receive the status
  73. for the transfer.
  74. Return Value:
  75. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  76. if there is an I/O error.
  77. TRUE - if the data is being delivered
  78. --*/
  79. {
  80. PFSRTL_COMMON_FCB_HEADER Header;
  81. BOOLEAN Status = TRUE;
  82. ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES((ULongToPtr(FileOffset->LowPart)), Length);
  83. LARGE_INTEGER BeyondLastByte;
  84. PDEVICE_OBJECT targetVdo;
  85. PAGED_CODE();
  86. //
  87. // Special case a read of zero length
  88. //
  89. if (Length != 0) {
  90. //
  91. // Get a real pointer to the common fcb header
  92. //
  93. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  94. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  95. //
  96. // Enter the file system
  97. //
  98. FsRtlEnterFileSystem();
  99. //
  100. // Increment performance counters and get the resource
  101. //
  102. if (Wait) {
  103. //
  104. // Acquired shared on the common fcb header
  105. //
  106. (VOID)ExAcquireResourceSharedLite( Header->Resource, TRUE );
  107. } else {
  108. //
  109. // Acquired shared on the common fcb header, and return if we
  110. // don't get it
  111. //
  112. if (!ExAcquireResourceSharedLite( Header->Resource, FALSE )) {
  113. FsRtlExitFileSystem();
  114. //the ntfs guys dont do this AND it causes a compile error for me so
  115. //comment it out
  116. //CcFastReadResourceMiss += 1;
  117. return FALSE;
  118. }
  119. }
  120. //
  121. // Now that the File is acquired shared, we can safely test if it
  122. // is really cached and if we can do fast i/o and if not, then
  123. // release the fcb and return.
  124. //
  125. if ((FileObject->PrivateCacheMap == NULL) ||
  126. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  127. ExReleaseResourceLite( Header->Resource );
  128. FsRtlExitFileSystem();
  129. return FALSE;
  130. }
  131. //
  132. // Check if fast I/O is questionable and if so then go ask the
  133. // file system the answer
  134. //
  135. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  136. PFAST_IO_DISPATCH FastIoDispatch;
  137. ASSERT(!KeIsExecutingDpc());
  138. targetVdo = IoGetRelatedDeviceObject( FileObject );
  139. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  140. //
  141. // All file systems that set "Is Questionable" had better support
  142. // fast I/O
  143. //
  144. ASSERT(FastIoDispatch != NULL);
  145. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  146. //
  147. // Call the file system to check for fast I/O. If the answer is
  148. // anything other than GoForIt then we cannot take the fast I/O
  149. // path.
  150. //
  151. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  152. FileOffset,
  153. Length,
  154. Wait,
  155. LockKey,
  156. TRUE, // read operation
  157. IoStatus,
  158. targetVdo )) {
  159. //
  160. // Fast I/O is not possible so release the Fcb and return.
  161. //
  162. ExReleaseResourceLite( Header->Resource );
  163. FsRtlExitFileSystem();
  164. return FALSE;
  165. }
  166. }
  167. //
  168. // Check for read past file size.
  169. //
  170. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  171. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  172. IoStatus->Status = STATUS_END_OF_FILE;
  173. IoStatus->Information = 0;
  174. ExReleaseResourceLite( Header->Resource );
  175. FsRtlExitFileSystem();
  176. return TRUE;
  177. }
  178. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  179. }
  180. //
  181. // We can do fast i/o so call the cc routine to do the work and then
  182. // release the fcb when we've done. If for whatever reason the
  183. // copy read fails, then return FALSE to our caller.
  184. //
  185. // Also mark this as the top level "Irp" so that lower file system
  186. // levels will not attempt a pop-up
  187. //
  188. //PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
  189. PsGetCurrentThread()->TopLevelIrp = TopLevelIrpValue;
  190. try {
  191. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  192. CcFastCopyRead( FileObject,
  193. FileOffset->LowPart,
  194. Length,
  195. PageCount,
  196. Buffer,
  197. IoStatus );
  198. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  199. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  200. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  201. } else {
  202. Status = CcCopyRead( FileObject,
  203. FileOffset,
  204. Length,
  205. Wait,
  206. Buffer,
  207. IoStatus );
  208. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  209. ASSERT( !Status || (IoStatus->Status == STATUS_END_OF_FILE) ||
  210. (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <= (ULONGLONG)Header->FileSize.QuadPart));
  211. }
  212. if (Status) {
  213. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
  214. }
  215. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  216. ? EXCEPTION_EXECUTE_HANDLER
  217. : EXCEPTION_CONTINUE_SEARCH ) {
  218. Status = FALSE;
  219. }
  220. PsGetCurrentThread()->TopLevelIrp = 0;
  221. ExReleaseResourceLite( Header->Resource );
  222. FsRtlExitFileSystem();
  223. return Status;
  224. } else {
  225. //
  226. // A zero length transfer was requested.
  227. //
  228. IoStatus->Status = STATUS_SUCCESS;
  229. IoStatus->Information = 0;
  230. return TRUE;
  231. }
  232. }
  233. BOOLEAN
  234. FsRtlCopyWrite2 (
  235. IN PFILE_OBJECT FileObject,
  236. IN PLARGE_INTEGER FileOffset,
  237. IN ULONG Length,
  238. IN BOOLEAN Wait,
  239. IN ULONG LockKey,
  240. IN PVOID Buffer,
  241. OUT PIO_STATUS_BLOCK IoStatus,
  242. IN PDEVICE_OBJECT DeviceObject,
  243. IN ULONG_PTR TopLevelIrpValue
  244. )
  245. /*++
  246. Routine Description:
  247. This routine does a fast cached write bypassing the usual file system
  248. entry routine (i.e., without the Irp). It is used to do a copy write
  249. of a cached file object. For a complete description of the arguments
  250. see CcCopyWrite.
  251. Arguments:
  252. FileObject - Pointer to the file object being write.
  253. FileOffset - Byte offset in file for desired data.
  254. Length - Length of desired data in bytes.
  255. Wait - FALSE if caller may not block, TRUE otherwise
  256. Buffer - Pointer to output buffer to which data should be copied.
  257. IoStatus - Pointer to standard I/O status block to receive the status
  258. for the transfer.
  259. Return Value:
  260. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  261. if there is an I/O error.
  262. TRUE - if the data is being delivered
  263. --*/
  264. {
  265. PFSRTL_COMMON_FCB_HEADER Header;
  266. BOOLEAN AcquiredShared = FALSE;
  267. BOOLEAN Status = TRUE;
  268. BOOLEAN FileSizeChanged = FALSE;
  269. BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
  270. (FileOffset->HighPart == -1));
  271. PAGED_CODE();
  272. //
  273. // Get a real pointer to the common fcb header
  274. //
  275. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  276. //
  277. // Do we need to verify the volume? If so, we must go to the file
  278. // system. Also return FALSE if FileObject is write through, the
  279. // File System must do that.
  280. //
  281. if (CcCanIWrite( FileObject, Length, Wait, FALSE ) &&
  282. !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) &&
  283. CcCopyWriteWontFlush(FileObject, FileOffset, Length)) {
  284. //
  285. // Assume our transfer will work
  286. //
  287. IoStatus->Status = STATUS_SUCCESS;
  288. IoStatus->Information = Length;
  289. //
  290. // Special case the zero byte length
  291. //
  292. if (Length != 0) {
  293. //
  294. // Enter the file system
  295. //
  296. FsRtlEnterFileSystem();
  297. //
  298. // Split into separate paths for increased performance. First
  299. // we have the faster path which only supports Wait == TRUE and
  300. // 32 bits. We will make an unsafe test on whether the fast path
  301. // is ok, then just return FALSE later if we were wrong. This
  302. // should virtually never happen.
  303. //
  304. // IMPORTANT NOTE: It is very important that any changes mad to
  305. // this path also be applied to the 64-bit path
  306. // which is the else of this test!
  307. //
  308. if (Wait && (Header->AllocationSize.HighPart == 0)) {
  309. ULONG Offset, NewFileSize;
  310. ULONG OldFileSize;
  311. ULONG OldValidDataLength;
  312. BOOLEAN Wrapped;
  313. //
  314. // Make our best guess on whether we need the file exclusive
  315. // or shared. Note that we do not check FileOffset->HighPart
  316. // until below.
  317. //
  318. NewFileSize = FileOffset->LowPart + Length;
  319. if (WriteToEndOfFile || (NewFileSize > Header->ValidDataLength.LowPart)) {
  320. //
  321. // Acquired shared on the common fcb header
  322. //
  323. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  324. } else {
  325. //
  326. // Acquired shared on the common fcb header
  327. //
  328. ExAcquireResourceSharedLite( Header->Resource, TRUE );
  329. AcquiredShared = TRUE;
  330. }
  331. //
  332. // We have the fcb shared now check if we can do fast i/o
  333. // and if the file space is allocated, and if not then
  334. // release the fcb and return.
  335. //
  336. if (WriteToEndOfFile) {
  337. Offset = Header->FileSize.LowPart;
  338. NewFileSize = Header->FileSize.LowPart + Length;
  339. Wrapped = NewFileSize < Header->FileSize.LowPart;
  340. } else {
  341. Offset = FileOffset->LowPart;
  342. NewFileSize = FileOffset->LowPart + Length;
  343. Wrapped = (NewFileSize < FileOffset->LowPart) || (FileOffset->HighPart != 0);
  344. }
  345. //
  346. // Now that the File is acquired shared, we can safely test
  347. // if it is really cached and if we can do fast i/o and we
  348. // do not have to extend. If not then release the fcb and
  349. // return.
  350. //
  351. // Get out if we have too much to zero. This case is not important
  352. // for performance, and a file system supporting sparseness may have
  353. // a way to do this more efficiently.
  354. //
  355. if ((FileObject->PrivateCacheMap == NULL) ||
  356. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  357. (NewFileSize > Header->AllocationSize.LowPart) ||
  358. (Offset >= (Header->ValidDataLength.LowPart + 0x2000)) ||
  359. (Header->AllocationSize.HighPart != 0) || Wrapped) {
  360. ExReleaseResourceLite( Header->Resource );
  361. FsRtlExitFileSystem();
  362. return FALSE;
  363. }
  364. //
  365. // If we will be extending ValidDataLength, we will have to
  366. // get the Fcb exclusive, and make sure that FastIo is still
  367. // possible. We should only execute this block of code very
  368. // rarely, when the unsafe test for ValidDataLength failed
  369. // above.
  370. //
  371. if (AcquiredShared && (NewFileSize > Header->ValidDataLength.LowPart)) {
  372. ExReleaseResourceLite( Header->Resource );
  373. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  374. //
  375. // If writing to end of file, we must recalculate new size.
  376. //
  377. if (WriteToEndOfFile) {
  378. Offset = Header->FileSize.LowPart;
  379. NewFileSize = Header->FileSize.LowPart + Length;
  380. Wrapped = NewFileSize < Header->FileSize.LowPart;
  381. }
  382. if ((FileObject->PrivateCacheMap == NULL) ||
  383. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  384. (NewFileSize > Header->AllocationSize.LowPart) ||
  385. (Header->AllocationSize.HighPart != 0) || Wrapped) {
  386. ExReleaseResourceLite( Header->Resource );
  387. FsRtlExitFileSystem();
  388. return FALSE;
  389. }
  390. }
  391. //
  392. // Check if fast I/O is questionable and if so then go ask
  393. // the file system the answer
  394. //
  395. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  396. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  397. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  398. IO_STATUS_BLOCK IoStatus;
  399. //
  400. // All file system then set "Is Questionable" had better
  401. // support fast I/O
  402. //
  403. ASSERT(FastIoDispatch != NULL);
  404. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  405. //
  406. // Call the file system to check for fast I/O. If the
  407. // answer is anything other than GoForIt then we cannot
  408. // take the fast I/O path.
  409. //
  410. ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);
  411. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  412. FileOffset->QuadPart != (LONGLONG)-1 ?
  413. FileOffset : &Header->FileSize,
  414. Length,
  415. TRUE,
  416. LockKey,
  417. FALSE, // write operation
  418. &IoStatus,
  419. targetVdo )) {
  420. //
  421. // Fast I/O is not possible so release the Fcb and
  422. // return.
  423. //
  424. ExReleaseResourceLite( Header->Resource );
  425. FsRtlExitFileSystem();
  426. return FALSE;
  427. }
  428. }
  429. //
  430. // Now see if we will change FileSize. We have to do it now
  431. // so that our reads are not nooped.
  432. //
  433. if (NewFileSize > Header->FileSize.LowPart) {
  434. FileSizeChanged = TRUE;
  435. OldFileSize = Header->FileSize.LowPart;
  436. OldValidDataLength = Header->ValidDataLength.LowPart;
  437. Header->FileSize.LowPart = NewFileSize;
  438. }
  439. //
  440. // We can do fast i/o so call the cc routine to do the work
  441. // and then release the fcb when we've done. If for whatever
  442. // reason the copy write fails, then return FALSE to our
  443. // caller.
  444. //
  445. // Also mark this as the top level "Irp" so that lower file
  446. // system levels will not attempt a pop-up
  447. //
  448. PsGetCurrentThread()->TopLevelIrp = TopLevelIrpValue;
  449. try {
  450. //
  451. // See if we have to do some zeroing
  452. //
  453. if (Offset > Header->ValidDataLength.LowPart) {
  454. LARGE_INTEGER ZeroEnd;
  455. ZeroEnd.LowPart = Offset;
  456. ZeroEnd.HighPart = 0;
  457. CcZeroData( FileObject,
  458. &Header->ValidDataLength,
  459. &ZeroEnd,
  460. TRUE );
  461. }
  462. CcFastCopyWrite( FileObject,
  463. Offset,
  464. Length,
  465. Buffer );
  466. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  467. ? EXCEPTION_EXECUTE_HANDLER
  468. : EXCEPTION_CONTINUE_SEARCH ) {
  469. Status = FALSE;
  470. }
  471. PsGetCurrentThread()->TopLevelIrp = 0;
  472. //
  473. // If we succeeded, see if we have to update FileSize or
  474. // ValidDataLength.
  475. //
  476. if (Status) {
  477. //
  478. // In the case of ValidDataLength, we really have to
  479. // check again since we did not do this when we acquired
  480. // the resource exclusive.
  481. //
  482. if (NewFileSize > Header->ValidDataLength.LowPart) {
  483. Header->ValidDataLength.LowPart = NewFileSize;
  484. }
  485. //
  486. // Set this handle as having modified the file
  487. //
  488. FileObject->Flags |= FO_FILE_MODIFIED;
  489. if (FileSizeChanged) {
  490. CcGetFileSizePointer(FileObject)->LowPart = NewFileSize;
  491. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  492. }
  493. //
  494. // Also update the file position pointer
  495. //
  496. FileObject->CurrentByteOffset.LowPart = Offset + Length;
  497. FileObject->CurrentByteOffset.HighPart = 0;
  498. //
  499. // If we did not succeed, then we must restore the original
  500. // FileSize while holding the PagingIoResource exclusive if
  501. // it exists.
  502. //
  503. } else if (FileSizeChanged) {
  504. if ( Header->PagingIoResource != NULL ) {
  505. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  506. Header->FileSize.LowPart = OldFileSize;
  507. Header->ValidDataLength.LowPart = OldValidDataLength;
  508. ExReleaseResourceLite( Header->PagingIoResource );
  509. } else {
  510. Header->FileSize.LowPart = OldFileSize;
  511. Header->ValidDataLength.LowPart = OldValidDataLength;
  512. }
  513. }
  514. //
  515. // Here is the 64-bit or no-wait path.
  516. //
  517. } else {
  518. LARGE_INTEGER Offset, NewFileSize;
  519. LARGE_INTEGER OldFileSize;
  520. LARGE_INTEGER OldValidDataLength;
  521. ASSERT(!KeIsExecutingDpc());
  522. //
  523. // Make our best guess on whether we need the file exclusive
  524. // or shared.
  525. //
  526. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  527. if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  528. //
  529. // Acquired shared on the common fcb header, and return
  530. // if we don't get it.
  531. //
  532. if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {
  533. FsRtlExitFileSystem();
  534. return FALSE;
  535. }
  536. } else {
  537. //
  538. // Acquired shared on the common fcb header, and return
  539. // if we don't get it.
  540. //
  541. if (!ExAcquireResourceSharedLite( Header->Resource, Wait )) {
  542. FsRtlExitFileSystem();
  543. return FALSE;
  544. }
  545. AcquiredShared = TRUE;
  546. }
  547. //
  548. // We have the fcb shared now check if we can do fast i/o
  549. // and if the file space is allocated, and if not then
  550. // release the fcb and return.
  551. //
  552. if (WriteToEndOfFile) {
  553. Offset = Header->FileSize;
  554. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  555. } else {
  556. Offset = *FileOffset;
  557. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  558. }
  559. //
  560. // Now that the File is acquired shared, we can safely test
  561. // if it is really cached and if we can do fast i/o and we
  562. // do not have to extend. If not then release the fcb and
  563. // return.
  564. //
  565. // Get out if we are about to zero too much as well, as commented above.
  566. //
  567. if ((FileObject->PrivateCacheMap == NULL) ||
  568. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  569. (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000)) ||
  570. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {
  571. ExReleaseResourceLite( Header->Resource );
  572. FsRtlExitFileSystem();
  573. return FALSE;
  574. }
  575. //
  576. // If we will be extending ValidDataLength, we will have to
  577. // get the Fcb exclusive, and make sure that FastIo is still
  578. // possible. We should only execute this block of code very
  579. // rarely, when the unsafe test for ValidDataLength failed
  580. // above.
  581. //
  582. if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) {
  583. ExReleaseResourceLite( Header->Resource );
  584. if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {
  585. FsRtlExitFileSystem();
  586. return FALSE;
  587. }
  588. //
  589. // If writing to end of file, we must recalculate new size.
  590. //
  591. if (WriteToEndOfFile) {
  592. Offset = Header->FileSize;
  593. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  594. }
  595. if ((FileObject->PrivateCacheMap == NULL) ||
  596. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  597. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {
  598. ExReleaseResourceLite( Header->Resource );
  599. FsRtlExitFileSystem();
  600. return FALSE;
  601. }
  602. }
  603. //
  604. // Check if fast I/O is questionable and if so then go ask
  605. // the file system the answer
  606. //
  607. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  608. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  609. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  610. IO_STATUS_BLOCK IoStatus;
  611. //
  612. // All file system then set "Is Questionable" had better
  613. // support fast I/O
  614. //
  615. ASSERT(FastIoDispatch != NULL);
  616. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  617. //
  618. // Call the file system to check for fast I/O. If the
  619. // answer is anything other than GoForIt then we cannot
  620. // take the fast I/O path.
  621. //
  622. ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);
  623. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  624. FileOffset->QuadPart != (LONGLONG)-1 ?
  625. FileOffset : &Header->FileSize,
  626. Length,
  627. Wait,
  628. LockKey,
  629. FALSE, // write operation
  630. &IoStatus,
  631. targetVdo )) {
  632. //
  633. // Fast I/O is not possible so release the Fcb and
  634. // return.
  635. //
  636. ExReleaseResourceLite( Header->Resource );
  637. FsRtlExitFileSystem();
  638. return FALSE;
  639. }
  640. }
  641. //
  642. // Now see if we will change FileSize. We have to do it now
  643. // so that our reads are not nooped.
  644. //
  645. if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) {
  646. FileSizeChanged = TRUE;
  647. OldFileSize = Header->FileSize;
  648. OldValidDataLength = Header->ValidDataLength;
  649. //
  650. // Deal with an extremely rare pathalogical case here the
  651. // file size wraps.
  652. //
  653. if ( (Header->FileSize.HighPart != NewFileSize.HighPart) &&
  654. (Header->PagingIoResource != NULL) ) {
  655. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  656. Header->FileSize = NewFileSize;
  657. ExReleaseResourceLite( Header->PagingIoResource );
  658. } else {
  659. Header->FileSize = NewFileSize;
  660. }
  661. }
  662. //
  663. // We can do fast i/o so call the cc routine to do the work
  664. // and then release the fcb when we've done. If for whatever
  665. // reason the copy write fails, then return FALSE to our
  666. // caller.
  667. //
  668. // Also mark this as the top level "Irp" so that lower file
  669. // system levels will not attempt a pop-up
  670. //
  671. PsGetCurrentThread()->TopLevelIrp = TopLevelIrpValue;
  672. try {
  673. //
  674. // See if we have to do some zeroing
  675. //
  676. if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {
  677. Status = CcZeroData( FileObject,
  678. &Header->ValidDataLength,
  679. &Offset,
  680. Wait );
  681. }
  682. if (Status) {
  683. Status = CcCopyWrite( FileObject,
  684. &Offset,
  685. Length,
  686. Wait,
  687. Buffer );
  688. }
  689. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  690. ? EXCEPTION_EXECUTE_HANDLER
  691. : EXCEPTION_CONTINUE_SEARCH ) {
  692. Status = FALSE;
  693. }
  694. PsGetCurrentThread()->TopLevelIrp = 0;
  695. //
  696. // If we succeeded, see if we have to update FileSize or
  697. // ValidDataLength.
  698. //
  699. if (Status) {
  700. //
  701. // In the case of ValidDataLength, we really have to
  702. // check again since we did not do this when we acquired
  703. // the resource exclusive.
  704. //
  705. if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) {
  706. //
  707. // Deal with an extremely rare pathalogical case here
  708. // the ValidDataLength wraps.
  709. //
  710. if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) &&
  711. (Header->PagingIoResource != NULL) ) {
  712. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  713. Header->ValidDataLength = NewFileSize;
  714. ExReleaseResourceLite( Header->PagingIoResource );
  715. } else {
  716. Header->ValidDataLength = NewFileSize;
  717. }
  718. }
  719. //
  720. // Set this handle as having modified the file
  721. //
  722. FileObject->Flags |= FO_FILE_MODIFIED;
  723. if (FileSizeChanged) {
  724. *CcGetFileSizePointer(FileObject) = NewFileSize;
  725. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  726. }
  727. //
  728. // Also update the current file position pointer
  729. //
  730. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  731. //
  732. // If we did not succeed, then we must restore the original
  733. // FileSize while holding the PagingIoResource exclusive if
  734. // it exists.
  735. //
  736. } else if (FileSizeChanged) {
  737. if ( Header->PagingIoResource != NULL ) {
  738. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  739. Header->FileSize = OldFileSize;
  740. Header->ValidDataLength = OldValidDataLength;
  741. ExReleaseResourceLite( Header->PagingIoResource );
  742. } else {
  743. Header->FileSize = OldFileSize;
  744. Header->ValidDataLength = OldValidDataLength;
  745. }
  746. }
  747. }
  748. ExReleaseResourceLite( Header->Resource );
  749. FsRtlExitFileSystem();
  750. return Status;
  751. } else {
  752. //
  753. // A zero length transfer was requested.
  754. //
  755. return TRUE;
  756. }
  757. } else {
  758. //
  759. // The volume must be verified or the file is write through.
  760. //
  761. return FALSE;
  762. }
  763. }