Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / reiserfs / src / read.c
1 /*
2 * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
3 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
4 * FILE: read.c
5 * PURPOSE:
6 * PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
7 * HOMEPAGE:
8 * UPDATE HISTORY:
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include "rfsd.h"
14
15 /* GLOBALS ***************************************************************/
16
17 extern PRFSD_GLOBAL RfsdGlobal;
18
19 /* DEFINITIONS *************************************************************/
20
21 NTSTATUS
22 RfsdReadComplete (IN PRFSD_IRP_CONTEXT IrpContext);
23
24 NTSTATUS
25 RfsdReadFile (IN PRFSD_IRP_CONTEXT IrpContext);
26
27 NTSTATUS
28 RfsdReadVolume (IN PRFSD_IRP_CONTEXT IrpContext);
29
30 #ifdef ALLOC_PRAGMA
31 #pragma alloc_text(PAGE, RfsdCompleteIrpContext)
32 #pragma alloc_text(PAGE, RfsdCopyRead)
33 #pragma alloc_text(PAGE, RfsdRead)
34 #pragma alloc_text(PAGE, RfsdReadVolume)
35 #pragma alloc_text(PAGE, RfsdReadInode)
36 #pragma alloc_text(PAGE, RfsdReadFile)
37 #pragma alloc_text(PAGE, RfsdReadComplete)
38 #endif
39
40 /* FUNCTIONS *************************************************************/
41
42 /** Proxy to CcCopyRead, which simply asserts the success of the IoStatus. */
43 BOOLEAN
44 RfsdCopyRead(
45 IN PFILE_OBJECT FileObject,
46 IN PLARGE_INTEGER FileOffset,
47 IN ULONG Length,
48 IN BOOLEAN Wait,
49 OUT PVOID Buffer,
50 OUT PIO_STATUS_BLOCK IoStatus
51 )
52 {
53 BOOLEAN bRet;
54
55 PAGED_CODE();
56
57 bRet= CcCopyRead(FileObject,
58 FileOffset,
59 Length,
60 Wait,
61 Buffer,
62 IoStatus );
63
64 if (bRet) {
65 ASSERT(NT_SUCCESS(IoStatus->Status));
66 }
67
68 return bRet;
69 /*
70 PVOID Bcb = NULL;
71 PVOID Buf = NULL;
72
73 if (CcMapData( FileObject,
74 FileOffset,
75 Length,
76 Wait,
77 &Bcb,
78 &Buf )) {
79 RtlCopyMemory(Buffer, Buf, Length);
80 IoStatus->Status = STATUS_SUCCESS;
81 IoStatus->Information = Length;
82 CcUnpinData(Bcb);
83 return TRUE;
84
85 } else {
86 // IoStatus->Status = STATUS_
87 return FALSE;
88 }
89 */
90 }
91
92 __drv_mustHoldCriticalRegion
93 NTSTATUS
94 RfsdReadVolume (IN PRFSD_IRP_CONTEXT IrpContext)
95 {
96 NTSTATUS Status = STATUS_UNSUCCESSFUL;
97
98 PRFSD_VCB Vcb = 0;
99 PRFSD_CCB Ccb;
100 PRFSD_FCBVCB FcbOrVcb;
101 PFILE_OBJECT FileObject;
102
103 PDEVICE_OBJECT DeviceObject;
104
105 PIRP Irp;
106 PIO_STACK_LOCATION IoStackLocation;
107
108 ULONG Length;
109 LARGE_INTEGER ByteOffset;
110
111 BOOLEAN PagingIo;
112 BOOLEAN Nocache;
113 BOOLEAN SynchronousIo;
114 BOOLEAN MainResourceAcquired = FALSE;
115 BOOLEAN PagingIoResourceAcquired = FALSE;
116
117 PUCHAR Buffer = NULL;
118 PRFSD_BDL rfsd_bdl = NULL;
119
120 PAGED_CODE();
121
122 _SEH2_TRY {
123
124 ASSERT(IrpContext);
125
126 ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
127 (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
128
129 DeviceObject = IrpContext->DeviceObject;
130
131 Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
132
133 ASSERT(Vcb != NULL);
134
135 ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
136 (Vcb->Identifier.Size == sizeof(RFSD_VCB)));
137
138 FileObject = IrpContext->FileObject;
139
140 FcbOrVcb = (PRFSD_FCBVCB) FileObject->FsContext;
141
142 ASSERT(FcbOrVcb);
143
144 if (!(FcbOrVcb->Identifier.Type == RFSDVCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) {
145
146 Status = STATUS_INVALID_DEVICE_REQUEST;
147 _SEH2_LEAVE;
148 }
149
150 Ccb = (PRFSD_CCB) FileObject->FsContext2;
151
152 Irp = IrpContext->Irp;
153
154 Irp->IoStatus.Information = 0;
155
156 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
157
158 Length = IoStackLocation->Parameters.Read.Length;
159 ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
160
161 PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
162 Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
163 SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);
164
165 if (Length == 0) {
166
167 Irp->IoStatus.Information = 0;
168 Status = STATUS_SUCCESS;
169 _SEH2_LEAVE;
170 }
171
172 if (Ccb != NULL) {
173
174 if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) {
175 if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) {
176 Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
177 }
178 }
179
180 {
181 RFSD_BDL BlockArray;
182
183 if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
184 (Length & (SECTOR_SIZE - 1)) ) {
185 Status = STATUS_INVALID_PARAMETER;
186 _SEH2_LEAVE;
187 }
188
189 Status = RfsdLockUserBuffer(
190 IrpContext->Irp,
191 Length,
192 IoReadAccess );
193
194 if (!NT_SUCCESS(Status)) {
195 _SEH2_LEAVE;
196 }
197
198 BlockArray.Irp = NULL;
199 BlockArray.Lba = ByteOffset.QuadPart;;
200 BlockArray.Offset = 0;
201 BlockArray.Length = Length;
202
203 Status = RfsdReadWriteBlocks(IrpContext,
204 Vcb,
205 &BlockArray,
206 Length,
207 1,
208 FALSE );
209 Irp = IrpContext->Irp;
210
211 _SEH2_LEAVE;
212 }
213 }
214
215 if (Nocache &&
216 ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
217 (Length & (SECTOR_SIZE - 1)) )) {
218 DbgBreak();
219
220 Status = STATUS_INVALID_PARAMETER;
221 _SEH2_LEAVE;
222 }
223
224 if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
225 ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
226 Status = STATUS_PENDING;
227 _SEH2_LEAVE;
228 }
229
230 if (!PagingIo) {
231 if (!ExAcquireResourceSharedLite(
232 &Vcb->MainResource,
233 IrpContext->IsSynchronous )) {
234 Status = STATUS_PENDING;
235 _SEH2_LEAVE;
236 }
237
238 MainResourceAcquired = TRUE;
239
240 } else {
241
242 if (!ExAcquireResourceSharedLite(
243 &Vcb->PagingIoResource,
244 IrpContext->IsSynchronous ))
245 {
246 Status = STATUS_PENDING;
247 _SEH2_LEAVE;
248 }
249
250 PagingIoResourceAcquired = TRUE;
251 }
252
253
254 if (ByteOffset.QuadPart >=
255 Vcb->PartitionInformation.PartitionLength.QuadPart ) {
256 Irp->IoStatus.Information = 0;
257 Status = STATUS_END_OF_FILE;
258 _SEH2_LEAVE;
259 }
260
261 if (!Nocache) {
262
263 if ((ByteOffset.QuadPart + Length) >
264 Vcb->PartitionInformation.PartitionLength.QuadPart ){
265 Length = (ULONG) (
266 Vcb->PartitionInformation.PartitionLength.QuadPart -
267 ByteOffset.QuadPart);
268 Length &= ~((ULONG)SECTOR_SIZE - 1);
269 }
270
271 if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
272
273 CcMdlRead(
274 Vcb->StreamObj,
275 &ByteOffset,
276 Length,
277 &Irp->MdlAddress,
278 &Irp->IoStatus );
279
280 Status = Irp->IoStatus.Status;
281
282 } else {
283
284 Buffer = RfsdGetUserBuffer(Irp);
285
286 if (Buffer == NULL) {
287 DbgBreak();
288 Status = STATUS_INVALID_USER_BUFFER;
289 _SEH2_LEAVE;
290 }
291
292 if (!CcCopyRead(
293 Vcb->StreamObj,
294 (PLARGE_INTEGER)&ByteOffset,
295 Length,
296 IrpContext->IsSynchronous,
297 Buffer,
298 &Irp->IoStatus )) {
299 Status = STATUS_PENDING;
300 _SEH2_LEAVE;
301 }
302
303 Status = Irp->IoStatus.Status;
304 }
305
306 } else {
307
308 if ((ByteOffset.QuadPart + Length) >
309 Vcb->PartitionInformation.PartitionLength.QuadPart ) {
310 Length = (ULONG) (
311 Vcb->PartitionInformation.PartitionLength.QuadPart -
312 ByteOffset.QuadPart);
313
314 Length &= ~((ULONG)SECTOR_SIZE - 1);
315 }
316
317 Status = RfsdLockUserBuffer(
318 IrpContext->Irp,
319 Length,
320 IoWriteAccess );
321
322 if (!NT_SUCCESS(Status)) {
323 _SEH2_LEAVE;
324 }
325
326 #if DBG
327 Buffer = RfsdGetUserBuffer(Irp);
328 #endif
329 rfsd_bdl = ExAllocatePoolWithTag(PagedPool, sizeof(RFSD_BDL), RFSD_POOL_TAG);
330
331 if (!rfsd_bdl)
332 {
333 Status = STATUS_INSUFFICIENT_RESOURCES;
334 _SEH2_LEAVE;
335 }
336
337 rfsd_bdl->Irp = NULL;
338 rfsd_bdl->Lba = ByteOffset.QuadPart;
339 rfsd_bdl->Length = Length;
340 rfsd_bdl->Offset = 0;
341
342 Status = RfsdReadWriteBlocks(IrpContext,
343 Vcb,
344 rfsd_bdl,
345 Length,
346 1,
347 FALSE );
348
349 Irp = IrpContext->Irp;
350
351 if (!Irp)
352 _SEH2_LEAVE;
353 }
354
355 } _SEH2_FINALLY {
356
357 if (PagingIoResourceAcquired) {
358 ExReleaseResourceForThreadLite(
359 &Vcb->PagingIoResource,
360 ExGetCurrentResourceThread());
361 }
362
363 if (MainResourceAcquired) {
364 ExReleaseResourceForThreadLite(
365 &Vcb->MainResource,
366 ExGetCurrentResourceThread());
367 }
368
369 if (rfsd_bdl)
370 ExFreePool(rfsd_bdl);
371
372 if (!IrpContext->ExceptionInProgress) {
373
374 if (IrpContext->Irp) {
375
376 if (Status == STATUS_PENDING &&
377 !IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED)) {
378
379 Status = RfsdLockUserBuffer(
380 IrpContext->Irp,
381 Length,
382 IoWriteAccess );
383
384 if (NT_SUCCESS(Status)) {
385 Status = RfsdQueueRequest(IrpContext);
386 } else {
387 RfsdCompleteIrpContext(IrpContext, Status);
388 }
389
390 } else {
391
392 if (NT_SUCCESS(Status)) {
393
394 if (!PagingIo) {
395
396 if (SynchronousIo) {
397
398 IrpContext->FileObject->CurrentByteOffset.QuadPart =
399 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
400 }
401
402 IrpContext->FileObject->Flags |= FO_FILE_FAST_IO_READ;
403 }
404 }
405
406 RfsdCompleteIrpContext(IrpContext, Status);;
407 }
408
409 } else {
410 RfsdFreeIrpContext(IrpContext);
411 }
412 }
413 } _SEH2_END;
414
415 return Status;
416 }
417
418 // [mark] read some goop [from the file pt'd to by inode -- from whatever blocks buildbdl makes] into the buffer
419 NTSTATUS
420 RfsdReadInode (
421 IN PRFSD_IRP_CONTEXT IrpContext, // [may be null]
422 IN PRFSD_VCB Vcb,
423 IN PRFSD_KEY_IN_MEMORY Key, // Key that identifies the data on disk to be read. This is simply forwarded through to BuildBDL. (NOTE: IN THIS CASE, THE OFFSET AND TYPE FIELDS MATTER)
424 IN PRFSD_INODE Inode, // a filled Inode / stat data structure
425 IN ULONGLONG Offset, // User's requested offset to read within the file (relative to the file)
426 IN OUT PVOID Buffer, // buffer to read out to
427 IN ULONG Size, // size of destination buffer
428 OUT PULONG dwRet ) // some kind of size [probably bytes read?]
429 {
430 PRFSD_BDL Bdl = NULL;
431 ULONG blocks, i, j;
432 NTSTATUS Status = STATUS_UNSUCCESSFUL;
433 IO_STATUS_BLOCK IoStatus;
434
435 ULONGLONG FileSize;
436 ULONGLONG AllocSize;
437
438 PAGED_CODE();
439
440 if (dwRet) {
441 *dwRet = 0;
442 }
443
444 //
445 // Calculate the inode size
446 //
447
448 FileSize = (ULONGLONG) Inode->i_size;
449
450 //KdPrint(("Rfsd: RfsdReadInode: file size = %I64u, offset = %I64u, length = %u\n", FileSize, Offset, Size));
451
452 // TODO: temporary hack to get correct alloc size for dir tails... but i doubt 8 works in all cases :-) [what i should really be using is the size of the direct item in the block header!]
453 // AllocSize = CEILING_ALIGNED(FileSize, (ULONGLONG)Vcb->BlockSize);
454 // AllocSize = CEILING_ALIGNED(FileSize, (ULONGLONG) 8);
455 AllocSize = CEILING_ALIGNED(FileSize, (ULONGLONG) 1); // temp hack to ensure that i'll read out EXACTLY the # of bytes he requested
456
457 //
458 // Check inputed parameters: Offset / Size
459 //
460
461 if (Offset >= AllocSize) {
462
463 RfsdPrint((DBG_ERROR, "RfsdReadInode: beyond the file range.\n"));
464 return STATUS_SUCCESS;
465 }
466
467 if (Offset + Size > AllocSize) {
468
469 Size = (ULONG)(AllocSize - Offset);
470 }
471
472
473 //-----------------------------
474
475 //
476 // Build the scatterred block ranges to be read
477 //
478
479 Status = RfsdBuildBDL2(
480 Vcb, Key, Inode,
481 &(blocks), &(Bdl)
482 );
483
484 if (!NT_SUCCESS(Status)) {
485 goto errorout;
486 }
487
488 if (blocks <= 0) {
489 Status = STATUS_SUCCESS;
490 goto errorout;
491 }
492
493
494 {
495 ULONGLONG bufferPos = 0;
496
497 for(i = 0, j = 0; i < blocks; i++) {
498 if ( // The block is needed for the user's requested contents
499 // (The user's requested offset lies within the block, or the block's start is within the user's requested range)
500 ( (Offset >= Bdl[i].Offset) && (Offset < (Bdl[i].Offset + Bdl[i].Length)) ) || // The user's offset is within the block's range
501 ( (Bdl[i].Offset >= Offset) && (Bdl[i].Offset < (Offset + Size)) ) // The block's offset is within the user's range
502 )
503 {
504 ULONGLONG offsetFromDisk = Bdl[i].Lba;
505 ULONGLONG lengthToRead = min(Size - bufferPos, Bdl[i].Length);
506 j++;
507
508 //KdPrint(("Rfsd: blocks = %u, i = %u, j = %u\n", blocks, i, j));
509 //KdPrint(("Rfsd: Bdl[%u].Lba = %I64u, Bdl[%u].Offset = %I64u, Bdl[%u].Length = %u\n", i, Bdl[i].Lba, i, Bdl[i].Offset, i, Bdl[i].Length));
510 //KdPrint(("Rfsd: offsetFromDisk = %I64u, lengthToRead = %I64u\n", offsetFromDisk, lengthToRead));
511 //KdPrint(("Rfsd: Buffer = %p, bufferPos = %I64u\n", Buffer, bufferPos));
512
513 IoStatus.Information = 0;
514
515 RfsdCopyRead(
516 Vcb->StreamObj,
517 (PLARGE_INTEGER) (&offsetFromDisk), // offset (relative to partition)
518 (ULONG) lengthToRead, // length to read
519 PIN_WAIT, //
520 (PVOID)((PUCHAR)Buffer + bufferPos), // buffer to read into
521 &IoStatus );
522
523 Status = IoStatus.Status;
524 bufferPos += IoStatus.Information;
525 //KdPrint(("Rfsd: IoStatus.Status = %#x, IoStatus.Information = %u\n", IoStatus.Status, IoStatus.Information));
526 }
527 }
528
529 }
530
531 errorout:
532
533 if (Bdl) ExFreePool(Bdl);
534
535 if (NT_SUCCESS(Status)) {
536
537 if (dwRet) *dwRet = Size;
538 }
539
540 return Status;
541 }
542
543 __drv_mustHoldCriticalRegion
544 NTSTATUS
545 RfsdReadFile(IN PRFSD_IRP_CONTEXT IrpContext)
546 {
547 NTSTATUS Status = STATUS_UNSUCCESSFUL;
548
549 PRFSD_VCB Vcb;
550 PRFSD_FCB Fcb = 0;
551 PRFSD_CCB Ccb;
552 PFILE_OBJECT FileObject;
553 PFILE_OBJECT CacheObject;
554
555 PDEVICE_OBJECT DeviceObject;
556
557 PIRP Irp;
558 PIO_STACK_LOCATION IoStackLocation;
559
560 ULONG Length;
561 ULONG ReturnedLength;
562 LARGE_INTEGER ByteOffset;
563
564 BOOLEAN PagingIo;
565 BOOLEAN Nocache;
566 BOOLEAN SynchronousIo;
567 BOOLEAN MainResourceAcquired = FALSE;
568 BOOLEAN PagingIoResourceAcquired = FALSE;
569
570 PUCHAR Buffer;
571
572 PAGED_CODE();
573
574 _SEH2_TRY {
575
576 ASSERT(IrpContext);
577
578 ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
579 (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
580
581 DeviceObject = IrpContext->DeviceObject;
582
583 Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
584
585 ASSERT(Vcb != NULL);
586
587 ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
588 (Vcb->Identifier.Size == sizeof(RFSD_VCB)));
589
590 FileObject = IrpContext->FileObject;
591
592 Fcb = (PRFSD_FCB) FileObject->FsContext;
593
594 ASSERT(Fcb);
595
596 ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
597 (Fcb->Identifier.Size == sizeof(RFSD_FCB)));
598
599 Ccb = (PRFSD_CCB) FileObject->FsContext2;
600
601 Irp = IrpContext->Irp;
602
603 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
604
605 Length = IoStackLocation->Parameters.Read.Length;
606 ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
607
608 #ifdef _MSC_VER
609 KdPrint(("$$$ " __FUNCTION__ " on key: %x,%xh to read %i bytes at the offset %xh in the file\n",
610 Fcb->RfsdMcb->Key.k_dir_id, Fcb->RfsdMcb->Key.k_objectid,
611 Length, ByteOffset.QuadPart));
612 #endif
613
614 PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
615 Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
616 SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);
617
618 /*
619 if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) {
620 Status = STATUS_FILE_DELETED;
621 _SEH2_LEAVE;
622 }
623
624 if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
625 Status = STATUS_DELETE_PENDING;
626 _SEH2_LEAVE;
627 }
628 */
629
630 if (Length == 0) {
631 Irp->IoStatus.Information = 0;
632 Status = STATUS_SUCCESS;
633 _SEH2_LEAVE;
634 }
635
636 if (Nocache &&
637 (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
638 Length & (SECTOR_SIZE - 1))) {
639 Status = STATUS_INVALID_PARAMETER;
640 DbgBreak();
641 _SEH2_LEAVE;
642 }
643
644 if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
645 ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
646 Status = STATUS_PENDING;
647 DbgBreak();
648 _SEH2_LEAVE;
649 }
650
651 if (!PagingIo) {
652 if (!ExAcquireResourceSharedLite(
653 &Fcb->MainResource,
654 IrpContext->IsSynchronous )) {
655 Status = STATUS_PENDING;
656 _SEH2_LEAVE;
657 }
658
659 MainResourceAcquired = TRUE;
660
661 if (!FsRtlCheckLockForReadAccess(
662 &Fcb->FileLockAnchor,
663 Irp )) {
664 Status = STATUS_FILE_LOCK_CONFLICT;
665 _SEH2_LEAVE;
666 }
667 } else {
668 if (!ExAcquireResourceSharedLite(
669 &Fcb->PagingIoResource,
670 IrpContext->IsSynchronous )) {
671 Status = STATUS_PENDING;
672 _SEH2_LEAVE;
673 }
674
675 PagingIoResourceAcquired = TRUE;
676 }
677
678 if (!Nocache) {
679 // Attempt cached access...
680
681 if ((ByteOffset.QuadPart + (LONGLONG)Length) >
682 Fcb->Header.FileSize.QuadPart ) {
683 if (ByteOffset.QuadPart >= (Fcb->Header.FileSize.QuadPart)) {
684 Irp->IoStatus.Information = 0;
685 Status = STATUS_END_OF_FILE;
686 _SEH2_LEAVE;
687 }
688
689 Length =
690 (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
691
692 }
693
694 ReturnedLength = Length;
695
696 if (IsDirectory(Fcb)) {
697 _SEH2_LEAVE;
698 }
699
700 {
701 if (FileObject->PrivateCacheMap == NULL) {
702 CcInitializeCacheMap(
703 FileObject,
704 (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
705 FALSE,
706 &RfsdGlobal->CacheManagerCallbacks,
707 Fcb );
708 }
709
710 CacheObject = FileObject;
711 }
712
713 if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
714 CcMdlRead(
715 CacheObject,
716 (&ByteOffset),
717 Length,
718 &Irp->MdlAddress,
719 &Irp->IoStatus );
720
721 Status = Irp->IoStatus.Status;
722
723 } else {
724 Buffer = RfsdGetUserBuffer(Irp);
725
726 if (Buffer == NULL) {
727 Status = STATUS_INVALID_USER_BUFFER;
728 DbgBreak();
729 _SEH2_LEAVE;
730 }
731
732 if (!CcCopyRead(
733 CacheObject, // the file object (representing the open operation performed by the thread)
734 (PLARGE_INTEGER)&ByteOffset, // starting offset IN THE FILE, from where the read should be performed
735 Length, // number of bytes requested in the read operation
736 IrpContext->IsSynchronous,
737 Buffer, // < buffer to read the contents to
738 &Irp->IoStatus )) {
739 Status = STATUS_PENDING;
740 DbgBreak();
741 _SEH2_LEAVE;
742 }
743
744 Status = Irp->IoStatus.Status;
745 }
746
747 } else {
748 // Attempt access without the cache...
749
750 if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.AllocationSize.QuadPart) {
751
752 if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
753 Irp->IoStatus.Information = 0;
754 Status = STATUS_END_OF_FILE;
755 DbgBreak();
756 _SEH2_LEAVE;
757 }
758
759 Length =
760 (ULONG)(Fcb->Header.AllocationSize.QuadPart- ByteOffset.QuadPart);
761 }
762
763 ReturnedLength = Length;
764
765 /* lock the user buffer into MDL and make them paged-in */
766 Status = RfsdLockUserBuffer(
767 IrpContext->Irp,
768 Length,
769 IoWriteAccess );
770
771 if (NT_SUCCESS(Status)) {
772
773 /* Zero the total buffer */
774 PVOID SystemVA = RfsdGetUserBuffer(IrpContext->Irp);
775 if (SystemVA) {
776
777 RtlZeroMemory(SystemVA, Length);
778
779 RfsdPrint((DBG_INFO, "RfsdReadFile: Zero read buffer: Offset=%I64xh Size=%xh ... \n",
780 ByteOffset.QuadPart, Length));
781 }
782
783 } else {
784 _SEH2_LEAVE;
785 }
786
787 Irp->IoStatus.Status = STATUS_SUCCESS;
788 Irp->IoStatus.Information = Length;
789
790
791 Status = RfsdReadInode(
792 IrpContext,
793 Vcb,
794 &(Fcb->RfsdMcb->Key),
795 Fcb->Inode,
796 ByteOffset.QuadPart,
797 RfsdGetUserBuffer(IrpContext->Irp), // NOTE: Ext2fsd just passes NULL for the buffer, and relies on the initial cache call to retrieve tha data. We'll instead be explicitly putting it into the user's buffer, via a much different mechanism.
798 Length,
799 &ReturnedLength);
800
801 Irp = IrpContext->Irp;
802
803 }
804
805 } _SEH2_FINALLY {
806
807 if (PagingIoResourceAcquired) {
808 ExReleaseResourceForThreadLite(
809 &Fcb->PagingIoResource,
810 ExGetCurrentResourceThread());
811 }
812
813 if (MainResourceAcquired) {
814 ExReleaseResourceForThreadLite(
815 &Fcb->MainResource,
816 ExGetCurrentResourceThread());
817 }
818
819 if (!IrpContext->ExceptionInProgress) {
820 if (IrpContext->Irp) {
821 if (Status == STATUS_PENDING) {
822
823 Status = RfsdLockUserBuffer(
824 IrpContext->Irp,
825 Length,
826 IoWriteAccess );
827
828 if (NT_SUCCESS(Status)) {
829 Status = RfsdQueueRequest(IrpContext);
830 } else {
831 RfsdCompleteIrpContext(IrpContext, Status);
832 }
833 } else {
834 if (NT_SUCCESS(Status)) {
835 if (!PagingIo) {
836 if (SynchronousIo) {
837 IrpContext->FileObject->CurrentByteOffset.QuadPart =
838 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
839 }
840
841 IrpContext->FileObject->Flags |= FO_FILE_FAST_IO_READ;
842 }
843 }
844
845 RfsdCompleteIrpContext(IrpContext, Status);
846 }
847 } else {
848 RfsdFreeIrpContext(IrpContext);
849 }
850 }
851 } _SEH2_END;
852
853 return Status;
854 }
855
856 NTSTATUS
857 RfsdReadComplete (IN PRFSD_IRP_CONTEXT IrpContext)
858 {
859 NTSTATUS Status = STATUS_UNSUCCESSFUL;
860 PFILE_OBJECT FileObject;
861 PIRP Irp;
862
863 PAGED_CODE();
864
865 _SEH2_TRY {
866
867 ASSERT(IrpContext);
868
869 ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
870 (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
871
872 FileObject = IrpContext->FileObject;
873
874 Irp = IrpContext->Irp;
875
876 CcMdlReadComplete(FileObject, Irp->MdlAddress);
877
878 Irp->MdlAddress = NULL;
879
880 Status = STATUS_SUCCESS;
881
882 } _SEH2_FINALLY {
883
884 if (!IrpContext->ExceptionInProgress) {
885 RfsdCompleteIrpContext(IrpContext, Status);
886 }
887 } _SEH2_END;
888
889 return Status;
890 }
891
892 __drv_mustHoldCriticalRegion
893 NTSTATUS
894 RfsdRead (IN PRFSD_IRP_CONTEXT IrpContext)
895 {
896 NTSTATUS Status;
897 PRFSD_VCB Vcb;
898 PRFSD_FCBVCB FcbOrVcb;
899 PDEVICE_OBJECT DeviceObject;
900 PFILE_OBJECT FileObject;
901 BOOLEAN bCompleteRequest;
902
903 PAGED_CODE();
904
905 ASSERT(IrpContext);
906
907 ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
908 (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
909
910 _SEH2_TRY {
911
912 if (FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE)) {
913 // Caller wants to tell the Cache Manager that a previously allocated MDL can be freed.
914 Status = RfsdReadComplete(IrpContext);
915 bCompleteRequest = FALSE;
916
917 } else {
918
919 DeviceObject = IrpContext->DeviceObject;
920
921 if (DeviceObject == RfsdGlobal->DeviceObject) {
922 Status = STATUS_INVALID_DEVICE_REQUEST;
923 bCompleteRequest = TRUE;
924 _SEH2_LEAVE;
925 }
926
927 Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
928
929 if (Vcb->Identifier.Type != RFSDVCB ||
930 Vcb->Identifier.Size != sizeof(RFSD_VCB) ) {
931 Status = STATUS_INVALID_DEVICE_REQUEST;
932 bCompleteRequest = TRUE;
933
934 _SEH2_LEAVE;
935 }
936
937 if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
938
939 Status = STATUS_TOO_LATE;
940 bCompleteRequest = TRUE;
941 _SEH2_LEAVE;
942 }
943
944 FileObject = IrpContext->FileObject;
945
946 FcbOrVcb = (PRFSD_FCBVCB) FileObject->FsContext;
947
948 if (FcbOrVcb->Identifier.Type == RFSDVCB) {
949 Status = RfsdReadVolume(IrpContext);
950 bCompleteRequest = FALSE;
951 } else if (FcbOrVcb->Identifier.Type == RFSDFCB) {
952 Status = RfsdReadFile(IrpContext);
953 bCompleteRequest = FALSE;
954 } else {
955 RfsdPrint((DBG_ERROR, "RfsdRead: INVALID PARAMETER ... \n"));
956 DbgBreak();
957
958 Status = STATUS_INVALID_PARAMETER;
959 bCompleteRequest = TRUE;
960 }
961 }
962
963 } _SEH2_FINALLY {
964 if (bCompleteRequest) {
965 RfsdCompleteIrpContext(IrpContext, Status);
966 }
967 } _SEH2_END;
968
969 return Status;
970 }