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
;
543 if (NT_SUCCESS(Status
) && ClusterCount
!= 0 && DeviceExt
->FatInfo
.FatType
== FAT32
)
545 FAT32UpdateFreeClustersCount(DeviceExt
, ClusterCount
, FALSE
);
553 PVFAT_IRP_CONTEXT IrpContext
)
559 ULONG BytesPerSector
;
560 LARGE_INTEGER ByteOffset
;
561 ULONG ReturnedLength
= 0;
562 BOOLEAN PagingIo
, CanWait
, IsVolume
, NoCache
;
564 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
565 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
566 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
567 Fcb
= IrpContext
->FileObject
->FsContext
;
568 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
570 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
571 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
572 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
575 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
577 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
579 return STATUS_FILE_LOCK_CONFLICT
;
583 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, PagingIo
);
585 if (!PagingIo
&& !NoCache
&& !IsVolume
)
588 Status
= STATUS_SUCCESS
;
589 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
591 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
592 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
595 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileReads
, 1);
596 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileReadBytes
, Length
);
600 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
602 CcInitializeCacheMap(IrpContext
->FileObject
,
603 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
605 &(VfatGlobalData
->CacheMgrCallbacks
),
609 if (!CcCopyRead(IrpContext
->FileObject
,
614 &IrpContext
->Irp
->IoStatus
))
617 Status
= STATUS_PENDING
;
621 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
623 Status
= _SEH2_GetExceptionCode();
628 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
630 Status
= IrpContext
->Irp
->IoStatus
.Status
;
636 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
637 if (!NT_SUCCESS(Status
))
642 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
644 Length
= (ULONG
)(ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
649 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedReads
, 1);
650 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedReadBytes
, Length
);
654 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataReads
, 1);
655 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataReadBytes
, Length
);
658 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
659 if (NT_SUCCESS(Status
))
661 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
671 VfatStackOverflowRead(
675 PVFAT_IRP_CONTEXT IrpContext
;
677 IrpContext
= Context
;
678 /* In a separate thread, we can wait and resources got locked */
679 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
681 /* Perform the read operation */
682 DPRINT1("Performing posted read\n");
683 VfatCommonRead(IrpContext
);
685 KeSetEvent(Event
, 0, FALSE
);
690 PVFAT_IRP_CONTEXT IrpContext
,
696 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
698 ExAcquireResourceSharedLite(Lock
, TRUE
);
700 /* If paging IO, call the non failing but blocking routine */
703 FsRtlPostPagingFileStackOverflow(IrpContext
, &Event
, VfatStackOverflowRead
);
707 FsRtlPostStackOverflow(IrpContext
, &Event
, VfatStackOverflowRead
);
710 /* Wait till it's done */
711 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
716 PVFAT_IRP_CONTEXT IrpContext
)
721 PERESOURCE Resource
= NULL
;
722 LARGE_INTEGER ByteOffset
;
723 ULONG BytesPerSector
;
724 BOOLEAN PagingIo
, CanWait
, IsVolume
, NoCache
;
728 DPRINT("VfatRead(IrpContext %p)\n", IrpContext
);
730 ASSERT(IrpContext
->DeviceObject
);
732 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
733 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
734 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
736 // This request is not allowed on the main device object
737 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
739 DPRINT("VfatRead is called with the main device object.\n");
740 Status
= STATUS_INVALID_DEVICE_REQUEST
;
744 ASSERT(IrpContext
->DeviceExt
);
745 ASSERT(IrpContext
->FileObject
);
746 Fcb
= IrpContext
->FileObject
->FsContext
;
749 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
751 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_PAGE_FILE
))
753 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
754 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
755 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
756 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
757 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
758 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
762 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
764 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
765 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
766 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
768 /* fail if file is a directory and no paged read */
769 if (vfatFCBIsDirectory(Fcb
) && !PagingIo
)
771 Status
= STATUS_INVALID_PARAMETER
;
775 DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
777 if (ByteOffset
.u
.HighPart
&& !IsVolume
)
779 Status
= STATUS_INVALID_PARAMETER
;
785 IrpContext
->Irp
->IoStatus
.Information
= 0;
786 Status
= STATUS_SUCCESS
;
790 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
792 IrpContext
->Irp
->IoStatus
.Information
= 0;
793 Status
= STATUS_END_OF_FILE
;
797 if (NoCache
|| PagingIo
|| IsVolume
)
799 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
801 DPRINT("%u %u\n", ByteOffset
.u
.LowPart
, Length
);
802 // non cached read must be sector aligned
803 Status
= STATUS_INVALID_PARAMETER
;
810 Resource
= &IrpContext
->DeviceExt
->DirResource
;
814 Resource
= &Fcb
->PagingIoResource
;
818 Resource
= &Fcb
->MainResource
;
821 /* Are we out of stack for the rest of the operation? */
822 if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD
)
824 /* Lock the buffer */
825 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
826 if (!NT_SUCCESS(Status
))
831 /* And post the read to the overflow thread */
832 VfatPostRead(IrpContext
, Resource
, PagingIo
);
834 /* Return the appropriate status */
835 return IrpContext
->Irp
->IoStatus
.Status
;
838 if (!ExAcquireResourceSharedLite(Resource
, CanWait
))
841 Status
= STATUS_PENDING
;
845 Status
= VfatCommonRead(IrpContext
);
850 ExReleaseResourceLite(Resource
);
853 if (Status
== STATUS_PENDING
)
855 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
856 if (NT_SUCCESS(Status
))
858 Status
= VfatMarkIrpContextForQueue(IrpContext
);
863 IrpContext
->Irp
->IoStatus
.Status
= Status
;
864 if (BooleanFlagOn(IrpContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
) &&
866 (NT_SUCCESS(Status
) || Status
== STATUS_END_OF_FILE
))
868 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
869 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
872 if (NT_SUCCESS(Status
))
873 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
875 DPRINT("%x\n", Status
);
881 PVFAT_IRP_CONTEXT IrpContext
)
884 PERESOURCE Resource
= NULL
;
885 LARGE_INTEGER ByteOffset
;
886 LARGE_INTEGER OldFileSize
;
887 NTSTATUS Status
= STATUS_SUCCESS
;
890 ULONG BytesPerSector
;
891 BOOLEAN PagingIo
, CanWait
, IsVolume
, IsFAT
, NoCache
;
895 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
897 ASSERT(IrpContext
->DeviceObject
);
899 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
900 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
901 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
903 // This request is not allowed on the main device object
904 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
906 DPRINT("VfatWrite is called with the main device object.\n");
907 Status
= STATUS_INVALID_DEVICE_REQUEST
;
911 ASSERT(IrpContext
->DeviceExt
);
912 ASSERT(IrpContext
->FileObject
);
913 Fcb
= IrpContext
->FileObject
->FsContext
;
916 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
917 IsFAT
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_FAT
);
919 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_PAGE_FILE
))
921 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
922 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
923 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
924 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
925 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
926 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
930 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
932 /* fail if file is a directory and no paged read */
933 if (vfatFCBIsDirectory(Fcb
) && !PagingIo
)
935 Status
= STATUS_INVALID_PARAMETER
;
939 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
940 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
941 ByteOffset
.u
.HighPart
== -1)
943 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
945 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
946 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
948 if (ByteOffset
.u
.HighPart
&& !IsVolume
)
950 Status
= STATUS_INVALID_PARAMETER
;
954 if (IsFAT
|| IsVolume
||
955 vfatDirEntryGetFirstCluster(IrpContext
->DeviceExt
, &Fcb
->entry
) == 1)
957 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
959 // we can't extend the FAT, the volume or the root on FAT12/FAT16
960 Status
= STATUS_END_OF_FILE
;
965 if (PagingIo
|| NoCache
|| IsVolume
)
967 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
969 // non cached write must be sector aligned
970 Status
= STATUS_INVALID_PARAMETER
;
975 OldFileSize
= Fcb
->RFCB
.FileSize
;
979 /* Update last write time */
980 IrpContext
->Irp
->IoStatus
.Information
= 0;
981 Status
= STATUS_SUCCESS
;
987 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
989 Status
= STATUS_INVALID_PARAMETER
;
993 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
995 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
999 if (!NoCache
&& !CcCanIWrite(IrpContext
->FileObject
, Length
, CanWait
,
1000 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
)))
1004 Retrying
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
);
1005 SetFlag(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
);
1007 Status
= STATUS_PENDING
;
1008 CcDeferWrite(IrpContext
->FileObject
, VfatHandleDeferredWrite
,
1009 IrpContext
, NULL
, Length
, Retrying
);
1011 DPRINT1("Dererring write!\n");
1018 Resource
= &IrpContext
->DeviceExt
->DirResource
;
1022 Resource
= &Fcb
->PagingIoResource
;
1026 Resource
= &Fcb
->MainResource
;
1031 if (!ExAcquireResourceSharedLite(Resource
, CanWait
))
1034 Status
= STATUS_PENDING
;
1040 if (!ExAcquireResourceExclusiveLite(Resource
, CanWait
))
1043 Status
= STATUS_PENDING
;
1049 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
1051 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
1053 Status
= STATUS_FILE_LOCK_CONFLICT
;
1058 if (!CanWait
&& !IsVolume
)
1060 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1062 Status
= STATUS_PENDING
;
1067 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, PagingIo
);
1069 if (!IsFAT
&& !IsVolume
&& !PagingIo
&&
1070 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
1072 LARGE_INTEGER AllocationSize
;
1074 if (!ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, CanWait
))
1076 Status
= STATUS_PENDING
;
1080 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
1081 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
1082 IrpContext
->DeviceExt
, &AllocationSize
);
1084 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
1086 if (!NT_SUCCESS (Status
))
1092 if (!NoCache
&& !PagingIo
&& !IsVolume
)
1096 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileWrites
, 1);
1097 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileWriteBytes
, Length
);
1101 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
1103 CcInitializeCacheMap(IrpContext
->FileObject
,
1104 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
1106 &VfatGlobalData
->CacheMgrCallbacks
,
1110 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1112 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1115 if (CcCopyWrite(IrpContext
->FileObject
,
1121 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1122 Status
= STATUS_SUCCESS
;
1126 ASSERT(FALSE
/*!CanWait*/);
1127 Status
= STATUS_UNSUCCESSFUL
;
1130 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1132 Status
= _SEH2_GetExceptionCode();
1139 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1140 if (!NT_SUCCESS(Status
))
1142 Status
= STATUS_INVALID_USER_BUFFER
;
1146 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1148 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1153 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedWrites
, 1);
1154 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedWriteBytes
, Length
);
1158 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataWrites
, 1);
1159 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataWriteBytes
, Length
);
1162 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
1163 if (NT_SUCCESS(Status
))
1165 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1170 if (!PagingIo
&& !IsFAT
&& !IsVolume
)
1172 if(!vfatFCBIsDirectory(Fcb
))
1174 LARGE_INTEGER SystemTime
;
1177 // set dates and times
1178 KeQuerySystemTime (&SystemTime
);
1179 if (vfatVolumeIsFatX(IrpContext
->DeviceExt
))
1181 FsdSystemTimeToDosDateTime(IrpContext
->DeviceExt
,
1182 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
1183 &Fcb
->entry
.FatX
.UpdateTime
);
1184 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
1185 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
1189 FsdSystemTimeToDosDateTime(IrpContext
->DeviceExt
,
1190 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1191 &Fcb
->entry
.Fat
.UpdateTime
);
1192 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1194 /* set date and times to dirty */
1195 Fcb
->Flags
|= FCB_IS_DIRTY
;
1197 /* Time to notify the OS */
1198 Filter
= FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1199 if (ByteOffset
.QuadPart
!= OldFileSize
.QuadPart
) Filter
|= FILE_NOTIFY_CHANGE_SIZE
;
1201 vfatReportChange(IrpContext
->DeviceExt
, Fcb
, Filter
, FILE_ACTION_MODIFIED
);
1208 ExReleaseResourceLite(Resource
);
1211 if (Status
== STATUS_PENDING
)
1213 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1214 if (NT_SUCCESS(Status
))
1216 Status
= VfatMarkIrpContextForQueue(IrpContext
);
1221 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1222 if (BooleanFlagOn(IrpContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
) &&
1223 !PagingIo
&& NT_SUCCESS(Status
))
1225 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1226 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1229 if (NT_SUCCESS(Status
))
1230 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
1232 DPRINT("%x\n", Status
);