xref: /reactos/drivers/filesystems/ext2/src/read.c (revision 1734f297)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             read.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 
14 /* GLOBALS ***************************************************************/
15 
16 extern PEXT2_GLOBAL Ext2Global;
17 
18 /* DEFINITIONS *************************************************************/
19 
20 NTSTATUS
21 Ext2ReadComplete (IN PEXT2_IRP_CONTEXT IrpContext);
22 
23 NTSTATUS
24 Ext2ReadFile (IN PEXT2_IRP_CONTEXT IrpContext);
25 
26 NTSTATUS
27 Ext2ReadVolume (IN PEXT2_IRP_CONTEXT IrpContext);
28 
29 /* FUNCTIONS *************************************************************/
30 
31 NTSTATUS
32 Ext2CompleteIrpContext (
33     IN PEXT2_IRP_CONTEXT IrpContext,
34     IN NTSTATUS Status )
35 {
36     PIRP    Irp = NULL;
37     BOOLEAN bPrint;
38 
39     Irp = IrpContext->Irp;
40 
41     if (Irp != NULL) {
42 
43         if (NT_ERROR(Status)) {
44             Irp->IoStatus.Information = 0;
45         }
46 
47         Irp->IoStatus.Status = Status;
48         bPrint = !IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
49 
50         Ext2CompleteRequest(
51             Irp, bPrint, (CCHAR)(NT_SUCCESS(Status)?
52                                  IO_DISK_INCREMENT : IO_NO_INCREMENT) );
53 
54         IrpContext->Irp = NULL;
55     }
56 
57     Ext2FreeIrpContext(IrpContext);
58 
59     return Status;
60 }
61 
62 
63 NTSTATUS
64 Ext2ReadVolume (IN PEXT2_IRP_CONTEXT IrpContext)
65 {
66     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
67 
68     PEXT2_VCB           Vcb = NULL;
69     PEXT2_CCB           Ccb = NULL;
70     PEXT2_FCBVCB        FcbOrVcb = NULL;
71     PFILE_OBJECT        FileObject = NULL;
72 
73     PDEVICE_OBJECT      DeviceObject = NULL;
74 
75     PIRP                Irp = NULL;
76     PIO_STACK_LOCATION  IoStackLocation = NULL;
77 
78     ULONG               Length;
79     LARGE_INTEGER       ByteOffset;
80 
81     BOOLEAN             PagingIo;
82     BOOLEAN             Nocache;
83     BOOLEAN             SynchronousIo;
84     BOOLEAN             MainResourceAcquired = FALSE;
85 
86     PUCHAR              Buffer = NULL;
87     EXT2_EXTENT         BlockArray;
88 
89     _SEH2_TRY {
90 
91         ASSERT(IrpContext);
92         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
93                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
94 
95         DeviceObject = IrpContext->DeviceObject;
96         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
97         ASSERT(Vcb != NULL);
98         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
99                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
100 
101         FileObject = IrpContext->FileObject;
102         FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
103         ASSERT(FcbOrVcb);
104 
105         if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) {
106 
107             Status = STATUS_INVALID_DEVICE_REQUEST;
108             _SEH2_LEAVE;
109         }
110 
111         Ccb = (PEXT2_CCB) FileObject->FsContext2;
112         Irp = IrpContext->Irp;
113         Irp->IoStatus.Information = 0;
114         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
115 
116         Length = IoStackLocation->Parameters.Read.Length;
117         ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
118 
119         PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
120         Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE) || (Ccb != NULL);
121         SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
122 
123         if (PagingIo) {
124             ASSERT(Nocache);
125         }
126 
127         if (Length == 0) {
128             Irp->IoStatus.Information = 0;
129             Status = STATUS_SUCCESS;
130             _SEH2_LEAVE;
131         }
132 
133         if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
134             ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
135             Status = STATUS_PENDING;
136             _SEH2_LEAVE;
137         }
138 
139         if (ByteOffset.QuadPart >=
140                 Vcb->PartitionInformation.PartitionLength.QuadPart  ) {
141             Irp->IoStatus.Information = 0;
142             Status = STATUS_END_OF_FILE;
143             _SEH2_LEAVE;
144         }
145 
146         if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) {
147             Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
148         }
149 
150         /*
151          *  User direct volume access
152          */
153 
154         if (Ccb != NULL && !PagingIo) {
155 
156             if (!ExAcquireResourceExclusiveLite(
157                         &Vcb->MainResource,
158                         IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
159                 Status = STATUS_PENDING;
160                 _SEH2_LEAVE;
161             }
162             MainResourceAcquired = TRUE;
163 
164             if (!FlagOn(Ccb->Flags, CCB_VOLUME_DASD_PURGE)) {
165 
166                 if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
167                     Ext2FlushVolume(IrpContext, Vcb, FALSE);
168                 }
169 
170                 SetFlag(Ccb->Flags, CCB_VOLUME_DASD_PURGE);
171             }
172 
173             ExReleaseResourceLite(&Vcb->MainResource);
174             MainResourceAcquired = FALSE;
175 
176             /* will do Nocache i/o */
177         }
178 
179         /*
180          *  I/O to volume StreamObject
181          */
182 
183         if (!Nocache) {
184 
185             if (IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
186 
187                 CcMdlRead(
188                     Vcb->Volume,
189                     &ByteOffset,
190                     Length,
191                     &Irp->MdlAddress,
192                     &Irp->IoStatus );
193 
194                 Status = Irp->IoStatus.Status;
195 
196             } else {
197 
198                 Buffer = Ext2GetUserBuffer(Irp);
199                 if (Buffer == NULL) {
200                     DbgBreak();
201                     Status = STATUS_INVALID_USER_BUFFER;
202                     _SEH2_LEAVE;
203                 }
204 
205                 if (!CcCopyRead(
206                             Vcb->Volume,
207                             &ByteOffset,
208                             Length,
209                             Ext2CanIWait(),
210                             Buffer,
211                             &Irp->IoStatus )) {
212                     Status = STATUS_PENDING;
213                     _SEH2_LEAVE;
214                 }
215 
216                 Status = Irp->IoStatus.Status;
217             }
218 
219         } else {
220 
221             Length &= ~((ULONG)SECTOR_SIZE - 1);
222             Status = Ext2LockUserBuffer(
223                          IrpContext->Irp,
224                          Length,
225                          IoWriteAccess );
226 
227             if (!NT_SUCCESS(Status)) {
228                 _SEH2_LEAVE;
229             }
230 
231             BlockArray.Irp = NULL;
232             BlockArray.Lba = ByteOffset.QuadPart;
233             BlockArray.Offset = 0;
234             BlockArray.Length = Length;
235             BlockArray.Next = NULL;
236 
237             Status = Ext2ReadWriteBlocks(IrpContext,
238                                          Vcb,
239                                          &BlockArray,
240                                          Length );
241 
242             Irp = IrpContext->Irp;
243             if (!Irp) {
244                 _SEH2_LEAVE;
245             }
246         }
247 
248     } _SEH2_FINALLY {
249 
250         if (MainResourceAcquired) {
251             ExReleaseResourceLite(&Vcb->MainResource);
252         }
253 
254         if (!IrpContext->ExceptionInProgress) {
255 
256             if (Irp) {
257 
258                 if (Status == STATUS_PENDING &&
259                     !IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED)) {
260 
261                     Status = Ext2LockUserBuffer(
262                                  IrpContext->Irp,
263                                  Length,
264                                  IoWriteAccess );
265 
266                     if (NT_SUCCESS(Status)) {
267                         Status = Ext2QueueRequest(IrpContext);
268                     } else {
269                         Ext2CompleteIrpContext(IrpContext, Status);
270                     }
271 
272                 } else {
273 
274                     if (NT_SUCCESS(Status)) {
275 
276                         if (!PagingIo) {
277 
278                             if (SynchronousIo) {
279 
280                                 FileObject->CurrentByteOffset.QuadPart =
281                                     ByteOffset.QuadPart + Irp->IoStatus.Information;
282                             }
283 
284                             FileObject->Flags |= FO_FILE_FAST_IO_READ;
285                         }
286                     }
287 
288                     Ext2CompleteIrpContext(IrpContext, Status);;
289                 }
290 
291             } else {
292                 Ext2FreeIrpContext(IrpContext);
293             }
294         }
295     } _SEH2_END;
296 
297     return Status;
298 }
299 
300 
301 #define SafeZeroMemory(AT,BYTE_COUNT) {                                 \
302     _SEH2_TRY {                                                         \
303         if (AT)                                                         \
304             RtlZeroMemory((AT), (BYTE_COUNT));                          \
305     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                         \
306          Ext2RaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER );     \
307     } _SEH2_END;                                                        \
308 }
309 
310 NTSTATUS
311 Ext2ReadInode (
312     IN PEXT2_IRP_CONTEXT    IrpContext,
313     IN PEXT2_VCB            Vcb,
314     IN PEXT2_MCB            Mcb,
315     IN ULONGLONG            Offset,
316     IN PVOID                Buffer,
317     IN ULONG                Size,
318     IN BOOLEAN              bDirectIo,
319     OUT PULONG              BytesRead
320 )
321 {
322     PEXT2_EXTENT    Chain = NULL;
323     PEXT2_EXTENT    Extent = NULL, Prev = NULL;
324 
325     IO_STATUS_BLOCK IoStatus;
326     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
327     ULONG           RealSize ;
328 
329     if (BytesRead) {
330         *BytesRead = 0;
331     }
332 
333     _SEH2_TRY {
334 
335         Ext2ReferMcb(Mcb);
336 
337         ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
338                (Mcb->Identifier.Size == sizeof(EXT2_MCB)));
339 
340         if ((Mcb->Identifier.Type != EXT2MCB) ||
341                 (Mcb->Identifier.Size != sizeof(EXT2_MCB))) {
342             _SEH2_LEAVE;
343         }
344 
345         if (Buffer == NULL && IrpContext != NULL)
346             Buffer = Ext2GetUserBuffer(IrpContext->Irp);
347 
348 
349         /* handle fast symlinks */
350         if (S_ISLNK(Mcb->Inode.i_mode) && 0 == Mcb->Inode.i_blocks) {
351 
352             PUCHAR Data = (PUCHAR) (&Mcb->Inode.i_block[0]);
353             if (!Buffer) {
354                 Status = STATUS_INSUFFICIENT_RESOURCES;
355                 _SEH2_LEAVE;
356             }
357 
358             if (Offset < EXT2_LINKLEN_IN_INODE) {
359                 if ((ULONG)Offset + Size >= EXT2_LINKLEN_IN_INODE)
360                     Size = EXT2_LINKLEN_IN_INODE - (ULONG)Offset - 1;
361                 RtlCopyMemory(Buffer, Data + (ULONG)Offset, Size);
362                 Status = STATUS_SUCCESS;
363             } else {
364                 Status = STATUS_END_OF_FILE;
365             }
366             _SEH2_LEAVE;
367         }
368 
369         //
370         // Build the scatterred block ranges to be read
371         //
372 
373         if (bDirectIo) {
374             RealSize = CEILING_ALIGNED(ULONG, Size, SECTOR_SIZE - 1);
375         } else {
376             RealSize = Size;
377         }
378 
379         Status = Ext2BuildExtents(
380                      IrpContext,
381                      Vcb,
382                      Mcb,
383                      Offset,
384                      RealSize,
385                      FALSE,
386                      &Chain
387                  );
388 
389         if (!NT_SUCCESS(Status)) {
390             _SEH2_LEAVE;
391         }
392 
393         if (Chain == NULL) {
394             SafeZeroMemory((PCHAR)Buffer, Size);
395             Status = STATUS_SUCCESS;
396             _SEH2_LEAVE;
397         }
398 
399         /* for sparse file, we need zero the gaps */
400         for (Extent = Chain; Buffer != NULL && Extent != NULL; Extent = Extent->Next) {
401             if (NULL == Prev) {
402                 ASSERT(Extent == Chain);
403                 if (Extent->Offset) {
404                     SafeZeroMemory((PCHAR)Buffer, Extent->Offset);
405                 }
406             } else if (Extent->Offset > (Prev->Offset + Prev->Length)) {
407                 SafeZeroMemory((PCHAR)Buffer + Prev->Offset + Prev->Length,
408                                Extent->Offset - Prev->Offset - Prev->Length);
409             }
410             if (NULL == Extent->Next) {
411                 if (Extent->Offset + Extent->Length < Size) {
412                     SafeZeroMemory((PCHAR)Buffer + Extent->Offset + Extent->Length,
413                                    Size - Extent->Offset - Extent->Length);
414                 }
415             }
416             Prev = Extent;
417         }
418 
419         if (bDirectIo) {
420 
421             ASSERT(IrpContext != NULL);
422 
423             // Offset should be SECTOR_SIZE aligned ...
424             Status = Ext2ReadWriteBlocks(
425                          IrpContext,
426                          Vcb,
427                          Chain,
428                          Size
429                      );
430         } else {
431 
432             for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
433 
434                 if (!CcCopyRead(
435                             Vcb->Volume,
436                             (PLARGE_INTEGER)(&(Extent->Lba)),
437                             Extent->Length,
438                             PIN_WAIT,
439                             (PVOID)((PUCHAR)Buffer + Extent->Offset),
440                             &IoStatus
441                         )) {
442                     Status = STATUS_CANT_WAIT;
443                 } else {
444                     Status = IoStatus.Status;
445                 }
446 
447                 if (!NT_SUCCESS(Status)) {
448                     break;
449                 }
450             }
451         }
452 
453     } _SEH2_FINALLY {
454 
455         if (Chain) {
456             Ext2DestroyExtentChain(Chain);
457         }
458 
459         Ext2DerefMcb(Mcb);
460     } _SEH2_END;
461 
462     if (NT_SUCCESS(Status)) {
463         if (BytesRead)
464             *BytesRead = Size;
465     }
466 
467     return Status;
468 }
469 
470 NTSTATUS
471 Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
472 {
473     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
474 
475     PEXT2_VCB           Vcb = NULL;
476     PEXT2_FCB           Fcb = NULL;
477     PEXT2_CCB           Ccb = NULL;
478     PFILE_OBJECT        FileObject = NULL;
479 
480     PDEVICE_OBJECT      DeviceObject = NULL;
481 
482     PIRP                Irp = NULL;
483     PIO_STACK_LOCATION  IoStackLocation = NULL;
484 
485     ULONG               Length;
486     ULONG               ReturnedLength = 0;
487     LARGE_INTEGER       ByteOffset;
488 
489     BOOLEAN             OpPostIrp = FALSE;
490     BOOLEAN             PagingIo;
491     BOOLEAN             Nocache;
492     BOOLEAN             SynchronousIo;
493     BOOLEAN             MainResourceAcquired = FALSE;
494     BOOLEAN             PagingIoResourceAcquired = FALSE;
495 
496     PUCHAR              Buffer;
497 
498     _SEH2_TRY {
499 
500         ASSERT(IrpContext);
501         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
502                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
503 
504         DeviceObject = IrpContext->DeviceObject;
505         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
506         ASSERT(Vcb != NULL);
507         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
508                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
509 
510         FileObject = IrpContext->FileObject;
511         Fcb = (PEXT2_FCB) FileObject->FsContext;
512         ASSERT(Fcb);
513         ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
514                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
515 
516         Ccb = (PEXT2_CCB) FileObject->FsContext2;
517 
518         Irp = IrpContext->Irp;
519         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
520 
521         Length = IoStackLocation->Parameters.Read.Length;
522         ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
523 
524         PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
525         Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE);
526         SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
527 
528         if (PagingIo) {
529             ASSERT(Nocache);
530         }
531 
532         DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
533                        &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
534 
535         if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
536             Status = STATUS_INVALID_DEVICE_REQUEST;
537             _SEH2_LEAVE;
538         }
539 
540         if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ||
541             IsFileDeleted(Fcb->Mcb)) {
542             Status = STATUS_FILE_DELETED;
543             _SEH2_LEAVE;
544         }
545 
546         if (Length == 0) {
547             Irp->IoStatus.Information = 0;
548             Status = STATUS_SUCCESS;
549             _SEH2_LEAVE;
550         }
551 
552         if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
553             ByteOffset.HighPart == -1) {
554             ByteOffset = FileObject->CurrentByteOffset;
555         }
556 
557         if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
558                         Length & (SECTOR_SIZE - 1))) {
559             Status = STATUS_INVALID_PARAMETER;
560             DbgBreak();
561             _SEH2_LEAVE;
562         }
563 
564         if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
565             ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
566             Status = STATUS_PENDING;
567             DbgBreak();
568             _SEH2_LEAVE;
569         }
570 
571         ReturnedLength = Length;
572 
573         if (PagingIo) {
574 
575             if (!ExAcquireResourceSharedLite(
576                         &Fcb->PagingIoResource,
577                         IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
578                 Status = STATUS_PENDING;
579                 _SEH2_LEAVE;
580             }
581             PagingIoResourceAcquired = TRUE;
582 
583         } else {
584 
585             if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject) {
586 
587                 if (!ExAcquireResourceExclusiveLite(
588                             &Fcb->MainResource,
589                             IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
590                     Status = STATUS_PENDING;
591                     _SEH2_LEAVE;
592                 }
593                 MainResourceAcquired = TRUE;
594 
595                 CcFlushCache(&Fcb->SectionObject,
596                              &ByteOffset,
597                               Length,
598                              &Irp->IoStatus );
599                 if (!NT_SUCCESS(Irp->IoStatus.Status))
600                     _SEH2_LEAVE;
601                 ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
602 
603                 if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
604                     ExReleaseResourceLite(&(Fcb->PagingIoResource));
605                 }
606                 CcPurgeCacheSection( &Fcb->SectionObject,
607                                      NULL,
608                                      0,
609                                      FALSE );
610 
611                 ExConvertExclusiveToShared(&Fcb->MainResource);
612 
613             } else {
614 
615                 if (!ExAcquireResourceSharedLite(
616                             &Fcb->MainResource,
617                             IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
618                     Status = STATUS_PENDING;
619                     _SEH2_LEAVE;
620                 }
621                 MainResourceAcquired = TRUE;
622             }
623 
624             if (!FsRtlCheckLockForReadAccess(
625                         &Fcb->FileLockAnchor,
626                         Irp         )) {
627                 Status = STATUS_FILE_LOCK_CONFLICT;
628                 _SEH2_LEAVE;
629             }
630         }
631 
632         if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.FileSize.QuadPart) {
633             if (ByteOffset.QuadPart >= Fcb->Header.FileSize.QuadPart) {
634                 Irp->IoStatus.Information = 0;
635                 Status = STATUS_END_OF_FILE;
636                 _SEH2_LEAVE;
637             }
638             ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
639         }
640 
641 
642         if (!IsDirectory(Fcb) && Ccb != NULL) {
643             Status = FsRtlCheckOplock( &Fcb->Oplock,
644                                        Irp,
645                                        IrpContext,
646                                        Ext2OplockComplete,
647                                        Ext2LockIrp );
648 
649             if (Status != STATUS_SUCCESS) {
650                 OpPostIrp = TRUE;
651                 _SEH2_LEAVE;
652             }
653 
654             //
655             //  Set the flag indicating if Fast I/O is possible
656             //
657 
658             Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
659         }
660 
661         if (!Nocache) {
662 
663             if (IsDirectory(Fcb)) {
664                 _SEH2_LEAVE;
665             }
666 
667             if (FileObject->PrivateCacheMap == NULL) {
668                 CcInitializeCacheMap(
669                         FileObject,
670                         (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
671                         FALSE,
672                         &Ext2Global->CacheManagerCallbacks,
673                         Fcb );
674                 CcSetReadAheadGranularity(
675                         FileObject,
676                         READ_AHEAD_GRANULARITY );
677             }
678 
679             if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
680                 CcMdlRead(
681                     FileObject,
682                     (&ByteOffset),
683                     ReturnedLength,
684                     &Irp->MdlAddress,
685                     &Irp->IoStatus );
686 
687                 Status = Irp->IoStatus.Status;
688 
689             } else {
690 
691                 Buffer = Ext2GetUserBuffer(Irp);
692                 if (Buffer == NULL) {
693                     Status = STATUS_INVALID_USER_BUFFER;
694                     DbgBreak();
695                     _SEH2_LEAVE;
696                 }
697 
698                 if (!CcCopyRead(FileObject, &ByteOffset, ReturnedLength,
699                                 Ext2CanIWait(), Buffer, &Irp->IoStatus)) {
700 
701                     if (Ext2CanIWait() || !CcCopyRead(FileObject, &ByteOffset,
702                                                       ReturnedLength, TRUE,
703                                                       Buffer, &Irp->IoStatus)) {
704                         Status = STATUS_PENDING;
705                         DbgBreak();
706                         _SEH2_LEAVE;
707                     }
708                 }
709                 Status = Irp->IoStatus.Status;
710             }
711 
712         } else {
713 
714             ULONG   BytesRead = ReturnedLength;
715             PUCHAR  SystemVA  = Ext2GetUserBuffer(IrpContext->Irp);
716 
717             if (ByteOffset.QuadPart + BytesRead > Fcb->Header.ValidDataLength.QuadPart) {
718 
719                 if (ByteOffset.QuadPart >= Fcb->Header.ValidDataLength.QuadPart) {
720                     if (SystemVA) {
721                         SafeZeroMemory(SystemVA, Length);
722                     }
723                     Irp->IoStatus.Information = ReturnedLength;
724                     Status = STATUS_SUCCESS;
725                     _SEH2_LEAVE;
726                 } else {
727                     BytesRead = (ULONG)(Fcb->Header.ValidDataLength.QuadPart - ByteOffset.QuadPart);
728                     if (SystemVA) {
729                         SafeZeroMemory(SystemVA + BytesRead, Length - BytesRead);
730                     }
731                 }
732             }
733 
734             Status = Ext2LockUserBuffer(
735                          IrpContext->Irp,
736                          BytesRead,
737                          IoReadAccess );
738 
739             if (!NT_SUCCESS(Status)) {
740                 _SEH2_LEAVE;
741             }
742 
743             Status = Ext2ReadInode(
744                          IrpContext,
745                          Vcb,
746                          Fcb->Mcb,
747                          ByteOffset.QuadPart,
748                          NULL,
749                          BytesRead,
750                          TRUE,
751                          NULL );
752 
753             /* we need re-queue this request in case STATUS_CANT_WAIT
754                and fail it in other failure cases  */
755             if (!NT_SUCCESS(Status)) {
756                 _SEH2_LEAVE;
757             }
758 
759             /* pended by low level device */
760             if (Status == STATUS_PENDING) {
761                 IrpContext->Irp = Irp = NULL;
762                 _SEH2_LEAVE;
763             }
764 
765             Irp = IrpContext->Irp;
766             ASSERT(Irp);
767             Status = Irp->IoStatus.Status;
768 
769             if (!NT_SUCCESS(Status)) {
770                 Ext2NormalizeAndRaiseStatus(IrpContext, Status);
771             }
772         }
773 
774         Irp->IoStatus.Information = ReturnedLength;
775 
776     } _SEH2_FINALLY {
777 
778         if (Irp) {
779             if (PagingIoResourceAcquired) {
780                 ExReleaseResourceLite(&Fcb->PagingIoResource);
781             }
782 
783             if (MainResourceAcquired) {
784                 ExReleaseResourceLite(&Fcb->MainResource);
785             }
786         }
787 
788         if (!OpPostIrp && !IrpContext->ExceptionInProgress) {
789 
790             if (Irp) {
791                 if ( Status == STATUS_PENDING ||
792                      Status == STATUS_CANT_WAIT) {
793 
794                     Status = Ext2LockUserBuffer(
795                                  IrpContext->Irp,
796                                  Length,
797                                  IoWriteAccess );
798 
799                     if (NT_SUCCESS(Status)) {
800                         Status = Ext2QueueRequest(IrpContext);
801                     } else {
802                         Ext2CompleteIrpContext(IrpContext, Status);
803                     }
804                 } else {
805                     if (NT_SUCCESS(Status)) {
806                         if (!PagingIo) {
807                             if (SynchronousIo) {
808                                 FileObject->CurrentByteOffset.QuadPart =
809                                     ByteOffset.QuadPart + Irp->IoStatus.Information;
810                             }
811                             FileObject->Flags |= FO_FILE_FAST_IO_READ;
812                         }
813                     }
814 
815                     Ext2CompleteIrpContext(IrpContext, Status);
816                 }
817 
818             } else {
819 
820                 Ext2FreeIrpContext(IrpContext);
821             }
822         }
823     } _SEH2_END;
824 
825     DEBUG(DL_IO, ("Ext2ReadFile: %wZ fetch at Off=%I64xh Len=%xh Paging=%xh Nocache=%xh Returned=%xh Status=%xh\n",
826                   &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache, ReturnedLength, Status));
827     return Status;
828 
829 }
830 
831 NTSTATUS
832 Ext2ReadComplete (IN PEXT2_IRP_CONTEXT IrpContext)
833 {
834     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
835     PFILE_OBJECT    FileObject;
836     PIRP            Irp;
837 
838     _SEH2_TRY {
839 
840         ASSERT(IrpContext);
841         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
842                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
843 
844         FileObject = IrpContext->FileObject;
845         Irp = IrpContext->Irp;
846 
847         CcMdlReadComplete(FileObject, Irp->MdlAddress);
848         Irp->MdlAddress = NULL;
849         Status = STATUS_SUCCESS;
850 
851     } _SEH2_FINALLY {
852 
853         if (!IrpContext->ExceptionInProgress) {
854             Ext2CompleteIrpContext(IrpContext, Status);
855         }
856     } _SEH2_END;
857 
858     return Status;
859 }
860 
861 
862 NTSTATUS
863 Ext2Read (IN PEXT2_IRP_CONTEXT IrpContext)
864 {
865     NTSTATUS            Status;
866     PEXT2_VCB           Vcb;
867     PEXT2_FCBVCB        FcbOrVcb;
868     PDEVICE_OBJECT      DeviceObject;
869     PFILE_OBJECT        FileObject;
870     BOOLEAN             bCompleteRequest;
871 
872     ASSERT(IrpContext);
873 
874     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
875            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
876 
877     _SEH2_TRY {
878 
879         if (FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE)) {
880 
881             Status =  Ext2ReadComplete(IrpContext);
882             bCompleteRequest = FALSE;
883 
884         } else {
885 
886             DeviceObject = IrpContext->DeviceObject;
887 
888             if (IsExt2FsDevice(DeviceObject)) {
889                 Status = STATUS_INVALID_DEVICE_REQUEST;
890                 bCompleteRequest = TRUE;
891                 _SEH2_LEAVE;
892             }
893 
894             Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
895             if (Vcb->Identifier.Type != EXT2VCB ||
896                     Vcb->Identifier.Size != sizeof(EXT2_VCB) ) {
897                 Status = STATUS_INVALID_DEVICE_REQUEST;
898                 bCompleteRequest = TRUE;
899 
900                 _SEH2_LEAVE;
901             }
902 
903             FileObject = IrpContext->FileObject;
904 
905             if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
906                 Vcb->LockFile != FileObject ) {
907                 Status = STATUS_ACCESS_DENIED;
908                 _SEH2_LEAVE;
909             }
910 
911             FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
912 
913             if (FcbOrVcb->Identifier.Type == EXT2VCB) {
914 
915                 Status = Ext2ReadVolume(IrpContext);
916                 bCompleteRequest = FALSE;
917 
918             } else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
919 
920                 if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
921                     Status = STATUS_TOO_LATE;
922                     bCompleteRequest = TRUE;
923                     _SEH2_LEAVE;
924                 }
925 
926                 Status = Ext2ReadFile(IrpContext);
927                 bCompleteRequest = FALSE;
928             } else {
929                 DEBUG(DL_ERR, ( "Ext2Read: Inavlid FileObject (Vcb or Fcb corrupted)\n"));
930                 DbgBreak();
931 
932                 Status = STATUS_INVALID_PARAMETER;
933                 bCompleteRequest = TRUE;
934             }
935         }
936 
937     } _SEH2_FINALLY {
938         if (bCompleteRequest) {
939             Ext2CompleteIrpContext(IrpContext, Status);
940         }
941     } _SEH2_END;
942 
943     return Status;
944 }
945