2 /* $Id: rw.c,v 1.48 2002/09/08 10:22:12 chorns 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 /* FUNCTIONS *****************************************************************/
26 NextCluster(PDEVICE_EXTENSION DeviceExt
,
29 PULONG CurrentCluster
,
32 * Return the next cluster in a FAT chain, possibly extending the chain if
36 if (Fcb
!= NULL
&& Fcb
->Flags
& FCB_IS_PAGE_FILE
)
41 DPRINT("NextCluster(Fcb %x, FirstCluster %x, Extend %d)\n", Fcb
,
42 FirstCluster
, Extend
);
43 if (Fcb
->FatChainSize
== 0)
45 /* Paging file with zero length. */
46 *CurrentCluster
= 0xffffffff;
49 Fcb
->FatChain
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
));
50 if (Fcb
->FatChain
== NULL
)
52 return(STATUS_NO_MEMORY
);
54 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
, TRUE
);
55 if (!NT_SUCCESS(Status
))
57 ExFreePool(Fcb
->FatChain
);
60 Fcb
->FatChain
[0] = *CurrentCluster
;
61 Fcb
->FatChainSize
= 1;
66 return STATUS_UNSUCCESSFUL
;
71 for (i
= 0; i
< Fcb
->FatChainSize
; i
++)
73 if (Fcb
->FatChain
[i
] == *CurrentCluster
)
76 if (i
>= Fcb
->FatChainSize
)
78 return STATUS_UNSUCCESSFUL
;
80 if (i
== Fcb
->FatChainSize
- 1)
84 FatChain
= ExAllocatePool(NonPagedPool
,
85 (i
+ 2) * sizeof(ULONG
));
88 *CurrentCluster
= 0xffffffff;
89 return STATUS_NO_MEMORY
;
91 Status
= GetNextCluster(DeviceExt
, *CurrentCluster
,
92 CurrentCluster
, TRUE
);
93 if (NT_SUCCESS(Status
) && *CurrentCluster
!= 0xffffffff)
95 memcpy(FatChain
, Fcb
->FatChain
, (i
+ 1) * sizeof(ULONG
));
96 FatChain
[i
+ 1] = *CurrentCluster
;
97 ExFreePool(Fcb
->FatChain
);
98 Fcb
->FatChain
= FatChain
;
99 Fcb
->FatChainSize
= i
+ 2;
103 ExFreePool(FatChain
);
109 *CurrentCluster
= 0xffffffff;
110 return STATUS_SUCCESS
;
113 *CurrentCluster
= Fcb
->FatChain
[i
+ 1];
114 return STATUS_SUCCESS
;
117 if (FirstCluster
== 1)
119 (*CurrentCluster
) += DeviceExt
->FatInfo
.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
->FatInfo
.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
->FatInfo
.rootStart
+ FileOffset
237 / (DeviceExt
->FatInfo
.BytesPerCluster
) * DeviceExt
->FatInfo
.SectorsPerCluster
;
238 return(STATUS_SUCCESS
);
242 CurrentCluster
= FirstCluster
;
243 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
245 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
,
247 if (!NT_SUCCESS(Status
))
252 *Cluster
= CurrentCluster
;
253 return(STATUS_SUCCESS
);
258 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext
, PVOID Buffer
,
259 ULONG Length
, LARGE_INTEGER ReadOffset
, PULONG LengthRead
)
261 * FUNCTION: Reads data from a file
264 ULONG CurrentCluster
;
268 LARGE_INTEGER StartOffset
;
269 PDEVICE_EXTENSION DeviceExt
;
270 BOOLEAN First
= TRUE
;
275 ULONG BytesPerSector
;
276 ULONG BytesPerCluster
;
280 DeviceExt
= IrpContext
->DeviceExt
;
282 assert (DeviceExt
->FatInfo
.BytesPerCluster
);
283 assert (IrpContext
->FileObject
);
284 assert (IrpContext
->FileObject
->FsContext2
!= NULL
);
286 DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, Buffer %x, "
287 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt
,
288 IrpContext
->FileObject
, Buffer
, Length
, ReadOffset
.QuadPart
);
292 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
294 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
295 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
297 assert(ReadOffset
.QuadPart
+ Length
<= ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
));
298 assert(ReadOffset
.u
.LowPart
% BytesPerSector
== 0);
299 assert(Length
% BytesPerSector
== 0);
301 /* Is this a read of the FAT? */
302 if (Fcb
->Flags
& FCB_IS_FAT
)
304 ReadOffset
.QuadPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
305 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &ReadOffset
, Length
, Buffer
);
307 if (NT_SUCCESS(Status
))
309 *LengthRead
= Length
;
313 DPRINT1("FAT reading failed, Status %x\n", Status
);
317 /* Is this a read of the Volume ? */
318 if (Fcb
->Flags
& FCB_IS_VOLUME
)
320 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &ReadOffset
, Length
, Buffer
);
321 if (NT_SUCCESS(Status
))
323 *LengthRead
= Length
;
327 DPRINT1("Volume reading failed, Status %x\n", Status
);
333 * Find the first cluster
335 FirstCluster
= CurrentCluster
=
336 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
338 if (FirstCluster
== 1)
340 // Directory of FAT12/16 needs a special handling
342 if (ReadOffset
.u
.LowPart
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
)
344 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
- ReadOffset
.u
.LowPart
;
346 ReadOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
348 // Fire up the read command
350 Status
= VfatReadDisk (DeviceExt
->StorageDevice
, &ReadOffset
, Length
, Buffer
);
351 if (NT_SUCCESS(Status
))
353 *LengthRead
+= Length
;
358 * Find the cluster to start the read from
360 if (Ccb
->LastCluster
> 0 && ReadOffset
.u
.LowPart
> Ccb
->LastOffset
)
362 CurrentCluster
= Ccb
->LastCluster
;
364 Status
= OffsetToCluster(DeviceExt
, Fcb
, FirstCluster
,
365 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
366 &CurrentCluster
, FALSE
);
367 if (!NT_SUCCESS(Status
))
372 Ccb
->LastCluster
= CurrentCluster
;
373 Ccb
->LastOffset
= ROUND_DOWN (ReadOffset
.u
.LowPart
, BytesPerCluster
);
375 while (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
377 StartCluster
= CurrentCluster
;
378 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
387 BytesDone
= min (Length
, BytesPerCluster
- (ReadOffset
.u
.LowPart
% BytesPerCluster
));
388 StartOffset
.QuadPart
+= ReadOffset
.u
.LowPart
% BytesPerCluster
;
393 if (Length
- BytesDone
> BytesPerCluster
)
395 BytesDone
+= BytesPerCluster
;
402 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
404 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
405 DPRINT("start %08x, next %08x, count %d\n",
406 StartCluster
, CurrentCluster
, ClusterCount
);
408 Ccb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
409 Ccb
->LastOffset
= ReadOffset
.u
.LowPart
+ (ClusterCount
- 1) * BytesPerCluster
;
411 // Fire up the read command
412 Status
= VfatReadDisk (DeviceExt
->StorageDevice
, &StartOffset
, BytesDone
, Buffer
);
414 if (NT_SUCCESS(Status
))
416 *LengthRead
+= BytesDone
;
419 ReadOffset
.u
.LowPart
+= BytesDone
;
425 NTSTATUS
VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext
,
428 LARGE_INTEGER WriteOffset
)
430 PDEVICE_EXTENSION DeviceExt
;
435 ULONG CurrentCluster
;
440 BOOLEAN First
= TRUE
;
441 ULONG BytesPerSector
;
442 ULONG BytesPerCluster
;
443 LARGE_INTEGER StartOffset
;
447 DeviceExt
= IrpContext
->DeviceExt
;
449 assert (DeviceExt
->FatInfo
.BytesPerCluster
);
450 assert (IrpContext
->FileObject
);
451 assert (IrpContext
->FileObject
->FsContext2
!= NULL
);
453 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
455 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
456 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
458 DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, Buffer %x, "
459 "Length %d, WriteOffset 0x%I64x), '%S'\n", DeviceExt
,
460 IrpContext
->FileObject
, Buffer
, Length
, WriteOffset
,
463 assert(WriteOffset
.QuadPart
+ Length
<= Fcb
->RFCB
.AllocationSize
.QuadPart
);
464 assert(WriteOffset
.u
.LowPart
% BytesPerSector
== 0);
465 assert(Length
% BytesPerSector
== 0)
467 // Is this a write of the volume ?
468 if (Fcb
->Flags
& FCB_IS_VOLUME
)
470 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &WriteOffset
, Length
, Buffer
);
471 if (!NT_SUCCESS(Status
))
473 DPRINT1("Volume writing failed, Status %x\n", Status
);
478 // Is this a write to the FAT ?
479 if (Fcb
->Flags
& FCB_IS_FAT
)
481 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
482 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
484 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &WriteOffset
, Length
, Buffer
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("FAT writing failed, Status %x\n", Status
);
489 WriteOffset
.u
.LowPart
+= Fcb
->RFCB
.FileSize
.u
.LowPart
;
495 * Find the first cluster
497 FirstCluster
= CurrentCluster
=
498 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
500 if (FirstCluster
== 1)
502 assert(WriteOffset
.u
.LowPart
+ Length
<= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
);
503 // Directory of FAT12/16 needs a special handling
504 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
505 // Fire up the write command
506 Status
= VfatWriteDisk (DeviceExt
->StorageDevice
, &WriteOffset
, Length
, Buffer
);
511 * Find the cluster to start the write from
513 if (Ccb
->LastCluster
> 0 && WriteOffset
.u
.LowPart
> Ccb
->LastOffset
)
515 CurrentCluster
= Ccb
->LastCluster
;
518 Status
= OffsetToCluster(DeviceExt
, Fcb
, FirstCluster
,
519 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
520 &CurrentCluster
, FALSE
);
522 if (!NT_SUCCESS(Status
))
527 Ccb
->LastCluster
= CurrentCluster
;
528 Ccb
->LastOffset
= ROUND_DOWN (WriteOffset
.u
.LowPart
, BytesPerCluster
);
530 while (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
532 StartCluster
= CurrentCluster
;
533 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
542 BytesDone
= min (Length
, BytesPerCluster
- (WriteOffset
.u
.LowPart
% BytesPerCluster
));
543 StartOffset
.QuadPart
+= WriteOffset
.u
.LowPart
% BytesPerCluster
;
548 if (Length
- BytesDone
> BytesPerCluster
)
550 BytesDone
+= BytesPerCluster
;
557 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
559 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
560 DPRINT("start %08x, next %08x, count %d\n",
561 StartCluster
, CurrentCluster
, ClusterCount
);
563 Ccb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
564 Ccb
->LastOffset
= WriteOffset
.u
.LowPart
+ (ClusterCount
- 1) * BytesPerCluster
;
566 // Fire up the write command
567 Status
= VfatWriteDisk (DeviceExt
->StorageDevice
, &StartOffset
, BytesDone
, Buffer
);
568 if (NT_SUCCESS(Status
))
572 WriteOffset
.u
.LowPart
+= BytesDone
;
579 VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
585 ULONG ReturnedLength
= 0;
586 PERESOURCE Resource
= NULL
;
587 LARGE_INTEGER ByteOffset
;
589 PDEVICE_OBJECT DeviceToVerify
;
590 ULONG BytesPerSector
;
594 DPRINT("VfatRead(IrpContext %x)\n", IrpContext
);
596 assert(IrpContext
->DeviceObject
);
598 // This request is not allowed on the main device object
599 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
601 DPRINT("VfatRead is called with the main device object.\n");
602 Status
= STATUS_INVALID_DEVICE_REQUEST
;
606 assert(IrpContext
->DeviceExt
);
607 assert(IrpContext
->FileObject
);
608 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
613 DPRINT("<%S>\n", Fcb
->PathName
);
615 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
616 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
617 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
619 /* fail if file is a directory and no paged read */
620 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
622 Status
= STATUS_INVALID_PARAMETER
;
627 DPRINT("'%S', Offset: %d, Length %d\n", Fcb
->PathName
, ByteOffset
.u
.LowPart
, Length
);
629 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
631 Status
= STATUS_INVALID_PARAMETER
;
634 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
636 IrpContext
->Irp
->IoStatus
.Information
= 0;
637 Status
= STATUS_END_OF_FILE
;
640 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
642 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
644 DPRINT("%d %d\n", ByteOffset
.u
.LowPart
, Length
);
645 // non chached read must be sector aligned
646 Status
= STATUS_INVALID_PARAMETER
;
652 IrpContext
->Irp
->IoStatus
.Information
= 0;
653 Status
= STATUS_SUCCESS
;
657 if (Fcb
->Flags
& FCB_IS_VOLUME
)
659 Resource
= &IrpContext
->DeviceExt
->DirResource
;
661 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
663 Resource
= &Fcb
->PagingIoResource
;
667 Resource
= &Fcb
->MainResource
;
669 if (!ExAcquireResourceSharedLite(Resource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
672 Status
= STATUS_PENDING
;
675 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
676 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
680 Status
= STATUS_SUCCESS
;
681 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
683 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
684 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
687 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
690 Status
= STATUS_INVALID_USER_BUFFER
;
695 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
698 CacheSize
= IrpContext
->DeviceExt
->FatInfo
.BytesPerCluster
;
699 if (CacheSize
< PAGESIZE
)
701 CacheSize
= PAGESIZE
;
703 CcRosInitializeFileCache(IrpContext
->FileObject
, &Fcb
->RFCB
.Bcb
, CacheSize
);
705 if (!CcCopyRead(IrpContext
->FileObject
, &ByteOffset
, Length
,
706 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
, Buffer
,
707 &IrpContext
->Irp
->IoStatus
))
709 Status
= STATUS_PENDING
;
713 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
715 Status
= IrpContext
->Irp
->IoStatus
.Status
;
722 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
724 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
;
727 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
730 Status
= STATUS_INVALID_USER_BUFFER
;
734 Status
= VfatReadFileData(IrpContext
, Buffer
, Length
, ByteOffset
, &ReturnedLength
);
736 if (Status == STATUS_VERIFY_REQUIRED)
738 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
739 DeviceToVerify = IoGetDeviceToVerify(KeGetCurrentThread());
740 IoSetDeviceToVerify(KeGetCurrentThread(), NULL);
741 Status = IoVerifyVolume (DeviceToVerify, FALSE);
743 if (NT_SUCCESS(Status))
745 Status = VfatReadFileData(IrpContext, Buffer, Length,
746 ByteOffset.u.LowPart, &ReturnedLength);
750 if (NT_SUCCESS(Status
))
752 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
759 ExReleaseResourceLite(Resource
);
762 if (Status
== STATUS_PENDING
)
764 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
765 if (NT_SUCCESS(Status
))
767 Status
= VfatQueueRequest(IrpContext
);
771 IrpContext
->Irp
->IoStatus
.Status
= Status
;
772 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
773 VfatFreeIrpContext(IrpContext
);
778 IrpContext
->Irp
->IoStatus
.Status
= Status
;
779 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
780 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
781 (NT_SUCCESS(Status
) || Status
==STATUS_END_OF_FILE
))
783 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
784 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
787 IoCompleteRequest(IrpContext
->Irp
,
788 NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
);
789 VfatFreeIrpContext(IrpContext
);
791 DPRINT("%x\n", Status
);
795 NTSTATUS
VfatWrite (PVFAT_IRP_CONTEXT IrpContext
)
799 PERESOURCE Resource
= NULL
;
800 LARGE_INTEGER ByteOffset
;
801 LARGE_INTEGER OldFileSize
;
802 NTSTATUS Status
= STATUS_SUCCESS
;
804 ULONG OldAllocationSize
;
806 ULONG BytesPerSector
;
810 DPRINT("VfatWrite(IrpContext %x)\n", IrpContext
);
812 assert(IrpContext
->DeviceObject
);
814 // This request is not allowed on the main device object
815 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
817 DPRINT("VfatWrite is called with the main device object.\n");
818 Status
= STATUS_INVALID_DEVICE_REQUEST
;
822 assert(IrpContext
->DeviceExt
);
823 assert(IrpContext
->FileObject
);
824 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
829 DPRINT("<%S>\n", Fcb
->PathName
);
831 /* fail if file is a directory and no paged read */
832 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
834 Status
= STATUS_INVALID_PARAMETER
;
838 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
839 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
840 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
842 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
844 Status
= STATUS_INVALID_PARAMETER
;
848 if (Fcb
->Flags
& (FCB_IS_FAT
| FCB_IS_VOLUME
) ||
849 1 == vfatDirEntryGetFirstCluster (IrpContext
->DeviceExt
, &Fcb
->entry
))
851 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
853 // we can't extend the FAT, the volume or the root on FAT12/FAT16
854 Status
= STATUS_END_OF_FILE
;
859 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
|IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
861 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
863 // non chached write must be sector aligned
864 Status
= STATUS_INVALID_PARAMETER
;
871 IrpContext
->Irp
->IoStatus
.Information
= 0;
872 Status
= STATUS_SUCCESS
;
876 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
878 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
880 Status
= STATUS_INVALID_PARAMETER
;
883 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
885 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
889 if (Fcb
->Flags
& FCB_IS_VOLUME
)
891 Resource
= &IrpContext
->DeviceExt
->DirResource
;
893 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
895 Resource
= &Fcb
->PagingIoResource
;
899 Resource
= &Fcb
->MainResource
;
902 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
904 if (!ExAcquireResourceSharedLite(Resource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
907 Status
= STATUS_PENDING
;
913 if (!ExAcquireResourceExclusiveLite(Resource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
916 Status
= STATUS_PENDING
;
921 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
923 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
925 Status
= STATUS_PENDING
;
930 OldFileSize
= Fcb
->RFCB
.FileSize
;
931 OldAllocationSize
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
;
933 if (!(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)) &&
934 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
935 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
937 LARGE_INTEGER AllocationSize
;
938 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
939 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
940 IrpContext
->DeviceExt
, &AllocationSize
);
941 if (!NT_SUCCESS (Status
))
948 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
950 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
953 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
954 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
959 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
962 Status
= STATUS_INVALID_USER_BUFFER
;
966 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
969 CacheSize
= IrpContext
->DeviceExt
->FatInfo
.BytesPerCluster
;
970 if (CacheSize
< PAGESIZE
)
972 CacheSize
= PAGESIZE
;
974 CcRosInitializeFileCache(IrpContext
->FileObject
, &Fcb
->RFCB
.Bcb
, CacheSize
);
976 if (CcCopyWrite(IrpContext
->FileObject
, &ByteOffset
, Length
,
977 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer
))
979 IrpContext
->Irp
->IoStatus
.Information
= Length
;
980 Status
= STATUS_SUCCESS
;
984 Status
= STATUS_UNSUCCESSFUL
;
993 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
996 Status
= STATUS_INVALID_USER_BUFFER
;
1000 Status
= VfatWriteFileData(IrpContext
, Buffer
, Length
, ByteOffset
);
1001 if (NT_SUCCESS(Status
))
1003 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1007 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
1008 !(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
1010 if(!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1012 LARGE_INTEGER SystemTime
, LocalTime
;
1013 // set dates and times
1014 KeQuerySystemTime (&SystemTime
);
1015 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
1016 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
, &Fcb
->entry
.UpdateDate
,
1017 &Fcb
->entry
.UpdateTime
);
1018 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
1019 // update dates/times and length
1020 if (OldAllocationSize
!= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1022 VfatUpdateEntry (IrpContext
->DeviceExt
, IrpContext
->FileObject
);
1023 Fcb
->Flags
&= ~FCB_UPDATE_DIRENTRY
;
1026 Fcb
->Flags
|= FCB_UPDATE_DIRENTRY
;
1033 ExReleaseResourceLite(Resource
);
1036 if (Status
== STATUS_PENDING
)
1038 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1039 if (NT_SUCCESS(Status
))
1041 Status
= VfatQueueRequest(IrpContext
);
1045 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1046 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1047 VfatFreeIrpContext(IrpContext
);
1052 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1053 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
1054 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
1056 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1057 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1060 IoCompleteRequest(IrpContext
->Irp
,
1061 NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
);
1062 VfatFreeIrpContext(IrpContext
);
1064 DPRINT("%x\n", Status
);