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
FsRtlIncrementCcFastReadResourceMiss(VOID)24 FsRtlIncrementCcFastReadResourceMiss(VOID)
25 {
26 CcFastReadResourceMiss++;
27 }
28
29 /*
30 * @implemented
31 */
32 VOID
33 NTAPI
FsRtlIncrementCcFastReadNotPossible(VOID)34 FsRtlIncrementCcFastReadNotPossible(VOID)
35 {
36 CcFastReadNotPossible++;
37 }
38
39 /*
40 * @implemented
41 */
42 VOID
43 NTAPI
FsRtlIncrementCcFastReadWait(VOID)44 FsRtlIncrementCcFastReadWait(VOID)
45 {
46 CcFastReadWait++;
47 }
48
49 /*
50 * @implemented
51 */
52 VOID
53 NTAPI
FsRtlIncrementCcFastReadNoWait(VOID)54 FsRtlIncrementCcFastReadNoWait(VOID)
55 {
56 CcFastReadNoWait++;
57 }
58
59 /*
60 * @implemented
61 */
62 BOOLEAN
63 NTAPI
FsRtlCopyRead(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,IN ULONG LockKey,OUT PVOID Buffer,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)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
FsRtlCopyWrite(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,IN ULONG LockKey,OUT PVOID Buffer,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)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
FsRtlGetFileSize(IN PFILE_OBJECT FileObject,IN OUT PLARGE_INTEGER FileSize)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
FsRtlMdlRead(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG LockKey,OUT PMDL * MdlChain,OUT PIO_STATUS_BLOCK IoStatus)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
FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject,IN OUT PMDL MdlChain)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
FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject,IN PMDL MemoryDescriptorList,IN PDEVICE_OBJECT DeviceObject)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
FsRtlMdlReadDev(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG LockKey,OUT PMDL * MdlChain,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)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
FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN PMDL MdlChain)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
FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN PMDL MdlChain,IN PDEVICE_OBJECT DeviceObject)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
FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG LockKey,OUT PMDL * MdlChain,OUT PIO_STATUS_BLOCK IoStatus)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
FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG LockKey,OUT PMDL * MdlChain,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)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
FsRtlAcquireFileExclusiveCommon(IN PFILE_OBJECT FileObject,IN FS_FILTER_SECTION_SYNC_TYPE SyncType,IN ULONG Reserved)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 PEXTENDED_DRIVER_EXTENSION DriverExtension;
1565 PFS_FILTER_CALLBACKS FilterCallbacks;
1566
1567 /* Get Device Object and Fast Calls */
1568 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1569 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1570
1571 /* Get master FsRtl lock */
1572 FsRtlEnterFileSystem();
1573
1574 DriverExtension = (PEXTENDED_DRIVER_EXTENSION)DeviceObject->DriverObject->DriverExtension;
1575 FilterCallbacks = DriverExtension->FsFilterCallbacks;
1576
1577 /* Check if Filter Cllbacks are supported */
1578 if (FilterCallbacks && FilterCallbacks->PreAcquireForSectionSynchronization)
1579 {
1580 NTSTATUS Status;
1581 PVOID CompletionContext;
1582
1583 FS_FILTER_CALLBACK_DATA CbData;
1584
1585 RtlZeroMemory(&CbData, sizeof(CbData));
1586
1587 CbData.SizeOfFsFilterCallbackData = sizeof(CbData);
1588 CbData.Operation = FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION;
1589 CbData.DeviceObject = DeviceObject;
1590 CbData.FileObject = FileObject;
1591 CbData.Parameters.AcquireForSectionSynchronization.PageProtection = Reserved;
1592 CbData.Parameters.AcquireForSectionSynchronization.SyncType = SyncType;
1593
1594 Status = FilterCallbacks->PreAcquireForSectionSynchronization(&CbData, &CompletionContext);
1595 if (!NT_SUCCESS(Status))
1596 {
1597 FsRtlExitFileSystem();
1598 return Status;
1599 }
1600
1601 /* Should we do something in-between ? */
1602
1603 if (FilterCallbacks->PostAcquireForSectionSynchronization)
1604 {
1605 FilterCallbacks->PostAcquireForSectionSynchronization(&CbData, Status, CompletionContext);
1606 }
1607
1608 return Status;
1609 }
1610
1611 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1612
1613 /* Check if Fast Calls are supported, and check AcquireFileForNtCreateSection */
1614 if (FastDispatch &&
1615 FastDispatch->AcquireFileForNtCreateSection)
1616 {
1617 /* Call the AcquireFileForNtCreateSection FastIo handler */
1618 FastDispatch->AcquireFileForNtCreateSection(FileObject);
1619 }
1620 else
1621 {
1622 /* No FastIo handler, acquire file's resource exclusively */
1623 if (FcbHeader && FcbHeader->Resource) ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
1624 }
1625
1626 return STATUS_SUCCESS;
1627 }
1628
1629 /*
1630 * @implemented
1631 */
1632 VOID
1633 NTAPI
FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject)1634 FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject)
1635 {
1636 PAGED_CODE();
1637
1638 /* Call the common routine. Don't care about the result */
1639 (VOID)FsRtlAcquireFileExclusiveCommon(FileObject, SyncTypeOther, 0);
1640 }
1641
1642 /*
1643 * @implemented
1644 */
1645 NTSTATUS
1646 NTAPI
FsRtlAcquireToCreateMappedSection(_In_ PFILE_OBJECT FileObject,_In_ ULONG SectionPageProtection)1647 FsRtlAcquireToCreateMappedSection(_In_ PFILE_OBJECT FileObject,
1648 _In_ ULONG SectionPageProtection)
1649 {
1650 PAGED_CODE();
1651
1652 return FsRtlAcquireFileExclusiveCommon(FileObject, SyncTypeCreateSection, SectionPageProtection);
1653 }
1654 /*
1655 * @implemented
1656 */
1657 VOID
1658 NTAPI
FsRtlReleaseFile(IN PFILE_OBJECT FileObject)1659 FsRtlReleaseFile(IN PFILE_OBJECT FileObject)
1660 {
1661 PFSRTL_COMMON_FCB_HEADER FcbHeader;
1662 PDEVICE_OBJECT DeviceObject;
1663 PFAST_IO_DISPATCH FastDispatch;
1664
1665 /* Get Device Object and Fast Calls */
1666 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1667 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1668 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1669
1670 /* Check if Fast Calls are supported and check ReleaseFileForNtCreateSection */
1671 if (FastDispatch &&
1672 FastDispatch->ReleaseFileForNtCreateSection)
1673 {
1674 /* Call the ReleaseFileForNtCreateSection FastIo handler */
1675 FastDispatch->ReleaseFileForNtCreateSection(FileObject);
1676 }
1677 else
1678 {
1679 /* No FastIo handler, release file's resource */
1680 if (FcbHeader && FcbHeader->Resource) ExReleaseResourceLite(FcbHeader->Resource);
1681 }
1682
1683 /* Release master FsRtl lock */
1684 FsRtlExitFileSystem();
1685 }
1686
1687 /*
1688 * @implemented
1689 */
1690 NTSTATUS
1691 NTAPI
FsRtlAcquireFileForCcFlushEx(IN PFILE_OBJECT FileObject)1692 FsRtlAcquireFileForCcFlushEx(IN PFILE_OBJECT FileObject)
1693 {
1694 PFSRTL_COMMON_FCB_HEADER FcbHeader;
1695 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
1696 PFAST_IO_DISPATCH FastDispatch;
1697 NTSTATUS Status;
1698
1699 /* Get the Base File System (Volume) and Fast Calls */
1700 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1701 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1702 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
1703 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1704
1705 /* Get master FsRtl lock */
1706 FsRtlEnterFileSystem();
1707
1708 /* Check if Fast Calls are supported, and check AcquireForCcFlush */
1709 if (FastDispatch &&
1710 FastDispatch->AcquireForCcFlush)
1711 {
1712 /* Call the AcquireForCcFlush FastIo handler */
1713 Status = FastDispatch->AcquireForCcFlush(FileObject, BaseDeviceObject);
1714
1715 /* Return either success or inability to wait.
1716 In case of other failure - fall through */
1717 if (NT_SUCCESS(Status))
1718 return Status;
1719
1720 if (Status == STATUS_CANT_WAIT)
1721 {
1722 DPRINT1("STATUS_CANT_WAIT\n");
1723 FsRtlExitFileSystem();
1724 return Status;
1725 }
1726 }
1727
1728 /* No FastIo handler (or it failed). Acquire Main resource */
1729 if (FcbHeader->Resource)
1730 {
1731 /* Acquire it - either shared if it's already acquired
1732 or exclusively if we are the first */
1733 if (ExIsResourceAcquiredSharedLite(FcbHeader->Resource))
1734 ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
1735 else
1736 ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
1737 }
1738
1739 /* Also acquire its PagingIO resource */
1740 if (FcbHeader->PagingIoResource)
1741 ExAcquireResourceSharedLite(FcbHeader->PagingIoResource, TRUE);
1742
1743 return STATUS_SUCCESS;
1744 }
1745
1746 /*
1747 * @implemented
1748 */
1749 VOID
1750 NTAPI
FsRtlAcquireFileForCcFlush(IN PFILE_OBJECT FileObject)1751 FsRtlAcquireFileForCcFlush(IN PFILE_OBJECT FileObject)
1752 {
1753 PAGED_CODE();
1754
1755 /* Call the common routine. Don't care about the result */
1756 (VOID)FsRtlAcquireFileForCcFlushEx(FileObject);
1757 }
1758
1759
1760 /*
1761 * @implemented
1762 */
1763 VOID
1764 NTAPI
FsRtlReleaseFileForCcFlush(IN PFILE_OBJECT FileObject)1765 FsRtlReleaseFileForCcFlush(IN PFILE_OBJECT FileObject)
1766 {
1767 PFSRTL_COMMON_FCB_HEADER FcbHeader;
1768 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
1769 PFAST_IO_DISPATCH FastDispatch;
1770 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
1771
1772 /* Get Device Object and Fast Calls */
1773 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1774 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1775 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
1776 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1777
1778 /* Check if Fast Calls are supported, and check ReleaseForCcFlush */
1779 if (FastDispatch &&
1780 FastDispatch->ReleaseForCcFlush)
1781 {
1782 /* Call the ReleaseForCcFlush FastIo handler */
1783 Status = FastDispatch->ReleaseForCcFlush(FileObject, BaseDeviceObject);
1784 }
1785
1786 if (!NT_SUCCESS(Status))
1787 {
1788 /* No FastIo handler (or it failed). Release PagingIO resource and
1789 then Main resource */
1790 if (FcbHeader->PagingIoResource) ExReleaseResourceLite(FcbHeader->PagingIoResource);
1791 if (FcbHeader->Resource) ExReleaseResourceLite(FcbHeader->Resource);
1792 }
1793
1794 /* Release master FsRtl lock */
1795 FsRtlExitFileSystem();
1796 }
1797
1798 /**
1799 * @brief Get the resource to acquire when Mod Writer flushes data to disk
1800 *
1801 * @param FcbHeader - FCB header from the file object
1802 * @param EndingOffset - The end offset of the write to be done
1803 * @param ResourceToAcquire - Pointer receiving the resource to acquire before doing the write
1804 *
1805 * @return BOOLEAN specifying whether the resource must be acquired exclusively
1806 */
1807 static
1808 BOOLEAN
FsRtlpGetResourceForModWrite(_In_ PFSRTL_COMMON_FCB_HEADER FcbHeader,_In_ PLARGE_INTEGER EndingOffset,_Outptr_result_maybenull_ PERESOURCE * ResourceToAcquire)1809 FsRtlpGetResourceForModWrite(_In_ PFSRTL_COMMON_FCB_HEADER FcbHeader,
1810 _In_ PLARGE_INTEGER EndingOffset,
1811 _Outptr_result_maybenull_ PERESOURCE* ResourceToAcquire)
1812 {
1813 /*
1814 * Decide on type of locking and type of resource based on
1815 * - Flags
1816 * - Whether we're extending ValidDataLength
1817 */
1818 if (FlagOn(FcbHeader->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX))
1819 {
1820 /* Acquire main resource, exclusive */
1821 *ResourceToAcquire = FcbHeader->Resource;
1822 return TRUE;
1823 }
1824
1825 /* We will acquire shared. Which one ? */
1826 if (FlagOn(FcbHeader->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH))
1827 {
1828 *ResourceToAcquire = FcbHeader->Resource;
1829 }
1830 else
1831 {
1832 *ResourceToAcquire = FcbHeader->PagingIoResource;
1833 }
1834
1835 /* We force exclusive lock if this write modifies the valid data length */
1836 return (EndingOffset->QuadPart > FcbHeader->ValidDataLength.QuadPart);
1837 }
1838
1839 /**
1840 * @brief Lock a file object before flushing pages to disk.
1841 * To be called by the Modified Page Writer (MPW)
1842 *
1843 * @param FileObject - The file object to lock
1844 * @param EndingOffset - The end offset of the write to be done
1845 * @param ResourceToRelease - Pointer receiving the resource to release after the write
1846 *
1847 * @return Relevant NTSTATUS value
1848 */
1849 _Check_return_
1850 NTSTATUS
1851 NTAPI
FsRtlAcquireFileForModWriteEx(_In_ PFILE_OBJECT FileObject,_In_ PLARGE_INTEGER EndingOffset,_Outptr_result_maybenull_ PERESOURCE * ResourceToRelease)1852 FsRtlAcquireFileForModWriteEx(_In_ PFILE_OBJECT FileObject,
1853 _In_ PLARGE_INTEGER EndingOffset,
1854 _Outptr_result_maybenull_ PERESOURCE *ResourceToRelease)
1855 {
1856 PFSRTL_COMMON_FCB_HEADER FcbHeader;
1857 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
1858 PFAST_IO_DISPATCH FastDispatch;
1859 PERESOURCE ResourceToAcquire = NULL;
1860 BOOLEAN Exclusive;
1861 BOOLEAN Result;
1862 NTSTATUS Status = STATUS_SUCCESS;
1863
1864 /* Get Device Object and Fast Calls */
1865 FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
1866 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1867 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
1868 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1869
1870 /* Check if Fast Calls are supported, and check AcquireForModWrite */
1871 if (FastDispatch &&
1872 FastDispatch->AcquireForModWrite)
1873 {
1874 /* Call the AcquireForModWrite FastIo handler */
1875 Status = FastDispatch->AcquireForModWrite(FileObject,
1876 EndingOffset,
1877 ResourceToRelease,
1878 BaseDeviceObject);
1879
1880 /* Return either success or inability to wait.
1881 In case of other failure - fall through */
1882 if (Status == STATUS_SUCCESS ||
1883 Status == STATUS_CANT_WAIT)
1884 {
1885 return Status;
1886 }
1887 }
1888
1889 /* Check what and how we should acquire */
1890 Exclusive = FsRtlpGetResourceForModWrite(FcbHeader, EndingOffset, &ResourceToAcquire);
1891
1892 /* Acquire the resource and loop until we're sure we got this right. */
1893 while (TRUE)
1894 {
1895 BOOLEAN OldExclusive;
1896 PERESOURCE OldResourceToAcquire;
1897
1898 if (ResourceToAcquire == NULL)
1899 {
1900 /*
1901 * There's nothing to acquire, we can simply return success
1902 */
1903
1904 break;
1905 }
1906
1907 if (Exclusive)
1908 {
1909 Result = ExAcquireResourceExclusiveLite(ResourceToAcquire, FALSE);
1910 }
1911 else
1912 {
1913 Result = ExAcquireSharedWaitForExclusive(ResourceToAcquire, FALSE);
1914 }
1915
1916 if (!Result)
1917 {
1918 return STATUS_CANT_WAIT;
1919 }
1920
1921 /* Does this still hold true? */
1922 OldExclusive = Exclusive;
1923 OldResourceToAcquire = ResourceToAcquire;
1924 Exclusive = FsRtlpGetResourceForModWrite(FcbHeader, EndingOffset, &ResourceToAcquire);
1925
1926 if ((OldExclusive == Exclusive) && (OldResourceToAcquire == ResourceToAcquire))
1927 {
1928 /* We're good */
1929 break;
1930 }
1931
1932 /* Can we fix this situation? */
1933 if ((OldResourceToAcquire == ResourceToAcquire) && !Exclusive)
1934 {
1935 /* We can easily do so */
1936 ExConvertExclusiveToSharedLite(ResourceToAcquire);
1937 break;
1938 }
1939
1940 /* Things have changed since we acquired the lock. Start again */
1941 ExReleaseResourceLite(OldResourceToAcquire);
1942 }
1943
1944 /* If we're here, this means that we succeeded */
1945 *ResourceToRelease = ResourceToAcquire;
1946 return STATUS_SUCCESS;
1947 }
1948
1949 /**
1950 * @brief Unlock a file object after flushing pages to disk.
1951 * To be called by the Modified Page Writer (MPW) after a succesful call to
1952 * FsRtlAcquireFileForModWriteEx
1953 *
1954 * @param FileObject - The file object to unlock
1955 * @param ResourceToRelease - The resource to release
1956 */
1957 VOID
1958 NTAPI
FsRtlReleaseFileForModWrite(_In_ PFILE_OBJECT FileObject,_In_ PERESOURCE ResourceToRelease)1959 FsRtlReleaseFileForModWrite(_In_ PFILE_OBJECT FileObject,
1960 _In_ PERESOURCE ResourceToRelease)
1961 {
1962 PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
1963 PFAST_IO_DISPATCH FastDispatch;
1964 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1965
1966 /* Get Device Object and Fast Calls */
1967 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1968 BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
1969 FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
1970
1971 /* Check if Fast Calls are supported and check ReleaseForModWrite */
1972 if (FastDispatch &&
1973 FastDispatch->ReleaseForModWrite)
1974 {
1975 /* Call the ReleaseForModWrite FastIo handler */
1976 Status = FastDispatch->ReleaseForModWrite(FileObject,
1977 ResourceToRelease,
1978 BaseDeviceObject);
1979 }
1980
1981 /* Just release the resource if previous op failed */
1982 if (!NT_SUCCESS(Status))
1983 {
1984 ExReleaseResourceLite(ResourceToRelease);
1985 }
1986 }
1987
1988
1989 /*++
1990 * @name FsRtlRegisterFileSystemFilterCallbacks
1991 * @unimplemented
1992 *
1993 * FILLME
1994 *
1995 * @param FilterDriverObject
1996 * FILLME
1997 *
1998 * @param Callbacks
1999 * FILLME
2000 *
2001 * @return None
2002 *
2003 * @remarks None
2004 *
2005 *--*/
2006 NTSTATUS
2007 NTAPI
FsRtlRegisterFileSystemFilterCallbacks(PDRIVER_OBJECT FilterDriverObject,PFS_FILTER_CALLBACKS Callbacks)2008 FsRtlRegisterFileSystemFilterCallbacks(
2009 PDRIVER_OBJECT FilterDriverObject,
2010 PFS_FILTER_CALLBACKS Callbacks)
2011 {
2012 PFS_FILTER_CALLBACKS NewCallbacks;
2013 PEXTENDED_DRIVER_EXTENSION DriverExtension;
2014 PAGED_CODE();
2015
2016 /* Verify parameters */
2017 if ((FilterDriverObject == NULL) || (Callbacks == NULL))
2018 {
2019 return STATUS_INVALID_PARAMETER;
2020 }
2021
2022 /* Allocate a buffer for a copy of the callbacks */
2023 NewCallbacks = ExAllocatePoolWithTag(NonPagedPool,
2024 Callbacks->SizeOfFsFilterCallbacks,
2025 'gmSF');
2026 if (NewCallbacks == NULL)
2027 {
2028 return STATUS_INSUFFICIENT_RESOURCES;
2029 }
2030
2031 /* Copy the callbacks */
2032 RtlCopyMemory(NewCallbacks, Callbacks, Callbacks->SizeOfFsFilterCallbacks);
2033
2034 /* Set the callbacks in the driver extension */
2035 DriverExtension = (PEXTENDED_DRIVER_EXTENSION)FilterDriverObject->DriverExtension;
2036 DriverExtension->FsFilterCallbacks = NewCallbacks;
2037
2038 return STATUS_SUCCESS;
2039 }
2040