2 /* $Id: rw.c,v 1.39 2002/03/18 22:37:13 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
,
47 FirstCluster
, Extend
);
48 if (Fcb
->FatChainSize
== 0)
50 /* Paging file with zero length. */
51 *CurrentCluster
= 0xffffffff;
54 Fcb
->FatChain
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
));
57 return STATUS_NO_MEMORY
;
59 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
, TRUE
);
60 if (!NT_SUCCESS(Status
))
62 ExFreePool(Fcb
->FatChain
);
65 Fcb
->FatChain
[0] = *CurrentCluster
;
66 Fcb
->FatChainSize
= 1;
71 return STATUS_UNSUCCESSFUL
;
76 for (i
= 0; i
< Fcb
->FatChainSize
; i
++)
78 if (Fcb
->FatChain
[i
] == *CurrentCluster
)
81 if (i
>= Fcb
->FatChainSize
)
83 return STATUS_UNSUCCESSFUL
;
85 if (i
== Fcb
->FatChainSize
- 1)
89 FatChain
= ExAllocatePool(NonPagedPool
,
90 (i
+ 2) * sizeof(ULONG
));
93 *CurrentCluster
= 0xffffffff;
94 return STATUS_NO_MEMORY
;
96 Status
= GetNextCluster(DeviceExt
, *CurrentCluster
,
97 CurrentCluster
, TRUE
);
98 if (NT_SUCCESS(Status
) && *CurrentCluster
!= 0xffffffff)
100 memcpy(FatChain
, Fcb
->FatChain
, (i
+ 1) * sizeof(ULONG
));
101 FatChain
[i
+ 1] = *CurrentCluster
;
102 ExFreePool(Fcb
->FatChain
);
103 Fcb
->FatChain
= FatChain
;
104 Fcb
->FatChainSize
= i
+ 2;
108 ExFreePool(FatChain
);
114 *CurrentCluster
= 0xffffffff;
115 return STATUS_UNSUCCESSFUL
;
118 *CurrentCluster
= Fcb
->FatChain
[i
+ 1];
119 return STATUS_SUCCESS
;
122 if (FirstCluster
== 1)
124 (*CurrentCluster
) += DeviceExt
->FatInfo
.SectorsPerCluster
;
125 return(STATUS_SUCCESS
);
130 * CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't
133 if (FirstCluster
== 0)
137 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
,
145 Status
= GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
,
153 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
160 * Return the cluster corresponding to an offset within a file,
161 * possibly extending the file if necessary
164 ULONG CurrentCluster
;
167 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
168 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt
,
169 Fcb
, FirstCluster
, FileOffset
, Cluster
, Extend
);
170 if (FirstCluster
== 0)
172 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
176 if (Fcb
!= NULL
&& Fcb
->Flags
& FCB_IS_PAGE_FILE
)
179 ULONG Offset
= FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
;
182 if (Fcb
->FatChainSize
== 0)
184 DbgPrint("OffsetToCluster is called with FirstCluster = %x"
185 " and Fcb->FatChainSize = 0!\n", FirstCluster
);
188 if (Offset
< Fcb
->FatChainSize
)
190 *Cluster
= Fcb
->FatChain
[Offset
];
191 return STATUS_SUCCESS
;
197 *Cluster
= 0xffffffff;
198 return STATUS_UNSUCCESSFUL
;
202 FatChain
= ExAllocatePool(NonPagedPool
, (Offset
+ 1) * sizeof(ULONG
));
205 *Cluster
= 0xffffffff;
206 return STATUS_UNSUCCESSFUL
;
209 CurrentCluster
= Fcb
->FatChain
[Fcb
->FatChainSize
- 1];
210 FatChain
[Fcb
->FatChainSize
- 1] = CurrentCluster
;
211 for (i
= Fcb
->FatChainSize
; i
< Offset
+ 1; i
++)
213 Status
= GetNextCluster(DeviceExt
, CurrentCluster
, &CurrentCluster
, TRUE
);
214 if (!NT_SUCCESS(Status
) || CurrentCluster
== 0xFFFFFFFF)
216 while (i
>= Fcb
->FatChainSize
)
218 WriteCluster(DeviceExt
, FatChain
[i
- 1], 0xFFFFFFFF);
221 *Cluster
= 0xffffffff;
222 ExFreePool(FatChain
);
223 if (!NT_SUCCESS(Status
))
225 return STATUS_UNSUCCESSFUL
;
227 FatChain
[i
] = CurrentCluster
;
229 memcpy (FatChain
, Fcb
->FatChain
, Fcb
->FatChainSize
* sizeof(ULONG
));
230 ExFreePool(Fcb
->FatChain
);
231 Fcb
->FatChain
= FatChain
;
232 Fcb
->FatChainSize
= Offset
+ 1;
235 *Cluster
= CurrentCluster
;
236 return(STATUS_SUCCESS
);
238 if (FirstCluster
== 1)
240 /* root of FAT16 or FAT12 */
241 *Cluster
= DeviceExt
->FatInfo
.rootStart
+ FileOffset
242 / (DeviceExt
->FatInfo
.BytesPerCluster
) * DeviceExt
->FatInfo
.SectorsPerCluster
;
243 return(STATUS_SUCCESS
);
247 CurrentCluster
= FirstCluster
;
248 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
250 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
,
252 if (!NT_SUCCESS(Status
))
257 *Cluster
= CurrentCluster
;
258 return(STATUS_SUCCESS
);
263 VfatReadCluster(PDEVICE_EXTENSION DeviceExt
,
266 PULONG CurrentCluster
,
268 ULONG InternalOffset
,
269 ULONG InternalLength
)
271 PVOID BaseAddress
= NULL
;
274 if (InternalLength
== DeviceExt
->FatInfo
.BytesPerCluster
)
276 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
277 Destination
, *CurrentCluster
, 1);
281 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->FatInfo
.BytesPerCluster
);
282 if (BaseAddress
== NULL
)
284 return(STATUS_NO_MEMORY
);
286 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
287 BaseAddress
, *CurrentCluster
, 1);
288 memcpy(Destination
, BaseAddress
+ InternalOffset
, InternalLength
);
289 ExFreePool(BaseAddress
);
291 if (!NT_SUCCESS(Status
))
295 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, CurrentCluster
, FALSE
);
300 VfatReadFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
301 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
302 PULONG LengthRead
, ULONG NoCache
)
304 * FUNCTION: Reads data from a file
307 ULONG CurrentCluster
;
315 LARGE_INTEGER FileOffset
;
316 IO_STATUS_BLOCK IoStatus
;
320 assert (DeviceExt
!= NULL
);
321 assert (DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
322 assert (FileObject
!= NULL
);
323 assert (FileObject
->FsContext2
!= NULL
);
325 DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
326 "Length %d, ReadOffset 0x%x)\n", DeviceExt
, FileObject
, Buffer
,
331 Ccb
= (PVFATCCB
)FileObject
->FsContext2
;
334 /* Is this a read of the FAT? */
335 if (Fcb
->Flags
& FCB_IS_FAT
)
339 DbgPrint ("Cached FAT read outside from VFATFS.SYS\n");
342 if (ReadOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
||
343 ReadOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
345 DbgPrint ("Start or end of FAT read is not on a sector boundary\n");
348 if (ReadOffset
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
350 Length
= Fcb
->RFCB
.FileSize
.QuadPart
- ReadOffset
;
353 Status
= VfatReadSectors(DeviceExt
->StorageDevice
,
354 DeviceExt
->FatInfo
.FATStart
+ ReadOffset
/ BLOCKSIZE
,
355 Length
/ BLOCKSIZE
, Buffer
);
356 if (NT_SUCCESS(Status
))
358 *LengthRead
= Length
;
362 DPRINT1("FAT reading failed, Status %x\n", Status
);
368 * Find the first cluster
370 FirstCluster
= CurrentCluster
=
371 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
374 * Truncate the read if necessary
376 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
378 if (ReadOffset
>= Fcb
->entry
.FileSize
)
380 return (STATUS_END_OF_FILE
);
382 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
384 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
388 if (FirstCluster
== 1)
390 /* root directory of FAT12 or FAT16 */
391 if (ReadOffset
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BLOCKSIZE
)
393 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BLOCKSIZE
- ReadOffset
;
397 /* Using the Cc-interface if possible. */
400 FileOffset
.QuadPart
= ReadOffset
;
401 CcCopyRead(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
, &IoStatus
);
402 *LengthRead
= IoStatus
.Information
;
403 return IoStatus
.Status
;
407 * Find the cluster to start the read from
409 if (Ccb
->LastCluster
> 0 && ReadOffset
> Ccb
->LastOffset
)
411 CurrentCluster
= Ccb
->LastCluster
;
413 Status
= OffsetToCluster(DeviceExt
,
416 ROUND_DOWN(ReadOffset
, DeviceExt
->FatInfo
.BytesPerCluster
),
419 if (!NT_SUCCESS(Status
))
424 * If the read doesn't begin on a chunk boundary then we need special
427 if ((ReadOffset
% DeviceExt
->FatInfo
.BytesPerCluster
) != 0 )
429 TempLength
= min (Length
, DeviceExt
->FatInfo
.BytesPerCluster
-
430 (ReadOffset
% DeviceExt
->FatInfo
.BytesPerCluster
));
431 Ccb
->LastCluster
= CurrentCluster
;
432 Ccb
->LastOffset
= ROUND_DOWN(ReadOffset
, DeviceExt
->FatInfo
.BytesPerCluster
);
433 Status
= VfatReadCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
435 ReadOffset
% DeviceExt
->FatInfo
.BytesPerCluster
,
437 if (NT_SUCCESS(Status
))
439 (*LengthRead
) = (*LengthRead
) + TempLength
;
440 Length
= Length
- TempLength
;
441 Buffer
= Buffer
+ TempLength
;
442 ReadOffset
= ReadOffset
+ TempLength
;
446 while (Length
>= DeviceExt
->FatInfo
.BytesPerCluster
&&
447 CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
449 StartCluster
= CurrentCluster
;
452 /* Search for continous clusters. */
456 BytesDone
+= DeviceExt
->FatInfo
.BytesPerCluster
;
457 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
460 while (StartCluster
+ ClusterCount
== CurrentCluster
&&
461 NT_SUCCESS(Status
) &&
462 Length
- BytesDone
>= DeviceExt
->FatInfo
.BytesPerCluster
);
464 DPRINT("Count %d, Start %x Next %x\n", ClusterCount
, StartCluster
,
466 Ccb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
467 Ccb
->LastOffset
= ReadOffset
+
468 (ClusterCount
- 1) * DeviceExt
->FatInfo
.BytesPerCluster
;
470 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, Buffer
,
471 StartCluster
, ClusterCount
);
472 if (NT_SUCCESS(Status
))
474 ClusterCount
*= DeviceExt
->FatInfo
.BytesPerCluster
;
475 (*LengthRead
) = (*LengthRead
) + ClusterCount
;
476 Buffer
+= ClusterCount
;
477 Length
-= ClusterCount
;
478 ReadOffset
+= ClusterCount
;
482 * If the read doesn't end on a chunk boundary then we need special
485 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
487 Ccb
->LastCluster
= CurrentCluster
;
488 Ccb
->LastOffset
= ReadOffset
+ DeviceExt
->FatInfo
.BytesPerCluster
;
490 Status
= VfatReadCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
492 if (NT_SUCCESS(Status
))
494 (*LengthRead
) = (*LengthRead
) + Length
;
501 VfatWriteCluster(PDEVICE_EXTENSION DeviceExt
,
505 PULONG CurrentCluster
,
507 ULONG InternalOffset
,
508 ULONG InternalLength
)
513 if (InternalLength
!= DeviceExt
->FatInfo
.BytesPerCluster
)
515 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->FatInfo
.BytesPerCluster
);
516 if (BaseAddress
== NULL
)
518 return(STATUS_NO_MEMORY
);
522 BaseAddress
= Source
;
523 if (InternalLength
!= DeviceExt
->FatInfo
.BytesPerCluster
)
526 * If the data in the cache isn't valid or we are bypassing the
527 * cache and not writing a cluster aligned, cluster sized region
528 * then read data in to base address
530 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, BaseAddress
,
532 if (!NT_SUCCESS(Status
))
534 if (InternalLength
!= DeviceExt
->FatInfo
.BytesPerCluster
)
536 ExFreePool(BaseAddress
);
540 memcpy(BaseAddress
+ InternalOffset
, Source
, InternalLength
);
543 * Write the data back to disk
545 DPRINT("Writing 0x%x\n", *CurrentCluster
);
546 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, BaseAddress
,
548 if (InternalLength
!= DeviceExt
->FatInfo
.BytesPerCluster
)
550 ExFreePool(BaseAddress
);
552 if (!NT_SUCCESS(Status
))
556 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, CurrentCluster
, FALSE
);
561 VfatWriteFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
562 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
,
563 BOOLEAN NoCache
, BOOLEAN PageIo
)
565 * FUNCTION: Writes data to file
568 ULONG CurrentCluster
;
575 LARGE_INTEGER SystemTime
, LocalTime
;
578 LARGE_INTEGER FileOffset
;
580 DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
581 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
584 pCcb
= (PVFATCCB
) (FileObject
->FsContext2
);
589 // DPRINT1("%S\n", Fcb->PathName);
593 return STATUS_SUCCESS
;
596 // Is this a write to the FAT ?
597 if (Fcb
->Flags
& FCB_IS_FAT
)
599 if (!NoCache
&& !PageIo
)
601 DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
604 if (WriteOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| WriteOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
606 DbgPrint ("Start or end of FAT write is not on a sector boundary\n");
609 if (WriteOffset
+ Length
> (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
)
611 Length
= (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
- WriteOffset
;
614 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
616 Status
= VfatWriteSectors(DeviceExt
->StorageDevice
,
617 DeviceExt
->FatInfo
.FATStart
+ (Count
* (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
+ WriteOffset
) / BLOCKSIZE
,
618 Length
/ BLOCKSIZE
, Buffer
);
619 if (!NT_SUCCESS(Status
))
621 DPRINT1("FAT writing failed, Status %x\n", Status
);
627 /* Locate the first cluster of the file */
628 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
632 if (FirstCluster
== 0)
634 return STATUS_UNSUCCESSFUL
;
639 if (FirstCluster
== 1)
641 // root directory of FAT12 od FAT16
642 if (WriteOffset
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BLOCKSIZE
)
644 DPRINT("Writing over the end of the root directory on FAT12/16\n");
645 return STATUS_END_OF_FILE
;
649 Status
= vfatExtendSpace(DeviceExt
, FileObject
, WriteOffset
+ Length
);
650 if (!NT_SUCCESS (Status
))
656 if (NoCache
|| PageIo
)
659 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
660 if (pCcb
->LastCluster
> 0 && WriteOffset
> pCcb
->LastOffset
)
662 CurrentCluster
= pCcb
->LastCluster
;
664 Status
= OffsetToCluster(DeviceExt
,
667 ROUND_DOWN(WriteOffset
, DeviceExt
->FatInfo
.BytesPerCluster
),
670 if (!NT_SUCCESS(Status
) || CurrentCluster
== 0xffffffff)
675 pCcb
->LastCluster
= CurrentCluster
;
676 pCcb
->LastOffset
= ROUND_DOWN(WriteOffset
, DeviceExt
->FatInfo
.BytesPerCluster
);
679 * If the offset in the cluster doesn't fall on the cluster boundary
680 * then we have to write only from the specified offset
682 Status
= STATUS_SUCCESS
;
683 if ((WriteOffset
% DeviceExt
->FatInfo
.BytesPerCluster
) != 0)
685 TempLength
= min (Length
, DeviceExt
->FatInfo
.BytesPerCluster
686 - (WriteOffset
% DeviceExt
->FatInfo
.BytesPerCluster
));
687 Status
= VfatWriteCluster(DeviceExt
,
689 ROUND_DOWN(WriteOffset
, DeviceExt
->FatInfo
.BytesPerCluster
),
693 WriteOffset
% DeviceExt
->FatInfo
.BytesPerCluster
,
695 if (NT_SUCCESS(Status
))
697 Buffer
= Buffer
+ TempLength
;
698 Length
= Length
- TempLength
;
699 WriteOffset
= WriteOffset
+ TempLength
;
703 while (Length
>= DeviceExt
->FatInfo
.BytesPerCluster
&&
704 CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
706 StartCluster
= CurrentCluster
;
708 // search for continous clusters
712 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
714 while (StartCluster
+ Count
== CurrentCluster
&& NT_SUCCESS(Status
) &&
715 Length
- Count
* DeviceExt
->FatInfo
.BytesPerCluster
>= DeviceExt
->FatInfo
.BytesPerCluster
);
717 pCcb
->LastCluster
= StartCluster
+ (Count
- 1);
718 pCcb
->LastOffset
= WriteOffset
+ (Count
- 1) * DeviceExt
->FatInfo
.BytesPerCluster
;
720 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, Count
);
721 if (NT_SUCCESS(Status
))
723 Count
*= DeviceExt
->FatInfo
.BytesPerCluster
;
726 WriteOffset
+= Count
;
730 /* Write the remainder */
731 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
733 Status
= VfatWriteCluster(DeviceExt
,
741 if (NT_SUCCESS(Status
))
746 if (NT_SUCCESS(Status
) && Length
)
748 if (WriteOffset
< Fcb
->RFCB
.AllocationSize
.QuadPart
)
750 DPRINT1("%d %d\n", WriteOffset
, (ULONG
)Fcb
->RFCB
.AllocationSize
.QuadPart
);
751 Status
= STATUS_DISK_FULL
; // ???????????
757 // using the Cc-interface if possible
758 FileOffset
.QuadPart
= WriteOffset
;
759 if(CcCopyWrite(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
))
761 Status
= STATUS_SUCCESS
;
765 Status
= STATUS_UNSUCCESSFUL
;
772 if(!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
774 /* set dates and times */
775 KeQuerySystemTime (&SystemTime
);
776 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
777 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
,
778 &Fcb
->entry
.UpdateDate
,
779 &Fcb
->entry
.UpdateTime
);
780 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
781 // update dates/times and length
782 updEntry (DeviceExt
, FileObject
);
789 NTSTATUS
vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt
, PFILE_OBJECT pFileObject
, ULONG NewSize
)
792 ULONG CurrentCluster
;
798 pFcb
= ((PVFATCCB
) (pFileObject
->FsContext2
))->pFcb
;
800 DPRINT ("New Size %d, AllocationSize %d, BytesPerCluster %d\n", NewSize
,
801 (ULONG
)pFcb
->RFCB
.AllocationSize
.QuadPart
, pDeviceExt
->FatInfo
.BytesPerCluster
);
803 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (pDeviceExt
, &pFcb
->entry
);
805 if (NewSize
> pFcb
->RFCB
.AllocationSize
.QuadPart
|| FirstCluster
==0)
807 // size on disk must be extended
808 if (FirstCluster
== 0)
811 Status
= NextCluster (pDeviceExt
, pFcb
, FirstCluster
, &CurrentCluster
, TRUE
);
812 if (!NT_SUCCESS(Status
))
814 DPRINT1("NextCluster failed, Status %x\n", Status
);
817 NewCluster
= FirstCluster
= CurrentCluster
;
821 Status
= OffsetToCluster(pDeviceExt
, pFcb
, FirstCluster
,
822 pFcb
->RFCB
.AllocationSize
.QuadPart
- pDeviceExt
->FatInfo
.BytesPerCluster
,
823 &CurrentCluster
, FALSE
);
824 if (!NT_SUCCESS(Status
))
826 DPRINT1("OffsetToCluster failed, Status %x\n", Status
);
829 if (CurrentCluster
== 0xffffffff)
831 DPRINT1("Not enough disk space.\n");
832 return STATUS_DISK_FULL
;
834 // CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
835 NewCluster
= CurrentCluster
;
836 Status
= NextCluster(pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
837 if (NewCluster
!= 0xffffffff)
839 DPRINT1("Difference between size from direntry and the FAT.\n");
843 Status
= OffsetToCluster(pDeviceExt
, pFcb
, FirstCluster
,
844 ROUND_DOWN(NewSize
-1, pDeviceExt
->FatInfo
.BytesPerCluster
),
846 if (!NT_SUCCESS(Status
) || NewCluster
== 0xffffffff)
848 DPRINT1("Not enough free space on disk\n");
849 if (pFcb
->RFCB
.AllocationSize
.QuadPart
> 0)
851 NewCluster
= CurrentCluster
;
852 // FIXME: check status
853 NextCluster(pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
854 WriteCluster(pDeviceExt
, CurrentCluster
, 0xffffffff);
856 // free the allocated space
857 while (NewCluster
!= 0xffffffff)
859 CurrentCluster
= NewCluster
;
860 // FIXME: check status
861 NextCluster (pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
862 WriteCluster (pDeviceExt
, CurrentCluster
, 0);
864 return STATUS_DISK_FULL
;
866 if (pFcb
->RFCB
.AllocationSize
.QuadPart
== 0)
868 pFcb
->entry
.FirstCluster
= FirstCluster
;
869 if(pDeviceExt
->FatInfo
.FatType
== FAT32
)
870 pFcb
->entry
.FirstClusterHigh
= FirstCluster
>> 16;
872 pFcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(NewSize
, pDeviceExt
->FatInfo
.BytesPerCluster
);
873 if (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
875 pFcb
->RFCB
.FileSize
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
876 pFcb
->RFCB
.ValidDataLength
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
880 pFcb
->entry
.FileSize
= NewSize
;
881 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
882 pFcb
->RFCB
.ValidDataLength
.QuadPart
= NewSize
;
884 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
888 if (NewSize
> pFcb
->RFCB
.FileSize
.QuadPart
)
890 // size on disk must not be extended
891 if (!(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
893 pFcb
->entry
.FileSize
= NewSize
;
894 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
895 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
903 return STATUS_SUCCESS
;
907 VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
911 NTSTATUS Status
= STATUS_SUCCESS
;
913 ULONG ReturnedReadLength
= 0;
914 LARGE_INTEGER ReadOffset
;
917 DPRINT ("VfatRead(IrpContext %x)\n", IrpContext
);
919 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
924 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
926 if (!ExAcquireResourceSharedLite(&Fcb
->PagingIoResource
,
927 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
929 return VfatQueueRequest (IrpContext
);
934 if (!ExAcquireResourceSharedLite(&Fcb
->MainResource
,
935 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
937 return VfatQueueRequest (IrpContext
);
941 ReadLength
= IrpContext
->Stack
->Parameters
.Read
.Length
;
942 ReadOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
943 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
945 /* fail if file is a directory and no paged read */
946 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&&
947 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
949 Status
= STATUS_FILE_IS_A_DIRECTORY
;
954 NoCache
= IrpContext
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
955 || IrpContext
->Irp
->Flags
& IRP_PAGING_IO
;
956 Status
= VfatReadFile (IrpContext
->DeviceExt
, IrpContext
->FileObject
,
957 Buffer
, ReadLength
, ReadOffset
.u
.LowPart
,
962 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
964 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
968 ExReleaseResourceLite(&Fcb
->MainResource
);
971 if (NT_SUCCESS(Status
))
973 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
974 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
976 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
977 ReadOffset
.QuadPart
+ ReturnedReadLength
;
979 IrpContext
->Irp
->IoStatus
.Information
= ReturnedReadLength
;
983 IrpContext
->Irp
->IoStatus
.Information
= 0;
986 IrpContext
->Irp
->IoStatus
.Status
= Status
;
987 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
988 VfatFreeIrpContext (IrpContext
);
993 NTSTATUS
VfatWrite(PVFAT_IRP_CONTEXT IrpContext
)
997 NTSTATUS Status
= STATUS_SUCCESS
;
999 LARGE_INTEGER WriteOffset
;
1002 DPRINT ("VfatWrite(), %S\n", ((PVFATCCB
) IrpContext
->FileObject
->FsContext2
)->pFcb
->FileName
);
1003 assert (IrpContext
);
1004 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
1009 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
1011 if (!ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
1013 return VfatQueueRequest (IrpContext
);
1018 if (!ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
1020 return VfatQueueRequest (IrpContext
);
1024 WriteLength
= IrpContext
->Stack
->Parameters
.Write
.Length
;
1025 WriteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
1026 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
1028 /* fail if file is a directory and no paged read */
1029 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
1031 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1035 Status
= VfatWriteFile (IrpContext
->DeviceExt
, IrpContext
->FileObject
,
1036 Buffer
, WriteLength
, WriteOffset
.u
.LowPart
,
1037 IrpContext
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
,
1038 IrpContext
->Irp
->Flags
& IRP_PAGING_IO
);
1041 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
1043 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1047 ExReleaseResourceLite(&Fcb
->MainResource
);
1050 if (NT_SUCCESS(Status
))
1052 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
1054 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
= WriteOffset
.QuadPart
+ WriteLength
;
1056 IrpContext
->Irp
->IoStatus
.Information
= WriteLength
;
1060 IrpContext
->Irp
->IoStatus
.Information
= 0;
1063 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1064 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
1065 VfatFreeIrpContext (IrpContext
);