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