[EXT2]
[reactos.git] / reactos / drivers / filesystems / ext2 / src / read.c
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 }