xref: /reactos/ntoskrnl/fsrtl/fastio.c (revision 2ae9feb5)
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