changes in IRP for compatibility
[reactos.git] / reactos / drivers / fs / vfat / rw.c
1 /* $Id: rw.c,v 1.8 2000/09/12 10:12:13 jean Exp $
2 *
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)
8 *
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <wchar.h>
15 #include <ddk/cctypes.h>
16 #include <ntos/minmax.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 /* FUNCTIONS ****************************************************************/
24
25 NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
26 PVOID Buffer, ULONG Length, ULONG ReadOffset,
27 PULONG LengthRead)
28 /*
29 * FUNCTION: Reads data from a file
30 */
31 {
32 ULONG CurrentCluster;
33 ULONG FileOffset;
34 ULONG FirstCluster;
35 PVFATFCB Fcb;
36 PVOID Temp;
37 ULONG TempLength;
38
39 /* PRECONDITION */
40 assert(DeviceExt != NULL);
41 assert(DeviceExt->BytesPerCluster != 0);
42 assert(FileObject != NULL);
43 assert(FileObject->FsContext != NULL);
44
45 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
46 "Length %d, ReadOffset %d)\n",DeviceExt,FileObject,Buffer,
47 Length,ReadOffset);
48
49 Fcb = ((PVFATCCB)(FileObject->FsContext2))->pFcb;
50 if (DeviceExt->FatType == FAT32)
51 CurrentCluster = Fcb->entry.FirstCluster
52 +Fcb->entry.FirstClusterHigh*65536;
53 else
54 CurrentCluster = Fcb->entry.FirstCluster;
55 FirstCluster=CurrentCluster;
56 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
57
58 if (ReadOffset >= Fcb->entry.FileSize)
59 {
60 return(STATUS_END_OF_FILE);
61 }
62 if ((ReadOffset + Length) > Fcb->entry.FileSize)
63 {
64 Length = Fcb->entry.FileSize - ReadOffset;
65 }
66 *LengthRead = 0;
67 /* FIXME: optimize by remembering the last cluster read and using if possible */
68 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
69 if(!Temp) return STATUS_UNSUCCESSFUL;
70 if (FirstCluster==1)
71 { //root of FAT16 or FAT12
72 CurrentCluster=DeviceExt->rootStart+ReadOffset
73 /(DeviceExt->BytesPerCluster)*DeviceExt->Boot->SectorsPerCluster;
74 }
75 else
76 for (FileOffset=0; FileOffset < ReadOffset / DeviceExt->BytesPerCluster
77 ; FileOffset++)
78 {
79 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
80 }
81 CHECKPOINT;
82 if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
83 {
84 if (FirstCluster == 1)
85 {
86 VFATReadSectors(DeviceExt->StorageDevice,
87 CurrentCluster,
88 DeviceExt->Boot->SectorsPerCluster,
89 Temp);
90 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
91 }
92 else
93 {
94 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
95 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
96 }
97 TempLength = min(Length,DeviceExt->BytesPerCluster -
98 (ReadOffset % DeviceExt->BytesPerCluster));
99
100 memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
101 TempLength);
102
103 (*LengthRead) = (*LengthRead) + TempLength;
104 Length = Length - TempLength;
105 Buffer = Buffer + TempLength;
106 }
107 CHECKPOINT;
108 while (Length >= DeviceExt->BytesPerCluster)
109 {
110 if (FirstCluster == 1)
111 {
112 VFATReadSectors(DeviceExt->StorageDevice,
113 CurrentCluster,
114 DeviceExt->Boot->SectorsPerCluster,
115 Buffer);
116 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
117 }
118 else
119 {
120 VFATLoadCluster(DeviceExt,Buffer,CurrentCluster);
121 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
122 }
123 if (CurrentCluster == 0xffffffff)
124 {
125 ExFreePool(Temp);
126 return(STATUS_SUCCESS);
127 }
128
129 (*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
130 Buffer = Buffer + DeviceExt->BytesPerCluster;
131 Length = Length - DeviceExt->BytesPerCluster;
132 }
133 CHECKPOINT;
134 if (Length > 0)
135 {
136 (*LengthRead) = (*LengthRead) + Length;
137 if (FirstCluster == 1)
138 {
139 VFATReadSectors(DeviceExt->StorageDevice,
140 CurrentCluster,
141 DeviceExt->Boot->SectorsPerCluster,
142 Temp);
143 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
144 }
145 else
146 {
147 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
148 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
149 }
150 memcpy(Buffer, Temp, Length);
151 }
152 ExFreePool(Temp);
153 return(STATUS_SUCCESS);
154 }
155
156 NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
157 PVOID Buffer, ULONG Length, ULONG WriteOffset)
158 /*
159 * FUNCTION: Writes data to file
160 */
161 {
162 ULONG CurrentCluster;
163 ULONG FileOffset;
164 ULONG FirstCluster;
165 PVFATFCB Fcb;
166 PVFATCCB pCcb;
167 PVOID Temp;
168 ULONG TempLength,Length2=Length;
169 LARGE_INTEGER SystemTime, LocalTime;
170
171 DPRINT1("FsdWriteFile(FileObject %x, Buffer %x, Length %x, "
172 "WriteOffset %x\n", FileObject, Buffer, Length, WriteOffset);
173
174 /* Locate the first cluster of the file */
175 assert(FileObject);
176 pCcb=(PVFATCCB)(FileObject->FsContext2);
177 assert(pCcb);
178 Fcb = pCcb->pFcb;
179 assert(Fcb);
180 if (DeviceExt->FatType == FAT32)
181 {
182 CurrentCluster =
183 Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
184 }
185 else
186 {
187 CurrentCluster = Fcb->entry.FirstCluster;
188 }
189 FirstCluster=CurrentCluster;
190
191 /* Allocate a buffer to hold 1 cluster of data */
192 Temp = ExAllocatePool(NonPagedPool, DeviceExt->BytesPerCluster);
193 assert(Temp);
194
195 /* Find the cluster according to the offset in the file */
196 if (CurrentCluster==1)
197 {
198 CurrentCluster=DeviceExt->rootStart+WriteOffset
199 / DeviceExt->BytesPerCluster*DeviceExt->Boot->SectorsPerCluster;
200 }
201 else
202 {
203 if (CurrentCluster==0)
204 {
205 /*
206 * File of size zero
207 */
208 CurrentCluster=GetNextWriteCluster(DeviceExt,0);
209 if (DeviceExt->FatType == FAT32)
210 {
211 Fcb->entry.FirstClusterHigh = CurrentCluster>>16;
212 Fcb->entry.FirstCluster = CurrentCluster;
213 }
214 else
215 Fcb->entry.FirstCluster=CurrentCluster;
216 }
217 else
218 {
219 for (FileOffset=0;
220 FileOffset < WriteOffset / DeviceExt->BytesPerCluster;
221 FileOffset++)
222 {
223 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
224 }
225 }
226 CHECKPOINT;
227 }
228
229 /*
230 * If the offset in the cluster doesn't fall on the cluster boundary
231 * then we have to write only from the specified offset
232 */
233
234 if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
235 {
236 CHECKPOINT;
237 TempLength = min(Length,DeviceExt->BytesPerCluster -
238 (WriteOffset % DeviceExt->BytesPerCluster));
239 /* Read in the existing cluster data */
240 if (FirstCluster==1)
241 {
242 VFATReadSectors(DeviceExt->StorageDevice,
243 CurrentCluster,
244 DeviceExt->Boot->SectorsPerCluster,
245 Temp);
246 }
247 else
248 {
249 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
250 }
251
252 /* Overwrite the last parts of the data as necessary */
253 memcpy(Temp + (WriteOffset % DeviceExt->BytesPerCluster),
254 Buffer,
255 TempLength);
256
257 /* Write the cluster back */
258 if (FirstCluster==1)
259 {
260 VFATWriteSectors(DeviceExt->StorageDevice,
261 CurrentCluster,
262 DeviceExt->Boot->SectorsPerCluster,
263 Temp);
264 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
265 }
266 else
267 {
268 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
269 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
270 }
271 Length2 -= TempLength;
272 Buffer = Buffer + TempLength;
273 }
274 CHECKPOINT;
275
276 /* Write the buffer in chunks of 1 cluster */
277
278 while (Length2 >= DeviceExt->BytesPerCluster)
279 {
280 CHECKPOINT;
281 if (CurrentCluster == 0)
282 {
283 ExFreePool(Temp);
284 return(STATUS_UNSUCCESSFUL);
285 }
286 if (FirstCluster==1)
287 {
288 VFATWriteSectors(DeviceExt->StorageDevice,
289 CurrentCluster,
290 DeviceExt->Boot->SectorsPerCluster,
291 Buffer);
292 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
293 }
294 else
295 {
296 VFATWriteCluster(DeviceExt,Buffer,CurrentCluster);
297 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
298 }
299 Buffer = Buffer + DeviceExt->BytesPerCluster;
300 Length2 -= DeviceExt->BytesPerCluster;
301 }
302 CHECKPOINT;
303
304 /* Write the remainder */
305
306 if (Length2 > 0)
307 {
308 CHECKPOINT;
309 if (CurrentCluster == 0)
310 {
311 ExFreePool(Temp);
312 return(STATUS_UNSUCCESSFUL);
313 }
314 CHECKPOINT;
315 /* Read in the existing cluster data */
316 if (FirstCluster==1)
317 {
318 VFATReadSectors(DeviceExt->StorageDevice,
319 CurrentCluster,
320 DeviceExt->Boot->SectorsPerCluster,
321 Temp);
322 }
323 else
324 {
325 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
326 CHECKPOINT;
327 memcpy(Temp, Buffer, Length2);
328 CHECKPOINT;
329 if (FirstCluster==1)
330 {
331 VFATWriteSectors(DeviceExt->StorageDevice,
332 CurrentCluster,
333 DeviceExt->Boot->SectorsPerCluster,
334 Temp);
335 }
336 else
337 {
338 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
339 }
340 }
341 CHECKPOINT;
342 }
343
344
345 /* set dates and times */
346 KeQuerySystemTime (&SystemTime);
347 ExSystemTimeToLocalTime (&SystemTime,
348 &LocalTime);
349 FsdFileTimeToDosDateTime ((TIME*)&LocalTime,
350 &Fcb->entry.UpdateDate,
351 &Fcb->entry.UpdateTime);
352 Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
353
354 if (Fcb->entry.FileSize < WriteOffset+Length)
355 {
356 Fcb->entry.FileSize = WriteOffset+Length;
357 /*
358 * update entry in directory
359 */
360 updEntry(DeviceExt,FileObject);
361 }
362
363 ExFreePool(Temp);
364 return (STATUS_SUCCESS);
365 }
366
367 NTSTATUS STDCALL FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
368 /*
369 * FUNCTION: Write to a file
370 */
371 {
372 ULONG Length;
373 PVOID Buffer;
374 ULONG Offset;
375 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
376 PFILE_OBJECT FileObject = Stack->FileObject;
377 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
378 NTSTATUS Status;
379
380 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
381
382 Length = Stack->Parameters.Write.Length;
383 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
384 Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
385
386 Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
387
388 Irp->IoStatus.Status = Status;
389 Irp->IoStatus.Information = Length;
390 IoCompleteRequest(Irp,IO_NO_INCREMENT);
391
392 return(Status);
393 }
394
395 NTSTATUS STDCALL FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
396 /*
397 * FUNCTION: Read from a file
398 */
399 {
400 ULONG Length;
401 PVOID Buffer;
402 ULONG Offset;
403 PIO_STACK_LOCATION Stack;
404 PFILE_OBJECT FileObject;
405 PDEVICE_EXTENSION DeviceExt;
406 NTSTATUS Status;
407 ULONG LengthRead;
408 PVFATFCB Fcb;
409
410 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
411
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);
420
421 Length = Stack->Parameters.Read.Length;
422 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
423 Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
424
425 /* fail if file is a directory */
426 Fcb = ((PVFATCCB)(FileObject->FsContext2))->pFcb;
427 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
428 {
429 Status = STATUS_FILE_IS_A_DIRECTORY;
430 }
431 else
432 {
433 Status = FsdReadFile(DeviceExt,
434 FileObject,
435 Buffer,
436 Length,
437 Offset,
438 &LengthRead);
439 }
440
441 Irp->IoStatus.Status = Status;
442 Irp->IoStatus.Information = LengthRead;
443 IoCompleteRequest(Irp,IO_NO_INCREMENT);
444
445 return(Status);
446 }
447
448