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