xref: /reactos/sdk/lib/drivers/copysup/copysup.c (revision 541cb0d9)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2017 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:        See COPYING in the top level directory
21  * PROJECT:          ReactOS kernel
22  * FILE:             sdk/lib/drivers/copysup/copysup.c
23  * PURPOSE:          CopySup library
24  * PROGRAMMER:       Pierre Schweitzer (pierre@reactos.org)
25  */
26 
27 /* INCLUDES *****************************************************************/
28 
29 #include "copysup.h"
30 #include <pseh/pseh2.h>
31 #define NDEBUG
32 #include <debug.h>
33 
34 /* FUNCTIONS ****************************************************************/
35 
36 /*
37  * @implemented
38  */
39 BOOLEAN
40 FsRtlCopyRead2(
41     IN PFILE_OBJECT FileObject,
42     IN PLARGE_INTEGER FileOffset,
43     IN ULONG Length,
44     IN BOOLEAN Wait,
45     IN ULONG LockKey,
46     OUT PVOID Buffer,
47     OUT PIO_STATUS_BLOCK IoStatus,
48     IN PDEVICE_OBJECT DeviceObject,
49     IN PVOID TopLevelContext)
50 {
51     BOOLEAN Ret;
52     ULONG PageCount;
53     LARGE_INTEGER FinalOffset;
54     PFSRTL_COMMON_FCB_HEADER Fcb;
55     PFAST_IO_DISPATCH FastIoDispatch;
56     PDEVICE_OBJECT RelatedDeviceObject;
57 
58     PAGED_CODE();
59 
60     Ret = TRUE;
61     PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset, Length);
62 
63     /* Null-length read is always OK */
64     if (Length == 0)
65     {
66         IoStatus->Information = 0;
67         IoStatus->Status = STATUS_SUCCESS;
68 
69         return TRUE;
70     }
71 
72     /* Check we don't overflow */
73     FinalOffset.QuadPart = FileOffset->QuadPart + Length;
74     if (FinalOffset.QuadPart <= 0)
75     {
76         return FALSE;
77     }
78 
79     /* Get the FCB (at least, its header) */
80     Fcb = FileObject->FsContext;
81 
82     FsRtlEnterFileSystem();
83 
84     /* Acquire its resource (shared) */
85     if (Wait)
86     {
87         ExAcquireResourceSharedLite(Fcb->Resource, TRUE);
88     }
89     else
90     {
91         if (!ExAcquireResourceSharedLite(Fcb->Resource, FALSE))
92         {
93             Ret = FALSE;
94             goto CriticalSection;
95         }
96     }
97 
98     /* If cache wasn't initialized, or FastIO isn't possible, fail */
99     if (FileObject->PrivateCacheMap == NULL || Fcb->IsFastIoPossible == FastIoIsNotPossible)
100     {
101             Ret = FALSE;
102             goto Resource;
103     }
104 
105     /* If FastIO is questionable, then, question! */
106     if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
107     {
108         RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
109         FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
110         ASSERT(FastIoDispatch != NULL);
111         ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
112 
113         /* If it's not possible, then fail */
114         if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, FileOffset, Length,
115                                                    Wait, LockKey, TRUE, IoStatus, RelatedDeviceObject))
116         {
117             Ret = FALSE;
118             goto Resource;
119         }
120     }
121 
122     /* If we get beyond file end... */
123     if (FinalOffset.QuadPart > Fcb->FileSize.QuadPart)
124     {
125         /* Fail if the offset was already beyond file end */
126         if (FileOffset->QuadPart >= Fcb->FileSize.QuadPart)
127         {
128             IoStatus->Information = 0;
129             IoStatus->Status = STATUS_END_OF_FILE;
130             goto Resource;
131         }
132 
133         /* Otherwise, just fix read length */
134         Length = (ULONG)(Fcb->FileSize.QuadPart - FileOffset->QuadPart);
135     }
136 
137     /* Set caller provided context as TLI */
138     IoSetTopLevelIrp(TopLevelContext);
139 
140     _SEH2_TRY
141     {
142         /* If we cannot wait, or if file is bigger than 4GB */
143         if (!Wait || (FinalOffset.HighPart | Fcb->FileSize.HighPart) != 0)
144         {
145             /* Forward to Cc */
146             Ret = CcCopyRead(FileObject, FileOffset, Length, Wait, Buffer, IoStatus);
147             SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
148 
149             /* Validate output */
150             ASSERT(!Ret || (IoStatus->Status == STATUS_END_OF_FILE) || (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <= (ULONGLONG)Fcb->FileSize.QuadPart));
151         }
152         else
153         {
154             /* Forward to Cc */
155             CcFastCopyRead(FileObject, FileOffset->LowPart, Length, PageCount, Buffer, IoStatus);
156             SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
157 
158             /* Validate output */
159             ASSERT((IoStatus->Status == STATUS_END_OF_FILE) || ((FileOffset->LowPart + IoStatus->Information) <= Fcb->FileSize.LowPart));
160         }
161 
162         /* If read was successful, update the byte offset in the FO */
163         if (Ret)
164         {
165             FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
166         }
167     }
168     _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
169                  EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
170     {
171         Ret = FALSE;
172     }
173     _SEH2_END;
174 
175     /* Reset TLI */
176     IoSetTopLevelIrp(NULL);
177 
178 Resource:
179     ExReleaseResourceLite(Fcb->Resource);
180 CriticalSection:
181     FsRtlExitFileSystem();
182 
183     return Ret;
184 }
185 
186 /*
187  * @implemented
188  */
189 BOOLEAN
190 FsRtlCopyWrite2(
191     IN PFILE_OBJECT FileObject,
192     IN PLARGE_INTEGER FileOffset,
193     IN ULONG Length,
194     IN BOOLEAN Wait,
195     IN ULONG LockKey,
196     IN PVOID Buffer,
197     OUT PIO_STATUS_BLOCK IoStatus,
198     IN PDEVICE_OBJECT DeviceObject,
199     IN PVOID TopLevelContext)
200 {
201     IO_STATUS_BLOCK LocalIoStatus;
202     PFSRTL_ADVANCED_FCB_HEADER Fcb;
203     BOOLEAN WriteToEof, AcquiredShared, FileSizeChanged, Ret;
204     LARGE_INTEGER WriteOffset, LastOffset, InitialFileSize, InitialValidDataLength;
205 
206     PAGED_CODE();
207 
208     /* First, check whether we're writing to EOF */
209     WriteToEof = ((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
210                   (FileOffset->HighPart == -1));
211 
212     /* If Cc says we cannot write, fail now */
213     if (!CcCanIWrite(FileObject, Length, Wait, FALSE))
214     {
215         return FALSE;
216     }
217 
218     /* Write through means no cache */
219     if (BooleanFlagOn(FileObject->Flags, FO_WRITE_THROUGH))
220     {
221         return FALSE;
222     }
223 
224     /* If write is > 64Kb, don't use FastIO */
225     if (!CcCopyWriteWontFlush(FileObject, FileOffset, Length))
226     {
227         return FALSE;
228     }
229 
230     /* Initialize the IO_STATUS_BLOCK */
231     IoStatus->Status = STATUS_SUCCESS;
232     IoStatus->Information = Length;
233 
234     /* No length, it's already written! */
235     if (Length == 0)
236     {
237         return TRUE;
238     }
239 
240     AcquiredShared = FALSE;
241     FileSizeChanged = FALSE;
242     Fcb = FileObject->FsContext;
243 
244     FsRtlEnterFileSystem();
245 
246     /* If we cannot wait, or deal with files bigger then 4GB */
247     if (!Wait || (Fcb->AllocationSize.HighPart != 0))
248     {
249         /* If we're to extend the file, then, acquire exclusively */
250         if (WriteToEof || FileOffset->QuadPart + Length > Fcb->ValidDataLength.QuadPart)
251         {
252             if (!ExAcquireResourceExclusiveLite(Fcb->Resource, Wait))
253             {
254                 FsRtlExitFileSystem();
255                 return FALSE;
256             }
257         }
258         /* Otherwise, a shared lock is enough */
259         else
260         {
261             if (!ExAcquireResourceSharedLite(Fcb->Resource, Wait))
262             {
263                 FsRtlExitFileSystem();
264                 return FALSE;
265             }
266 
267             AcquiredShared = TRUE;
268         }
269 
270         /* Get first write offset, and last */
271         if (WriteToEof)
272         {
273             WriteOffset.QuadPart = Fcb->FileSize.QuadPart;
274             LastOffset.QuadPart = WriteOffset.QuadPart + Length;
275         }
276         else
277         {
278             WriteOffset.QuadPart = FileOffset->QuadPart;
279             LastOffset.QuadPart = WriteOffset.QuadPart + Length;
280         }
281 
282         /* If cache wasn't initialized, fail */
283         if (FileObject->PrivateCacheMap == NULL ||
284             Fcb->IsFastIoPossible == FastIoIsNotPossible)
285         {
286             ExReleaseResourceLite(Fcb->Resource);
287             FsRtlExitFileSystem();
288 
289             return FALSE;
290         }
291 
292         /* If we're to write beyond allocation size, it's no go,
293          * same is we create a hole bigger than 8kb
294          */
295         if ((Fcb->ValidDataLength.QuadPart + 0x2000 <= WriteOffset.QuadPart) ||
296             (Length > MAXLONGLONG - WriteOffset.QuadPart) ||
297             (Fcb->AllocationSize.QuadPart < LastOffset.QuadPart))
298         {
299             ExReleaseResourceLite(Fcb->Resource);
300             FsRtlExitFileSystem();
301 
302             return FALSE;
303         }
304 
305         /* If we have to extend the VDL, shared lock isn't enough */
306         if (AcquiredShared && LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
307         {
308             /* So release, and attempt to acquire exclusively */
309             ExReleaseResourceLite(Fcb->Resource);
310             if (!ExAcquireResourceExclusiveLite(Fcb->Resource, Wait))
311             {
312                 FsRtlExitFileSystem();
313                 return FALSE;
314             }
315 
316             /* Get again EOF, in case file size changed in between */
317             if (WriteToEof)
318             {
319                 WriteOffset.QuadPart = Fcb->FileSize.QuadPart;
320                 LastOffset.QuadPart = WriteOffset.QuadPart + Length;
321             }
322 
323             /* Make sure caching is still enabled */
324             if (FileObject->PrivateCacheMap == NULL ||
325                 Fcb->IsFastIoPossible == FastIoIsNotPossible)
326             {
327                 ExReleaseResourceLite(Fcb->Resource);
328                 FsRtlExitFileSystem();
329 
330                 return FALSE;
331             }
332 
333             /* And that we're not writing beyond allocation size */
334             if (Fcb->AllocationSize.QuadPart < LastOffset.QuadPart)
335             {
336                 ExReleaseResourceLite(Fcb->Resource);
337                 FsRtlExitFileSystem();
338 
339                 return FALSE;
340             }
341         }
342 
343         /* If FastIO is questionable, then question */
344         if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
345         {
346             PFAST_IO_DISPATCH FastIoDispatch;
347             PDEVICE_OBJECT RelatedDeviceObject;
348 
349             RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
350             FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
351             ASSERT(FastIoDispatch != NULL);
352             ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
353 
354             if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
355                                                        &WriteOffset,
356                                                        Length, Wait, LockKey,
357                                                        FALSE, &LocalIoStatus,
358                                                        RelatedDeviceObject))
359             {
360                 ExReleaseResourceLite(Fcb->Resource);
361                 FsRtlExitFileSystem();
362 
363                 return FALSE;
364             }
365         }
366 
367         /* If we write beyond EOF, then, save previous sizes (in case of failure)
368          * and update file size, to allow writing
369          */
370         if (LastOffset.QuadPart > Fcb->FileSize.QuadPart)
371         {
372             FileSizeChanged = TRUE;
373             InitialFileSize.QuadPart = Fcb->FileSize.QuadPart;
374             InitialValidDataLength.QuadPart = Fcb->ValidDataLength.QuadPart;
375 
376             if (LastOffset.HighPart != Fcb->FileSize.HighPart &&
377                 Fcb->PagingIoResource != NULL)
378             {
379                 ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
380                 Fcb->FileSize.QuadPart = LastOffset.QuadPart;
381                 ExReleaseResourceLite(Fcb->PagingIoResource);
382             }
383             else
384             {
385                 Fcb->FileSize.QuadPart = LastOffset.QuadPart;
386             }
387         }
388 
389         /* Set caller provided context as top level IRP */
390         IoSetTopLevelIrp(TopLevelContext);
391 
392         Ret = TRUE;
393 
394         /* And perform the writing */
395         _SEH2_TRY
396         {
397             /* Check whether we've to create a hole first */
398             if (LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
399             {
400                 Ret = CcZeroData(FileObject, &Fcb->ValidDataLength,
401                                  &WriteOffset, Wait);
402             }
403 
404             /* If not needed, or if it worked, write data */
405             if (Ret)
406             {
407                 Ret = CcCopyWrite(FileObject, &WriteOffset,
408                                   Length, Wait, Buffer);
409             }
410         }
411         _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
412                                              EXCEPTION_EXECUTE_HANDLER :
413                                              EXCEPTION_CONTINUE_SEARCH)
414         {
415             Ret = FALSE;
416         }
417         _SEH2_END;
418 
419         /* Restore top level IRP */
420         IoSetTopLevelIrp(NULL);
421 
422         /* If writing succeed */
423         if (Ret)
424         {
425             /* If we wrote beyond VDL, update it */
426             if (LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
427             {
428                 if (LastOffset.HighPart != Fcb->ValidDataLength.HighPart &&
429                     Fcb->PagingIoResource != NULL)
430                 {
431                     ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
432                     Fcb->ValidDataLength.QuadPart = LastOffset.QuadPart;
433                     ExReleaseResourceLite(Fcb->PagingIoResource);
434                 }
435                 else
436                 {
437                     Fcb->ValidDataLength.QuadPart = LastOffset.QuadPart;
438                 }
439             }
440 
441             /* File was obviously modified */
442             SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
443 
444             /* And if we increased it, modify size in Cc and update FO */
445             if (FileSizeChanged)
446             {
447                 (*CcGetFileSizePointer(FileObject)).QuadPart = LastOffset.QuadPart;
448                 SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
449             }
450 
451             /* Update offset */
452             FileObject->CurrentByteOffset.QuadPart = WriteOffset.QuadPart + Length;
453         }
454         else
455         {
456             /* We failed, we need to restore previous sizes */
457             if (FileSizeChanged)
458             {
459                 if (Fcb->PagingIoResource != NULL)
460                 {
461                     ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
462                     Fcb->FileSize.QuadPart = InitialFileSize.QuadPart;
463                     Fcb->ValidDataLength.QuadPart = InitialValidDataLength.QuadPart;
464                     ExReleaseResourceLite(Fcb->PagingIoResource);
465                 }
466                 else
467                 {
468                     Fcb->FileSize.QuadPart = InitialFileSize.QuadPart;
469                     Fcb->ValidDataLength.QuadPart = InitialValidDataLength.QuadPart;
470                 }
471             }
472         }
473     }
474     else
475     {
476         BOOLEAN AboveFour;
477 
478         WriteOffset.HighPart = 0;
479         LastOffset.HighPart = 0;
480 
481         /* If we're to extend the file, then, acquire exclusively
482          * Here, easy stuff, we know we can wait, no return to check!
483          */
484         if (WriteToEof || FileOffset->QuadPart + Length > Fcb->ValidDataLength.QuadPart)
485         {
486             ExAcquireResourceExclusiveLite(Fcb->Resource, TRUE);
487         }
488         /* Otherwise, a shared lock is enough */
489         else
490         {
491             ExAcquireResourceSharedLite(Fcb->Resource, TRUE);
492             AcquiredShared = TRUE;
493         }
494 
495         /* Get first write offset, and last
496          * Also check whether our writing will bring us
497          * beyond the 4GB
498          */
499         if (WriteToEof)
500         {
501             WriteOffset.LowPart = Fcb->FileSize.LowPart;
502             LastOffset.LowPart = WriteOffset.LowPart + Length;
503             AboveFour = (LastOffset.LowPart < Fcb->FileSize.LowPart);
504         }
505         else
506         {
507             WriteOffset.LowPart = FileOffset->LowPart;
508             LastOffset.LowPart = WriteOffset.LowPart + Length;
509             AboveFour = (LastOffset.LowPart < FileOffset->LowPart) ||
510                          (FileOffset->HighPart != 0);
511         }
512 
513         /* If cache wasn't initialized, fail */
514         if (FileObject->PrivateCacheMap == NULL ||
515             Fcb->IsFastIoPossible == FastIoIsNotPossible)
516         {
517             ExReleaseResourceLite(Fcb->Resource);
518             FsRtlExitFileSystem();
519 
520             return FALSE;
521         }
522 
523         /* If we're to write beyond allocation size, it's no go,
524          * same is we create a hole bigger than 8kb
525          * same if we end writing beyond 4GB
526          */
527         if ((Fcb->AllocationSize.LowPart < LastOffset.LowPart) ||
528             (WriteOffset.LowPart >= Fcb->ValidDataLength.LowPart + 0x2000) ||
529             AboveFour)
530         {
531             ExReleaseResourceLite(Fcb->Resource);
532             FsRtlExitFileSystem();
533 
534             return FALSE;
535         }
536 
537         /* If we have to extend the VDL, shared lock isn't enough */
538         if (AcquiredShared && LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
539         {
540             /* So release, and acquire exclusively */
541             ExReleaseResourceLite(Fcb->Resource);
542             ExAcquireResourceExclusiveLite(Fcb->Resource, TRUE);
543 
544             /* Get again EOF, in case file size changed in between and
545              * recheck we won't go beyond 4GB
546              */
547             if (WriteToEof)
548             {
549                 WriteOffset.LowPart = Fcb->FileSize.LowPart;
550                 LastOffset.LowPart = WriteOffset.LowPart + Length;
551                 AboveFour = (LastOffset.LowPart < Fcb->FileSize.LowPart);
552             }
553 
554             /* Make sure caching is still enabled */
555             if (FileObject->PrivateCacheMap == NULL ||
556                 Fcb->IsFastIoPossible == FastIoIsNotPossible)
557             {
558                 ExReleaseResourceLite(Fcb->Resource);
559                 FsRtlExitFileSystem();
560 
561                 return FALSE;
562             }
563 
564             /* And that we're not writing beyond allocation size
565              * and that we're not going above 4GB
566              */
567             if ((Fcb->AllocationSize.LowPart < LastOffset.LowPart) ||
568                 (Fcb->AllocationSize.HighPart != 0) || AboveFour)
569             {
570                 ExReleaseResourceLite(Fcb->Resource);
571                 FsRtlExitFileSystem();
572 
573                 return FALSE;
574             }
575         }
576 
577         /* If FastIO is questionable, then question */
578         if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
579         {
580             PFAST_IO_DISPATCH FastIoDispatch;
581             PDEVICE_OBJECT RelatedDeviceObject;
582 
583             RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
584             FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
585             ASSERT(FastIoDispatch != NULL);
586             ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
587 
588             if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
589                                                        &WriteOffset,
590                                                        Length, Wait, LockKey,
591                                                        FALSE, &LocalIoStatus,
592                                                        RelatedDeviceObject))
593             {
594                 ExReleaseResourceLite(Fcb->Resource);
595                 FsRtlExitFileSystem();
596 
597                 return FALSE;
598             }
599         }
600 
601         /* If we write beyond EOF, then, save previous sizes (in case of failure)
602          * and update file size, to allow writing
603          */
604         if (LastOffset.LowPart > Fcb->FileSize.LowPart)
605         {
606             FileSizeChanged = TRUE;
607             InitialFileSize.LowPart = Fcb->FileSize.LowPart;
608             InitialValidDataLength.LowPart = Fcb->ValidDataLength.LowPart;
609             Fcb->FileSize.LowPart = LastOffset.LowPart;
610         }
611 
612         /* Set caller provided context as top level IRP */
613         IoSetTopLevelIrp(TopLevelContext);
614 
615         Ret = TRUE;
616 
617         /* And perform the writing */
618         _SEH2_TRY
619         {
620             /* Check whether we've to create a hole first -
621              * it cannot fail, we can wait
622              */
623             if (LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
624             {
625                 CcZeroData(FileObject, &Fcb->ValidDataLength, &WriteOffset, TRUE);
626             }
627 
628             /* Write data */
629             CcFastCopyWrite(FileObject, WriteOffset.LowPart, Length, Buffer);
630         }
631         _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
632                                              EXCEPTION_EXECUTE_HANDLER :
633                                              EXCEPTION_CONTINUE_SEARCH)
634         {
635             Ret = FALSE;
636         }
637         _SEH2_END;
638 
639         /* Restore top level IRP */
640         IoSetTopLevelIrp(NULL);
641 
642         /* If writing succeed */
643         if (Ret)
644         {
645             /* If we wrote beyond VDL, update it */
646             if (LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
647             {
648                 Fcb->ValidDataLength.LowPart = LastOffset.LowPart;
649             }
650 
651             /* File was obviously modified */
652             SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
653 
654             /* And if we increased it, modify size in Cc and update FO */
655             if (FileSizeChanged)
656             {
657                 (*CcGetFileSizePointer(FileObject)).LowPart = LastOffset.LowPart;
658                 SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
659             }
660 
661             /* Update offset - we're still below 4GB, so high part must be 0 */
662             FileObject->CurrentByteOffset.LowPart = WriteOffset.LowPart + Length;
663             FileObject->CurrentByteOffset.HighPart = 0;
664         }
665         else
666         {
667             /* We failed, we need to restore previous sizes */
668             if (FileSizeChanged)
669             {
670                 if (Fcb->PagingIoResource != NULL)
671                 {
672                     ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
673                     Fcb->FileSize.LowPart = InitialFileSize.LowPart;
674                     Fcb->ValidDataLength.LowPart = InitialValidDataLength.LowPart;
675                     ExReleaseResourceLite(Fcb->PagingIoResource);
676                 }
677                 else
678                 {
679                     Fcb->FileSize.LowPart = InitialFileSize.LowPart;
680                     Fcb->ValidDataLength.LowPart = InitialValidDataLength.LowPart;
681                 }
682             }
683         }
684     }
685 
686     /* Release our resource and leave */
687     ExReleaseResourceLite(Fcb->Resource);
688 
689     FsRtlExitFileSystem();
690 
691     return Ret;
692 }
693