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