1 /* $Id: rw.c,v 1.12 2000/12/29 23:17:12 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 <ntos/minmax.h>
22 /* FUNCTIONS ****************************************************************/
25 VfatReadFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
26 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
, PULONG LengthRead
)
28 * FUNCTION: Reads data from a file
39 assert (DeviceExt
!= NULL
);
40 assert (DeviceExt
->BytesPerCluster
!= 0);
41 assert (FileObject
!= NULL
);
42 assert (FileObject
->FsContext
!= NULL
);
44 DPRINT ("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
45 "Length %d, ReadOffset %d)\n", DeviceExt
, FileObject
, Buffer
,
48 Fcb
= ((PVFATCCB
) (FileObject
->FsContext2
))->pFcb
;
49 if (DeviceExt
->FatType
== FAT32
)
50 CurrentCluster
= Fcb
->entry
.FirstCluster
51 + Fcb
->entry
.FirstClusterHigh
* 65536;
53 CurrentCluster
= Fcb
->entry
.FirstCluster
;
54 FirstCluster
= CurrentCluster
;
55 DPRINT ("DeviceExt->BytesPerCluster %x\n", DeviceExt
->BytesPerCluster
);
57 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
59 if (ReadOffset
>= Fcb
->entry
.FileSize
)
61 return (STATUS_END_OF_FILE
);
63 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
65 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
70 /* FIXME: optimize by remembering the last cluster read and using if possible */
71 Temp
= ExAllocatePool (NonPagedPool
, DeviceExt
->BytesPerCluster
);
73 return STATUS_UNSUCCESSFUL
;
74 if (FirstCluster
== 1)
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
, Temp
);
93 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
97 VFATLoadCluster (DeviceExt
, Temp
, CurrentCluster
);
98 CurrentCluster
= GetNextCluster (DeviceExt
, CurrentCluster
);
100 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
-
101 (ReadOffset
% DeviceExt
->BytesPerCluster
));
103 memcpy (Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
106 (*LengthRead
) = (*LengthRead
) + TempLength
;
107 Length
= Length
- TempLength
;
108 Buffer
= Buffer
+ TempLength
;
111 while (Length
>= DeviceExt
->BytesPerCluster
)
113 if (FirstCluster
== 1)
115 VFATReadSectors (DeviceExt
->StorageDevice
,
117 DeviceExt
->Boot
->SectorsPerCluster
, Buffer
);
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
, Temp
);
144 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
148 VFATLoadCluster (DeviceExt
, Temp
, CurrentCluster
);
149 CurrentCluster
= GetNextCluster (DeviceExt
, CurrentCluster
);
151 memcpy (Buffer
, Temp
, Length
);
154 return (STATUS_SUCCESS
);
158 VfatWriteFile (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
;
226 GetNextWriteCluster (DeviceExt
, CurrentCluster
);
233 * If the offset in the cluster doesn't fall on the cluster boundary
234 * then we have to write only from the specified offset
237 if ((WriteOffset
% DeviceExt
->BytesPerCluster
) != 0)
240 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
-
241 (WriteOffset
% DeviceExt
->BytesPerCluster
));
242 /* Read in the existing cluster data */
243 if (FirstCluster
== 1)
245 VFATReadSectors (DeviceExt
->StorageDevice
,
247 DeviceExt
->Boot
->SectorsPerCluster
, Temp
);
251 VFATLoadCluster (DeviceExt
, Temp
, CurrentCluster
);
254 /* Overwrite the last parts of the data as necessary */
255 memcpy (Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
),
258 /* Write the cluster back */
259 Length2
-= TempLength
;
260 if (FirstCluster
== 1)
262 VFATWriteSectors (DeviceExt
->StorageDevice
,
264 DeviceExt
->Boot
->SectorsPerCluster
, Temp
);
265 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
269 VFATWriteCluster (DeviceExt
, Temp
, CurrentCluster
);
271 CurrentCluster
= GetNextWriteCluster (DeviceExt
, CurrentCluster
);
273 Buffer
= Buffer
+ TempLength
;
277 /* Write the buffer in chunks of 1 cluster */
279 while (Length2
>= DeviceExt
->BytesPerCluster
)
282 if (CurrentCluster
== 0)
285 return (STATUS_UNSUCCESSFUL
);
287 Length2
-= DeviceExt
->BytesPerCluster
;
288 if (FirstCluster
== 1)
290 VFATWriteSectors (DeviceExt
->StorageDevice
,
292 DeviceExt
->Boot
->SectorsPerCluster
, Buffer
);
293 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
297 VFATWriteCluster (DeviceExt
, Buffer
, CurrentCluster
);
299 CurrentCluster
= GetNextWriteCluster (DeviceExt
, CurrentCluster
);
301 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
305 /* Write the remainder */
310 if (CurrentCluster
== 0)
313 return (STATUS_UNSUCCESSFUL
);
316 /* Read in the existing cluster data */
317 if (FirstCluster
== 1)
319 VFATReadSectors (DeviceExt
->StorageDevice
,
321 DeviceExt
->Boot
->SectorsPerCluster
, Temp
);
325 VFATLoadCluster (DeviceExt
, Temp
, CurrentCluster
);
327 memcpy (Temp
, Buffer
, Length2
);
329 if (FirstCluster
== 1)
331 VFATWriteSectors (DeviceExt
->StorageDevice
,
333 DeviceExt
->Boot
->SectorsPerCluster
, Temp
);
337 VFATWriteCluster (DeviceExt
, Temp
, CurrentCluster
);
344 /* set dates and times */
345 KeQuerySystemTime (&SystemTime
);
346 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
347 FsdFileTimeToDosDateTime ((TIME
*) & LocalTime
,
348 &Fcb
->entry
.UpdateDate
, &Fcb
->entry
.UpdateTime
);
349 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
351 if (Fcb
->entry
.FileSize
< WriteOffset
+ Length
352 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
354 Fcb
->entry
.FileSize
= WriteOffset
+ Length
;
356 * update entry in directory
358 updEntry (DeviceExt
, FileObject
);
362 return (STATUS_SUCCESS
);
366 VfatWrite (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
368 * FUNCTION: Write to a file
374 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation (Irp
);
375 PFILE_OBJECT FileObject
= Stack
->FileObject
;
376 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
379 DPRINT ("VfatWrite(DeviceObject %x Irp %x)\n", DeviceObject
, Irp
);
381 Length
= Stack
->Parameters
.Write
.Length
;
382 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
383 Offset
= Stack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
385 Status
= VfatWriteFile (DeviceExt
, FileObject
, Buffer
, Length
, Offset
);
387 Irp
->IoStatus
.Status
= Status
;
388 Irp
->IoStatus
.Information
= Length
;
389 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
395 VfatRead (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
397 * FUNCTION: Read from a file
403 PIO_STACK_LOCATION Stack
;
404 PFILE_OBJECT FileObject
;
405 PDEVICE_EXTENSION DeviceExt
;
410 DPRINT ("VfatRead(DeviceObject %x, Irp %x)\n", DeviceObject
, Irp
);
412 /* Precondition / Initialization */
413 assert (Irp
!= NULL
);
414 Stack
= IoGetCurrentIrpStackLocation (Irp
);
415 assert (Stack
!= NULL
);
416 FileObject
= Stack
->FileObject
;
417 assert (FileObject
!= NULL
);
418 DeviceExt
= DeviceObject
->DeviceExtension
;
419 assert (DeviceExt
!= NULL
);
421 Length
= Stack
->Parameters
.Read
.Length
;
422 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
423 Offset
= Stack
->Parameters
.Read
.ByteOffset
.u
.LowPart
;
425 /* fail if file is a directory */
426 Fcb
= ((PVFATCCB
) (FileObject
->FsContext2
))->pFcb
;
427 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
429 Status
= STATUS_FILE_IS_A_DIRECTORY
;
433 Status
= VfatReadFile (DeviceExt
,
434 FileObject
, Buffer
, Length
, Offset
, &LengthRead
);
437 Irp
->IoStatus
.Status
= Status
;
438 Irp
->IoStatus
.Information
= LengthRead
;
439 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);