1 /* $Id: rw.c,v 1.11 2000/12/05 17:12:16 jean Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/rw.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
11 /* INCLUDES *****************************************************************/
13 #include <ddk/ntddk.h>
15 #include <ddk/cctypes.h>
16 #include <ntos/minmax.h>
23 /* FUNCTIONS ****************************************************************/
25 NTSTATUS
FsdReadFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
26 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
29 * FUNCTION: Reads data from a file
40 assert(DeviceExt
!= NULL
);
41 assert(DeviceExt
->BytesPerCluster
!= 0);
42 assert(FileObject
!= NULL
);
43 assert(FileObject
->FsContext
!= NULL
);
45 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
46 "Length %d, ReadOffset %d)\n",DeviceExt
,FileObject
,Buffer
,
49 Fcb
= ((PVFATCCB
)(FileObject
->FsContext2
))->pFcb
;
50 if (DeviceExt
->FatType
== FAT32
)
51 CurrentCluster
= Fcb
->entry
.FirstCluster
52 +Fcb
->entry
.FirstClusterHigh
*65536;
54 CurrentCluster
= Fcb
->entry
.FirstCluster
;
55 FirstCluster
=CurrentCluster
;
56 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt
->BytesPerCluster
);
58 if ( !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
60 if (ReadOffset
>= Fcb
->entry
.FileSize
)
62 return(STATUS_END_OF_FILE
);
64 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
66 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
71 /* FIXME: optimize by remembering the last cluster read and using if possible */
72 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
73 if(!Temp
) return STATUS_UNSUCCESSFUL
;
75 { //root of FAT16 or FAT12
76 CurrentCluster
=DeviceExt
->rootStart
+ReadOffset
77 /(DeviceExt
->BytesPerCluster
)*DeviceExt
->Boot
->SectorsPerCluster
;
80 for (FileOffset
=0; FileOffset
< ReadOffset
/ DeviceExt
->BytesPerCluster
83 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
86 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
88 if (FirstCluster
== 1)
90 VFATReadSectors(DeviceExt
->StorageDevice
,
92 DeviceExt
->Boot
->SectorsPerCluster
,
94 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
98 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
99 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
101 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
102 (ReadOffset
% DeviceExt
->BytesPerCluster
));
104 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
107 (*LengthRead
) = (*LengthRead
) + TempLength
;
108 Length
= Length
- TempLength
;
109 Buffer
= Buffer
+ TempLength
;
112 while (Length
>= DeviceExt
->BytesPerCluster
)
114 if (FirstCluster
== 1)
116 VFATReadSectors(DeviceExt
->StorageDevice
,
118 DeviceExt
->Boot
->SectorsPerCluster
,
120 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
124 VFATLoadCluster(DeviceExt
,Buffer
,CurrentCluster
);
125 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
127 if (CurrentCluster
== 0xffffffff)
130 return(STATUS_SUCCESS
);
133 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
134 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
135 Length
= Length
- DeviceExt
->BytesPerCluster
;
140 (*LengthRead
) = (*LengthRead
) + Length
;
141 if (FirstCluster
== 1)
143 VFATReadSectors(DeviceExt
->StorageDevice
,
145 DeviceExt
->Boot
->SectorsPerCluster
,
147 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
151 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
152 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
154 memcpy(Buffer
, Temp
, Length
);
157 return(STATUS_SUCCESS
);
160 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
161 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
163 * FUNCTION: Writes data to file
166 ULONG CurrentCluster
;
172 ULONG TempLength
,Length2
=Length
;
173 LARGE_INTEGER SystemTime
, LocalTime
;
175 DPRINT1("FsdWriteFile(FileObject %x, Buffer %x, Length %x, "
176 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
178 /* Locate the first cluster of the file */
180 pCcb
=(PVFATCCB
)(FileObject
->FsContext2
);
184 if (DeviceExt
->FatType
== FAT32
)
187 Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
191 CurrentCluster
= Fcb
->entry
.FirstCluster
;
193 FirstCluster
=CurrentCluster
;
195 /* Allocate a buffer to hold 1 cluster of data */
196 Temp
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
199 /* Find the cluster according to the offset in the file */
200 if (CurrentCluster
==1)
202 CurrentCluster
=DeviceExt
->rootStart
+WriteOffset
203 / DeviceExt
->BytesPerCluster
*DeviceExt
->Boot
->SectorsPerCluster
;
207 if (CurrentCluster
==0)
212 CurrentCluster
=GetNextWriteCluster(DeviceExt
,0);
213 if (DeviceExt
->FatType
== FAT32
)
215 Fcb
->entry
.FirstClusterHigh
= CurrentCluster
>>16;
216 Fcb
->entry
.FirstCluster
= CurrentCluster
;
219 Fcb
->entry
.FirstCluster
=CurrentCluster
;
224 FileOffset
< WriteOffset
/ DeviceExt
->BytesPerCluster
;
227 CurrentCluster
= GetNextWriteCluster(DeviceExt
,CurrentCluster
);
234 * If the offset in the cluster doesn't fall on the cluster boundary
235 * then we have to write only from the specified offset
238 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
241 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
242 (WriteOffset
% DeviceExt
->BytesPerCluster
));
243 /* Read in the existing cluster data */
246 VFATReadSectors(DeviceExt
->StorageDevice
,
248 DeviceExt
->Boot
->SectorsPerCluster
,
253 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
256 /* Overwrite the last parts of the data as necessary */
257 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
),
261 /* Write the cluster back */
262 Length2
-= TempLength
;
265 VFATWriteSectors(DeviceExt
->StorageDevice
,
267 DeviceExt
->Boot
->SectorsPerCluster
,
269 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
273 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
275 CurrentCluster
= GetNextWriteCluster(DeviceExt
, CurrentCluster
);
277 Buffer
= Buffer
+ TempLength
;
281 /* Write the buffer in chunks of 1 cluster */
283 while (Length2
>= DeviceExt
->BytesPerCluster
)
286 if (CurrentCluster
== 0)
289 return(STATUS_UNSUCCESSFUL
);
291 Length2
-= DeviceExt
->BytesPerCluster
;
294 VFATWriteSectors(DeviceExt
->StorageDevice
,
296 DeviceExt
->Boot
->SectorsPerCluster
,
298 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
302 VFATWriteCluster(DeviceExt
,Buffer
,CurrentCluster
);
304 CurrentCluster
= GetNextWriteCluster(DeviceExt
, CurrentCluster
);
306 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
310 /* Write the remainder */
315 if (CurrentCluster
== 0)
318 return(STATUS_UNSUCCESSFUL
);
321 /* Read in the existing cluster data */
324 VFATReadSectors(DeviceExt
->StorageDevice
,
326 DeviceExt
->Boot
->SectorsPerCluster
,
331 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
333 memcpy(Temp
, Buffer
, Length2
);
337 VFATWriteSectors(DeviceExt
->StorageDevice
,
339 DeviceExt
->Boot
->SectorsPerCluster
,
344 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
351 /* set dates and times */
352 KeQuerySystemTime (&SystemTime
);
353 ExSystemTimeToLocalTime (&SystemTime
,
355 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
,
356 &Fcb
->entry
.UpdateDate
,
357 &Fcb
->entry
.UpdateTime
);
358 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
360 if (Fcb
->entry
.FileSize
< WriteOffset
+Length
361 && ! (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
363 Fcb
->entry
.FileSize
= WriteOffset
+Length
;
365 * update entry in directory
367 updEntry(DeviceExt
,FileObject
);
371 return (STATUS_SUCCESS
);
374 NTSTATUS STDCALL
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
376 * FUNCTION: Write to a file
382 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
383 PFILE_OBJECT FileObject
= Stack
->FileObject
;
384 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
387 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
389 Length
= Stack
->Parameters
.Write
.Length
;
390 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
391 Offset
= Stack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
393 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
395 Irp
->IoStatus
.Status
= Status
;
396 Irp
->IoStatus
.Information
= Length
;
397 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
402 NTSTATUS STDCALL
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
404 * FUNCTION: Read from a file
410 PIO_STACK_LOCATION Stack
;
411 PFILE_OBJECT FileObject
;
412 PDEVICE_EXTENSION DeviceExt
;
417 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
419 /* Precondition / Initialization */
421 Stack
= IoGetCurrentIrpStackLocation(Irp
);
422 assert(Stack
!= NULL
);
423 FileObject
= Stack
->FileObject
;
424 assert(FileObject
!= NULL
);
425 DeviceExt
= DeviceObject
->DeviceExtension
;
426 assert(DeviceExt
!= NULL
);
428 Length
= Stack
->Parameters
.Read
.Length
;
429 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
430 Offset
= Stack
->Parameters
.Read
.ByteOffset
.u
.LowPart
;
432 /* fail if file is a directory */
433 Fcb
= ((PVFATCCB
)(FileObject
->FsContext2
))->pFcb
;
434 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
436 Status
= STATUS_FILE_IS_A_DIRECTORY
;
440 Status
= FsdReadFile(DeviceExt
,
448 Irp
->IoStatus
.Status
= Status
;
449 Irp
->IoStatus
.Information
= LengthRead
;
450 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);