2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/filesystems/fastfat/rw.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Pierre Schweitzer (pierre@reactos.org)
11 /* INCLUDES *****************************************************************/
19 * Uncomment to enable strict verification of cluster/offset pair
20 * caching. If this option is enabled you lose all the benefits of
21 * the caching and the read/write operations will actually be
22 * slower. It's meant only for debugging!!!
23 * - Filip Navara, 26/07/2004
25 /* #define DEBUG_VERIFY_OFFSET_CACHING */
27 /* Arbitrary, taken from MS FastFAT, should be
28 * refined given what we experience in common
29 * out of stack operations
31 #define OVERFLOW_READ_THRESHHOLD 0xE00
33 /* FUNCTIONS *****************************************************************/
36 * Return the next cluster in a FAT chain, possibly extending the chain if
41 PDEVICE_EXTENSION DeviceExt
,
43 PULONG CurrentCluster
,
46 if (FirstCluster
== 1)
48 (*CurrentCluster
) += DeviceExt
->FatInfo
.SectorsPerCluster
;
49 return STATUS_SUCCESS
;
54 return GetNextClusterExtend(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
56 return GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
62 PDEVICE_EXTENSION DeviceExt
,
72 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
73 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
74 Fcb, FirstCluster, FileOffset, Cluster, Extend);
76 if (FirstCluster
== 0)
78 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
82 if (FirstCluster
== 1)
84 /* root of FAT16 or FAT12 */
85 *Cluster
= DeviceExt
->FatInfo
.rootStart
+ FileOffset
86 / (DeviceExt
->FatInfo
.BytesPerCluster
) * DeviceExt
->FatInfo
.SectorsPerCluster
;
87 return STATUS_SUCCESS
;
91 CurrentCluster
= FirstCluster
;
94 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
96 Status
= GetNextClusterExtend (DeviceExt
, CurrentCluster
, &CurrentCluster
);
97 if (!NT_SUCCESS(Status
))
100 *Cluster
= CurrentCluster
;
104 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
106 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
);
107 if (!NT_SUCCESS(Status
))
110 *Cluster
= CurrentCluster
;
112 return STATUS_SUCCESS
;
117 * FUNCTION: Reads data from a file
122 PVFAT_IRP_CONTEXT IrpContext
,
124 LARGE_INTEGER ReadOffset
,
127 ULONG CurrentCluster
;
131 LARGE_INTEGER StartOffset
;
132 PDEVICE_EXTENSION DeviceExt
;
133 BOOLEAN First
= TRUE
;
137 ULONG BytesPerSector
;
138 ULONG BytesPerCluster
;
144 DeviceExt
= IrpContext
->DeviceExt
;
146 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
147 ASSERT(IrpContext
->FileObject
);
148 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
150 DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, "
151 "Length %u, ReadOffset 0x%I64x)\n", DeviceExt
,
152 IrpContext
->FileObject
, Length
, ReadOffset
.QuadPart
);
156 Fcb
= IrpContext
->FileObject
->FsContext
;
157 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
158 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
160 ASSERT(ReadOffset
.QuadPart
+ Length
<= ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
));
161 ASSERT(ReadOffset
.u
.LowPart
% BytesPerSector
== 0);
162 ASSERT(Length
% BytesPerSector
== 0);
164 /* Is this a read of the FAT? */
165 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_FAT
))
167 ReadOffset
.QuadPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
168 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
170 if (NT_SUCCESS(Status
))
172 *LengthRead
= Length
;
176 DPRINT1("FAT reading failed, Status %x\n", Status
);
181 /* Is this a read of the Volume ? */
182 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
))
184 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
185 if (NT_SUCCESS(Status
))
187 *LengthRead
= Length
;
191 DPRINT1("Volume reading failed, Status %x\n", Status
);
196 /* Find the first cluster */
198 CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
200 if (FirstCluster
== 1)
202 /* Directory of FAT12/16 needs a special handling */
203 if (ReadOffset
.u
.LowPart
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
)
205 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
- ReadOffset
.u
.LowPart
;
207 ReadOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
209 /* Fire up the read command */
210 Status
= VfatReadDiskPartial (IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
211 if (NT_SUCCESS(Status
))
213 *LengthRead
= Length
;
218 ExAcquireFastMutex(&Fcb
->LastMutex
);
219 LastCluster
= Fcb
->LastCluster
;
220 LastOffset
= Fcb
->LastOffset
;
221 ExReleaseFastMutex(&Fcb
->LastMutex
);
223 /* Find the cluster to start the read from */
224 if (LastCluster
> 0 && ReadOffset
.u
.LowPart
>= LastOffset
)
226 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
227 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) -
229 &CurrentCluster
, FALSE
);
230 #ifdef DEBUG_VERIFY_OFFSET_CACHING
231 /* DEBUG VERIFICATION */
233 ULONG CorrectCluster
;
234 OffsetToCluster(DeviceExt
, FirstCluster
,
235 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
236 &CorrectCluster
, FALSE
);
237 if (CorrectCluster
!= CurrentCluster
)
238 KeBugCheck(FAT_FILE_SYSTEM
);
244 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
245 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
246 &CurrentCluster
, FALSE
);
249 if (!NT_SUCCESS(Status
))
254 ExAcquireFastMutex(&Fcb
->LastMutex
);
255 Fcb
->LastCluster
= CurrentCluster
;
256 Fcb
->LastOffset
= ROUND_DOWN (ReadOffset
.u
.LowPart
, BytesPerCluster
);
257 ExReleaseFastMutex(&Fcb
->LastMutex
);
259 KeInitializeEvent(&IrpContext
->Event
, NotificationEvent
, FALSE
);
260 IrpContext
->RefCount
= 1;
262 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
264 StartCluster
= CurrentCluster
;
265 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
274 BytesDone
= min (Length
, BytesPerCluster
- (ReadOffset
.u
.LowPart
% BytesPerCluster
));
275 StartOffset
.QuadPart
+= ReadOffset
.u
.LowPart
% BytesPerCluster
;
280 if (Length
- BytesDone
> BytesPerCluster
)
282 BytesDone
+= BytesPerCluster
;
289 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
291 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
292 DPRINT("start %08x, next %08x, count %u\n",
293 StartCluster
, CurrentCluster
, ClusterCount
);
295 ExAcquireFastMutex(&Fcb
->LastMutex
);
296 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
297 Fcb
->LastOffset
= ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
298 ExReleaseFastMutex(&Fcb
->LastMutex
);
300 /* Fire up the read command */
301 Status
= VfatReadDiskPartial (IrpContext
, &StartOffset
, BytesDone
, *LengthRead
, FALSE
);
302 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
306 *LengthRead
+= BytesDone
;
308 ReadOffset
.u
.LowPart
+= BytesDone
;
311 if (InterlockedDecrement((PLONG
)&IrpContext
->RefCount
) != 0)
313 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
316 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
320 Status
= STATUS_UNSUCCESSFUL
;
324 Status
= IrpContext
->Irp
->IoStatus
.Status
;
334 PVFAT_IRP_CONTEXT IrpContext
,
336 LARGE_INTEGER WriteOffset
)
338 PDEVICE_EXTENSION DeviceExt
;
342 ULONG CurrentCluster
;
346 NTSTATUS Status
= STATUS_SUCCESS
;
347 BOOLEAN First
= TRUE
;
348 ULONG BytesPerSector
;
349 ULONG BytesPerCluster
;
350 LARGE_INTEGER StartOffset
;
357 DeviceExt
= IrpContext
->DeviceExt
;
359 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
360 ASSERT(IrpContext
->FileObject
);
361 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
363 Fcb
= IrpContext
->FileObject
->FsContext
;
364 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
365 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
367 DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, "
368 "Length %u, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt
,
369 IrpContext
->FileObject
, Length
, WriteOffset
.QuadPart
,
372 ASSERT(WriteOffset
.QuadPart
+ Length
<= Fcb
->RFCB
.AllocationSize
.QuadPart
);
373 ASSERT(WriteOffset
.u
.LowPart
% BytesPerSector
== 0);
374 ASSERT(Length
% BytesPerSector
== 0);
376 /* Is this a write of the volume? */
377 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
))
379 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
380 if (!NT_SUCCESS(Status
))
382 DPRINT1("Volume writing failed, Status %x\n", Status
);
387 /* Is this a write to the FAT? */
388 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_FAT
))
390 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
391 IrpContext
->RefCount
= 1;
392 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
394 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, FALSE
);
395 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
397 DPRINT1("FAT writing failed, Status %x\n", Status
);
400 WriteOffset
.u
.LowPart
+= Fcb
->RFCB
.FileSize
.u
.LowPart
;
403 if (InterlockedDecrement((PLONG
)&IrpContext
->RefCount
) != 0)
405 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
408 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
410 Status
= IrpContext
->Irp
->IoStatus
.Status
;
416 * Find the first cluster
419 CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
421 if (FirstCluster
== 1)
423 ASSERT(WriteOffset
.u
.LowPart
+ Length
<= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
);
424 // Directory of FAT12/16 needs a special handling
425 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
426 // Fire up the write command
427 Status
= VfatWriteDiskPartial (IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
431 ExAcquireFastMutex(&Fcb
->LastMutex
);
432 LastCluster
= Fcb
->LastCluster
;
433 LastOffset
= Fcb
->LastOffset
;
434 ExReleaseFastMutex(&Fcb
->LastMutex
);
437 * Find the cluster to start the write from
439 if (LastCluster
> 0 && WriteOffset
.u
.LowPart
>= LastOffset
)
441 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
442 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) -
444 &CurrentCluster
, FALSE
);
445 #ifdef DEBUG_VERIFY_OFFSET_CACHING
446 /* DEBUG VERIFICATION */
448 ULONG CorrectCluster
;
449 OffsetToCluster(DeviceExt
, FirstCluster
,
450 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
451 &CorrectCluster
, FALSE
);
452 if (CorrectCluster
!= CurrentCluster
)
453 KeBugCheck(FAT_FILE_SYSTEM
);
459 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
460 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
461 &CurrentCluster
, FALSE
);
464 if (!NT_SUCCESS(Status
))
469 ExAcquireFastMutex(&Fcb
->LastMutex
);
470 Fcb
->LastCluster
= CurrentCluster
;
471 Fcb
->LastOffset
= ROUND_DOWN (WriteOffset
.u
.LowPart
, BytesPerCluster
);
472 ExReleaseFastMutex(&Fcb
->LastMutex
);
474 IrpContext
->RefCount
= 1;
477 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
479 StartCluster
= CurrentCluster
;
480 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
489 BytesDone
= min (Length
, BytesPerCluster
- (WriteOffset
.u
.LowPart
% BytesPerCluster
));
490 StartOffset
.QuadPart
+= WriteOffset
.u
.LowPart
% BytesPerCluster
;
495 if (Length
- BytesDone
> BytesPerCluster
)
497 BytesDone
+= BytesPerCluster
;
504 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
506 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
507 DPRINT("start %08x, next %08x, count %u\n",
508 StartCluster
, CurrentCluster
, ClusterCount
);
510 ExAcquireFastMutex(&Fcb
->LastMutex
);
511 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
512 Fcb
->LastOffset
= ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
513 ExReleaseFastMutex(&Fcb
->LastMutex
);
515 // Fire up the write command
516 Status
= VfatWriteDiskPartial (IrpContext
, &StartOffset
, BytesDone
, BufferOffset
, FALSE
);
517 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
521 BufferOffset
+= BytesDone
;
523 WriteOffset
.u
.LowPart
+= BytesDone
;
526 if (InterlockedDecrement((PLONG
)&IrpContext
->RefCount
) != 0)
528 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
531 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
535 Status
= STATUS_UNSUCCESSFUL
;
539 Status
= IrpContext
->Irp
->IoStatus
.Status
;
547 PVFAT_IRP_CONTEXT IrpContext
)
553 ULONG BytesPerSector
;
554 LARGE_INTEGER ByteOffset
;
555 ULONG ReturnedLength
= 0;
556 BOOLEAN PagingIo
, CanWait
, IsVolume
, NoCache
;
558 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
559 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
560 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
561 Fcb
= IrpContext
->FileObject
->FsContext
;
562 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
564 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
565 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
566 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
569 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
571 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
573 return STATUS_FILE_LOCK_CONFLICT
;
577 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, PagingIo
);
579 if (!PagingIo
&& !NoCache
&& !IsVolume
)
582 Status
= STATUS_SUCCESS
;
583 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
585 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
586 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
589 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileReads
, 1);
590 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileReadBytes
, Length
);
594 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
596 CcInitializeCacheMap(IrpContext
->FileObject
,
597 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
599 &(VfatGlobalData
->CacheMgrCallbacks
),
603 if (!CcCopyRead(IrpContext
->FileObject
,
608 &IrpContext
->Irp
->IoStatus
))
611 Status
= STATUS_PENDING
;
615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
617 Status
= _SEH2_GetExceptionCode();
622 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
624 Status
= IrpContext
->Irp
->IoStatus
.Status
;
630 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
631 if (!NT_SUCCESS(Status
))
636 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
638 Length
= (ULONG
)(ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
643 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedReads
, 1);
644 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedReadBytes
, Length
);
648 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataReads
, 1);
649 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataReadBytes
, Length
);
652 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
653 if (NT_SUCCESS(Status
))
655 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
665 VfatStackOverflowRead(
669 PVFAT_IRP_CONTEXT IrpContext
;
671 IrpContext
= Context
;
672 /* In a separate thread, we can wait and resources got locked */
673 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
675 /* Perform the read operation */
676 DPRINT1("Performing posted read\n");
677 VfatCommonRead(IrpContext
);
679 KeSetEvent(Event
, 0, FALSE
);
684 PVFAT_IRP_CONTEXT IrpContext
,
690 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
692 ExAcquireResourceSharedLite(Lock
, TRUE
);
694 /* If paging IO, call the non failing but blocking routine */
697 FsRtlPostPagingFileStackOverflow(IrpContext
, &Event
, VfatStackOverflowRead
);
701 FsRtlPostStackOverflow(IrpContext
, &Event
, VfatStackOverflowRead
);
704 /* Wait till it's done */
705 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
710 PVFAT_IRP_CONTEXT IrpContext
)
715 PERESOURCE Resource
= NULL
;
716 LARGE_INTEGER ByteOffset
;
717 ULONG BytesPerSector
;
718 BOOLEAN PagingIo
, CanWait
, IsVolume
, NoCache
;
722 DPRINT("VfatRead(IrpContext %p)\n", IrpContext
);
724 ASSERT(IrpContext
->DeviceObject
);
726 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
727 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
728 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
730 // This request is not allowed on the main device object
731 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
733 DPRINT("VfatRead is called with the main device object.\n");
734 Status
= STATUS_INVALID_DEVICE_REQUEST
;
738 ASSERT(IrpContext
->DeviceExt
);
739 ASSERT(IrpContext
->FileObject
);
740 Fcb
= IrpContext
->FileObject
->FsContext
;
743 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
745 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_PAGE_FILE
))
747 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
748 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
749 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
750 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
751 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
752 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
756 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
758 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
759 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
760 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
762 /* fail if file is a directory and no paged read */
763 if (vfatFCBIsDirectory(Fcb
) && !PagingIo
)
765 Status
= STATUS_INVALID_PARAMETER
;
769 DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
771 if (ByteOffset
.u
.HighPart
&& !IsVolume
)
773 Status
= STATUS_INVALID_PARAMETER
;
779 IrpContext
->Irp
->IoStatus
.Information
= 0;
780 Status
= STATUS_SUCCESS
;
784 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
786 IrpContext
->Irp
->IoStatus
.Information
= 0;
787 Status
= STATUS_END_OF_FILE
;
791 if (NoCache
|| PagingIo
|| IsVolume
)
793 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
795 DPRINT("%u %u\n", ByteOffset
.u
.LowPart
, Length
);
796 // non cached read must be sector aligned
797 Status
= STATUS_INVALID_PARAMETER
;
804 Resource
= &IrpContext
->DeviceExt
->DirResource
;
808 Resource
= &Fcb
->PagingIoResource
;
812 Resource
= &Fcb
->MainResource
;
815 /* Are we out of stack for the rest of the operation? */
816 if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD
)
818 /* Lock the buffer */
819 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
820 if (!NT_SUCCESS(Status
))
825 /* And post the read to the overflow thread */
826 VfatPostRead(IrpContext
, Resource
, PagingIo
);
828 /* Return the appropriate status */
829 return IrpContext
->Irp
->IoStatus
.Status
;
832 if (!ExAcquireResourceSharedLite(Resource
, CanWait
))
835 Status
= STATUS_PENDING
;
839 Status
= VfatCommonRead(IrpContext
);
844 ExReleaseResourceLite(Resource
);
847 if (Status
== STATUS_PENDING
)
849 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
850 if (NT_SUCCESS(Status
))
852 Status
= VfatMarkIrpContextForQueue(IrpContext
);
857 IrpContext
->Irp
->IoStatus
.Status
= Status
;
858 if (BooleanFlagOn(IrpContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
) &&
860 (NT_SUCCESS(Status
) || Status
== STATUS_END_OF_FILE
))
862 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
863 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
866 if (NT_SUCCESS(Status
))
867 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
869 DPRINT("%x\n", Status
);
875 PVFAT_IRP_CONTEXT IrpContext
)
878 PERESOURCE Resource
= NULL
;
879 LARGE_INTEGER ByteOffset
;
880 LARGE_INTEGER OldFileSize
;
881 NTSTATUS Status
= STATUS_SUCCESS
;
884 ULONG BytesPerSector
;
885 BOOLEAN PagingIo
, CanWait
, IsVolume
, IsFAT
, NoCache
;
889 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
891 ASSERT(IrpContext
->DeviceObject
);
893 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
894 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
895 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
897 // This request is not allowed on the main device object
898 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
900 DPRINT("VfatWrite is called with the main device object.\n");
901 Status
= STATUS_INVALID_DEVICE_REQUEST
;
905 ASSERT(IrpContext
->DeviceExt
);
906 ASSERT(IrpContext
->FileObject
);
907 Fcb
= IrpContext
->FileObject
->FsContext
;
910 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
911 IsFAT
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_FAT
);
913 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_PAGE_FILE
))
915 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
916 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
917 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
918 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
919 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
920 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
924 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
926 /* fail if file is a directory and no paged read */
927 if (vfatFCBIsDirectory(Fcb
) && !PagingIo
)
929 Status
= STATUS_INVALID_PARAMETER
;
933 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
934 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
935 ByteOffset
.u
.HighPart
== -1)
937 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
939 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
940 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
942 if (ByteOffset
.u
.HighPart
&& !IsVolume
)
944 Status
= STATUS_INVALID_PARAMETER
;
948 if (IsFAT
|| IsVolume
||
949 vfatDirEntryGetFirstCluster(IrpContext
->DeviceExt
, &Fcb
->entry
) == 1)
951 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
953 // we can't extend the FAT, the volume or the root on FAT12/FAT16
954 Status
= STATUS_END_OF_FILE
;
959 if (PagingIo
|| NoCache
|| IsVolume
)
961 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
963 // non cached write must be sector aligned
964 Status
= STATUS_INVALID_PARAMETER
;
969 OldFileSize
= Fcb
->RFCB
.FileSize
;
973 /* Update last write time */
974 IrpContext
->Irp
->IoStatus
.Information
= 0;
975 Status
= STATUS_SUCCESS
;
981 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
983 Status
= STATUS_INVALID_PARAMETER
;
987 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
989 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
993 if (!NoCache
&& !CcCanIWrite(IrpContext
->FileObject
, Length
, CanWait
,
994 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
)))
998 Retrying
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
);
999 SetFlag(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
);
1001 Status
= STATUS_PENDING
;
1002 CcDeferWrite(IrpContext
->FileObject
, VfatHandleDeferredWrite
,
1003 IrpContext
, NULL
, Length
, Retrying
);
1005 DPRINT1("Dererring write!\n");
1012 Resource
= &IrpContext
->DeviceExt
->DirResource
;
1016 Resource
= &Fcb
->PagingIoResource
;
1020 Resource
= &Fcb
->MainResource
;
1025 if (!ExAcquireResourceSharedLite(Resource
, CanWait
))
1028 Status
= STATUS_PENDING
;
1034 if (!ExAcquireResourceExclusiveLite(Resource
, CanWait
))
1037 Status
= STATUS_PENDING
;
1043 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
1045 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
1047 Status
= STATUS_FILE_LOCK_CONFLICT
;
1052 if (!CanWait
&& !IsVolume
)
1054 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1056 Status
= STATUS_PENDING
;
1061 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, PagingIo
);
1063 if (!IsFAT
&& !IsVolume
&& !PagingIo
&&
1064 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
1066 LARGE_INTEGER AllocationSize
;
1068 if (!ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, CanWait
))
1073 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
1074 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
1075 IrpContext
->DeviceExt
, &AllocationSize
);
1077 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
1079 if (!NT_SUCCESS (Status
))
1085 if (!NoCache
&& !PagingIo
&& !IsVolume
)
1089 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileWrites
, 1);
1090 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileWriteBytes
, Length
);
1094 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
1096 CcInitializeCacheMap(IrpContext
->FileObject
,
1097 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
1099 &VfatGlobalData
->CacheMgrCallbacks
,
1103 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1105 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1108 if (CcCopyWrite(IrpContext
->FileObject
,
1114 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1115 Status
= STATUS_SUCCESS
;
1119 ASSERT(FALSE
/*!CanWait*/);
1120 Status
= STATUS_UNSUCCESSFUL
;
1123 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1125 Status
= _SEH2_GetExceptionCode();
1132 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1133 if (!NT_SUCCESS(Status
))
1135 Status
= STATUS_INVALID_USER_BUFFER
;
1139 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1141 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1146 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedWrites
, 1);
1147 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedWriteBytes
, Length
);
1151 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataWrites
, 1);
1152 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataWriteBytes
, Length
);
1155 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
1156 if (NT_SUCCESS(Status
))
1158 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1163 if (!PagingIo
&& !IsFAT
&& !IsVolume
)
1165 if(!vfatFCBIsDirectory(Fcb
))
1167 LARGE_INTEGER SystemTime
;
1170 // set dates and times
1171 KeQuerySystemTime (&SystemTime
);
1172 if (vfatVolumeIsFatX(IrpContext
->DeviceExt
))
1174 FsdSystemTimeToDosDateTime(IrpContext
->DeviceExt
,
1175 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
1176 &Fcb
->entry
.FatX
.UpdateTime
);
1177 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
1178 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
1182 FsdSystemTimeToDosDateTime(IrpContext
->DeviceExt
,
1183 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1184 &Fcb
->entry
.Fat
.UpdateTime
);
1185 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1187 /* set date and times to dirty */
1188 Fcb
->Flags
|= FCB_IS_DIRTY
;
1190 /* Time to notify the OS */
1191 Filter
= FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1192 if (ByteOffset
.QuadPart
!= OldFileSize
.QuadPart
) Filter
|= FILE_NOTIFY_CHANGE_SIZE
;
1194 vfatReportChange(IrpContext
->DeviceExt
, Fcb
, Filter
, FILE_ACTION_MODIFIED
);
1201 ExReleaseResourceLite(Resource
);
1204 if (Status
== STATUS_PENDING
)
1206 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1207 if (NT_SUCCESS(Status
))
1209 Status
= VfatMarkIrpContextForQueue(IrpContext
);
1214 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1215 if (BooleanFlagOn(IrpContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
) &&
1216 !PagingIo
&& NT_SUCCESS(Status
))
1218 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1219 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1222 if (NT_SUCCESS(Status
))
1223 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
1225 DPRINT("%x\n", Status
);