2 /* $Id: rw.c,v 1.31 2001/08/14 20:47:30 hbirr Exp $
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/rw.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <ntos/minmax.h>
23 /* GLOBALS *******************************************************************/
25 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
26 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
28 /* FUNCTIONS *****************************************************************/
31 NextCluster(PDEVICE_EXTENSION DeviceExt
,
33 PULONG CurrentCluster
,
36 * Return the next cluster in a FAT chain, possibly extending the chain if
40 if (FirstCluster
== 1)
42 (*CurrentCluster
) += DeviceExt
->Boot
->SectorsPerCluster
;
43 return(STATUS_SUCCESS
);
46 /* CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't initialized when 0*/
47 if (FirstCluster
== 0)
51 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
,
59 Status
= GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
,
66 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
72 * Return the cluster corresponding to an offset within a file,
73 * possibly extending the file if necessary
80 if (FirstCluster
== 1)
82 /* root of FAT16 or FAT12 */
83 *Cluster
= DeviceExt
->rootStart
+ FileOffset
84 / (DeviceExt
->BytesPerCluster
) * DeviceExt
->Boot
->SectorsPerCluster
;
85 return(STATUS_SUCCESS
);
89 CurrentCluster
= FirstCluster
;
90 for (i
= 0; i
< FileOffset
/ DeviceExt
->BytesPerCluster
; i
++)
92 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
,
94 if (!NT_SUCCESS(Status
))
99 *Cluster
= CurrentCluster
;
100 return(STATUS_SUCCESS
);
105 VfatReadBigCluster(PDEVICE_EXTENSION DeviceExt
,
109 PULONG CurrentCluster
,
112 ULONG InternalOffset
,
113 ULONG InternalLength
)
116 PVOID BaseAddress
= NULL
;
117 PCACHE_SEGMENT CacheSeg
= NULL
;
121 * In this case the size of a cache segment is the same as a cluster
126 Status
= CcRosRequestCacheSegment(Fcb
->RFCB
.Bcb
,
131 if (!NT_SUCCESS(Status
))
139 if (InternalLength
== DeviceExt
->BytesPerCluster
)
141 BaseAddress
= Destination
;
145 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
146 if (BaseAddress
== NULL
)
148 return(STATUS_NO_MEMORY
);
156 * If necessary read the cluster from the disk
158 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, BaseAddress
,
160 if (!NT_SUCCESS(Status
))
164 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, FALSE
);
166 else if (InternalLength
!= DeviceExt
->BytesPerCluster
)
168 ExFreePool(BaseAddress
);
174 * Copy the data from the cache to the caller
176 if (InternalLength
!= DeviceExt
->BytesPerCluster
|| !NoCache
)
178 memcpy(Destination
, BaseAddress
+ InternalOffset
, InternalLength
);
182 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, TRUE
);
184 else if (InternalLength
!= DeviceExt
->BytesPerCluster
)
186 ExFreePool(BaseAddress
);
189 Status
= NextCluster(DeviceExt
, FirstCluster
, CurrentCluster
, FALSE
);
190 if (!NT_SUCCESS(Status
))
194 return(STATUS_SUCCESS
);
198 VfatReadSmallCluster(PDEVICE_EXTENSION DeviceExt
,
202 PULONG CurrentCluster
,
205 ULONG InternalOffset
,
206 ULONG InternalLength
)
209 PVOID BaseAddress
= NULL
;
210 PCACHE_SEGMENT CacheSeg
= NULL
;
215 * Otherwise we read a page of clusters together
219 Status
= CcRosRequestCacheSegment(Fcb
->RFCB
.Bcb
,
224 if (!NT_SUCCESS(Status
))
232 if (InternalLength
== PAGESIZE
)
234 BaseAddress
= Destination
;
238 BaseAddress
= ExAllocatePool(NonPagedPool
, PAGESIZE
);
239 if (BaseAddress
== NULL
)
241 return(STATUS_NO_MEMORY
);
247 * If necessary read all the data for the page, unfortunately the
248 * file length may not be page aligned in which case the page will
249 * only be partially filled.
250 * FIXME: So zero fill the rest?
254 for (i
= 0; i
< (PAGESIZE
/ DeviceExt
->BytesPerCluster
); i
++)
256 Status
= VfatRawReadCluster(DeviceExt
,
259 (i
* DeviceExt
->BytesPerCluster
),
261 if (!NT_SUCCESS(Status
))
265 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, FALSE
);
267 else if (InternalLength
!= PAGESIZE
)
269 ExFreePool(BaseAddress
);
273 Status
= NextCluster(DeviceExt
, FirstCluster
, CurrentCluster
, FALSE
);
274 if ((*CurrentCluster
) == 0xFFFFFFFF)
283 * Otherwise just move onto the next cluster
285 for (i
= 0; i
< (PAGESIZE
/ DeviceExt
->BytesPerCluster
); i
++)
287 NextCluster(DeviceExt
, FirstCluster
, CurrentCluster
, FALSE
);
288 if ((*CurrentCluster
) == 0xFFFFFFFF)
295 * Copy the data from the cache to the caller
297 if (InternalLength
!= PAGESIZE
|| !NoCache
)
299 memcpy(Destination
, BaseAddress
+ InternalOffset
, InternalLength
);
303 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
,
304 Valid
|| InternalLength
== PAGESIZE
? TRUE
: FALSE
);
306 else if (InternalLength
!= PAGESIZE
)
308 ExFreePool(BaseAddress
);
310 return(STATUS_SUCCESS
);
314 VfatReadCluster(PDEVICE_EXTENSION DeviceExt
,
318 PULONG CurrentCluster
,
321 ULONG InternalOffset
,
322 ULONG InternalLength
)
324 if (DeviceExt
->BytesPerCluster
>= PAGESIZE
)
326 return(VfatReadBigCluster(DeviceExt
,
338 return(VfatReadSmallCluster(DeviceExt
,
351 VfatReadFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
352 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
353 PULONG LengthRead
, ULONG NoCache
)
355 * FUNCTION: Reads data from a file
358 ULONG CurrentCluster
;
366 assert (DeviceExt
!= NULL
);
367 assert (DeviceExt
->BytesPerCluster
!= 0);
368 assert (FileObject
!= NULL
);
369 assert (FileObject
->FsContext2
!= NULL
);
371 DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
372 "Length %d, ReadOffset 0x%x)\n", DeviceExt
, FileObject
, Buffer
,
377 Fcb
= ((PVFATCCB
)FileObject
->FsContext2
)->pFcb
;
380 * Find the first cluster
382 if (DeviceExt
->FatType
== FAT32
)
383 CurrentCluster
= Fcb
->entry
.FirstCluster
384 + Fcb
->entry
.FirstClusterHigh
* 65536;
386 CurrentCluster
= Fcb
->entry
.FirstCluster
;
387 FirstCluster
= CurrentCluster
;
388 DPRINT( "FirstCluster = %x\n", FirstCluster
);
390 * Truncate the read if necessary
392 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
394 if (ReadOffset
>= Fcb
->entry
.FileSize
)
396 return (STATUS_END_OF_FILE
);
398 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
400 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
404 if (FirstCluster
== 1)
406 // root directory of FAT12 od FAT16
407 if (ReadOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
409 Length
= DeviceExt
->rootDirectorySectors
* BLOCKSIZE
- ReadOffset
;
414 * Select an appropiate size for reads
416 if (DeviceExt
->BytesPerCluster
>= PAGESIZE
)
418 ChunkSize
= DeviceExt
->BytesPerCluster
;
422 ChunkSize
= PAGESIZE
;
426 * Find the cluster to start the read from
427 * FIXME: Optimize by remembering the last cluster read and using if
430 Status
= OffsetToCluster(DeviceExt
,
432 ROUND_DOWN(ReadOffset
, ChunkSize
),
435 if (!NT_SUCCESS(Status
))
441 * If the read doesn't begin on a chunk boundary then we need special
444 if ((ReadOffset
% ChunkSize
) != 0 )
446 TempLength
= min (Length
, ChunkSize
- (ReadOffset
% ChunkSize
));
447 Status
= VfatReadCluster(DeviceExt
, Fcb
, ROUND_DOWN(ReadOffset
, ChunkSize
),
448 FirstCluster
, &CurrentCluster
, Buffer
, NoCache
,
449 ReadOffset
% ChunkSize
, TempLength
);
450 if (NT_SUCCESS(Status
))
452 (*LengthRead
) = (*LengthRead
) + TempLength
;
453 Length
= Length
- TempLength
;
454 Buffer
= Buffer
+ TempLength
;
455 ReadOffset
= ReadOffset
+ TempLength
;
459 while (Length
>= ChunkSize
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
461 Status
= VfatReadCluster(DeviceExt
, Fcb
, ReadOffset
,
462 FirstCluster
, &CurrentCluster
, Buffer
, NoCache
, 0,
464 if (NT_SUCCESS(Status
))
466 (*LengthRead
) = (*LengthRead
) + ChunkSize
;
467 Buffer
= Buffer
+ ChunkSize
;
468 Length
= Length
- ChunkSize
;
469 ReadOffset
= ReadOffset
+ ChunkSize
;
472 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
474 Status
= VfatReadCluster(DeviceExt
, Fcb
, ReadOffset
,
475 FirstCluster
, &CurrentCluster
, Buffer
, NoCache
, 0,
477 if (NT_SUCCESS(Status
))
479 (*LengthRead
) = (*LengthRead
) + Length
;
486 VfatWriteBigCluster(PDEVICE_EXTENSION DeviceExt
,
490 PULONG CurrentCluster
,
493 ULONG InternalOffset
,
494 ULONG InternalLength
,
499 PCACHE_SEGMENT CacheSeg
;
503 * In this case the size of a cache segment is the same as a cluster
507 Status
= CcRosRequestCacheSegment(Fcb
->RFCB
.Bcb
,
512 if (!NT_SUCCESS(Status
))
521 * If we are bypassing the cache and not writing starting on
522 * cluster boundary then allocate a temporary buffer
524 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
526 BaseAddress
= ExAllocatePool(NonPagedPool
,
527 DeviceExt
->BytesPerCluster
);
528 if (BaseAddress
== NULL
)
530 return(STATUS_NO_MEMORY
);
534 if (!Valid
&& InternalLength
!= DeviceExt
->BytesPerCluster
)
537 * If the data in the cache isn't valid or we are bypassing the
538 * cache and not writing a cluster aligned, cluster sized region
539 * then read data in to base address
541 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, BaseAddress
,
543 if (!NT_SUCCESS(Status
))
547 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, FALSE
);
549 else if (InternalLength
!= DeviceExt
->BytesPerCluster
)
551 ExFreePool(BaseAddress
);
556 if (!NoCache
|| InternalLength
!= DeviceExt
->BytesPerCluster
)
559 * If we are writing into the cache or we are writing from a
560 * temporary buffer then copy the data over
562 DPRINT("InternalOffset 0x%x InternalLength 0x%x BA %x\n",
563 InternalOffset
, InternalLength
, BaseAddress
);
564 memcpy(BaseAddress
+ InternalOffset
, Source
, InternalLength
);
567 * Write the data back to disk
569 DPRINT("Writing 0x%x\n", *CurrentCluster
);
570 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, BaseAddress
,
574 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, TRUE
);
576 else if (InternalLength
!= DeviceExt
->BytesPerCluster
)
578 ExFreePool(BaseAddress
);
581 Status
= NextCluster(DeviceExt
, FirstCluster
, CurrentCluster
, Extend
);
582 if (!NT_SUCCESS(Status
))
586 return(STATUS_SUCCESS
);
590 VfatWriteSmallCluster(PDEVICE_EXTENSION DeviceExt
,
594 PULONG CurrentCluster
,
597 ULONG InternalOffset
,
598 ULONG InternalLength
,
603 PCACHE_SEGMENT CacheSeg
;
609 * Otherwise we read a page of clusters together
614 Status
= CcRosRequestCacheSegment(Fcb
->RFCB
.Bcb
,
619 if (!NT_SUCCESS(Status
))
627 if (InternalLength
!= PAGESIZE
)
629 BaseAddress
= ExAllocatePool(NonPagedPool
, PAGESIZE
);
630 if (BaseAddress
== NULL
)
632 return(STATUS_NO_MEMORY
);
637 BaseAddress
= Source
;
642 * If necessary read all the data for the page, unfortunately the
643 * file length may not be page aligned in which case the page will
644 * only be partially filled.
645 * FIXME: So zero fill the rest?
647 if (!Valid
|| InternalLength
!= PAGESIZE
)
649 NCluster
= *CurrentCluster
;
651 for (i
= 0; i
< (PAGESIZE
/ DeviceExt
->BytesPerCluster
); i
++)
653 Status
= VfatRawReadCluster(DeviceExt
,
656 (i
* DeviceExt
->BytesPerCluster
),
658 if (!NT_SUCCESS(Status
))
662 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, FALSE
);
664 else if (InternalLength
!= PAGESIZE
)
666 ExFreePool(BaseAddress
);
670 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, Extend
);
671 if (NCluster
== 0xFFFFFFFF)
680 * Otherwise just move onto the next cluster
682 NCluster
= *CurrentCluster
;
683 for (i
= 0; i
< (PAGESIZE
/ DeviceExt
->BytesPerCluster
); i
++)
685 NextCluster(DeviceExt
, FirstCluster
, &NCluster
, Extend
);
686 if (NCluster
== 0xFFFFFFFF)
693 if (!NoCache
|| InternalLength
!= PAGESIZE
)
696 * Copy the caller's data if we are using the cache or writing
697 * from temporary buffer
699 memcpy(BaseAddress
+ InternalOffset
, Source
, InternalLength
);
703 * Write the data to the disk
705 NCluster
= *CurrentCluster
;
707 for (i
= 0; i
< (PAGESIZE
/ DeviceExt
->BytesPerCluster
); i
++)
709 Status
= VfatRawWriteCluster(DeviceExt
,
712 (i
* DeviceExt
->BytesPerCluster
),
714 if (!NT_SUCCESS(Status
))
718 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
, FALSE
);
720 else if (InternalLength
!= PAGESIZE
)
722 ExFreePool(BaseAddress
);
726 // FIXME: Overwriting the variable Extend isn't correct,
727 // but when VFatWriteFile writes the last cache segment,
728 // than is Extend set to FALSE. We must extend,
729 // when the data needs a next cluster.
730 if (i
< (PAGESIZE
/ DeviceExt
->BytesPerCluster
)-1 &&
731 InternalOffset
+ InternalLength
> (i
+1) * DeviceExt
->BytesPerCluster
)
739 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, Extend
);
740 if (NCluster
== 0xFFFFFFFF)
745 *CurrentCluster
= NCluster
;
750 CcRosReleaseCacheSegment(Fcb
->RFCB
.Bcb
, CacheSeg
,
751 Valid
|| InternalLength
== PAGESIZE
? TRUE
: FALSE
);
753 else if (InternalLength
!= PAGESIZE
)
755 ExFreePool(BaseAddress
);
757 return(STATUS_SUCCESS
);
761 VfatWriteCluster(PDEVICE_EXTENSION DeviceExt
,
765 PULONG CurrentCluster
,
768 ULONG InternalOffset
,
769 ULONG InternalLength
,
774 if (DeviceExt
->BytesPerCluster
>= PAGESIZE
)
776 return(VfatWriteBigCluster(DeviceExt
,
789 return(VfatWriteSmallCluster(DeviceExt
,
803 VfatWriteFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
804 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
,
807 * FUNCTION: Writes data to file
810 ULONG CurrentCluster
;
815 LARGE_INTEGER SystemTime
, LocalTime
;
820 DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
821 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
823 /* Locate the first cluster of the file */
825 pCcb
= (PVFATCCB
) (FileObject
->FsContext2
);
830 if (DeviceExt
->BytesPerCluster
>= PAGESIZE
)
832 ChunkSize
= DeviceExt
->BytesPerCluster
;
836 ChunkSize
= PAGESIZE
;
839 if (DeviceExt
->FatType
== FAT32
)
842 Fcb
->entry
.FirstCluster
+ Fcb
->entry
.FirstClusterHigh
* 65536;
846 CurrentCluster
= Fcb
->entry
.FirstCluster
;
848 FirstCluster
= CurrentCluster
;
850 /* Find the cluster according to the offset in the file */
851 if (CurrentCluster
== 0)
856 Status
= NextCluster (DeviceExt
, FirstCluster
, &CurrentCluster
,
858 if (DeviceExt
->FatType
== FAT32
)
860 Fcb
->entry
.FirstClusterHigh
= CurrentCluster
>> 16;
861 Fcb
->entry
.FirstCluster
= CurrentCluster
;
865 Fcb
->entry
.FirstCluster
= CurrentCluster
;
867 FirstCluster
= CurrentCluster
;
869 Status
= OffsetToCluster(DeviceExt
,
871 ROUND_DOWN(WriteOffset
, ChunkSize
),
875 if (WriteOffset
+ Length
> Fcb
->entry
.FileSize
&&
876 !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
878 Fcb
->entry
.FileSize
= WriteOffset
+ Length
;
881 if (FirstCluster
== 1)
883 // root directory of FAT12 od FAT16
884 if (WriteOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
885 return STATUS_END_OF_FILE
;
889 * If the offset in the cluster doesn't fall on the cluster boundary
890 * then we have to write only from the specified offset
892 Status
= STATUS_SUCCESS
;
893 if ((WriteOffset
% ChunkSize
) != 0)
895 TempLength
= min (Length
, ChunkSize
- (WriteOffset
% ChunkSize
));
896 if ((Length
- TempLength
) > 0)
904 Status
= VfatWriteCluster(DeviceExt
,
906 ROUND_DOWN(WriteOffset
, ChunkSize
),
911 WriteOffset
% ChunkSize
,
914 if (NT_SUCCESS(Status
))
916 Buffer
= Buffer
+ TempLength
;
917 Length
= Length
- TempLength
;
918 WriteOffset
= WriteOffset
+ TempLength
;
922 while (Length
>= ChunkSize
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
924 if ((Length
- ChunkSize
) > 0)
932 Status
= VfatWriteCluster(DeviceExt
,
934 ROUND_DOWN(WriteOffset
, ChunkSize
),
942 if (!NT_SUCCESS(Status
))
946 Buffer
= Buffer
+ ChunkSize
;
947 Length
= Length
- ChunkSize
;
948 WriteOffset
= WriteOffset
+ ChunkSize
;
951 /* Write the remainder */
952 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
954 Status
= VfatWriteCluster(DeviceExt
,
956 ROUND_DOWN(WriteOffset
, ChunkSize
),
964 if (NT_SUCCESS(Status
))
971 /* set dates and times */
972 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
974 KeQuerySystemTime (&SystemTime
);
975 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
976 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
,
977 &Fcb
->entry
.UpdateDate
,
978 &Fcb
->entry
.UpdateTime
);
979 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
980 updEntry (DeviceExt
, FileObject
);
983 if (!NT_SUCCESS(Status
))
989 return STATUS_DISK_FULL
;
991 return (STATUS_SUCCESS
);
995 VfatWrite (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
997 * FUNCTION: Write to a file
1003 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation (Irp
);
1004 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1005 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1009 DPRINT ("VfatWrite(DeviceObject %x Irp %x)\n", DeviceObject
, Irp
);
1011 Length
= Stack
->Parameters
.Write
.Length
;
1012 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
1013 Offset
= Stack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
1015 if (Irp
->Flags
& IRP_PAGING_IO
||
1016 FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
1025 Status
= VfatWriteFile (DeviceExt
, FileObject
, Buffer
, Length
, Offset
,
1028 Irp
->IoStatus
.Status
= Status
;
1029 Irp
->IoStatus
.Information
= Length
;
1030 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
1036 VfatRead (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1038 * FUNCTION: Read from a file
1044 PIO_STACK_LOCATION Stack
;
1045 PFILE_OBJECT FileObject
;
1046 PDEVICE_EXTENSION DeviceExt
;
1052 DPRINT ("VfatRead(DeviceObject %x, Irp %x)\n", DeviceObject
, Irp
);
1054 /* Precondition / Initialization */
1055 assert (Irp
!= NULL
);
1056 Stack
= IoGetCurrentIrpStackLocation (Irp
);
1057 assert (Stack
!= NULL
);
1058 FileObject
= Stack
->FileObject
;
1059 assert (FileObject
!= NULL
);
1060 DeviceExt
= DeviceObject
->DeviceExtension
;
1061 assert (DeviceExt
!= NULL
);
1063 Length
= Stack
->Parameters
.Read
.Length
;
1064 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
1065 Offset
= Stack
->Parameters
.Read
.ByteOffset
.u
.LowPart
;
1067 if (Irp
->Flags
& IRP_PAGING_IO
||
1068 FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
1077 /* fail if file is a directory */
1078 Fcb
= ((PVFATCCB
) (FileObject
->FsContext2
))->pFcb
;
1079 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
1081 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1085 Status
= VfatReadFile (DeviceExt
,
1086 FileObject
, Buffer
, Length
, Offset
, &LengthRead
,
1090 Irp
->IoStatus
.Status
= Status
;
1091 Irp
->IoStatus
.Information
= LengthRead
;
1092 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);