2 /* $Id: rw.c,v 1.36 2002/01/15 21:54:51 hbirr Exp $
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)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <ntos/minmax.h>
23 /* GLOBALS *******************************************************************/
25 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
26 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
28 /* FUNCTIONS *****************************************************************/
31 NextCluster(PDEVICE_EXTENSION DeviceExt
,
34 PULONG CurrentCluster
,
37 * Return the next cluster in a FAT chain, possibly extending the chain if
41 if (Fcb
!= NULL
&& Fcb
->Flags
& FCB_IS_PAGE_FILE
)
46 DPRINT("NextCluster(Fcb %x, FirstCluster %x, Extend %d)\n", Fcb
, FirstCluster
, Extend
);
47 if (Fcb
->FatChainSize
== 0)
49 // paging file with zero length
50 *CurrentCluster
= 0xffffffff;
53 Fcb
->FatChain
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
));
56 return STATUS_UNSUCCESSFUL
;
58 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
, TRUE
);
59 if (!NT_SUCCESS(Status
))
61 ExFreePool(Fcb
->FatChain
);
64 Fcb
->FatChain
[0] = *CurrentCluster
;
65 Fcb
->FatChainSize
= 1;
70 return STATUS_UNSUCCESSFUL
;
75 for (i
= 0; i
< Fcb
->FatChainSize
; i
++)
77 if (Fcb
->FatChain
[i
] == *CurrentCluster
)
80 if (i
>= Fcb
->FatChainSize
)
82 return STATUS_UNSUCCESSFUL
;
84 if (i
== Fcb
->FatChainSize
- 1)
88 FatChain
= ExAllocatePool(NonPagedPool
, (i
+ 2) * sizeof(ULONG
));
91 *CurrentCluster
= 0xffffffff;
92 return STATUS_UNSUCCESSFUL
;
94 Status
= GetNextCluster(DeviceExt
, *CurrentCluster
, CurrentCluster
, TRUE
);
95 if (NT_SUCCESS(Status
) && *CurrentCluster
!= 0xffffffff)
97 memcpy(FatChain
, Fcb
->FatChain
, (i
+ 1) * sizeof(ULONG
));
98 FatChain
[i
+ 1] = *CurrentCluster
;
99 ExFreePool(Fcb
->FatChain
);
100 Fcb
->FatChain
= FatChain
;
101 Fcb
->FatChainSize
= i
+ 2;
104 ExFreePool(FatChain
);
109 *CurrentCluster
= 0xffffffff;
110 return STATUS_UNSUCCESSFUL
;
113 *CurrentCluster
= Fcb
->FatChain
[i
+ 1];
114 return STATUS_SUCCESS
;
117 if (FirstCluster
== 1)
119 (*CurrentCluster
) += DeviceExt
->Boot
->SectorsPerCluster
;
120 return(STATUS_SUCCESS
);
125 * CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't
128 if (FirstCluster
== 0)
132 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
,
140 Status
= GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
,
148 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
155 * Return the cluster corresponding to an offset within a file,
156 * possibly extending the file if necessary
159 ULONG CurrentCluster
;
162 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
163 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt
,
164 Fcb
, FirstCluster
, FileOffset
, Cluster
, Extend
);
165 if (FirstCluster
== 0)
167 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
171 if (Fcb
!= NULL
&& Fcb
->Flags
& FCB_IS_PAGE_FILE
)
174 ULONG Offset
= FileOffset
/ DeviceExt
->BytesPerCluster
;
177 if (Fcb
->FatChainSize
== 0)
179 DbgPrint("OffsetToCluster is called with FirstCluster = %x"
180 " and Fcb->FatChainSize = 0!\n", FirstCluster
);
183 if (Offset
< Fcb
->FatChainSize
)
185 *Cluster
= Fcb
->FatChain
[Offset
];
186 return STATUS_SUCCESS
;
192 *Cluster
= 0xffffffff;
193 return STATUS_UNSUCCESSFUL
;
197 FatChain
= ExAllocatePool(NonPagedPool
, (Offset
+ 1) * sizeof(ULONG
));
200 *Cluster
= 0xffffffff;
201 return STATUS_UNSUCCESSFUL
;
204 CurrentCluster
= Fcb
->FatChain
[Fcb
->FatChainSize
- 1];
205 FatChain
[Fcb
->FatChainSize
- 1] = CurrentCluster
;
206 for (i
= Fcb
->FatChainSize
; i
< Offset
+ 1; i
++)
208 Status
= GetNextCluster(DeviceExt
, CurrentCluster
, &CurrentCluster
, TRUE
);
209 if (!NT_SUCCESS(Status
) || CurrentCluster
== 0xFFFFFFFF)
211 while (i
>= Fcb
->FatChainSize
)
213 WriteCluster(DeviceExt
, FatChain
[i
- 1], 0xFFFFFFFF);
216 *Cluster
= 0xffffffff;
217 ExFreePool(FatChain
);
218 if (!NT_SUCCESS(Status
))
220 return STATUS_UNSUCCESSFUL
;
222 FatChain
[i
] = CurrentCluster
;
224 memcpy (FatChain
, Fcb
->FatChain
, Fcb
->FatChainSize
* sizeof(ULONG
));
225 ExFreePool(Fcb
->FatChain
);
226 Fcb
->FatChain
= FatChain
;
227 Fcb
->FatChainSize
= Offset
+ 1;
230 *Cluster
= CurrentCluster
;
231 return(STATUS_SUCCESS
);
233 if (FirstCluster
== 1)
235 /* root of FAT16 or FAT12 */
236 *Cluster
= DeviceExt
->rootStart
+ FileOffset
237 / (DeviceExt
->BytesPerCluster
) * DeviceExt
->Boot
->SectorsPerCluster
;
238 return(STATUS_SUCCESS
);
242 CurrentCluster
= FirstCluster
;
243 for (i
= 0; i
< FileOffset
/ DeviceExt
->BytesPerCluster
; i
++)
245 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
,
247 if (!NT_SUCCESS(Status
))
252 *Cluster
= CurrentCluster
;
253 return(STATUS_SUCCESS
);
258 VfatReadCluster(PDEVICE_EXTENSION DeviceExt
,
261 PULONG CurrentCluster
,
263 ULONG InternalOffset
,
264 ULONG InternalLength
)
266 PVOID BaseAddress
= NULL
;
269 if (InternalLength
== DeviceExt
->BytesPerCluster
)
271 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
272 Destination
, *CurrentCluster
, 1);
276 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
277 if (BaseAddress
== NULL
)
279 return(STATUS_NO_MEMORY
);
281 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
282 BaseAddress
, *CurrentCluster
, 1);
283 memcpy(Destination
, BaseAddress
+ InternalOffset
, InternalLength
);
284 ExFreePool(BaseAddress
);
286 if (!NT_SUCCESS(Status
))
290 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, CurrentCluster
, FALSE
);
295 VfatReadFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
296 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
297 PULONG LengthRead
, ULONG NoCache
)
299 * FUNCTION: Reads data from a file
302 ULONG CurrentCluster
;
310 LARGE_INTEGER FileOffset
;
311 IO_STATUS_BLOCK IoStatus
;
314 assert (DeviceExt
!= NULL
);
315 assert (DeviceExt
->BytesPerCluster
!= 0);
316 assert (FileObject
!= NULL
);
317 assert (FileObject
->FsContext2
!= NULL
);
319 DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
320 "Length %d, ReadOffset 0x%x)\n", DeviceExt
, FileObject
, Buffer
,
325 Ccb
= (PVFATCCB
)FileObject
->FsContext2
;
328 // Is this a read of the FAT ?
329 if (Fcb
->Flags
& FCB_IS_FAT
)
333 DbgPrint ("Cached FAT read outside from VFATFS.SYS\n");
336 if (ReadOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| ReadOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
338 DbgPrint ("Start or end of FAT read is not on a sector boundary\n");
341 if (ReadOffset
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
343 Length
= Fcb
->RFCB
.FileSize
.QuadPart
- ReadOffset
;
346 Status
= VfatReadSectors(DeviceExt
->StorageDevice
,
347 DeviceExt
->FATStart
+ ReadOffset
/ BLOCKSIZE
, Length
/ BLOCKSIZE
, Buffer
);
348 if (NT_SUCCESS(Status
))
350 *LengthRead
= Length
;
354 DPRINT1("FAT reading failed, Status %x\n", Status
);
360 * Find the first cluster
362 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
365 * Truncate the read if necessary
367 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
369 if (ReadOffset
>= Fcb
->entry
.FileSize
)
371 return (STATUS_END_OF_FILE
);
373 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
375 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
379 if (FirstCluster
== 1)
381 // root directory of FAT12 od FAT16
382 if (ReadOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
384 Length
= DeviceExt
->rootDirectorySectors
* BLOCKSIZE
- ReadOffset
;
388 // using the Cc-interface if possible
391 FileOffset
.QuadPart
= ReadOffset
;
392 CcCopyRead(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
, &IoStatus
);
393 *LengthRead
= IoStatus
.Information
;
394 return IoStatus
.Status
;
398 * Find the cluster to start the read from
400 if (Ccb
->LastCluster
> 0 && ReadOffset
> Ccb
->LastOffset
)
402 CurrentCluster
= Ccb
->LastCluster
;
404 Status
= OffsetToCluster(DeviceExt
,
407 ROUND_DOWN(ReadOffset
, DeviceExt
->BytesPerCluster
),
410 if (!NT_SUCCESS(Status
))
415 * If the read doesn't begin on a chunk boundary then we need special
418 if ((ReadOffset
% DeviceExt
->BytesPerCluster
) != 0 )
420 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
- (ReadOffset
% DeviceExt
->BytesPerCluster
));
421 Ccb
->LastCluster
= CurrentCluster
;
422 Ccb
->LastOffset
= ROUND_DOWN(ReadOffset
, DeviceExt
->BytesPerCluster
);
423 Status
= VfatReadCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
424 Buffer
, ReadOffset
% DeviceExt
->BytesPerCluster
,
426 if (NT_SUCCESS(Status
))
428 (*LengthRead
) = (*LengthRead
) + TempLength
;
429 Length
= Length
- TempLength
;
430 Buffer
= Buffer
+ TempLength
;
431 ReadOffset
= ReadOffset
+ TempLength
;
435 while (Length
>= DeviceExt
->BytesPerCluster
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
437 StartCluster
= CurrentCluster
;
439 // search for continous clusters
443 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
445 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) &&
446 Length
- ClusterCount
* DeviceExt
->BytesPerCluster
>= DeviceExt
->BytesPerCluster
);
447 DPRINT("Count %d, Start %x Next %x\n", ClusterCount
, StartCluster
, CurrentCluster
);
448 Ccb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
449 Ccb
->LastOffset
= ReadOffset
+ (ClusterCount
- 1) * DeviceExt
->BytesPerCluster
;
451 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, ClusterCount
);
452 if (NT_SUCCESS(Status
))
454 ClusterCount
*= DeviceExt
->BytesPerCluster
;
455 (*LengthRead
) = (*LengthRead
) + ClusterCount
;
456 Buffer
+= ClusterCount
;
457 Length
-= ClusterCount
;
458 ReadOffset
+= ClusterCount
;
462 * If the read doesn't end on a chunk boundary then we need special
465 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
467 Ccb
->LastCluster
= CurrentCluster
;
468 Ccb
->LastOffset
= ReadOffset
+ DeviceExt
->BytesPerCluster
;
470 Status
= VfatReadCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
472 if (NT_SUCCESS(Status
))
474 (*LengthRead
) = (*LengthRead
) + Length
;
481 VfatWriteCluster(PDEVICE_EXTENSION DeviceExt
,
485 PULONG CurrentCluster
,
487 ULONG InternalOffset
,
488 ULONG InternalLength
)
493 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
495 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
496 if (BaseAddress
== NULL
)
498 return(STATUS_NO_MEMORY
);
502 BaseAddress
= Source
;
503 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
506 * If the data in the cache isn't valid or we are bypassing the
507 * cache and not writing a cluster aligned, cluster sized region
508 * then read data in to base address
510 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, BaseAddress
,
512 if (!NT_SUCCESS(Status
))
514 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
516 ExFreePool(BaseAddress
);
520 memcpy(BaseAddress
+ InternalOffset
, Source
, InternalLength
);
523 * Write the data back to disk
525 DPRINT("Writing 0x%x\n", *CurrentCluster
);
526 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, BaseAddress
,
528 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
530 ExFreePool(BaseAddress
);
532 if (!NT_SUCCESS(Status
))
536 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, CurrentCluster
, FALSE
);
541 VfatWriteFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
542 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
,
543 BOOLEAN NoCache
, BOOLEAN PageIo
)
545 * FUNCTION: Writes data to file
548 ULONG CurrentCluster
;
555 LARGE_INTEGER SystemTime
, LocalTime
;
558 LARGE_INTEGER FileOffset
;
560 DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
561 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
564 pCcb
= (PVFATCCB
) (FileObject
->FsContext2
);
569 // DPRINT1("%S\n", Fcb->PathName);
573 return STATUS_SUCCESS
;
576 // Is this a write to the FAT ?
577 if (Fcb
->Flags
& FCB_IS_FAT
)
579 if (!NoCache
&& !PageIo
)
581 DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
584 if (WriteOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| WriteOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
586 DbgPrint ("Start or end of FAT write is not on a sector boundary\n");
589 if (WriteOffset
+ Length
> (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
)
591 Length
= (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
- WriteOffset
;
594 for (Count
= 0; Count
< DeviceExt
->Boot
->FATCount
; Count
++)
596 Status
= VfatWriteSectors(DeviceExt
->StorageDevice
,
597 DeviceExt
->FATStart
+ (Count
* (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
+ WriteOffset
) / BLOCKSIZE
,
598 Length
/ BLOCKSIZE
, Buffer
);
599 if (!NT_SUCCESS(Status
))
601 DPRINT1("FAT writing failed, Status %x\n", Status
);
607 /* Locate the first cluster of the file */
608 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
612 if (FirstCluster
== 0)
614 return STATUS_UNSUCCESSFUL
;
619 if (FirstCluster
== 1)
621 // root directory of FAT12 od FAT16
622 if (WriteOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
624 DPRINT("Writing over the end of the root directory on FAT12/16\n");
625 return STATUS_END_OF_FILE
;
629 Status
= vfatExtendSpace(DeviceExt
, FileObject
, WriteOffset
+ Length
);
630 if (!NT_SUCCESS (Status
))
636 if (NoCache
|| PageIo
)
639 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
640 if (pCcb
->LastCluster
> 0 && WriteOffset
> pCcb
->LastOffset
)
642 CurrentCluster
= pCcb
->LastCluster
;
644 Status
= OffsetToCluster(DeviceExt
,
647 ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
),
650 if (!NT_SUCCESS(Status
) || CurrentCluster
== 0xffffffff)
655 pCcb
->LastCluster
= CurrentCluster
;
656 pCcb
->LastOffset
= ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
);
659 * If the offset in the cluster doesn't fall on the cluster boundary
660 * then we have to write only from the specified offset
662 Status
= STATUS_SUCCESS
;
663 if ((WriteOffset
% DeviceExt
->BytesPerCluster
) != 0)
665 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
- (WriteOffset
% DeviceExt
->BytesPerCluster
));
666 Status
= VfatWriteCluster(DeviceExt
,
668 ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
),
672 WriteOffset
% DeviceExt
->BytesPerCluster
,
674 if (NT_SUCCESS(Status
))
676 Buffer
= Buffer
+ TempLength
;
677 Length
= Length
- TempLength
;
678 WriteOffset
= WriteOffset
+ TempLength
;
682 while (Length
>= DeviceExt
->BytesPerCluster
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
684 StartCluster
= CurrentCluster
;
686 // search for continous clusters
690 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
692 while (StartCluster
+ Count
== CurrentCluster
&& NT_SUCCESS(Status
) &&
693 Length
- Count
* DeviceExt
->BytesPerCluster
>= DeviceExt
->BytesPerCluster
);
695 pCcb
->LastCluster
= StartCluster
+ (Count
- 1);
696 pCcb
->LastOffset
= WriteOffset
+ (Count
- 1) * DeviceExt
->BytesPerCluster
;
698 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, Count
);
699 if (NT_SUCCESS(Status
))
701 Count
*= DeviceExt
->BytesPerCluster
;
704 WriteOffset
+= Count
;
708 /* Write the remainder */
709 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
711 Status
= VfatWriteCluster(DeviceExt
,
719 if (NT_SUCCESS(Status
))
724 if (NT_SUCCESS(Status
) && Length
)
726 if (WriteOffset
< Fcb
->RFCB
.AllocationSize
.QuadPart
)
728 DPRINT1("%d %d\n", WriteOffset
, (ULONG
)Fcb
->RFCB
.AllocationSize
.QuadPart
);
729 Status
= STATUS_DISK_FULL
; // ???????????
735 // using the Cc-interface if possible
736 FileOffset
.QuadPart
= WriteOffset
;
737 if(CcCopyWrite(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
))
739 Status
= STATUS_SUCCESS
;
743 Status
= STATUS_UNSUCCESSFUL
;
750 if(!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
752 /* set dates and times */
753 KeQuerySystemTime (&SystemTime
);
754 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
755 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
,
756 &Fcb
->entry
.UpdateDate
,
757 &Fcb
->entry
.UpdateTime
);
758 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
759 // update dates/times and length
760 updEntry (DeviceExt
, FileObject
);
767 NTSTATUS
vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt
, PFILE_OBJECT pFileObject
, ULONG NewSize
)
770 ULONG CurrentCluster
;
776 pFcb
= ((PVFATCCB
) (pFileObject
->FsContext2
))->pFcb
;
778 DPRINT ("New Size %d, AllocationSize %d, BytesPerCluster %d\n", NewSize
,
779 (ULONG
)pFcb
->RFCB
.AllocationSize
.QuadPart
, pDeviceExt
->BytesPerCluster
);
781 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (pDeviceExt
, &pFcb
->entry
);
783 if (NewSize
> pFcb
->RFCB
.AllocationSize
.QuadPart
|| FirstCluster
==0)
785 // size on disk must be extended
786 if (FirstCluster
== 0)
789 Status
= NextCluster (pDeviceExt
, pFcb
, FirstCluster
, &CurrentCluster
, TRUE
);
790 if (!NT_SUCCESS(Status
))
792 DPRINT1("NextCluster failed, Status %x\n", Status
);
795 NewCluster
= FirstCluster
= CurrentCluster
;
799 Status
= OffsetToCluster(pDeviceExt
, pFcb
, FirstCluster
,
800 pFcb
->RFCB
.AllocationSize
.QuadPart
- pDeviceExt
->BytesPerCluster
,
801 &CurrentCluster
, FALSE
);
802 if (!NT_SUCCESS(Status
))
804 DPRINT1("OffsetToCluster failed, Status %x\n", Status
);
807 if (CurrentCluster
== 0xffffffff)
809 DPRINT1("Not enough disk space.\n");
810 return STATUS_DISK_FULL
;
812 // CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
813 NewCluster
= CurrentCluster
;
814 Status
= NextCluster(pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
815 if (NewCluster
!= 0xffffffff)
817 DPRINT1("Difference between size from direntry and the FAT.\n");
821 Status
= OffsetToCluster(pDeviceExt
, pFcb
, FirstCluster
,
822 ROUND_DOWN(NewSize
-1, pDeviceExt
->BytesPerCluster
),
824 if (!NT_SUCCESS(Status
) || NewCluster
== 0xffffffff)
826 DPRINT1("Not enough free space on disk\n");
827 if (pFcb
->RFCB
.AllocationSize
.QuadPart
> 0)
829 NewCluster
= CurrentCluster
;
830 // FIXME: check status
831 NextCluster(pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
832 WriteCluster(pDeviceExt
, CurrentCluster
, 0xffffffff);
834 // free the allocated space
835 while (NewCluster
!= 0xffffffff)
837 CurrentCluster
= NewCluster
;
838 // FIXME: check status
839 NextCluster (pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
840 WriteCluster (pDeviceExt
, CurrentCluster
, 0);
842 return STATUS_DISK_FULL
;
844 if (pFcb
->RFCB
.AllocationSize
.QuadPart
== 0)
846 pFcb
->entry
.FirstCluster
= FirstCluster
;
847 if(pDeviceExt
->FatType
== FAT32
)
848 pFcb
->entry
.FirstClusterHigh
= FirstCluster
>> 16;
850 pFcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(NewSize
, pDeviceExt
->BytesPerCluster
);
851 if (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
853 pFcb
->RFCB
.FileSize
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
854 pFcb
->RFCB
.ValidDataLength
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
858 pFcb
->entry
.FileSize
= NewSize
;
859 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
860 pFcb
->RFCB
.ValidDataLength
.QuadPart
= NewSize
;
862 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
866 if (NewSize
> pFcb
->RFCB
.FileSize
.QuadPart
)
868 // size on disk must not be extended
869 if (!(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
871 pFcb
->entry
.FileSize
= NewSize
;
872 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
873 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
881 return STATUS_SUCCESS
;
884 NTSTATUS
VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
888 NTSTATUS Status
= STATUS_SUCCESS
;
890 ULONG ReturnedReadLength
= 0;
891 LARGE_INTEGER ReadOffset
;
894 DPRINT ("VfatRead(IrpContext %x)\n", IrpContext
);
896 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
901 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
903 if (!ExAcquireResourceSharedLite(&Fcb
->PagingIoResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
905 return VfatQueueRequest (IrpContext
);
910 if (!ExAcquireResourceSharedLite(&Fcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
912 return VfatQueueRequest (IrpContext
);
916 ReadLength
= IrpContext
->Stack
->Parameters
.Read
.Length
;
917 ReadOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
918 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
920 /* fail if file is a directory and no paged read */
921 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
923 Status
= STATUS_FILE_IS_A_DIRECTORY
;
927 Status
= VfatReadFile (IrpContext
->DeviceExt
, IrpContext
->FileObject
,
928 Buffer
, ReadLength
, ReadOffset
.u
.LowPart
, &ReturnedReadLength
,
929 IrpContext
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
930 || IrpContext
->Irp
->Flags
& IRP_PAGING_IO
);
933 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
935 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
939 ExReleaseResourceLite(&Fcb
->MainResource
);
942 if (NT_SUCCESS(Status
))
944 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
946 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
= ReadOffset
.QuadPart
+ ReturnedReadLength
;
948 IrpContext
->Irp
->IoStatus
.Information
= ReturnedReadLength
;
952 IrpContext
->Irp
->IoStatus
.Information
= 0;
955 IrpContext
->Irp
->IoStatus
.Status
= Status
;
956 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
957 VfatFreeIrpContext (IrpContext
);
962 NTSTATUS
VfatWrite(PVFAT_IRP_CONTEXT IrpContext
)
966 NTSTATUS Status
= STATUS_SUCCESS
;
968 LARGE_INTEGER WriteOffset
;
971 DPRINT ("VfatWrite(), %S\n", ((PVFATCCB
) IrpContext
->FileObject
->FsContext2
)->pFcb
->FileName
);
973 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
978 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
980 if (!ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
982 return VfatQueueRequest (IrpContext
);
987 if (!ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
989 return VfatQueueRequest (IrpContext
);
993 WriteLength
= IrpContext
->Stack
->Parameters
.Write
.Length
;
994 WriteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
995 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
997 /* fail if file is a directory and no paged read */
998 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
1000 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1004 Status
= VfatWriteFile (IrpContext
->DeviceExt
, IrpContext
->FileObject
,
1005 Buffer
, WriteLength
, WriteOffset
.u
.LowPart
,
1006 IrpContext
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
,
1007 IrpContext
->Irp
->Flags
& IRP_PAGING_IO
);
1010 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
1012 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1016 ExReleaseResourceLite(&Fcb
->MainResource
);
1019 if (NT_SUCCESS(Status
))
1021 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
1023 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
= WriteOffset
.QuadPart
+ WriteLength
;
1025 IrpContext
->Irp
->IoStatus
.Information
= WriteLength
;
1029 IrpContext
->Irp
->IoStatus
.Information
= 0;
1032 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1033 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
1034 VfatFreeIrpContext (IrpContext
);