1 /* $Id: rw.c,v 1.5 2000/04/07 02:24:03 dwelch 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 <internal/string.h>
16 #include <ddk/cctypes.h>
19 #include <internal/debug.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 (ReadOffset
>= Fcb
->entry
.FileSize
59 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
61 return(STATUS_END_OF_FILE
);
63 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
64 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
66 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
69 /* FIXME: optimize by remembering the last cluster read and using if possible */
70 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
71 if(!Temp
) return STATUS_UNSUCCESSFUL
;
73 { //root of FAT16 or FAT12
74 CurrentCluster
=DeviceExt
->rootStart
+ReadOffset
75 /(DeviceExt
->BytesPerCluster
)*DeviceExt
->Boot
->SectorsPerCluster
;
78 for (FileOffset
=0; FileOffset
< ReadOffset
/ DeviceExt
->BytesPerCluster
81 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
84 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
86 if (FirstCluster
== 1)
88 VFATReadSectors(DeviceExt
->StorageDevice
,
90 DeviceExt
->Boot
->SectorsPerCluster
,
92 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
96 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
97 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
99 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
100 (ReadOffset
% DeviceExt
->BytesPerCluster
));
102 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
105 (*LengthRead
) = (*LengthRead
) + TempLength
;
106 Length
= Length
- TempLength
;
107 Buffer
= Buffer
+ TempLength
;
110 while (Length
>= DeviceExt
->BytesPerCluster
)
112 if (FirstCluster
== 1)
114 VFATReadSectors(DeviceExt
->StorageDevice
,
116 DeviceExt
->Boot
->SectorsPerCluster
,
118 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
122 VFATLoadCluster(DeviceExt
,Buffer
,CurrentCluster
);
123 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
125 if (CurrentCluster
== 0xffffffff)
128 return(STATUS_SUCCESS
);
131 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
132 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
133 Length
= Length
- DeviceExt
->BytesPerCluster
;
138 (*LengthRead
) = (*LengthRead
) + Length
;
139 if (FirstCluster
== 1)
141 VFATReadSectors(DeviceExt
->StorageDevice
,
143 DeviceExt
->Boot
->SectorsPerCluster
,
145 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
149 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
150 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
152 memcpy(Buffer
, Temp
, Length
);
155 return(STATUS_SUCCESS
);
158 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
159 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
161 * FUNCTION: Writes data to file
164 ULONG CurrentCluster
;
170 ULONG TempLength
,Length2
=Length
;
171 LARGE_INTEGER SystemTime
, LocalTime
;
173 DPRINT1("FsdWriteFile(FileObject %x, Buffer %x, Length %x, "
174 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
176 /* Locate the first cluster of the file */
178 pCcb
=(PVFATCCB
)(FileObject
->FsContext2
);
182 if (DeviceExt
->FatType
== FAT32
)
185 Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
189 CurrentCluster
= Fcb
->entry
.FirstCluster
;
191 FirstCluster
=CurrentCluster
;
193 /* Allocate a buffer to hold 1 cluster of data */
194 Temp
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
197 /* Find the cluster according to the offset in the file */
198 if (CurrentCluster
==1)
200 CurrentCluster
=DeviceExt
->rootStart
+WriteOffset
201 / DeviceExt
->BytesPerCluster
*DeviceExt
->Boot
->SectorsPerCluster
;
205 if (CurrentCluster
==0)
210 CurrentCluster
=GetNextWriteCluster(DeviceExt
,0);
211 if (DeviceExt
->FatType
== FAT32
)
213 Fcb
->entry
.FirstClusterHigh
= CurrentCluster
>>16;
214 Fcb
->entry
.FirstCluster
= CurrentCluster
;
217 Fcb
->entry
.FirstCluster
=CurrentCluster
;
222 FileOffset
< WriteOffset
/ DeviceExt
->BytesPerCluster
;
225 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
232 * If the offset in the cluster doesn't fall on the cluster boundary
233 * then we have to write only from the specified offset
236 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
239 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
240 (WriteOffset
% DeviceExt
->BytesPerCluster
));
241 /* Read in the existing cluster data */
244 VFATReadSectors(DeviceExt
->StorageDevice
,
246 DeviceExt
->Boot
->SectorsPerCluster
,
251 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
254 /* Overwrite the last parts of the data as necessary */
255 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
),
259 /* Write the cluster back */
262 VFATWriteSectors(DeviceExt
->StorageDevice
,
264 DeviceExt
->Boot
->SectorsPerCluster
,
266 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
270 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
271 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
273 Length2
-= TempLength
;
274 Buffer
= Buffer
+ TempLength
;
278 /* Write the buffer in chunks of 1 cluster */
280 while (Length2
>= DeviceExt
->BytesPerCluster
)
283 if (CurrentCluster
== 0)
286 return(STATUS_UNSUCCESSFUL
);
290 VFATWriteSectors(DeviceExt
->StorageDevice
,
292 DeviceExt
->Boot
->SectorsPerCluster
,
294 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
298 VFATWriteCluster(DeviceExt
,Buffer
,CurrentCluster
);
299 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
301 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
302 Length2
-= DeviceExt
->BytesPerCluster
;
306 /* Write the remainder */
311 if (CurrentCluster
== 0)
314 return(STATUS_UNSUCCESSFUL
);
317 /* Read in the existing cluster data */
320 VFATReadSectors(DeviceExt
->StorageDevice
,
322 DeviceExt
->Boot
->SectorsPerCluster
,
327 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
329 memcpy(Temp
, Buffer
, Length2
);
333 VFATWriteSectors(DeviceExt
->StorageDevice
,
335 DeviceExt
->Boot
->SectorsPerCluster
,
340 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
347 /* set dates and times */
348 KeQuerySystemTime (&SystemTime
);
349 ExSystemTimeToLocalTime (&SystemTime
,
351 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
,
352 &Fcb
->entry
.UpdateDate
,
353 &Fcb
->entry
.UpdateTime
);
354 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
356 if (Fcb
->entry
.FileSize
< WriteOffset
+Length
357 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
359 Fcb
->entry
.FileSize
= WriteOffset
+Length
;
361 * update entry in directory
363 updEntry(DeviceExt
,FileObject
);
367 return (STATUS_SUCCESS
);
370 NTSTATUS
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
372 * FUNCTION: Write to a file
378 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
379 PFILE_OBJECT FileObject
= Stack
->FileObject
;
380 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
383 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
385 Length
= Stack
->Parameters
.Write
.Length
;
386 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
387 Offset
= Stack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
389 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
391 Irp
->IoStatus
.Status
= Status
;
392 Irp
->IoStatus
.Information
= Length
;
393 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
398 NTSTATUS
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
400 * FUNCTION: Read from a file
406 PIO_STACK_LOCATION Stack
;
407 PFILE_OBJECT FileObject
;
408 PDEVICE_EXTENSION DeviceExt
;
413 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
415 /* Precondition / Initialization */
417 Stack
= IoGetCurrentIrpStackLocation(Irp
);
418 assert(Stack
!= NULL
);
419 FileObject
= Stack
->FileObject
;
420 assert(FileObject
!= NULL
);
421 DeviceExt
= DeviceObject
->DeviceExtension
;
422 assert(DeviceExt
!= NULL
);
424 Length
= Stack
->Parameters
.Read
.Length
;
425 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
426 Offset
= Stack
->Parameters
.Read
.ByteOffset
.u
.LowPart
;
428 /* fail if file is a directory */
429 Fcb
= ((PVFATCCB
)(FileObject
->FsContext2
))->pFcb
;
430 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
432 Status
= STATUS_FILE_IS_A_DIRECTORY
;
436 Status
= FsdReadFile(DeviceExt
,
444 Irp
->IoStatus
.Status
= Status
;
445 Irp
->IoStatus
.Information
= LengthRead
;
446 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);