Synchronize with trunk r58606.
[reactos.git] / ntoskrnl / fsrtl / fastio.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/fastio.c
5 * PURPOSE: Provides Fast I/O entrypoints to the Cache Manager
6 * PROGRAMMERS: buzdelabuz2@gmail.com,alex.ionescu@reactos.org
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PUBLIC FUNCTIONS **********************************************************/
16
17 /*
18 * @implemented
19 */
20 VOID
21 NTAPI
22 FsRtlIncrementCcFastReadResourceMiss(VOID)
23 {
24 CcFastReadResourceMiss++;
25 }
26
27 /*
28 * @implemented
29 */
30 VOID
31 NTAPI
32 FsRtlIncrementCcFastReadNotPossible(VOID)
33 {
34 CcFastReadNotPossible++;
35 }
36
37 /*
38 * @implemented
39 */
40 VOID
41 NTAPI
42 FsRtlIncrementCcFastReadWait(VOID)
43 {
44 CcFastReadWait++;
45 }
46
47 /*
48 * @implemented
49 */
50 VOID
51 NTAPI
52 FsRtlIncrementCcFastReadNoWait(VOID)
53 {
54 CcFastReadNoWait++;
55 }
56
57 /*
58 * @implemented
59 */
60 BOOLEAN
61 NTAPI
62 FsRtlCopyRead(IN PFILE_OBJECT FileObject,
63 IN PLARGE_INTEGER FileOffset,
64 IN ULONG Length,
65 IN BOOLEAN Wait,
66 IN ULONG LockKey,
67 OUT PVOID Buffer,
68 OUT PIO_STATUS_BLOCK IoStatus,
69 IN PDEVICE_OBJECT DeviceObject)
70 {
71
72 PFSRTL_COMMON_FCB_HEADER FcbHeader;
73 LARGE_INTEGER Offset;
74 PFAST_IO_DISPATCH FastIoDispatch;
75 PDEVICE_OBJECT Device;
76 BOOLEAN Result = TRUE;
77 ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset, Length);
78
79 PAGED_CODE();
80 ASSERT(FileObject);
81 ASSERT(FileObject->FsContext);
82
83 /* No actual read */
84 if (!Length)
85 {
86 /* Return success */
87 IoStatus->Status = STATUS_SUCCESS;
88 IoStatus->Information = 0;
89 return TRUE;
90 }
91
92 if (Length > MAXLONGLONG - FileOffset->QuadPart)
93 {
94 IoStatus->Status = STATUS_INVALID_PARAMETER;
95 IoStatus->Information = 0;
96 return FALSE;
97 }
98
99 /* Get the offset and FCB header */
100 Offset.QuadPart = FileOffset->QuadPart + Length;
101 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
102
103 if (Wait)
104 {
105 /* Use a Resource Acquire */
106 FsRtlEnterFileSystem();
107 CcFastReadWait++;
108 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
109 }
110 else
111 {
112 /* Acquire the resource without blocking. Return false and the I/O manager
113 * will retry using the standard IRP method. Use a Resource Acquire.
114 */
115 FsRtlEnterFileSystem();
116 if (!ExAcquireResourceSharedLite(FcbHeader->Resource, FALSE))
117 {
118 FsRtlExitFileSystem();
119 FsRtlIncrementCcFastReadResourceMiss();
120 return FALSE;
121 }
122 }
123
124 /* Check if this is a fast I/O cached file */
125 if (!(FileObject->PrivateCacheMap) ||
126 (FcbHeader->IsFastIoPossible == FastIoIsNotPossible))
127 {
128 /* It's not, so fail */
129 Result = FALSE;
130 goto Cleanup;
131 }
132
133 /* Check if we need to find out if fast I/O is available */
134 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable)
135 {
136 /* Sanity check */
137 ASSERT(!KeIsExecutingDpc());
138
139 /* Get the Fast I/O table */
140 Device = IoGetRelatedDeviceObject(FileObject);
141 FastIoDispatch = Device->DriverObject->FastIoDispatch;
142
143 /* Sanity check */
144 ASSERT(FastIoDispatch != NULL);
145 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
146
147 /* Ask the driver if we can do it */
148 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
149 FileOffset,
150 Length,
151 TRUE,
152 LockKey,
153 TRUE,
154 IoStatus,
155 Device))
156 {
157 /* It's not, fail */
158 Result = FALSE;
159 goto Cleanup;
160 }
161 }
162
163 /* Check if we read too much */
164 if (Offset.QuadPart > FcbHeader->FileSize.QuadPart)
165 {
166 /* We did, check if the file offset is past the end */
167 if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart)
168 {
169 /* Set end of file */
170 IoStatus->Status = STATUS_END_OF_FILE;
171 IoStatus->Information = 0;
172 goto Cleanup;
173 }
174
175 /* Otherwise, just normalize the length */
176 Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart);
177 }
178
179 /* Set this as top-level IRP */
180 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
181
182 _SEH2_TRY
183 {
184 /* Make sure the IO and file size is below 4GB */
185 if (Wait && !(Offset.HighPart | FcbHeader->FileSize.HighPart))
186 {
187
188 /* Call the cache controller */
189 CcFastCopyRead(FileObject,
190 FileOffset->LowPart,
191 Length,
192 PageCount,
193 Buffer,
194 IoStatus);
195
196 /* File was accessed */
197 FileObject->Flags |= FO_FILE_FAST_IO_READ;
198
199 if (IoStatus->Status != STATUS_END_OF_FILE)
200 {
201 ASSERT((ULONGLONG)FcbHeader->FileSize.QuadPart >=
202 ((ULONGLONG)FileOffset->QuadPart + IoStatus->Information));
203 }
204 }
205 else
206 {
207
208 /* Call the cache controller */
209 Result = CcCopyRead(FileObject,
210 FileOffset,
211 Length,
212 Wait,
213 Buffer,
214 IoStatus);
215
216 /* File was accessed */
217 FileObject->Flags |= FO_FILE_FAST_IO_READ;
218
219 if (Result == TRUE)
220 {
221 ASSERT((IoStatus->Status == STATUS_END_OF_FILE) ||
222 (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <=
223 (ULONGLONG)FcbHeader->FileSize.QuadPart));
224 }
225 }
226
227 /* Update the current file offset */
228 if (Result == TRUE)
229 {
230 FileObject->CurrentByteOffset.QuadPart += IoStatus->Information;
231 }
232 }
233 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
234 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
235 {
236 Result = FALSE;
237 }
238 _SEH2_END;
239
240 PsGetCurrentThread()->TopLevelIrp = 0;
241
242 /* Return to caller */
243 Cleanup:
244
245 ExReleaseResourceLite(FcbHeader->Resource);
246 FsRtlExitFileSystem();
247
248 if (Result == FALSE)
249 {
250 CcFastReadNotPossible += 1;
251 }
252
253 return Result;
254 }
255
256
257 /*
258 * @implemented
259 */
260 BOOLEAN
261 NTAPI
262 FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
263 IN PLARGE_INTEGER FileOffset,
264 IN ULONG Length,
265 IN BOOLEAN Wait,
266 IN ULONG LockKey,
267 OUT PVOID Buffer,
268 OUT PIO_STATUS_BLOCK IoStatus,
269 IN PDEVICE_OBJECT DeviceObject)
270 {
271 BOOLEAN Result = TRUE;
272 PFAST_IO_DISPATCH FastIoDispatch;
273 PDEVICE_OBJECT Device;
274 PFSRTL_COMMON_FCB_HEADER FcbHeader;
275 PSHARED_CACHE_MAP SharedCacheMap;
276
277 /* WDK doc.
278 * Offset == 0xffffffffffffffff indicates append to the end of file.
279 */
280 BOOLEAN FileOffsetAppend = (FileOffset->HighPart == (LONG)0xffffffff) &&
281 (FileOffset->LowPart == 0xffffffff);
282
283 BOOLEAN ResourceAquiredShared = FALSE;
284 BOOLEAN b_4GB = FALSE;
285 BOOLEAN FileSizeModified = FALSE;
286 LARGE_INTEGER OldFileSize;
287 LARGE_INTEGER OldValidDataLength;
288 LARGE_INTEGER NewSize;
289 LARGE_INTEGER Offset;
290
291 PAGED_CODE();
292
293 ASSERT(FileObject);
294 ASSERT(FileObject->FsContext);
295
296 #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ == 405)
297 /* Silence incorrect GCC 4.5.x warning */
298 OldFileSize.LowPart = 0;
299 #endif
300
301 /* Initialize some of the vars and pointers */
302 NewSize.QuadPart = 0;
303 Offset.QuadPart = FileOffset->QuadPart + Length;
304 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
305
306 /* Nagar p.544.
307 * Check with Cc if we can write and check if the IO > 64kB (WDK macro).
308 */
309 if ((CcCanIWrite(FileObject, Length, Wait, FALSE) == FALSE) ||
310 (CcCopyWriteWontFlush(FileObject, FileOffset, Length) == FALSE) ||
311 ((FileObject->Flags & FO_WRITE_THROUGH)))
312 {
313 return FALSE;
314 }
315
316 /* No actual read */
317 if (!Length)
318 {
319 IoStatus->Status = STATUS_SUCCESS;
320 IoStatus->Information = Length;
321 return TRUE;
322 }
323
324 FsRtlEnterFileSystem();
325
326 /* Nagar p.544/545.
327 * The CcFastCopyWrite doesn't deal with filesize beyond 4GB.
328 */
329 if (Wait && (FcbHeader->AllocationSize.HighPart == 0))
330 {
331 /* If the file offset is not past the file size,
332 * then we can acquire the lock shared.
333 */
334 if ((FileOffsetAppend == FALSE) &&
335 (Offset.LowPart <= FcbHeader->ValidDataLength.LowPart))
336 {
337 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
338 ResourceAquiredShared = TRUE;
339 }
340 else
341 {
342 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
343 }
344
345 /* Nagar p.544/545.
346 * If we append, use the file size as offset.
347 * Also, check that we aren't crossing the 4GB boundary.
348 */
349 if (FileOffsetAppend == TRUE)
350 {
351 Offset.LowPart = FcbHeader->FileSize.LowPart;
352 NewSize.LowPart = FcbHeader->FileSize.LowPart + Length;
353 b_4GB = (NewSize.LowPart < FcbHeader->FileSize.LowPart);
354
355 }
356 else
357 {
358 Offset.LowPart = FileOffset->LowPart;
359 NewSize.LowPart = FileOffset->LowPart + Length;
360 b_4GB = (NewSize.LowPart < FileOffset->LowPart) ||
361 (FileOffset->HighPart != 0);
362 }
363
364 /* Nagar p.544/545.
365 * Make sure that caching is initated.
366 * That fast are allowed for this file stream.
367 * That we are not extending past the allocated size.
368 * That we are not creating a hole bigger than 8k.
369 * That we are not crossing the 4GB boundary.
370 */
371 if ((FileObject->PrivateCacheMap != NULL) &&
372 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) &&
373 (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) &&
374 (Offset.LowPart < FcbHeader->ValidDataLength.LowPart + 0x2000) &&
375 !b_4GB)
376 {
377 /* If we are extending past the file size, we need to
378 * release the lock and acquire it exclusively, because
379 * we are going to need to update the FcbHeader.
380 */
381 if (ResourceAquiredShared &&
382 (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart + 0x2000))
383 {
384 /* Then we need to acquire the resource exclusive */
385 ExReleaseResourceLite(FcbHeader->Resource);
386 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
387 if (FileOffsetAppend == TRUE)
388 {
389 Offset.LowPart = FcbHeader->FileSize.LowPart; // ??
390 NewSize.LowPart = FcbHeader->FileSize.LowPart + Length;
391
392 /* Make sure we don't cross the 4GB boundary */
393 b_4GB = (NewSize.LowPart < Offset.LowPart);
394 }
395
396 /* Recheck some of the conditions since we let the lock go */
397 if ((FileObject->PrivateCacheMap != NULL) &&
398 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) &&
399 (FcbHeader->AllocationSize.LowPart >= NewSize.LowPart) &&
400 (FcbHeader->AllocationSize.HighPart == 0) &&
401 !b_4GB)
402 {
403 /* Do nothing? */
404 }
405 else
406 {
407 goto FailAndCleanup;
408 }
409 }
410
411 }
412 else
413 {
414 goto FailAndCleanup;
415 }
416
417 /* Check if we need to find out if fast I/O is available */
418 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable)
419 {
420 IO_STATUS_BLOCK FastIoCheckIfPossibleStatus;
421
422 /* Sanity check */
423 ASSERT(!KeIsExecutingDpc());
424
425 /* Get the Fast I/O table */
426 Device = IoGetRelatedDeviceObject(FileObject);
427 FastIoDispatch = Device->DriverObject->FastIoDispatch;
428
429 /* Sanity check */
430 ASSERT(FastIoDispatch != NULL);
431 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
432
433 /* Ask the driver if we can do it */
434 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
435 FileOffsetAppend ?
436 &FcbHeader->FileSize :
437 FileOffset,
438 Length,
439 TRUE,
440 LockKey,
441 FALSE,
442 &FastIoCheckIfPossibleStatus,
443 Device))
444 {
445 /* It's not, fail */
446 goto FailAndCleanup;
447 }
448 }
449
450 /* If we are going to extend the file then save
451 * the old file size in case the operation fails.
452 */
453 if (NewSize.LowPart > FcbHeader->FileSize.LowPart)
454 {
455 FileSizeModified = TRUE;
456 OldFileSize.LowPart = FcbHeader->FileSize.LowPart;
457 OldValidDataLength.LowPart = FcbHeader->ValidDataLength.LowPart;
458 FcbHeader->FileSize.LowPart = NewSize.LowPart;
459 }
460
461 /* Set this as top-level IRP */
462 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
463
464 _SEH2_TRY
465 {
466 if (Offset.LowPart > FcbHeader->ValidDataLength.LowPart)
467 {
468 LARGE_INTEGER OffsetVar;
469 OffsetVar.LowPart = Offset.LowPart;
470 OffsetVar.HighPart = 0;
471 CcZeroData(FileObject, &FcbHeader->ValidDataLength, &OffsetVar, TRUE);
472 }
473
474 /* Call the cache manager */
475 CcFastCopyWrite(FileObject, Offset.LowPart, Length, Buffer);
476 }
477 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
478 EXCEPTION_EXECUTE_HANDLER :
479 EXCEPTION_CONTINUE_SEARCH)
480 {
481 Result = FALSE;
482 }
483 _SEH2_END;
484
485 /* Remove ourselves at the top level component after the IO is done */
486 PsGetCurrentThread()->TopLevelIrp = 0;
487
488 /* Did the operation succeed? */
489 if (Result == TRUE)
490 {
491 /* Update the valid file size if necessary */
492 if (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart)
493 {
494 FcbHeader->ValidDataLength.LowPart = NewSize.LowPart;
495 }
496
497 /* Flag the file as modified */
498 FileObject->Flags |= FO_FILE_MODIFIED;
499
500 /* Update the strucutres if the file size changed */
501 if (FileSizeModified)
502 {
503 SharedCacheMap =
504 (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
505 SharedCacheMap->FileSize.LowPart = NewSize.LowPart;
506 FileObject->Flags |= FO_FILE_SIZE_CHANGED;
507 }
508
509 /* Update the file object current file offset */
510 FileObject->CurrentByteOffset.QuadPart = NewSize.LowPart;
511
512 }
513 else
514 {
515 /* Result == FALSE if we get here */
516 if (FileSizeModified)
517 {
518 /* If the file size was modified then restore the old file size */
519 if (FcbHeader->PagingIoResource != NULL)
520 {
521 /* Nagar P.544.
522 * Restore the old file size if operation didn't succeed.
523 */
524 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
525 FcbHeader->FileSize.LowPart = OldFileSize.LowPart;
526 FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart;
527 ExReleaseResourceLite(FcbHeader->PagingIoResource);
528 }
529 else
530 {
531 /* If there is no lock and do it without */
532 FcbHeader->FileSize.LowPart = OldFileSize.LowPart;
533 FcbHeader->ValidDataLength.LowPart = OldValidDataLength.LowPart;
534 }
535 }
536 else
537 {
538 /* Do nothing? */
539 }
540 }
541
542 goto Cleanup;
543 }
544 else
545 {
546 LARGE_INTEGER OldFileSize;
547
548 #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ == 405)
549 /* Silence incorrect GCC 4.5.x warning */
550 OldFileSize.QuadPart = 0;
551 #endif
552
553 /* Sanity check */
554 ASSERT(!KeIsExecutingDpc());
555
556 /* Nagar P.544.
557 * Check if we need to acquire the resource exclusive.
558 */
559 if ((FileOffsetAppend == FALSE) &&
560 (FileOffset->QuadPart + Length <= FcbHeader->ValidDataLength.QuadPart))
561 {
562 /* Acquire the resource shared */
563 if (!ExAcquireResourceSharedLite(FcbHeader->Resource, Wait))
564 {
565 goto LeaveCriticalAndFail;
566 }
567 ResourceAquiredShared = TRUE;
568 }
569 else
570 {
571 /* Acquire the resource exclusive */
572 if (!ExAcquireResourceExclusiveLite(FcbHeader->Resource, Wait))
573 {
574 goto LeaveCriticalAndFail;
575 }
576 }
577
578 /* Check if we are appending */
579 if (FileOffsetAppend == TRUE)
580 {
581 Offset.QuadPart = FcbHeader->FileSize.QuadPart;
582 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length;
583 }
584 else
585 {
586 Offset.QuadPart = FileOffset->QuadPart;
587 NewSize.QuadPart += FileOffset->QuadPart + Length;
588 }
589
590 /* Nagar p.544/545.
591 * Make sure that caching is initated.
592 * That fast are allowed for this file stream.
593 * That we are not extending past the allocated size.
594 * That we are not creating a hole bigger than 8k.
595 */
596 if ((FileObject->PrivateCacheMap != NULL) &&
597 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) &&
598 (FcbHeader->ValidDataLength.QuadPart + 0x2000 > Offset.QuadPart) &&
599 (Length <= MAXLONGLONG - Offset.QuadPart) &&
600 (FcbHeader->AllocationSize.QuadPart >= NewSize.QuadPart))
601 {
602 /* Check if we can keep the lock shared */
603 if (ResourceAquiredShared &&
604 (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart))
605 {
606 ExReleaseResourceLite(FcbHeader->Resource);
607 if (!ExAcquireResourceExclusiveLite(FcbHeader->Resource, Wait))
608 {
609 goto LeaveCriticalAndFail;
610 }
611
612 /* Compute the offset and the new filesize */
613 if (FileOffsetAppend)
614 {
615 Offset.QuadPart = FcbHeader->FileSize.QuadPart;
616 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length;
617 }
618
619 /* Recheck the above points since we released and reacquire the lock */
620 if ((FileObject->PrivateCacheMap != NULL) &&
621 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) &&
622 (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart))
623 {
624 /* Do nothing */
625 }
626 else
627 {
628 goto FailAndCleanup;
629 }
630 }
631
632 /* Check if we need to find out if fast I/O is available */
633 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable)
634 {
635 IO_STATUS_BLOCK FastIoCheckIfPossibleStatus;
636
637 /* Sanity check */
638 ASSERT(!KeIsExecutingDpc());
639
640 /* Get the Fast I/O table */
641 Device = IoGetRelatedDeviceObject(FileObject);
642 FastIoDispatch = Device->DriverObject->FastIoDispatch;
643
644 /* Sanity check */
645 ASSERT(FastIoDispatch != NULL);
646 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
647
648 /* Ask the driver if we can do it */
649 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
650 FileOffsetAppend ?
651 &FcbHeader->FileSize :
652 FileOffset,
653 Length,
654 TRUE,
655 LockKey,
656 FALSE,
657 &FastIoCheckIfPossibleStatus,
658 Device))
659 {
660 /* It's not, fail */
661 goto FailAndCleanup;
662 }
663 }
664
665 /* If we are going to modify the filesize,
666 * save the old fs in case the operation fails.
667 */
668 if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart)
669 {
670 FileSizeModified = TRUE;
671 OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart;
672 OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart;
673
674 /* If the high part of the filesize is going
675 * to change, grab the Paging IoResouce.
676 */
677 if (NewSize.HighPart != FcbHeader->FileSize.HighPart &&
678 FcbHeader->PagingIoResource)
679 {
680 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
681 FcbHeader->FileSize.QuadPart = NewSize.QuadPart;
682 ExReleaseResourceLite(FcbHeader->PagingIoResource);
683 }
684 else
685 {
686 FcbHeader->FileSize.QuadPart = NewSize.QuadPart;
687 }
688 }
689
690 /* Nagar p.544.
691 * Set ourselves as top component.
692 */
693 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
694
695 _SEH2_TRY
696 {
697 BOOLEAN CallCc = TRUE;
698
699 /* Check if there is a gap between the end of the file
700 * and the offset. If yes, then we have to zero the data.
701 */
702 if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart)
703 {
704 if (!(Result = CcZeroData(FileObject,
705 &FcbHeader->ValidDataLength,
706 &Offset,
707 Wait)))
708 {
709 /* If this operation fails, then we have to exit. We can jump
710 * outside the SEH, so I a using a variable to exit normally.
711 */
712 CallCc = FALSE;
713 }
714 }
715
716 /* Unless the CcZeroData failed, call the cache manager */
717 if (CallCc)
718 {
719 Result = CcCopyWrite(FileObject, &Offset, Length, Wait, Buffer);
720 }
721 }
722 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
723 EXCEPTION_EXECUTE_HANDLER :
724 EXCEPTION_CONTINUE_SEARCH)
725 {
726 Result = FALSE;
727 }
728 _SEH2_END;
729
730 /* Reset the top component */
731 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
732
733 /* Did the operation suceeded */
734 if (Result)
735 {
736 /* Check if we need to update the filesize */
737 if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart)
738 {
739 if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart &&
740 FcbHeader->PagingIoResource)
741 {
742 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
743 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart;
744 ExReleaseResourceLite(FcbHeader->PagingIoResource);
745 }
746 else
747 {
748 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart;
749 }
750 }
751
752 /* Flag the file as modified */
753 FileObject->Flags |= FO_FILE_MODIFIED;
754
755 /* Check if the filesize has changed */
756 if (FileSizeModified)
757 {
758 /* Update the file sizes */
759 SharedCacheMap =
760 (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
761 SharedCacheMap->FileSize.QuadPart = NewSize.QuadPart;
762 FileObject->Flags |= FO_FILE_SIZE_CHANGED;
763 }
764
765 /* Update the current FO byte offset */
766 FileObject->CurrentByteOffset.QuadPart = NewSize.QuadPart;
767 }
768 else
769 {
770 /* The operation did not succeed.
771 * Reset the file size to what it should be.
772 */
773 if (FileSizeModified)
774 {
775 if (FcbHeader->PagingIoResource)
776 {
777 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
778 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart;
779 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart;
780 ExReleaseResourceLite(FcbHeader->PagingIoResource);
781 }
782 else
783 {
784 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart;
785 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart;
786 }
787 }
788 }
789
790 goto Cleanup;
791 }
792 else
793 {
794 goto FailAndCleanup;
795 }
796 }
797
798 LeaveCriticalAndFail:
799
800 FsRtlExitFileSystem();
801 return FALSE;
802
803 FailAndCleanup:
804
805 ExReleaseResourceLite(FcbHeader->Resource);
806 FsRtlExitFileSystem();
807 return FALSE;
808
809 Cleanup:
810
811 ExReleaseResourceLite(FcbHeader->Resource);
812 FsRtlExitFileSystem();
813 return Result;
814 }
815
816 /*
817 * @implemented
818 */
819 NTSTATUS
820 NTAPI
821 FsRtlGetFileSize(IN PFILE_OBJECT FileObject,
822 IN OUT PLARGE_INTEGER FileSize)
823 {
824 FILE_STANDARD_INFORMATION Info;
825 NTSTATUS Status;
826 IO_STATUS_BLOCK IoStatus;
827 PDEVICE_OBJECT DeviceObject;
828 PFAST_IO_DISPATCH FastDispatch;
829 KEVENT Event;
830 PIO_STACK_LOCATION IoStackLocation;
831 PIRP Irp;
832 BOOLEAN OldHardError;
833
834 PAGED_CODE();
835
836 /* Get Device Object and Fast Calls */
837 DeviceObject = IoGetRelatedDeviceObject(FileObject);
838 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
839
840 /* Check if we support Fast Calls, and check FastIoQueryStandardInfo.
841 * Call the function and see if it succeeds.
842 */
843 if (!FastDispatch ||
844 !FastDispatch->FastIoQueryStandardInfo ||
845 !FastDispatch->FastIoQueryStandardInfo(FileObject,
846 TRUE,
847 &Info,
848 &IoStatus,
849 DeviceObject))
850 {
851 /* If any of the above failed, then we are going to send an
852 * IRP to the device object. Initialize the event for the IO.
853 */
854 KeInitializeEvent(&Event, NotificationEvent, FALSE);
855
856 /* Allocate the IRP */
857 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
858
859 if (Irp == NULL)
860 {
861 return STATUS_INSUFFICIENT_RESOURCES;
862 }
863
864 /* Don't process hard error */
865 OldHardError = IoSetThreadHardErrorMode(FALSE);
866
867 /* Setup the IRP */
868 Irp->UserIosb = &IoStatus;
869 Irp->UserEvent = &Event;
870 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
871 Irp->Flags = IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO;
872 Irp->RequestorMode = KernelMode;
873 Irp->Tail.Overlay.OriginalFileObject = FileObject;
874 Irp->AssociatedIrp.SystemBuffer = &Info;
875
876 /* Setup out stack location */
877 IoStackLocation = Irp->Tail.Overlay.CurrentStackLocation;
878 IoStackLocation--;
879 IoStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;
880 IoStackLocation->FileObject = FileObject;
881 IoStackLocation->DeviceObject = DeviceObject;
882 IoStackLocation->Parameters.QueryFile.Length =
883 ALIGN_UP(sizeof(FILE_INFORMATION_CLASS), ULONG);
884 IoStackLocation->Parameters.QueryFile.FileInformationClass =
885 FileStandardInformation;
886
887 /* Send the IRP to the related device object */
888 Status = IoCallDriver(DeviceObject, Irp);
889
890 /* Standard DDK IRP result processing */
891 if (Status == STATUS_PENDING)
892 {
893 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
894 }
895
896 /* If there was a synchronous error, signal it */
897 if (!NT_SUCCESS(Status))
898 {
899 IoStatus.Status = Status;
900 }
901
902 IoSetThreadHardErrorMode(OldHardError);
903 }
904
905 /* Check the sync/async IO result */
906 if (NT_SUCCESS(IoStatus.Status))
907 {
908 /* Was the request for a directory? */
909 if (Info.Directory)
910 {
911 IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY;
912 }
913 else
914 {
915 FileSize->QuadPart = Info.EndOfFile.QuadPart;
916 }
917 }
918
919 return IoStatus.Status;
920 }
921
922 /*
923 * @implemented
924 */
925 BOOLEAN
926 NTAPI
927 FsRtlMdlRead(IN PFILE_OBJECT FileObject,
928 IN PLARGE_INTEGER FileOffset,
929 IN ULONG Length,
930 IN ULONG LockKey,
931 OUT PMDL *MdlChain,
932 OUT PIO_STATUS_BLOCK IoStatus)
933 {
934 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
935 PFAST_IO_DISPATCH FastDispatch;
936
937 /* Get Device Object and Fast Calls */
938 DeviceObject = IoGetRelatedDeviceObject(FileObject);
939 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
940
941 /* Check if we support Fast Calls, and check this one */
942 if (FastDispatch && FastDispatch->MdlRead)
943 {
944 /* Use the fast path */
945 return FastDispatch->MdlRead(FileObject,
946 FileOffset,
947 Length,
948 LockKey,
949 MdlChain,
950 IoStatus,
951 DeviceObject);
952 }
953
954 /* Get the Base File System (Volume) and Fast Calls */
955 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
956 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch;
957
958 /* If the Base Device Object has its own FastDispatch Routine, fail */
959 if (FastDispatch && FastDispatch->MdlRead && BaseDeviceObject != DeviceObject)
960 {
961 return FALSE;
962 }
963
964 /* No fast path, use slow path */
965 return FsRtlMdlReadDev(FileObject,
966 FileOffset,
967 Length,
968 LockKey,
969 MdlChain,
970 IoStatus,
971 DeviceObject);
972 }
973
974 /*
975 * @implemented
976 */
977 BOOLEAN
978 NTAPI
979 FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject,
980 IN OUT PMDL MdlChain)
981 {
982 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
983 PFAST_IO_DISPATCH FastDispatch;
984
985 /* Get Device Object and Fast Calls */
986 DeviceObject = IoGetRelatedDeviceObject(FileObject);
987 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
988
989 /* Check if we support Fast Calls, and check this one */
990 if (FastDispatch && FastDispatch->MdlReadComplete)
991 {
992 /* Use the fast path */
993 return FastDispatch->MdlReadComplete(FileObject, MdlChain, DeviceObject);
994 }
995
996 /* Get the Base File System (Volume) and Fast Calls */
997 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
998 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch;
999
1000 /* If the Base Device Object has its own FastDispatch Routine, fail */
1001 if ((BaseDeviceObject != DeviceObject) &&
1002 FastDispatch &&
1003 FastDispatch->MdlReadComplete)
1004 {
1005 return FALSE;
1006 }
1007
1008 /* No fast path, use slow path */
1009 return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject);
1010 }
1011
1012 /*
1013 * @implemented
1014 */
1015 BOOLEAN
1016 NTAPI
1017 FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject,
1018 IN PMDL MemoryDescriptorList,
1019 IN PDEVICE_OBJECT DeviceObject)
1020 {
1021 /* Call the Cache Manager */
1022 CcMdlReadComplete2(MemoryDescriptorList, FileObject);
1023 return TRUE;
1024 }
1025
1026 /*
1027 * @implemented
1028 */
1029 BOOLEAN
1030 NTAPI
1031 FsRtlMdlReadDev(IN PFILE_OBJECT FileObject,
1032 IN PLARGE_INTEGER FileOffset,
1033 IN ULONG Length,
1034 IN ULONG LockKey,
1035 OUT PMDL *MdlChain,
1036 OUT PIO_STATUS_BLOCK IoStatus,
1037 IN PDEVICE_OBJECT DeviceObject)
1038 {
1039 PFSRTL_COMMON_FCB_HEADER FcbHeader;
1040 BOOLEAN Result = TRUE;
1041 LARGE_INTEGER Offset;
1042 PFAST_IO_DISPATCH FastIoDispatch;
1043 PDEVICE_OBJECT Device;
1044 PAGED_CODE();
1045
1046 /* No actual read */
1047 if (!Length)
1048 {
1049 /* Return success */
1050 IoStatus->Status = STATUS_SUCCESS;
1051 IoStatus->Information = 0;
1052 return TRUE;
1053 }
1054
1055 /* Sanity check */
1056 ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length);
1057
1058 /* Get the offset and FCB header */
1059 Offset.QuadPart = FileOffset->QuadPart + Length;
1060 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1061
1062 /* Enter the FS */
1063 FsRtlEnterFileSystem();
1064 CcFastMdlReadWait++;
1065
1066 /* Lock the FCB */
1067 ExAcquireResourceShared(FcbHeader->Resource, TRUE);
1068
1069 /* Check if this is a fast I/O cached file */
1070 if (!(FileObject->PrivateCacheMap) ||
1071 (FcbHeader->IsFastIoPossible == FastIoIsNotPossible))
1072 {
1073 /* It's not, so fail */
1074 CcFastMdlReadNotPossible += 1;
1075 Result = FALSE;
1076 goto Cleanup;
1077 }
1078
1079 /* Check if we need to find out if fast I/O is available */
1080 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable)
1081 {
1082 /* Get the Fast I/O table */
1083 Device = IoGetRelatedDeviceObject(FileObject);
1084 FastIoDispatch = Device->DriverObject->FastIoDispatch;
1085
1086 /* Sanity check */
1087 ASSERT(!KeIsExecutingDpc());
1088 ASSERT(FastIoDispatch != NULL);
1089 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
1090
1091 /* Ask the driver if we can do it */
1092 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
1093 FileOffset,
1094 Length,
1095 TRUE,
1096 LockKey,
1097 TRUE,
1098 IoStatus,
1099 Device))
1100 {
1101 /* It's not, fail */
1102 CcFastMdlReadNotPossible += 1;
1103 Result = FALSE;
1104 goto Cleanup;
1105 }
1106 }
1107
1108 /* Check if we read too much */
1109 if (Offset.QuadPart > FcbHeader->FileSize.QuadPart)
1110 {
1111 /* We did, check if the file offset is past the end */
1112 if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart)
1113 {
1114 /* Set end of file */
1115 IoStatus->Status = STATUS_END_OF_FILE;
1116 IoStatus->Information = 0;
1117 goto Cleanup;
1118 }
1119
1120 /* Otherwise, just normalize the length */
1121 Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart);
1122 }
1123
1124 /* Set this as top-level IRP */
1125 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
1126
1127 _SEH2_TRY
1128 {
1129 /* Attempt a read */
1130 CcMdlRead(FileObject, FileOffset, Length, MdlChain, IoStatus);
1131 FileObject->Flags |= FO_FILE_FAST_IO_READ;
1132 }
1133 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
1134 EXCEPTION_EXECUTE_HANDLER :
1135 EXCEPTION_CONTINUE_SEARCH)
1136 {
1137 Result = FALSE;
1138 }
1139 _SEH2_END;
1140
1141
1142 /* Remove the top-level IRP flag */
1143 PsGetCurrentThread()->TopLevelIrp = 0;
1144
1145 /* Return to caller */
1146 Cleanup:
1147
1148 ExReleaseResourceLite(FcbHeader->Resource);
1149 FsRtlExitFileSystem();
1150
1151 return Result;
1152 }
1153
1154 /*
1155 * @implemented
1156 */
1157 BOOLEAN
1158 NTAPI
1159 FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject,
1160 IN PLARGE_INTEGER FileOffset,
1161 IN PMDL MdlChain)
1162 {
1163 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
1164 PFAST_IO_DISPATCH FastDispatch;
1165
1166 /* Get Device Object and Fast Calls */
1167 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1168 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1169
1170 /* Check if we support Fast Calls, and check this one */
1171 if (FastDispatch && FastDispatch->MdlWriteComplete)
1172 {
1173 /* Use the fast path */
1174 return FastDispatch->MdlWriteComplete(FileObject,
1175 FileOffset,
1176 MdlChain,
1177 DeviceObject);
1178 }
1179
1180 /* Get the Base File System (Volume) and Fast Calls */
1181 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
1182 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch;
1183
1184 /* If the Base Device Object has its own FastDispatch Routine, fail */
1185 if (FastDispatch &&
1186 FastDispatch->MdlWriteComplete &&
1187 BaseDeviceObject != DeviceObject)
1188 {
1189 return FALSE;
1190 }
1191
1192 /* No fast path, use slow path */
1193 return FsRtlMdlWriteCompleteDev(FileObject,
1194 FileOffset,
1195 MdlChain,
1196 DeviceObject);
1197 }
1198
1199 /*
1200 * @implemented
1201 */
1202 BOOLEAN
1203 NTAPI
1204 FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject,
1205 IN PLARGE_INTEGER FileOffset,
1206 IN PMDL MdlChain,
1207 IN PDEVICE_OBJECT DeviceObject)
1208 {
1209 if (FileObject->Flags & FO_WRITE_THROUGH)
1210 {
1211 return FALSE;
1212 }
1213
1214 /* Call the Cache Manager */
1215 CcMdlWriteComplete2(FileObject, FileOffset, MdlChain);
1216 return TRUE;
1217 }
1218
1219 /*
1220 * @implemented
1221 */
1222 BOOLEAN
1223 NTAPI
1224 FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject,
1225 IN PLARGE_INTEGER FileOffset,
1226 IN ULONG Length,
1227 IN ULONG LockKey,
1228 OUT PMDL *MdlChain,
1229 OUT PIO_STATUS_BLOCK IoStatus)
1230 {
1231 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
1232 PFAST_IO_DISPATCH FastDispatch;
1233
1234 /* Get Device Object and Fast Calls */
1235 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1236 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1237
1238 /* Check if we support Fast Calls, and check this one */
1239 if (FastDispatch && FastDispatch->PrepareMdlWrite)
1240 {
1241 /* Use the fast path */
1242 return FastDispatch->PrepareMdlWrite(FileObject,
1243 FileOffset,
1244 Length,
1245 LockKey,
1246 MdlChain,
1247 IoStatus,
1248 DeviceObject);
1249 }
1250
1251 /* Get the Base File System (Volume) and Fast Calls */
1252 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
1253 FastDispatch = BaseDeviceObject->DriverObject->FastIoDispatch;
1254
1255 /* If the Base Device Object has its own FastDispatch Routine, fail */
1256 if (FastDispatch &&
1257 FastDispatch->PrepareMdlWrite &&
1258 BaseDeviceObject != DeviceObject)
1259 {
1260 return FALSE;
1261 }
1262
1263 /* No fast path, use slow path */
1264 return FsRtlPrepareMdlWriteDev(FileObject,
1265 FileOffset,
1266 Length,
1267 LockKey,
1268 MdlChain,
1269 IoStatus,
1270 DeviceObject);
1271 }
1272
1273 /*
1274 * @implemented
1275 */
1276 BOOLEAN
1277 NTAPI
1278 FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject,
1279 IN PLARGE_INTEGER FileOffset,
1280 IN ULONG Length,
1281 IN ULONG LockKey,
1282 OUT PMDL *MdlChain,
1283 OUT PIO_STATUS_BLOCK IoStatus,
1284 IN PDEVICE_OBJECT DeviceObject)
1285 {
1286 BOOLEAN Result = TRUE;
1287 PFAST_IO_DISPATCH FastIoDispatch;
1288 PDEVICE_OBJECT Device;
1289 PFSRTL_COMMON_FCB_HEADER FcbHeader;
1290 PSHARED_CACHE_MAP SharedCacheMap;
1291
1292 LARGE_INTEGER OldFileSize;
1293 LARGE_INTEGER OldValidDataLength;
1294 LARGE_INTEGER NewSize;
1295 LARGE_INTEGER Offset;
1296
1297 /* WDK doc.
1298 * Offset == 0xffffffffffffffff indicates append to the end of file.
1299 */
1300 BOOLEAN FileOffsetAppend = (FileOffset->HighPart == (LONG)0xffffffff) &&
1301 (FileOffset->LowPart == 0xffffffff);
1302
1303 BOOLEAN FileSizeModified = FALSE;
1304 BOOLEAN ResourceAquiredShared = FALSE;
1305
1306 /* Initialize some of the vars and pointers */
1307 OldFileSize.QuadPart = 0;
1308 OldValidDataLength.QuadPart = 0;
1309
1310 PAGED_CODE();
1311
1312 Offset.QuadPart = FileOffset->QuadPart + Length;
1313
1314 /* Nagar p.544.
1315 * Check with Cc if we can write.
1316 */
1317 if (!CcCanIWrite(FileObject, Length, TRUE, FALSE) ||
1318 (FileObject->Flags & FO_WRITE_THROUGH))
1319 {
1320 return FALSE;
1321 }
1322
1323 IoStatus->Status = STATUS_SUCCESS;
1324
1325 /* No actual read */
1326 if (!Length)
1327 {
1328 return TRUE;
1329 }
1330
1331 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1332 FsRtlEnterFileSystem();
1333
1334 /* Check we are going to extend the file */
1335 if ((FileOffsetAppend == FALSE) &&
1336 (FileOffset->QuadPart + Length <= FcbHeader->ValidDataLength.QuadPart))
1337 {
1338 /* Acquire the resource shared */
1339 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
1340 ResourceAquiredShared = TRUE;
1341 }
1342 else
1343 {
1344 /* Acquire the resource exclusive */
1345 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
1346 }
1347
1348 /* Check if we are appending */
1349 if (FileOffsetAppend == TRUE)
1350 {
1351 Offset.QuadPart = FcbHeader->FileSize.QuadPart;
1352 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length;
1353 }
1354 else
1355 {
1356 Offset.QuadPart = FileOffset->QuadPart;
1357 NewSize.QuadPart = FileOffset->QuadPart + Length;
1358 }
1359
1360 if ((FileObject->PrivateCacheMap) &&
1361 (FcbHeader->IsFastIoPossible) &&
1362 (Length <= MAXLONGLONG - FileOffset->QuadPart) &&
1363 (NewSize.QuadPart <= FcbHeader->AllocationSize.QuadPart))
1364 {
1365 /* Check if we can keep the lock shared */
1366 if (ResourceAquiredShared &&
1367 (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart))
1368 {
1369 ExReleaseResourceLite(FcbHeader->Resource);
1370 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
1371
1372 /* Compute the offset and the new filesize */
1373 if (FileOffsetAppend)
1374 {
1375 Offset.QuadPart = FcbHeader->FileSize.QuadPart;
1376 NewSize.QuadPart = FcbHeader->FileSize.QuadPart + Length;
1377 }
1378
1379 /* Recheck the above points since we released and reacquire the lock */
1380 if ((FileObject->PrivateCacheMap != NULL) &&
1381 (FcbHeader->IsFastIoPossible != FastIoIsNotPossible) &&
1382 (FcbHeader->AllocationSize.QuadPart > NewSize.QuadPart))
1383 {
1384 /* Do nothing */
1385 }
1386 else
1387 {
1388 goto FailAndCleanup;
1389 }
1390 }
1391
1392 /* Check if we need to find out if fast I/O is available */
1393 if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable)
1394 {
1395 /* Sanity check */
1396 /* ASSERT(!KeIsExecutingDpc()); */
1397
1398 /* Get the Fast I/O table */
1399 Device = IoGetRelatedDeviceObject(FileObject);
1400 FastIoDispatch = Device->DriverObject->FastIoDispatch;
1401
1402 /* Sanity check */
1403 ASSERT(FastIoDispatch != NULL);
1404 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
1405
1406 /* Ask the driver if we can do it */
1407 if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
1408 FileOffset,
1409 Length,
1410 TRUE,
1411 LockKey,
1412 FALSE,
1413 IoStatus,
1414 Device))
1415 {
1416 /* It's not, fail */
1417 goto FailAndCleanup;
1418 }
1419 }
1420
1421 /* If we are going to modify the filesize,
1422 * save the old fs in case the operation fails.
1423 */
1424 if (NewSize.QuadPart > FcbHeader->FileSize.QuadPart)
1425 {
1426 FileSizeModified = TRUE;
1427 OldFileSize.QuadPart = FcbHeader->FileSize.QuadPart;
1428 OldValidDataLength.QuadPart = FcbHeader->ValidDataLength.QuadPart;
1429
1430 /* If the high part of the filesize is going
1431 * to change, grab the Paging IoResouce.
1432 */
1433 if (NewSize.HighPart != FcbHeader->FileSize.HighPart &&
1434 FcbHeader->PagingIoResource)
1435 {
1436 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
1437 FcbHeader->FileSize.QuadPart = NewSize.QuadPart;
1438 ExReleaseResourceLite(FcbHeader->PagingIoResource);
1439 }
1440 else
1441 {
1442 FcbHeader->FileSize.QuadPart = NewSize.QuadPart;
1443 }
1444 }
1445
1446
1447 /* Nagar p.544.
1448 * Set ourselves as top component.
1449 */
1450 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
1451 _SEH2_TRY
1452 {
1453 /* Check if there is a gap between the end of the file and the offset.
1454 * If yes, then we have to zero the data.
1455 */
1456 if (Offset.QuadPart > FcbHeader->ValidDataLength.QuadPart)
1457 {
1458 Result = CcZeroData(FileObject,
1459 &FcbHeader->ValidDataLength,
1460 &Offset,
1461 TRUE);
1462 if (Result)
1463 {
1464 CcPrepareMdlWrite(FileObject,
1465 &Offset,
1466 Length,
1467 MdlChain,
1468 IoStatus);
1469 }
1470 }
1471 else
1472 {
1473 CcPrepareMdlWrite(FileObject, &Offset, Length, MdlChain, IoStatus);
1474 }
1475
1476 }
1477 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
1478 EXCEPTION_EXECUTE_HANDLER :
1479 EXCEPTION_CONTINUE_SEARCH)
1480 {
1481 Result = FALSE;
1482 }
1483 _SEH2_END;
1484
1485 /* Reset the top component */
1486 PsGetCurrentThread()->TopLevelIrp = 0;
1487
1488 /* Did the operation suceeded */
1489 if (Result)
1490 {
1491 /* Check if we need to update the filesize */
1492 if (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart)
1493 {
1494 if (NewSize.HighPart != FcbHeader->ValidDataLength.HighPart &&
1495 FcbHeader->PagingIoResource)
1496 {
1497 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
1498 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart;
1499 ExReleaseResourceLite(FcbHeader->PagingIoResource);
1500 }
1501 else
1502 {
1503 FcbHeader->ValidDataLength.QuadPart = NewSize.QuadPart;
1504 }
1505 }
1506
1507 /* Flag the file as modified */
1508 FileObject->Flags |= FO_FILE_MODIFIED;
1509
1510 /* Check if the filesize has changed */
1511 if (FileSizeModified)
1512 {
1513 SharedCacheMap =
1514 (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
1515 SharedCacheMap->FileSize.QuadPart = NewSize.QuadPart;
1516 FileObject->Flags |= FO_FILE_SIZE_CHANGED;
1517 }
1518 }
1519 else
1520 {
1521 /* The operation did not succeed.
1522 * Reset the file size to what it should be.
1523 */
1524 if (FileSizeModified)
1525 {
1526 if (FcbHeader->PagingIoResource)
1527 {
1528 ExAcquireResourceExclusiveLite(FcbHeader->PagingIoResource, TRUE);
1529 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart;
1530 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart;
1531 ExReleaseResourceLite(FcbHeader->PagingIoResource);
1532 }
1533 else
1534 {
1535 FcbHeader->FileSize.QuadPart = OldFileSize.QuadPart;
1536 FcbHeader->ValidDataLength.QuadPart = OldValidDataLength.QuadPart;
1537 }
1538 }
1539 }
1540
1541 goto Cleanup;
1542 }
1543 else
1544 {
1545 goto FailAndCleanup;
1546 }
1547
1548 FailAndCleanup:
1549
1550 ExReleaseResourceLite(FcbHeader->Resource);
1551 FsRtlExitFileSystem();
1552 return FALSE;
1553
1554 Cleanup:
1555
1556 ExReleaseResourceLite(FcbHeader->Resource);
1557 FsRtlExitFileSystem();
1558 return Result;
1559 }
1560
1561 /*
1562 * @implemented
1563 */
1564 VOID
1565 NTAPI
1566 FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject)
1567 {
1568 /* PAGED_CODE(); */
1569 /* FsRtlAcquireFileExclusiveCommon(FileObject, 0, 0); */
1570 KeBugCheck(FILE_SYSTEM);
1571 }
1572
1573 /*
1574 * @implemented
1575 */
1576 VOID
1577 NTAPI
1578 FsRtlReleaseFile(IN PFILE_OBJECT FileObject)
1579 {
1580 KeBugCheck(FILE_SYSTEM);
1581 }
1582
1583 /*++
1584 * @name FsRtlRegisterFileSystemFilterCallbacks
1585 * @unimplemented
1586 *
1587 * FILLME
1588 *
1589 * @param FilterDriverObject
1590 * FILLME
1591 *
1592 * @param Callbacks
1593 * FILLME
1594 *
1595 * @return None
1596 *
1597 * @remarks None
1598 *
1599 *--*/
1600 NTSTATUS
1601 NTAPI
1602 FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject,
1603 IN PFS_FILTER_CALLBACKS Callbacks)
1604 {
1605 UNIMPLEMENTED;
1606 return STATUS_NOT_IMPLEMENTED;
1607 }