Reworked code for handling of asynchonous i/o requests.
[reactos.git] / reactos / drivers / fs / vfat / rw.c
1
2 /* $Id: rw.c,v 1.34 2001/11/02 22:47:36 hbirr Exp $
3 *
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)
9 *
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <wchar.h>
16 #include <ntos/minmax.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 /* GLOBALS *******************************************************************/
24
25 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
26 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
27
28 /* FUNCTIONS *****************************************************************/
29
30 NTSTATUS
31 NextCluster(PDEVICE_EXTENSION DeviceExt,
32 ULONG FirstCluster,
33 PULONG CurrentCluster,
34 BOOLEAN Extend)
35 /*
36 * Return the next cluster in a FAT chain, possibly extending the chain if
37 * necessary
38 */
39 {
40 if (FirstCluster == 1)
41 {
42 (*CurrentCluster) += DeviceExt->Boot->SectorsPerCluster;
43 return(STATUS_SUCCESS);
44 }
45 else
46 /* CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't initialized when 0*/
47 if (FirstCluster == 0)
48 {
49 NTSTATUS Status;
50
51 Status = GetNextCluster(DeviceExt, 0, CurrentCluster,
52 Extend);
53 return(Status);
54 }
55 else
56 {
57 NTSTATUS Status;
58
59 Status = GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster,
60 Extend);
61 return(Status);
62 }
63 }
64
65 NTSTATUS
66 OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
67 ULONG FirstCluster,
68 ULONG FileOffset,
69 PULONG Cluster,
70 BOOLEAN Extend)
71 /*
72 * Return the cluster corresponding to an offset within a file,
73 * possibly extending the file if necessary
74 */
75 {
76 ULONG CurrentCluster;
77 ULONG i;
78 NTSTATUS Status;
79
80 if (FirstCluster == 1)
81 {
82 /* root of FAT16 or FAT12 */
83 *Cluster = DeviceExt->rootStart + FileOffset
84 / (DeviceExt->BytesPerCluster) * DeviceExt->Boot->SectorsPerCluster;
85 return(STATUS_SUCCESS);
86 }
87 else
88 {
89 CurrentCluster = FirstCluster;
90 for (i = 0; i < FileOffset / DeviceExt->BytesPerCluster; i++)
91 {
92 Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster,
93 Extend);
94 if (!NT_SUCCESS(Status))
95 {
96 return(Status);
97 }
98 }
99 *Cluster = CurrentCluster;
100 return(STATUS_SUCCESS);
101 }
102 }
103
104 NTSTATUS
105 VfatReadCluster(PDEVICE_EXTENSION DeviceExt,
106 ULONG FirstCluster,
107 PULONG CurrentCluster,
108 PVOID Destination,
109 ULONG InternalOffset,
110 ULONG InternalLength)
111 {
112 PVOID BaseAddress = NULL;
113 NTSTATUS Status;
114
115 if (InternalLength == DeviceExt->BytesPerCluster)
116 {
117 Status = VfatRawReadCluster(DeviceExt, FirstCluster,
118 Destination, *CurrentCluster, 1);
119 }
120 else
121 {
122 BaseAddress = ExAllocatePool(NonPagedPool, DeviceExt->BytesPerCluster);
123 if (BaseAddress == NULL)
124 {
125 return(STATUS_NO_MEMORY);
126 }
127 Status = VfatRawReadCluster(DeviceExt, FirstCluster,
128 BaseAddress, *CurrentCluster, 1);
129 memcpy(Destination, BaseAddress + InternalOffset, InternalLength);
130 ExFreePool(BaseAddress);
131 }
132 if (!NT_SUCCESS(Status))
133 {
134 return(Status);
135 }
136 Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
137 return(Status);
138 }
139
140 NTSTATUS
141 VfatReadFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
142 PVOID Buffer, ULONG Length, ULONG ReadOffset,
143 PULONG LengthRead, ULONG NoCache)
144 /*
145 * FUNCTION: Reads data from a file
146 */
147 {
148 ULONG CurrentCluster;
149 ULONG FirstCluster;
150 ULONG StartCluster;
151 ULONG ClusterCount;
152 PVFATFCB Fcb;
153 PVFATCCB Ccb;
154 NTSTATUS Status;
155 ULONG TempLength;
156 LARGE_INTEGER FileOffset;
157 IO_STATUS_BLOCK IoStatus;
158
159 /* PRECONDITION */
160 assert (DeviceExt != NULL);
161 assert (DeviceExt->BytesPerCluster != 0);
162 assert (FileObject != NULL);
163 assert (FileObject->FsContext2 != NULL);
164
165 DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
166 "Length %d, ReadOffset 0x%x)\n", DeviceExt, FileObject, Buffer,
167 Length, ReadOffset);
168
169 *LengthRead = 0;
170
171 Ccb = (PVFATCCB)FileObject->FsContext2;
172 Fcb = Ccb->pFcb;
173
174 // Is this a read of the FAT ?
175 if (Fcb->Flags & FCB_IS_FAT)
176 {
177 if (!NoCache)
178 {
179 DbgPrint ("Cached FAT read outside from VFATFS.SYS\n");
180 KeBugCheck (0);
181 }
182 if (ReadOffset >= Fcb->RFCB.FileSize.QuadPart || ReadOffset % BLOCKSIZE != 0 || Length % BLOCKSIZE != 0)
183 {
184 DbgPrint ("Start or end of FAT read is not on a sector boundary\n");
185 KeBugCheck (0);
186 }
187 if (ReadOffset + Length > Fcb->RFCB.FileSize.QuadPart)
188 {
189 Length = Fcb->RFCB.FileSize.QuadPart - ReadOffset;
190 }
191
192 Status = VfatReadSectors(DeviceExt->StorageDevice,
193 DeviceExt->FATStart + ReadOffset / BLOCKSIZE, Length / BLOCKSIZE, Buffer);
194 if (NT_SUCCESS(Status))
195 {
196 *LengthRead = Length;
197 }
198 else
199 {
200 DPRINT1("FAT reading failed, Status %x\n", Status);
201 }
202 return Status;
203 }
204
205 /*
206 * Find the first cluster
207 */
208 FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
209
210 /*
211 * Truncate the read if necessary
212 */
213 if (!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
214 {
215 if (ReadOffset >= Fcb->entry.FileSize)
216 {
217 return (STATUS_END_OF_FILE);
218 }
219 if ((ReadOffset + Length) > Fcb->entry.FileSize)
220 {
221 Length = Fcb->entry.FileSize - ReadOffset;
222 }
223 }
224
225 if (FirstCluster == 1)
226 {
227 // root directory of FAT12 od FAT16
228 if (ReadOffset + Length > DeviceExt->rootDirectorySectors * BLOCKSIZE)
229 {
230 Length = DeviceExt->rootDirectorySectors * BLOCKSIZE - ReadOffset;
231 }
232 }
233
234 // using the Cc-interface if possible
235 if (!NoCache)
236 {
237 FileOffset.QuadPart = ReadOffset;
238 CcCopyRead(FileObject, &FileOffset, Length, TRUE, Buffer, &IoStatus);
239 *LengthRead = IoStatus.Information;
240 return IoStatus.Status;
241 }
242
243 /*
244 * Find the cluster to start the read from
245 */
246 if (Ccb->LastCluster > 0 && ReadOffset > Ccb->LastOffset)
247 {
248 CurrentCluster = Ccb->LastCluster;
249 }
250 Status = OffsetToCluster(DeviceExt,
251 FirstCluster,
252 ROUND_DOWN(ReadOffset, DeviceExt->BytesPerCluster),
253 &CurrentCluster,
254 FALSE);
255 if (!NT_SUCCESS(Status))
256 {
257 return(Status);
258 }
259 /*
260 * If the read doesn't begin on a chunk boundary then we need special
261 * handling
262 */
263 if ((ReadOffset % DeviceExt->BytesPerCluster) != 0 )
264 {
265 TempLength = min (Length, DeviceExt->BytesPerCluster - (ReadOffset % DeviceExt->BytesPerCluster));
266 Ccb->LastCluster = CurrentCluster;
267 Ccb->LastOffset = ROUND_DOWN(ReadOffset, DeviceExt->BytesPerCluster);
268 Status = VfatReadCluster(DeviceExt, FirstCluster, &CurrentCluster, Buffer,
269 ReadOffset % DeviceExt->BytesPerCluster, TempLength);
270 if (NT_SUCCESS(Status))
271 {
272 (*LengthRead) = (*LengthRead) + TempLength;
273 Length = Length - TempLength;
274 Buffer = Buffer + TempLength;
275 ReadOffset = ReadOffset + TempLength;
276 }
277 }
278
279 while (Length >= DeviceExt->BytesPerCluster && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
280 {
281 StartCluster = CurrentCluster;
282 ClusterCount = 0;
283 // search for continous clusters
284 do
285 {
286 ClusterCount++;
287 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
288 }
289 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) &&
290 Length - ClusterCount * DeviceExt->BytesPerCluster >= DeviceExt->BytesPerCluster);
291 DPRINT("Count %d, Start %x Next %x\n", ClusterCount, StartCluster, CurrentCluster);
292 Ccb->LastCluster = StartCluster + (ClusterCount - 1);
293 Ccb->LastOffset = ReadOffset + (ClusterCount - 1) * DeviceExt->BytesPerCluster;
294
295 Status = VfatRawReadCluster(DeviceExt, FirstCluster, Buffer, StartCluster, ClusterCount);
296 if (NT_SUCCESS(Status))
297 {
298 ClusterCount *= DeviceExt->BytesPerCluster;
299 (*LengthRead) = (*LengthRead) + ClusterCount;
300 Buffer += ClusterCount;
301 Length -= ClusterCount;
302 ReadOffset += ClusterCount;
303 }
304 }
305 /*
306 * If the read doesn't end on a chunk boundary then we need special
307 * handling
308 */
309 if (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
310 {
311 Ccb->LastCluster = CurrentCluster;
312 Ccb->LastOffset = ReadOffset + DeviceExt->BytesPerCluster;
313
314 Status = VfatReadCluster(DeviceExt, FirstCluster, &CurrentCluster,
315 Buffer, 0, Length);
316 if (NT_SUCCESS(Status))
317 {
318 (*LengthRead) = (*LengthRead) + Length;
319 }
320 }
321 return Status;
322 }
323
324 NTSTATUS
325 VfatWriteCluster(PDEVICE_EXTENSION DeviceExt,
326 ULONG StartOffset,
327 ULONG FirstCluster,
328 PULONG CurrentCluster,
329 PVOID Source,
330 ULONG InternalOffset,
331 ULONG InternalLength)
332 {
333 PVOID BaseAddress;
334 NTSTATUS Status;
335
336 if (InternalLength != DeviceExt->BytesPerCluster)
337 {
338 BaseAddress = ExAllocatePool(NonPagedPool, DeviceExt->BytesPerCluster);
339 if (BaseAddress == NULL)
340 {
341 return(STATUS_NO_MEMORY);
342 }
343 }
344 else
345 BaseAddress = Source;
346 if (InternalLength != DeviceExt->BytesPerCluster)
347 {
348 /*
349 * If the data in the cache isn't valid or we are bypassing the
350 * cache and not writing a cluster aligned, cluster sized region
351 * then read data in to base address
352 */
353 Status = VfatRawReadCluster(DeviceExt, FirstCluster, BaseAddress,
354 *CurrentCluster, 1);
355 if (!NT_SUCCESS(Status))
356 {
357 if (InternalLength != DeviceExt->BytesPerCluster)
358 {
359 ExFreePool(BaseAddress);
360 }
361 return(Status);
362 }
363 memcpy(BaseAddress + InternalOffset, Source, InternalLength);
364 }
365 /*
366 * Write the data back to disk
367 */
368 DPRINT("Writing 0x%x\n", *CurrentCluster);
369 Status = VfatRawWriteCluster(DeviceExt, FirstCluster, BaseAddress,
370 *CurrentCluster, 1);
371 if (InternalLength != DeviceExt->BytesPerCluster)
372 {
373 ExFreePool(BaseAddress);
374 }
375 if (!NT_SUCCESS(Status))
376 {
377 return Status;
378 }
379 Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
380 return(Status);
381 }
382
383 NTSTATUS
384 VfatWriteFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
385 PVOID Buffer, ULONG Length, ULONG WriteOffset,
386 BOOLEAN NoCache, BOOLEAN PageIo)
387 /*
388 * FUNCTION: Writes data to file
389 */
390 {
391 ULONG CurrentCluster;
392 ULONG FirstCluster;
393 ULONG StartCluster;
394 ULONG Count;
395 PVFATFCB Fcb;
396 PVFATCCB pCcb;
397 ULONG TempLength;
398 LARGE_INTEGER SystemTime, LocalTime;
399 NTSTATUS Status;
400 BOOLEAN Extend;
401 LARGE_INTEGER FileOffset;
402
403 DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
404 "WriteOffset %x\n", FileObject, Buffer, Length, WriteOffset);
405
406 assert (FileObject);
407 pCcb = (PVFATCCB) (FileObject->FsContext2);
408 assert (pCcb);
409 Fcb = pCcb->pFcb;
410 assert (Fcb);
411
412 // DPRINT1("%S\n", Fcb->PathName);
413
414 if (Length == 0)
415 {
416 return STATUS_SUCCESS;
417 }
418
419 // Is this a write to the FAT ?
420 if (Fcb->Flags & FCB_IS_FAT)
421 {
422 if (!NoCache && !PageIo)
423 {
424 DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
425 KeBugCheck (0);
426 }
427 if (WriteOffset >= Fcb->RFCB.FileSize.QuadPart || WriteOffset % BLOCKSIZE != 0 || Length % BLOCKSIZE != 0)
428 {
429 DbgPrint ("Start or end of FAT write is not on a sector boundary\n");
430 KeBugCheck (0);
431 }
432 if (WriteOffset + Length > (ULONG)Fcb->RFCB.FileSize.QuadPart)
433 {
434 Length = (ULONG)Fcb->RFCB.FileSize.QuadPart - WriteOffset;
435 }
436
437 for (Count = 0; Count < DeviceExt->Boot->FATCount; Count++)
438 {
439 Status = VfatWriteSectors(DeviceExt->StorageDevice,
440 DeviceExt->FATStart + (Count * (ULONG)Fcb->RFCB.FileSize.QuadPart + WriteOffset) / BLOCKSIZE,
441 Length / BLOCKSIZE, Buffer);
442 if (!NT_SUCCESS(Status))
443 {
444 DPRINT1("FAT writing failed, Status %x\n", Status);
445 }
446 }
447 return Status;
448 }
449
450 /* Locate the first cluster of the file */
451 FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
452
453 if (PageIo)
454 {
455 if (FirstCluster == 0)
456 {
457 return STATUS_UNSUCCESSFUL;
458 }
459 }
460 else
461 {
462 if (FirstCluster == 1)
463 {
464 // root directory of FAT12 od FAT16
465 if (WriteOffset + Length > DeviceExt->rootDirectorySectors * BLOCKSIZE)
466 {
467 DPRINT("Writing over the end of the root directory on FAT12/16\n");
468 return STATUS_END_OF_FILE;
469 }
470 }
471
472 Status = vfatExtendSpace(DeviceExt, FileObject, WriteOffset + Length);
473 if (!NT_SUCCESS (Status))
474 {
475 return Status;
476 }
477 }
478
479 if (NoCache || PageIo)
480 {
481
482 FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
483 if (pCcb->LastCluster > 0 && WriteOffset > pCcb->LastOffset)
484 {
485 CurrentCluster = pCcb->LastCluster;
486 }
487 Status = OffsetToCluster(DeviceExt,
488 FirstCluster,
489 ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster),
490 &CurrentCluster,
491 FALSE);
492 if (!NT_SUCCESS(Status) || CurrentCluster == 0xffffffff)
493 {
494 DPRINT1("????\n");
495 return(Status);
496 }
497 pCcb->LastCluster = CurrentCluster;
498 pCcb->LastOffset = ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster);
499
500 /*
501 * If the offset in the cluster doesn't fall on the cluster boundary
502 * then we have to write only from the specified offset
503 */
504 Status = STATUS_SUCCESS;
505 if ((WriteOffset % DeviceExt->BytesPerCluster) != 0)
506 {
507 TempLength = min (Length, DeviceExt->BytesPerCluster - (WriteOffset % DeviceExt->BytesPerCluster));
508 Status = VfatWriteCluster(DeviceExt,
509 ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster),
510 FirstCluster,
511 &CurrentCluster,
512 Buffer,
513 WriteOffset % DeviceExt->BytesPerCluster,
514 TempLength);
515 if (NT_SUCCESS(Status))
516 {
517 Buffer = Buffer + TempLength;
518 Length = Length - TempLength;
519 WriteOffset = WriteOffset + TempLength;
520 }
521 }
522
523 while (Length >= DeviceExt->BytesPerCluster && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
524 {
525 StartCluster = CurrentCluster;
526 Count = 0;
527 // search for continous clusters
528 do
529 {
530 Count++;
531 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
532 }
533 while (StartCluster + Count == CurrentCluster && NT_SUCCESS(Status) &&
534 Length - Count * DeviceExt->BytesPerCluster >= DeviceExt->BytesPerCluster);
535
536 pCcb->LastCluster = StartCluster + (Count - 1);
537 pCcb->LastOffset = WriteOffset + (Count - 1) * DeviceExt->BytesPerCluster;
538
539 Status = VfatRawWriteCluster(DeviceExt, FirstCluster, Buffer, StartCluster, Count);
540 if (NT_SUCCESS(Status))
541 {
542 Count *= DeviceExt->BytesPerCluster;
543 Buffer += Count;
544 Length -= Count;
545 WriteOffset += Count;
546 }
547 }
548
549 /* Write the remainder */
550 if (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
551 {
552 Status = VfatWriteCluster(DeviceExt,
553 WriteOffset,
554 FirstCluster,
555 &CurrentCluster,
556 Buffer,
557 0,
558 Length);
559 if (NT_SUCCESS(Status))
560 {
561 Length = 0;
562 }
563 }
564 if (NT_SUCCESS(Status) && Length)
565 {
566 if (WriteOffset < Fcb->RFCB.AllocationSize.QuadPart)
567 {
568 DPRINT1("%d %d\n", WriteOffset, (ULONG)Fcb->RFCB.AllocationSize.QuadPart);
569 Status = STATUS_DISK_FULL; // ???????????
570 }
571 }
572 }
573 else
574 {
575 // using the Cc-interface if possible
576 FileOffset.QuadPart = WriteOffset;
577 if(CcCopyWrite(FileObject, &FileOffset, Length, TRUE, Buffer))
578 {
579 Status = STATUS_SUCCESS;
580 }
581 else
582 {
583 Status = STATUS_UNSUCCESSFUL;
584 }
585 }
586
587
588 if (!PageIo)
589 {
590 if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
591 {
592 /* set dates and times */
593 KeQuerySystemTime (&SystemTime);
594 ExSystemTimeToLocalTime (&SystemTime, &LocalTime);
595 FsdFileTimeToDosDateTime ((TIME*)&LocalTime,
596 &Fcb->entry.UpdateDate,
597 &Fcb->entry.UpdateTime);
598 Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
599 // update dates/times and length
600 updEntry (DeviceExt, FileObject);
601 }
602 }
603
604 return Status;
605 }
606
607 NTSTATUS vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt, PFILE_OBJECT pFileObject, ULONG NewSize)
608 {
609 ULONG FirstCluster;
610 ULONG CurrentCluster;
611 ULONG NewCluster;
612 NTSTATUS Status;
613 PVFATFCB pFcb;
614
615
616 pFcb = ((PVFATCCB) (pFileObject->FsContext2))->pFcb;
617
618 DPRINT ("New Size %d, AllocationSize %d, BytesPerCluster %d\n", NewSize,
619 (ULONG)pFcb->RFCB.AllocationSize.QuadPart, pDeviceExt->BytesPerCluster);
620
621 FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (pDeviceExt, &pFcb->entry);
622
623 if (NewSize > pFcb->RFCB.AllocationSize.QuadPart || FirstCluster==0)
624 {
625 // size on disk must be extended
626 if (FirstCluster == 0)
627 {
628 // file of size zero
629 Status = NextCluster (pDeviceExt, FirstCluster, &CurrentCluster, TRUE);
630 if (!NT_SUCCESS(Status))
631 {
632 DPRINT1("NextCluster failed, Status %x\n", Status);
633 return Status;
634 }
635 NewCluster = FirstCluster = CurrentCluster;
636 }
637 else
638 {
639 Status = OffsetToCluster(pDeviceExt, FirstCluster,
640 pFcb->RFCB.AllocationSize.QuadPart - pDeviceExt->BytesPerCluster,
641 &CurrentCluster, FALSE);
642 if (!NT_SUCCESS(Status))
643 {
644 DPRINT1("OffsetToCluster failed, Status %x\n", Status);
645 return Status;
646 }
647 if (CurrentCluster == 0xffffffff)
648 {
649 DPRINT1("Not enough disk space.\n");
650 return STATUS_DISK_FULL;
651 }
652 // CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
653 NewCluster = CurrentCluster;
654 Status = NextCluster(pDeviceExt, FirstCluster, &NewCluster, FALSE);
655 if (NewCluster != 0xffffffff)
656 {
657 DPRINT1("Difference between size from direntry and the FAT.\n");
658 }
659 }
660
661 Status = OffsetToCluster(pDeviceExt, FirstCluster,
662 ROUND_DOWN(NewSize-1, pDeviceExt->BytesPerCluster),
663 &NewCluster, TRUE);
664 if (!NT_SUCCESS(Status) || NewCluster == 0xffffffff)
665 {
666 DPRINT1("Not enough free space on disk\n");
667 if (pFcb->RFCB.AllocationSize.QuadPart > 0)
668 {
669 NewCluster = CurrentCluster;
670 // FIXME: check status
671 NextCluster(pDeviceExt, FirstCluster, &NewCluster, FALSE);
672 WriteCluster(pDeviceExt, CurrentCluster, 0xffffffff);
673 }
674 // free the allocated space
675 while (NewCluster != 0xffffffff)
676 {
677 CurrentCluster = NewCluster;
678 // FIXME: check status
679 NextCluster (pDeviceExt, FirstCluster, &NewCluster, FALSE);
680 WriteCluster (pDeviceExt, CurrentCluster, 0);
681 }
682 return STATUS_DISK_FULL;
683 }
684 if (pFcb->RFCB.AllocationSize.QuadPart == 0)
685 {
686 pFcb->entry.FirstCluster = FirstCluster;
687 if(pDeviceExt->FatType == FAT32)
688 pFcb->entry.FirstClusterHigh = FirstCluster >> 16;
689 }
690 pFcb->RFCB.AllocationSize.QuadPart = ROUND_UP(NewSize, pDeviceExt->BytesPerCluster);
691 if (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
692 {
693 pFcb->RFCB.FileSize.QuadPart = pFcb->RFCB.AllocationSize.QuadPart;
694 pFcb->RFCB.ValidDataLength.QuadPart = pFcb->RFCB.AllocationSize.QuadPart;
695 }
696 else
697 {
698 pFcb->entry.FileSize = NewSize;
699 pFcb->RFCB.FileSize.QuadPart = NewSize;
700 pFcb->RFCB.ValidDataLength.QuadPart = NewSize;
701 }
702 CcSetFileSizes(pFileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
703 }
704 else
705 {
706 if (NewSize > pFcb->RFCB.FileSize.QuadPart)
707 {
708 // size on disk must not be extended
709 if (!(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
710 {
711 pFcb->entry.FileSize = NewSize;
712 pFcb->RFCB.FileSize.QuadPart = NewSize;
713 CcSetFileSizes(pFileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
714 }
715 }
716 else
717 {
718 // nothing to do
719 }
720 }
721 return STATUS_SUCCESS;
722 }
723
724 NTSTATUS VfatRead(PVFAT_IRP_CONTEXT IrpContext)
725 {
726 PVFATFCB Fcb;
727 PVFATCCB Ccb;
728 NTSTATUS Status = STATUS_SUCCESS;
729 ULONG ReadLength;
730 ULONG ReturnedReadLength = 0;
731 LARGE_INTEGER ReadOffset;
732 PVOID Buffer;
733
734 DPRINT ("VfatRead(IrpContext %x)\n", IrpContext);
735 assert (IrpContext);
736 Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
737 assert (Ccb);
738 Fcb = Ccb->pFcb;
739 assert (Fcb);
740
741 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
742 {
743 if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
744 {
745 return VfatQueueRequest (IrpContext);
746 }
747 }
748 else
749 {
750 if (!ExAcquireResourceSharedLite(&Fcb->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
751 {
752 return VfatQueueRequest (IrpContext);
753 }
754 }
755
756 ReadLength = IrpContext->Stack->Parameters.Read.Length;
757 ReadOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
758 Buffer = MmGetSystemAddressForMdl (IrpContext->Irp->MdlAddress);
759
760 /* fail if file is a directory and no paged read */
761 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
762 {
763 Status = STATUS_FILE_IS_A_DIRECTORY;
764 }
765 else
766 {
767 Status = VfatReadFile (IrpContext->DeviceExt, IrpContext->FileObject,
768 Buffer, ReadLength, ReadOffset.u.LowPart, &ReturnedReadLength,
769 IrpContext->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING
770 || IrpContext->Irp->Flags & IRP_PAGING_IO);
771 }
772
773 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
774 {
775 ExReleaseResourceLite(&Fcb->PagingIoResource);
776 }
777 else
778 {
779 ExReleaseResourceLite(&Fcb->MainResource);
780 }
781
782 if (NT_SUCCESS(Status))
783 {
784 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
785 {
786 IrpContext->FileObject->CurrentByteOffset.QuadPart = ReadOffset.QuadPart + ReturnedReadLength;
787 }
788 IrpContext->Irp->IoStatus.Information = ReturnedReadLength;
789 }
790 else
791 {
792 IrpContext->Irp->IoStatus.Information = 0;
793 }
794
795 IrpContext->Irp->IoStatus.Status = Status;
796 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
797 VfatFreeIrpContext (IrpContext);
798
799 return Status;
800 }
801
802 NTSTATUS VfatWrite(PVFAT_IRP_CONTEXT IrpContext)
803 {
804 PVFATFCB Fcb;
805 PVFATCCB Ccb;
806 NTSTATUS Status = STATUS_SUCCESS;
807 ULONG WriteLength;
808 LARGE_INTEGER WriteOffset;
809 PVOID Buffer;
810
811 DPRINT ("VfatWrite(), %S\n", ((PVFATCCB) IrpContext->FileObject->FsContext2)->pFcb->FileName);
812 assert (IrpContext);
813 Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
814 assert (Ccb);
815 Fcb = Ccb->pFcb;
816 assert (Fcb);
817
818 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
819 {
820 if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
821 {
822 return VfatQueueRequest (IrpContext);
823 }
824 }
825 else
826 {
827 if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
828 {
829 return VfatQueueRequest (IrpContext);
830 }
831 }
832
833 WriteLength = IrpContext->Stack->Parameters.Write.Length;
834 WriteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
835 Buffer = MmGetSystemAddressForMdl (IrpContext->Irp->MdlAddress);
836
837 /* fail if file is a directory and no paged read */
838 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
839 {
840 Status = STATUS_FILE_IS_A_DIRECTORY;
841 }
842 else
843 {
844 Status = VfatWriteFile (IrpContext->DeviceExt, IrpContext->FileObject,
845 Buffer, WriteLength, WriteOffset.u.LowPart,
846 IrpContext->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING,
847 IrpContext->Irp->Flags & IRP_PAGING_IO);
848 }
849
850 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
851 {
852 ExReleaseResourceLite(&Fcb->PagingIoResource);
853 }
854 else
855 {
856 ExReleaseResourceLite(&Fcb->MainResource);
857 }
858
859 if (NT_SUCCESS(Status))
860 {
861 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
862 {
863 IrpContext->FileObject->CurrentByteOffset.QuadPart = WriteOffset.QuadPart + WriteLength;
864 }
865 IrpContext->Irp->IoStatus.Information = WriteLength;
866 }
867 else
868 {
869 IrpContext->Irp->IoStatus.Information = 0;
870 }
871
872 IrpContext->Irp->IoStatus.Status = Status;
873 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
874 VfatFreeIrpContext (IrpContext);
875 return Status;
876 }
877
878