2 /* $Id: rw.c,v 1.32 2001/10/10 22:19: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
,
33 PULONG CurrentCluster
,
36 * Return the next cluster in a FAT chain, possibly extending the chain if
40 if (FirstCluster
== 1)
42 (*CurrentCluster
) += DeviceExt
->Boot
->SectorsPerCluster
;
43 return(STATUS_SUCCESS
);
46 /* CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't initialized when 0*/
47 if (FirstCluster
== 0)
51 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
,
59 Status
= GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
,
66 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
72 * Return the cluster corresponding to an offset within a file,
73 * possibly extending the file if necessary
80 if (FirstCluster
== 1)
82 /* root of FAT16 or FAT12 */
83 *Cluster
= DeviceExt
->rootStart
+ FileOffset
84 / (DeviceExt
->BytesPerCluster
) * DeviceExt
->Boot
->SectorsPerCluster
;
85 return(STATUS_SUCCESS
);
89 CurrentCluster
= FirstCluster
;
90 for (i
= 0; i
< FileOffset
/ DeviceExt
->BytesPerCluster
; i
++)
92 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
,
94 if (!NT_SUCCESS(Status
))
99 *Cluster
= CurrentCluster
;
100 return(STATUS_SUCCESS
);
105 VfatReadCluster(PDEVICE_EXTENSION DeviceExt
,
107 PULONG CurrentCluster
,
109 ULONG InternalOffset
,
110 ULONG InternalLength
)
112 PVOID BaseAddress
= NULL
;
115 if (InternalLength
== DeviceExt
->BytesPerCluster
)
117 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
118 Destination
, *CurrentCluster
, 1);
122 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
123 if (BaseAddress
== NULL
)
125 return(STATUS_NO_MEMORY
);
127 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
128 BaseAddress
, *CurrentCluster
, 1);
129 memcpy(Destination
, BaseAddress
+ InternalOffset
, InternalLength
);
130 ExFreePool(BaseAddress
);
132 if (!NT_SUCCESS(Status
))
136 Status
= NextCluster(DeviceExt
, FirstCluster
, CurrentCluster
, FALSE
);
141 VfatReadFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
142 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
143 PULONG LengthRead
, ULONG NoCache
)
145 * FUNCTION: Reads data from a file
148 ULONG CurrentCluster
;
156 LARGE_INTEGER FileOffset
;
157 IO_STATUS_BLOCK IoStatus
;
160 assert (DeviceExt
!= NULL
);
161 assert (DeviceExt
->BytesPerCluster
!= 0);
162 assert (FileObject
!= NULL
);
163 assert (FileObject
->FsContext2
!= NULL
);
165 DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
166 "Length %d, ReadOffset 0x%x)\n", DeviceExt
, FileObject
, Buffer
,
171 Ccb
= (PVFATCCB
)FileObject
->FsContext2
;
174 // Is this a read of the FAT ?
175 if (Fcb
->Flags
& FCB_IS_FAT
)
179 DbgPrint ("Cached FAT read outside from VFATFS.SYS\n");
182 if (ReadOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| ReadOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
184 DbgPrint ("Start or end of FAT read is not on a sector boundary\n");
187 if (ReadOffset
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
189 Length
= Fcb
->RFCB
.FileSize
.QuadPart
- ReadOffset
;
192 Status
= VfatReadSectors(DeviceExt
->StorageDevice
,
193 DeviceExt
->FATStart
+ ReadOffset
/ BLOCKSIZE
, Length
/ BLOCKSIZE
, Buffer
);
194 if (NT_SUCCESS(Status
))
196 *LengthRead
= Length
;
200 DPRINT1("FAT reading failed, Status %x\n", Status
);
206 * Find the first cluster
208 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
211 * Truncate the read if necessary
213 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
215 if (ReadOffset
>= Fcb
->entry
.FileSize
)
217 return (STATUS_END_OF_FILE
);
219 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
221 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
225 if (FirstCluster
== 1)
227 // root directory of FAT12 od FAT16
228 if (ReadOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
230 Length
= DeviceExt
->rootDirectorySectors
* BLOCKSIZE
- ReadOffset
;
234 // using the Cc-interface if possible
237 FileOffset
.QuadPart
= ReadOffset
;
238 CcCopyRead(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
, &IoStatus
);
239 *LengthRead
= IoStatus
.Information
;
240 return IoStatus
.Status
;
244 * Find the cluster to start the read from
246 if (Ccb
->LastCluster
> 0 && ReadOffset
> Ccb
->LastOffset
)
248 CurrentCluster
= Ccb
->LastCluster
;
250 Status
= OffsetToCluster(DeviceExt
,
252 ROUND_DOWN(ReadOffset
, DeviceExt
->BytesPerCluster
),
255 if (!NT_SUCCESS(Status
))
260 * If the read doesn't begin on a chunk boundary then we need special
263 if ((ReadOffset
% DeviceExt
->BytesPerCluster
) != 0 )
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
))
272 (*LengthRead
) = (*LengthRead
) + TempLength
;
273 Length
= Length
- TempLength
;
274 Buffer
= Buffer
+ TempLength
;
275 ReadOffset
= ReadOffset
+ TempLength
;
279 while (Length
>= DeviceExt
->BytesPerCluster
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
281 StartCluster
= CurrentCluster
;
283 // search for continous clusters
287 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
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
;
295 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, ClusterCount
);
296 if (NT_SUCCESS(Status
))
298 ClusterCount
*= DeviceExt
->BytesPerCluster
;
299 (*LengthRead
) = (*LengthRead
) + ClusterCount
;
300 Buffer
+= ClusterCount
;
301 Length
-= ClusterCount
;
302 ReadOffset
+= ClusterCount
;
306 * If the read doesn't end on a chunk boundary then we need special
309 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
311 Ccb
->LastCluster
= CurrentCluster
;
312 Ccb
->LastOffset
= ReadOffset
+ DeviceExt
->BytesPerCluster
;
314 Status
= VfatReadCluster(DeviceExt
, FirstCluster
, &CurrentCluster
,
316 if (NT_SUCCESS(Status
))
318 (*LengthRead
) = (*LengthRead
) + Length
;
325 VfatWriteCluster(PDEVICE_EXTENSION DeviceExt
,
328 PULONG CurrentCluster
,
330 ULONG InternalOffset
,
331 ULONG InternalLength
)
336 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
338 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
339 if (BaseAddress
== NULL
)
341 return(STATUS_NO_MEMORY
);
345 BaseAddress
= Source
;
346 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
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
353 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, BaseAddress
,
355 if (!NT_SUCCESS(Status
))
357 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
359 ExFreePool(BaseAddress
);
363 memcpy(BaseAddress
+ InternalOffset
, Source
, InternalLength
);
366 * Write the data back to disk
368 DPRINT("Writing 0x%x\n", *CurrentCluster
);
369 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, BaseAddress
,
371 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
373 ExFreePool(BaseAddress
);
375 if (!NT_SUCCESS(Status
))
379 Status
= NextCluster(DeviceExt
, FirstCluster
, CurrentCluster
, FALSE
);
384 VfatWriteFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
385 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
,
386 BOOLEAN NoCache
, BOOLEAN PageIo
)
388 * FUNCTION: Writes data to file
391 ULONG CurrentCluster
;
398 LARGE_INTEGER SystemTime
, LocalTime
;
401 LARGE_INTEGER FileOffset
;
403 DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
404 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
407 pCcb
= (PVFATCCB
) (FileObject
->FsContext2
);
412 // DPRINT1("%S\n", Fcb->PathName);
416 return STATUS_SUCCESS
;
419 // Is this a write to the FAT ?
420 if (Fcb
->Flags
& FCB_IS_FAT
)
424 DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
427 if (WriteOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| WriteOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
429 DbgPrint ("Start or end of FAT write is not on a sector boundary\n");
432 if (WriteOffset
+ Length
> (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
)
434 Length
= (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
- WriteOffset
;
437 for (Count
= 0; Count
< DeviceExt
->Boot
->FATCount
; Count
++)
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
))
444 DPRINT1("FAT writing failed, Status %x\n", Status
);
450 /* Locate the first cluster of the file */
451 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
455 if (FirstCluster
== 0)
457 return STATUS_UNSUCCESSFUL
;
462 if (FirstCluster
== 1)
464 // root directory of FAT12 od FAT16
465 if (WriteOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
467 DPRINT("Writing over the end of the root directory on FAT12/16\n");
468 return STATUS_END_OF_FILE
;
472 Status
= vfatExtendSpace(DeviceExt
, FileObject
, WriteOffset
+ Length
);
473 if (!NT_SUCCESS (Status
))
479 if (NoCache
|| PageIo
)
482 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
483 if (pCcb
->LastCluster
> 0 && WriteOffset
> pCcb
->LastOffset
)
485 CurrentCluster
= pCcb
->LastCluster
;
487 Status
= OffsetToCluster(DeviceExt
,
489 ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
),
492 if (!NT_SUCCESS(Status
) || CurrentCluster
== 0xffffffff)
497 pCcb
->LastCluster
= CurrentCluster
;
498 pCcb
->LastOffset
= ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
);
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
504 Status
= STATUS_SUCCESS
;
505 if ((WriteOffset
% DeviceExt
->BytesPerCluster
) != 0)
507 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
- (WriteOffset
% DeviceExt
->BytesPerCluster
));
508 Status
= VfatWriteCluster(DeviceExt
,
509 ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
),
513 WriteOffset
% DeviceExt
->BytesPerCluster
,
515 if (NT_SUCCESS(Status
))
517 Buffer
= Buffer
+ TempLength
;
518 Length
= Length
- TempLength
;
519 WriteOffset
= WriteOffset
+ TempLength
;
523 while (Length
>= DeviceExt
->BytesPerCluster
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
525 StartCluster
= CurrentCluster
;
527 // search for continous clusters
531 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
533 while (StartCluster
+ Count
== CurrentCluster
&& NT_SUCCESS(Status
) &&
534 Length
- Count
* DeviceExt
->BytesPerCluster
>= DeviceExt
->BytesPerCluster
);
536 pCcb
->LastCluster
= StartCluster
+ (Count
- 1);
537 pCcb
->LastOffset
= WriteOffset
+ (Count
- 1) * DeviceExt
->BytesPerCluster
;
539 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, Count
);
540 if (NT_SUCCESS(Status
))
542 Count
*= DeviceExt
->BytesPerCluster
;
545 WriteOffset
+= Count
;
549 /* Write the remainder */
550 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
552 Status
= VfatWriteCluster(DeviceExt
,
559 if (NT_SUCCESS(Status
))
564 if (NT_SUCCESS(Status
) && Length
)
566 if (WriteOffset
< Fcb
->RFCB
.AllocationSize
.QuadPart
)
568 DPRINT1("%d %d\n", WriteOffset
, (ULONG
)Fcb
->RFCB
.AllocationSize
.QuadPart
);
569 Status
= STATUS_DISK_FULL
; // ???????????
575 // using the Cc-interface if possible
576 FileOffset
.QuadPart
= WriteOffset
;
577 if(CcCopyWrite(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
))
579 Status
= STATUS_SUCCESS
;
583 Status
= STATUS_UNSUCCESSFUL
;
590 if(!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
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
;
600 // update dates/times and length
601 updEntry (DeviceExt
, FileObject
);
608 VfatWrite (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
610 * FUNCTION: Write to a file
616 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation (Irp
);
617 PFILE_OBJECT FileObject
= Stack
->FileObject
;
618 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
622 DPRINT ("VfatWrite(DeviceObject %x Irp %x)\n", DeviceObject
, Irp
);
624 Length
= Stack
->Parameters
.Write
.Length
;
625 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
626 Offset
= Stack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
628 if (Irp
->Flags
& IRP_PAGING_IO
||
629 FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
638 Status
= VfatWriteFile (DeviceExt
, FileObject
, Buffer
, Length
, Offset
,
639 NoCache
, Irp
->Flags
& IRP_PAGING_IO
? TRUE
: FALSE
);
641 if (!(Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
643 FileObject
->CurrentByteOffset
.QuadPart
= Offset
+ Length
;
646 Irp
->IoStatus
.Status
= Status
;
647 Irp
->IoStatus
.Information
= Length
;
648 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
654 VfatRead (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
656 * FUNCTION: Read from a file
662 PIO_STACK_LOCATION Stack
;
663 PFILE_OBJECT FileObject
;
664 PDEVICE_EXTENSION DeviceExt
;
670 DPRINT ("VfatRead(DeviceObject %x, Irp %x)\n", DeviceObject
, Irp
);
672 /* Precondition / Initialization */
673 assert (Irp
!= NULL
);
674 Stack
= IoGetCurrentIrpStackLocation (Irp
);
675 assert (Stack
!= NULL
);
676 FileObject
= Stack
->FileObject
;
677 assert (FileObject
!= NULL
);
678 DeviceExt
= DeviceObject
->DeviceExtension
;
679 assert (DeviceExt
!= NULL
);
681 Length
= Stack
->Parameters
.Read
.Length
;
682 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
683 Offset
= Stack
->Parameters
.Read
.ByteOffset
.u
.LowPart
;
685 if (Irp
->Flags
& IRP_PAGING_IO
||
686 FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
695 Fcb
= ((PVFATCCB
) (FileObject
->FsContext2
))->pFcb
;
696 /* fail if file is a directory and no paged read */
697 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(Irp
->Flags
& IRP_PAGING_IO
))
699 Status
= STATUS_FILE_IS_A_DIRECTORY
;
703 Status
= VfatReadFile (DeviceExt
, FileObject
, Buffer
, Length
,
704 Offset
, &LengthRead
, NoCache
);
707 if (!(Irp
->Flags
& IRP_PAGING_IO
))
709 // update the file pointer
710 FileObject
->CurrentByteOffset
.QuadPart
= Offset
+ LengthRead
;
713 Irp
->IoStatus
.Status
= Status
;
714 Irp
->IoStatus
.Information
= LengthRead
;
715 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
720 NTSTATUS
vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt
, PFILE_OBJECT pFileObject
, ULONG NewSize
)
723 ULONG CurrentCluster
;
729 pFcb
= ((PVFATCCB
) (pFileObject
->FsContext2
))->pFcb
;
731 DPRINT ("New Size %d, AllocationSize %d, BytesPerCluster %d\n", NewSize
,
732 (ULONG
)pFcb
->RFCB
.AllocationSize
.QuadPart
, pDeviceExt
->BytesPerCluster
);
734 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (pDeviceExt
, &pFcb
->entry
);
736 if (NewSize
> pFcb
->RFCB
.AllocationSize
.QuadPart
|| FirstCluster
==0)
738 // size on disk must be extended
739 if (FirstCluster
== 0)
742 Status
= NextCluster (pDeviceExt
, FirstCluster
, &CurrentCluster
, TRUE
);
743 if (!NT_SUCCESS(Status
))
745 DPRINT1("NextCluster failed, Status %x\n", Status
);
748 NewCluster
= FirstCluster
= CurrentCluster
;
752 Status
= OffsetToCluster(pDeviceExt
, FirstCluster
,
753 pFcb
->RFCB
.AllocationSize
.QuadPart
- pDeviceExt
->BytesPerCluster
,
754 &CurrentCluster
, FALSE
);
755 if (!NT_SUCCESS(Status
))
757 DPRINT1("OffsetToCluster failed, Status %x\n", Status
);
760 if (CurrentCluster
== 0xffffffff)
762 DPRINT1("Not enough disk space.\n");
763 return STATUS_DISK_FULL
;
765 // CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
766 NewCluster
= CurrentCluster
;
767 Status
= NextCluster(pDeviceExt
, FirstCluster
, &NewCluster
, FALSE
);
768 if (NewCluster
!= 0xffffffff)
770 DPRINT1("Difference between size from direntry and the FAT.\n");
774 Status
= OffsetToCluster(pDeviceExt
, FirstCluster
,
775 ROUND_DOWN(NewSize
-1, pDeviceExt
->BytesPerCluster
),
777 if (!NT_SUCCESS(Status
) || NewCluster
== 0xffffffff)
779 DPRINT1("Not enough free space on disk\n");
780 if (pFcb
->RFCB
.AllocationSize
.QuadPart
> 0)
782 NewCluster
= CurrentCluster
;
783 // FIXME: check status
784 NextCluster(pDeviceExt
, FirstCluster
, &NewCluster
, FALSE
);
785 WriteCluster(pDeviceExt
, CurrentCluster
, 0xffffffff);
787 // free the allocated space
788 while (NewCluster
!= 0xffffffff)
790 CurrentCluster
= NewCluster
;
791 // FIXME: check status
792 NextCluster (pDeviceExt
, FirstCluster
, &NewCluster
, FALSE
);
793 WriteCluster (pDeviceExt
, CurrentCluster
, 0);
795 return STATUS_DISK_FULL
;
797 if (pFcb
->RFCB
.AllocationSize
.QuadPart
== 0)
799 pFcb
->entry
.FirstCluster
= FirstCluster
;
800 if(pDeviceExt
->FatType
== FAT32
)
801 pFcb
->entry
.FirstClusterHigh
= FirstCluster
>> 16;
803 pFcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(NewSize
, pDeviceExt
->BytesPerCluster
);
804 if (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
806 pFcb
->RFCB
.FileSize
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
807 pFcb
->RFCB
.ValidDataLength
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
811 pFcb
->entry
.FileSize
= NewSize
;
812 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
813 pFcb
->RFCB
.ValidDataLength
.QuadPart
= NewSize
;
815 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
819 if (NewSize
> pFcb
->RFCB
.FileSize
.QuadPart
)
821 // size on disk must not be extended
822 if (!(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
824 pFcb
->entry
.FileSize
= NewSize
;
825 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
826 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
834 return STATUS_SUCCESS
;