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