2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/rw.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
10 /* INCLUDES *****************************************************************/
16 * Uncomment to enable strict verification of cluster/offset pair
17 * caching. If this option is enabled you lose all the benefits of
18 * the caching and the read/write operations will actually be
19 * slower. It's meant only for debugging!!!
20 * - Filip Navara, 26/07/2004
22 /* #define DEBUG_VERIFY_OFFSET_CACHING */
24 /* FUNCTIONS *****************************************************************/
27 NextCluster(PDEVICE_EXTENSION DeviceExt
,
29 PULONG CurrentCluster
,
32 * Return the next cluster in a FAT chain, possibly extending the chain if
36 if (FirstCluster
== 1)
38 (*CurrentCluster
) += DeviceExt
->FatInfo
.SectorsPerCluster
;
39 return(STATUS_SUCCESS
);
44 return GetNextClusterExtend(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
46 return GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
51 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
57 * Return the cluster corresponding to an offset within a file,
58 * possibly extending the file if necessary
65 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
66 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
67 Fcb, FirstCluster, FileOffset, Cluster, Extend);
69 if (FirstCluster
== 0)
71 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
75 if (FirstCluster
== 1)
77 /* root of FAT16 or FAT12 */
78 *Cluster
= DeviceExt
->FatInfo
.rootStart
+ FileOffset
79 / (DeviceExt
->FatInfo
.BytesPerCluster
) * DeviceExt
->FatInfo
.SectorsPerCluster
;
80 return(STATUS_SUCCESS
);
84 CurrentCluster
= FirstCluster
;
87 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
89 Status
= GetNextClusterExtend (DeviceExt
, CurrentCluster
, &CurrentCluster
);
90 if (!NT_SUCCESS(Status
))
93 *Cluster
= CurrentCluster
;
97 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
99 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
);
100 if (!NT_SUCCESS(Status
))
103 *Cluster
= CurrentCluster
;
105 return(STATUS_SUCCESS
);
110 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext
,
112 LARGE_INTEGER ReadOffset
,
115 * FUNCTION: Reads data from a file
118 ULONG CurrentCluster
;
122 LARGE_INTEGER StartOffset
;
123 PDEVICE_EXTENSION DeviceExt
;
124 BOOLEAN First
= TRUE
;
129 ULONG BytesPerSector
;
130 ULONG BytesPerCluster
;
136 DeviceExt
= IrpContext
->DeviceExt
;
138 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
139 ASSERT(IrpContext
->FileObject
);
140 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
142 DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, "
143 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt
,
144 IrpContext
->FileObject
, Length
, ReadOffset
.QuadPart
);
148 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
149 Fcb
= IrpContext
->FileObject
->FsContext
;
150 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
151 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
153 ASSERT(ReadOffset
.QuadPart
+ Length
<= ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
));
154 ASSERT(ReadOffset
.u
.LowPart
% BytesPerSector
== 0);
155 ASSERT(Length
% BytesPerSector
== 0);
157 /* Is this a read of the FAT? */
158 if (Fcb
->Flags
& FCB_IS_FAT
)
160 ReadOffset
.QuadPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
161 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
163 if (NT_SUCCESS(Status
))
165 *LengthRead
= Length
;
169 DPRINT1("FAT reading failed, Status %x\n", Status
);
173 /* Is this a read of the Volume ? */
174 if (Fcb
->Flags
& FCB_IS_VOLUME
)
176 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
177 if (NT_SUCCESS(Status
))
179 *LengthRead
= Length
;
183 DPRINT1("Volume reading failed, Status %x\n", Status
);
189 * Find the first cluster
191 FirstCluster
= CurrentCluster
=
192 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
194 if (FirstCluster
== 1)
196 // Directory of FAT12/16 needs a special handling
197 if (ReadOffset
.u
.LowPart
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
)
199 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
- ReadOffset
.u
.LowPart
;
201 ReadOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
203 // Fire up the read command
205 Status
= VfatReadDiskPartial (IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
206 if (NT_SUCCESS(Status
))
208 *LengthRead
= Length
;
213 ExAcquireFastMutex(&Fcb
->LastMutex
);
214 LastCluster
= Fcb
->LastCluster
;
215 LastOffset
= Fcb
->LastOffset
;
216 ExReleaseFastMutex(&Fcb
->LastMutex
);
219 * Find the cluster to start the read from
221 if (LastCluster
> 0 && ReadOffset
.u
.LowPart
>= LastOffset
)
223 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
224 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) -
226 &CurrentCluster
, FALSE
);
227 #ifdef DEBUG_VERIFY_OFFSET_CACHING
228 /* DEBUG VERIFICATION */
230 ULONG CorrectCluster
;
231 OffsetToCluster(DeviceExt
, FirstCluster
,
232 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
233 &CorrectCluster
, FALSE
);
234 if (CorrectCluster
!= CurrentCluster
)
235 KeBugCheck(FAT_FILE_SYSTEM
);
241 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
242 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
243 &CurrentCluster
, FALSE
);
245 if (!NT_SUCCESS(Status
))
250 ExAcquireFastMutex(&Fcb
->LastMutex
);
251 Fcb
->LastCluster
= CurrentCluster
;
252 Fcb
->LastOffset
= ROUND_DOWN (ReadOffset
.u
.LowPart
, BytesPerCluster
);
253 ExReleaseFastMutex(&Fcb
->LastMutex
);
255 KeInitializeEvent(&IrpContext
->Event
, NotificationEvent
, FALSE
);
256 IrpContext
->RefCount
= 1;
258 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
260 StartCluster
= CurrentCluster
;
261 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
270 BytesDone
= min (Length
, BytesPerCluster
- (ReadOffset
.u
.LowPart
% BytesPerCluster
));
271 StartOffset
.QuadPart
+= ReadOffset
.u
.LowPart
% BytesPerCluster
;
276 if (Length
- BytesDone
> BytesPerCluster
)
278 BytesDone
+= BytesPerCluster
;
285 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
287 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
288 DPRINT("start %08x, next %08x, count %d\n",
289 StartCluster
, CurrentCluster
, ClusterCount
);
291 ExAcquireFastMutex(&Fcb
->LastMutex
);
292 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
293 Fcb
->LastOffset
= ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
294 ExReleaseFastMutex(&Fcb
->LastMutex
);
296 // Fire up the read command
297 Status
= VfatReadDiskPartial (IrpContext
, &StartOffset
, BytesDone
, *LengthRead
, FALSE
);
298 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
302 *LengthRead
+= BytesDone
;
304 ReadOffset
.u
.LowPart
+= BytesDone
;
306 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
308 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
310 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
314 Status
= STATUS_UNSUCCESSFUL
;
318 Status
= IrpContext
->Irp
->IoStatus
.Status
;
325 VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext
,
327 LARGE_INTEGER WriteOffset
)
329 PDEVICE_EXTENSION DeviceExt
;
334 ULONG CurrentCluster
;
338 NTSTATUS Status
= STATUS_SUCCESS
;
339 BOOLEAN First
= TRUE
;
340 ULONG BytesPerSector
;
341 ULONG BytesPerCluster
;
342 LARGE_INTEGER StartOffset
;
349 DeviceExt
= IrpContext
->DeviceExt
;
351 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
352 ASSERT(IrpContext
->FileObject
);
353 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
355 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
356 Fcb
= IrpContext
->FileObject
->FsContext
;
357 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
358 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
360 DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, "
361 "Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt
,
362 IrpContext
->FileObject
, Length
, WriteOffset
,
365 ASSERT(WriteOffset
.QuadPart
+ Length
<= Fcb
->RFCB
.AllocationSize
.QuadPart
);
366 ASSERT(WriteOffset
.u
.LowPart
% BytesPerSector
== 0);
367 ASSERT(Length
% BytesPerSector
== 0);
369 // Is this a write of the volume ?
370 if (Fcb
->Flags
& FCB_IS_VOLUME
)
372 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
373 if (!NT_SUCCESS(Status
))
375 DPRINT1("Volume writing failed, Status %x\n", Status
);
380 // Is this a write to the FAT ?
381 if (Fcb
->Flags
& FCB_IS_FAT
)
383 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
384 IrpContext
->RefCount
= 1;
385 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
387 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, FALSE
);
388 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
390 DPRINT1("FAT writing failed, Status %x\n", Status
);
393 WriteOffset
.u
.LowPart
+= Fcb
->RFCB
.FileSize
.u
.LowPart
;
395 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
397 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
399 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
401 Status
= IrpContext
->Irp
->IoStatus
.Status
;
407 * Find the first cluster
409 FirstCluster
= CurrentCluster
=
410 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
412 if (FirstCluster
== 1)
414 ASSERT(WriteOffset
.u
.LowPart
+ Length
<= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
);
415 // Directory of FAT12/16 needs a special handling
416 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
417 // Fire up the write command
418 Status
= VfatWriteDiskPartial (IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
422 ExAcquireFastMutex(&Fcb
->LastMutex
);
423 LastCluster
= Fcb
->LastCluster
;
424 LastOffset
= Fcb
->LastOffset
;
425 ExReleaseFastMutex(&Fcb
->LastMutex
);
428 * Find the cluster to start the write from
430 if (LastCluster
> 0 && WriteOffset
.u
.LowPart
>= LastOffset
)
432 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
433 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) -
435 &CurrentCluster
, FALSE
);
436 #ifdef DEBUG_VERIFY_OFFSET_CACHING
437 /* DEBUG VERIFICATION */
439 ULONG CorrectCluster
;
440 OffsetToCluster(DeviceExt
, FirstCluster
,
441 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
442 &CorrectCluster
, FALSE
);
443 if (CorrectCluster
!= CurrentCluster
)
444 KeBugCheck(FAT_FILE_SYSTEM
);
450 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
451 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
452 &CurrentCluster
, FALSE
);
455 if (!NT_SUCCESS(Status
))
460 ExAcquireFastMutex(&Fcb
->LastMutex
);
461 Fcb
->LastCluster
= CurrentCluster
;
462 Fcb
->LastOffset
= ROUND_DOWN (WriteOffset
.u
.LowPart
, BytesPerCluster
);
463 ExReleaseFastMutex(&Fcb
->LastMutex
);
465 IrpContext
->RefCount
= 1;
468 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
470 StartCluster
= CurrentCluster
;
471 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
480 BytesDone
= min (Length
, BytesPerCluster
- (WriteOffset
.u
.LowPart
% BytesPerCluster
));
481 StartOffset
.QuadPart
+= WriteOffset
.u
.LowPart
% BytesPerCluster
;
486 if (Length
- BytesDone
> BytesPerCluster
)
488 BytesDone
+= BytesPerCluster
;
495 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
497 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
498 DPRINT("start %08x, next %08x, count %d\n",
499 StartCluster
, CurrentCluster
, ClusterCount
);
501 ExAcquireFastMutex(&Fcb
->LastMutex
);
502 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
503 Fcb
->LastOffset
= ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
504 ExReleaseFastMutex(&Fcb
->LastMutex
);
506 // Fire up the write command
507 Status
= VfatWriteDiskPartial (IrpContext
, &StartOffset
, BytesDone
, BufferOffset
, FALSE
);
508 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
512 BufferOffset
+= BytesDone
;
514 WriteOffset
.u
.LowPart
+= BytesDone
;
516 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
518 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
520 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
524 Status
= STATUS_UNSUCCESSFUL
;
528 Status
= IrpContext
->Irp
->IoStatus
.Status
;
535 VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
540 ULONG ReturnedLength
= 0;
541 PERESOURCE Resource
= NULL
;
542 LARGE_INTEGER ByteOffset
;
544 PDEVICE_OBJECT DeviceToVerify
;
545 ULONG BytesPerSector
;
549 DPRINT("VfatRead(IrpContext %p)\n", IrpContext
);
551 ASSERT(IrpContext
->DeviceObject
);
553 // This request is not allowed on the main device object
554 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
556 DPRINT("VfatRead is called with the main device object.\n");
557 Status
= STATUS_INVALID_DEVICE_REQUEST
;
561 ASSERT(IrpContext
->DeviceExt
);
562 ASSERT(IrpContext
->FileObject
);
563 Fcb
= IrpContext
->FileObject
->FsContext
;
566 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
568 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
570 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
571 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
572 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
573 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
574 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
575 VfatFreeIrpContext(IrpContext
);
579 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
580 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
581 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
583 /* fail if file is a directory and no paged read */
584 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
586 Status
= STATUS_INVALID_PARAMETER
;
591 DPRINT("'%wZ', Offset: %d, Length %d\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
593 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
595 Status
= STATUS_INVALID_PARAMETER
;
598 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
600 IrpContext
->Irp
->IoStatus
.Information
= 0;
601 Status
= STATUS_END_OF_FILE
;
604 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
606 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
608 DPRINT("%d %d\n", ByteOffset
.u
.LowPart
, Length
);
609 // non cached read must be sector aligned
610 Status
= STATUS_INVALID_PARAMETER
;
616 IrpContext
->Irp
->IoStatus
.Information
= 0;
617 Status
= STATUS_SUCCESS
;
621 if (Fcb
->Flags
& FCB_IS_VOLUME
)
623 Resource
= &IrpContext
->DeviceExt
->DirResource
;
625 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
627 Resource
= &Fcb
->PagingIoResource
;
631 Resource
= &Fcb
->MainResource
;
633 if (!ExAcquireResourceSharedLite(Resource
,
634 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
? TRUE
: FALSE
))
637 Status
= STATUS_PENDING
;
641 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
642 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
644 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
646 Status
= STATUS_FILE_LOCK_CONFLICT
;
651 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
654 Status
= STATUS_INVALID_USER_BUFFER
;
658 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
659 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
662 Status
= STATUS_SUCCESS
;
663 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
665 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
666 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
669 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
671 CcInitializeCacheMap(IrpContext
->FileObject
,
672 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
674 &(VfatGlobalData
->CacheMgrCallbacks
),
677 if (!CcCopyRead(IrpContext
->FileObject
, &ByteOffset
, Length
,
678 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
), Buffer
,
679 &IrpContext
->Irp
->IoStatus
))
681 Status
= STATUS_PENDING
;
684 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
686 Status
= IrpContext
->Irp
->IoStatus
.Status
;
692 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
694 Length
= (ULONG
)(ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
697 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
698 if (!NT_SUCCESS(Status
))
703 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
705 if (Status
== STATUS_VERIFY_REQUIRED
)
707 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
708 DeviceToVerify
= IoGetDeviceToVerify(PsGetCurrentThread());
709 IoSetDeviceToVerify(PsGetCurrentThread(), DeviceToVerify
);
710 Status
= IoVerifyVolume (DeviceToVerify
, FALSE
);
712 if (NT_SUCCESS(Status
))
714 Status
= VfatReadFileData(IrpContext
, Length
,
715 ByteOffset
, &ReturnedLength
);
720 if (NT_SUCCESS(Status
))
722 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
729 ExReleaseResourceLite(Resource
);
732 if (Status
== STATUS_PENDING
)
734 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
735 if (NT_SUCCESS(Status
))
737 Status
= VfatQueueRequest(IrpContext
);
741 IrpContext
->Irp
->IoStatus
.Status
= Status
;
742 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
743 VfatFreeIrpContext(IrpContext
);
748 IrpContext
->Irp
->IoStatus
.Status
= Status
;
749 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
750 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
751 (NT_SUCCESS(Status
) || Status
==STATUS_END_OF_FILE
))
753 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
754 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
757 IoCompleteRequest(IrpContext
->Irp
,
758 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
759 VfatFreeIrpContext(IrpContext
);
761 DPRINT("%x\n", Status
);
765 NTSTATUS
VfatWrite (PVFAT_IRP_CONTEXT IrpContext
)
768 PERESOURCE Resource
= NULL
;
769 LARGE_INTEGER ByteOffset
;
770 LARGE_INTEGER OldFileSize
;
771 NTSTATUS Status
= STATUS_SUCCESS
;
773 ULONG OldAllocationSize
;
775 ULONG BytesPerSector
;
779 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
781 ASSERT(IrpContext
->DeviceObject
);
783 // This request is not allowed on the main device object
784 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
786 DPRINT("VfatWrite is called with the main device object.\n");
787 Status
= STATUS_INVALID_DEVICE_REQUEST
;
791 ASSERT(IrpContext
->DeviceExt
);
792 ASSERT(IrpContext
->FileObject
);
793 Fcb
= IrpContext
->FileObject
->FsContext
;
796 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
798 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
800 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
801 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
802 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
803 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
804 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
805 VfatFreeIrpContext(IrpContext
);
809 /* fail if file is a directory and no paged read */
810 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
812 Status
= STATUS_INVALID_PARAMETER
;
816 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
817 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
818 ByteOffset
.u
.HighPart
== -1)
820 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
822 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
823 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
825 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
827 Status
= STATUS_INVALID_PARAMETER
;
831 if (Fcb
->Flags
& (FCB_IS_FAT
| FCB_IS_VOLUME
) ||
832 1 == vfatDirEntryGetFirstCluster (IrpContext
->DeviceExt
, &Fcb
->entry
))
834 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
836 // we can't extend the FAT, the volume or the root on FAT12/FAT16
837 Status
= STATUS_END_OF_FILE
;
842 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
|IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
844 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
846 // non cached write must be sector aligned
847 Status
= STATUS_INVALID_PARAMETER
;
855 * Update last write time
857 IrpContext
->Irp
->IoStatus
.Information
= 0;
858 Status
= STATUS_SUCCESS
;
862 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
864 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
866 Status
= STATUS_INVALID_PARAMETER
;
869 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
871 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
875 if (Fcb
->Flags
& FCB_IS_VOLUME
)
877 Resource
= &IrpContext
->DeviceExt
->DirResource
;
879 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
881 Resource
= &Fcb
->PagingIoResource
;
885 Resource
= &Fcb
->MainResource
;
888 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
890 if (!ExAcquireResourceSharedLite(Resource
,
891 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
894 Status
= STATUS_PENDING
;
900 if (!ExAcquireResourceExclusiveLite(Resource
,
901 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
904 Status
= STATUS_PENDING
;
909 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
910 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
912 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
914 Status
= STATUS_FILE_LOCK_CONFLICT
;
919 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
921 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
923 Status
= STATUS_PENDING
;
928 OldFileSize
= Fcb
->RFCB
.FileSize
;
929 OldAllocationSize
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
;
931 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
934 Status
= STATUS_INVALID_USER_BUFFER
;
939 if (!(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)) &&
940 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
941 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
943 LARGE_INTEGER AllocationSize
;
944 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
945 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
946 IrpContext
->DeviceExt
, &AllocationSize
);
947 if (!NT_SUCCESS (Status
))
953 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
954 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
958 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
960 CcInitializeCacheMap(IrpContext
->FileObject
,
961 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
963 &VfatGlobalData
->CacheMgrCallbacks
,
966 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
968 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
970 if (CcCopyWrite(IrpContext
->FileObject
, &ByteOffset
, Length
,
971 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer
))
973 IrpContext
->Irp
->IoStatus
.Information
= Length
;
974 Status
= STATUS_SUCCESS
;
978 Status
= STATUS_UNSUCCESSFUL
;
985 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
987 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
990 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
991 if (!NT_SUCCESS(Status
))
996 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
997 if (NT_SUCCESS(Status
))
999 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1003 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
1004 !(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
1006 if(!(*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
1008 LARGE_INTEGER SystemTime
;
1009 // set dates and times
1010 KeQuerySystemTime (&SystemTime
);
1011 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1013 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
1014 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
1015 &Fcb
->entry
.FatX
.UpdateTime
);
1016 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
1017 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
1021 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
1022 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1023 &Fcb
->entry
.Fat
.UpdateTime
);
1024 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1026 /* set date and times to dirty */
1027 Fcb
->Flags
|= FCB_IS_DIRTY
;
1034 ExReleaseResourceLite(Resource
);
1037 if (Status
== STATUS_PENDING
)
1039 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1040 if (NT_SUCCESS(Status
))
1042 Status
= VfatQueueRequest(IrpContext
);
1046 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1047 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1048 VfatFreeIrpContext(IrpContext
);
1053 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1054 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
1055 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
1057 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1058 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1061 IoCompleteRequest(IrpContext
->Irp
,
1062 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
1063 VfatFreeIrpContext(IrpContext
);
1065 DPRINT("%x\n", Status
);