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