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
;
548 PVFAT_IRP_CONTEXT IrpContext
)
554 ULONG BytesPerSector
;
555 LARGE_INTEGER ByteOffset
;
556 ULONG ReturnedLength
= 0;
557 BOOLEAN PagingIo
, CanWait
, IsVolume
, NoCache
;
559 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
560 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
561 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
562 Fcb
= IrpContext
->FileObject
->FsContext
;
563 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
565 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
566 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
567 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
570 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
572 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
574 return STATUS_FILE_LOCK_CONFLICT
;
578 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, PagingIo
);
580 if (!PagingIo
&& !NoCache
&& !IsVolume
)
583 Status
= STATUS_SUCCESS
;
584 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
586 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
587 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
590 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileReads
, 1);
591 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileReadBytes
, Length
);
595 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
597 CcInitializeCacheMap(IrpContext
->FileObject
,
598 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
600 &(VfatGlobalData
->CacheMgrCallbacks
),
604 if (!CcCopyRead(IrpContext
->FileObject
,
609 &IrpContext
->Irp
->IoStatus
))
612 Status
= STATUS_PENDING
;
616 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
618 Status
= _SEH2_GetExceptionCode();
623 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
625 Status
= IrpContext
->Irp
->IoStatus
.Status
;
631 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
632 if (!NT_SUCCESS(Status
))
637 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
639 Length
= (ULONG
)(ROUND_UP_64(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
644 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedReads
, 1);
645 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedReadBytes
, Length
);
649 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataReads
, 1);
650 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataReadBytes
, Length
);
653 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
654 if (NT_SUCCESS(Status
))
656 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
666 VfatStackOverflowRead(
670 PVFAT_IRP_CONTEXT IrpContext
;
672 IrpContext
= Context
;
673 /* In a separate thread, we can wait and resources got locked */
674 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
676 /* Perform the read operation */
677 DPRINT1("Performing posted read\n");
678 VfatCommonRead(IrpContext
);
680 KeSetEvent(Event
, 0, FALSE
);
685 PVFAT_IRP_CONTEXT IrpContext
,
691 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
693 ExAcquireResourceSharedLite(Lock
, TRUE
);
695 /* If paging IO, call the non failing but blocking routine */
698 FsRtlPostPagingFileStackOverflow(IrpContext
, &Event
, VfatStackOverflowRead
);
702 FsRtlPostStackOverflow(IrpContext
, &Event
, VfatStackOverflowRead
);
705 /* Wait till it's done */
706 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
711 PVFAT_IRP_CONTEXT IrpContext
)
716 PERESOURCE Resource
= NULL
;
717 LARGE_INTEGER ByteOffset
;
718 ULONG BytesPerSector
;
719 BOOLEAN PagingIo
, CanWait
, IsVolume
, NoCache
;
723 DPRINT("VfatRead(IrpContext %p)\n", IrpContext
);
725 ASSERT(IrpContext
->DeviceObject
);
727 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
728 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
729 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
731 // This request is not allowed on the main device object
732 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
734 DPRINT("VfatRead is called with the main device object.\n");
735 Status
= STATUS_INVALID_DEVICE_REQUEST
;
739 ASSERT(IrpContext
->DeviceExt
);
740 ASSERT(IrpContext
->FileObject
);
741 Fcb
= IrpContext
->FileObject
->FsContext
;
744 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
746 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_PAGE_FILE
))
748 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
749 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
750 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
751 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
752 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
753 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
757 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
759 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
760 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
761 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
763 /* fail if file is a directory and no paged read */
764 if (vfatFCBIsDirectory(Fcb
) && !PagingIo
)
766 Status
= STATUS_INVALID_PARAMETER
;
770 DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
772 if (ByteOffset
.u
.HighPart
&& !IsVolume
)
774 Status
= STATUS_INVALID_PARAMETER
;
780 IrpContext
->Irp
->IoStatus
.Information
= 0;
781 Status
= STATUS_SUCCESS
;
785 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
787 IrpContext
->Irp
->IoStatus
.Information
= 0;
788 Status
= STATUS_END_OF_FILE
;
792 if (NoCache
|| PagingIo
|| IsVolume
)
794 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
796 DPRINT("%u %u\n", ByteOffset
.u
.LowPart
, Length
);
797 // non cached read must be sector aligned
798 Status
= STATUS_INVALID_PARAMETER
;
805 Resource
= &IrpContext
->DeviceExt
->DirResource
;
809 Resource
= &Fcb
->PagingIoResource
;
813 Resource
= &Fcb
->MainResource
;
816 /* Are we out of stack for the rest of the operation? */
817 if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD
)
819 /* Lock the buffer */
820 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
821 if (!NT_SUCCESS(Status
))
826 /* And post the read to the overflow thread */
827 VfatPostRead(IrpContext
, Resource
, PagingIo
);
829 /* Return the appropriate status */
830 return IrpContext
->Irp
->IoStatus
.Status
;
833 if (!ExAcquireResourceSharedLite(Resource
, CanWait
))
836 Status
= STATUS_PENDING
;
840 Status
= VfatCommonRead(IrpContext
);
845 ExReleaseResourceLite(Resource
);
848 if (Status
== STATUS_PENDING
)
850 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
851 if (NT_SUCCESS(Status
))
853 Status
= VfatMarkIrpContextForQueue(IrpContext
);
858 IrpContext
->Irp
->IoStatus
.Status
= Status
;
859 if (BooleanFlagOn(IrpContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
) &&
861 (NT_SUCCESS(Status
) || Status
== STATUS_END_OF_FILE
))
863 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
864 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
867 if (NT_SUCCESS(Status
))
868 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
870 DPRINT("%x\n", Status
);
876 PVFAT_IRP_CONTEXT IrpContext
)
879 PERESOURCE Resource
= NULL
;
880 LARGE_INTEGER ByteOffset
;
881 LARGE_INTEGER OldFileSize
;
882 NTSTATUS Status
= STATUS_SUCCESS
;
885 ULONG BytesPerSector
;
886 BOOLEAN PagingIo
, CanWait
, IsVolume
, IsFAT
, NoCache
;
890 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
892 ASSERT(IrpContext
->DeviceObject
);
894 PagingIo
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_PAGING_IO
);
895 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
896 NoCache
= BooleanFlagOn(IrpContext
->Irp
->Flags
, IRP_NOCACHE
);
898 // This request is not allowed on the main device object
899 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
901 DPRINT("VfatWrite is called with the main device object.\n");
902 Status
= STATUS_INVALID_DEVICE_REQUEST
;
906 ASSERT(IrpContext
->DeviceExt
);
907 ASSERT(IrpContext
->FileObject
);
908 Fcb
= IrpContext
->FileObject
->FsContext
;
911 IsVolume
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_VOLUME
);
912 IsFAT
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_FAT
);
914 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_PAGE_FILE
))
916 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
917 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
918 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
919 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
920 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
921 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
925 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
927 /* fail if file is a directory and no paged read */
928 if (vfatFCBIsDirectory(Fcb
) && !PagingIo
)
930 Status
= STATUS_INVALID_PARAMETER
;
934 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
935 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
936 ByteOffset
.u
.HighPart
== -1)
938 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
940 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
941 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
943 if (ByteOffset
.u
.HighPart
&& !IsVolume
)
945 Status
= STATUS_INVALID_PARAMETER
;
949 if (IsFAT
|| IsVolume
||
950 vfatDirEntryGetFirstCluster(IrpContext
->DeviceExt
, &Fcb
->entry
) == 1)
952 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
954 // we can't extend the FAT, the volume or the root on FAT12/FAT16
955 Status
= STATUS_END_OF_FILE
;
960 if (PagingIo
|| NoCache
|| IsVolume
)
962 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
964 // non cached write must be sector aligned
965 Status
= STATUS_INVALID_PARAMETER
;
970 OldFileSize
= Fcb
->RFCB
.FileSize
;
974 /* Update last write time */
975 IrpContext
->Irp
->IoStatus
.Information
= 0;
976 Status
= STATUS_SUCCESS
;
982 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
984 Status
= STATUS_INVALID_PARAMETER
;
988 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
990 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
994 if (!NoCache
&& !CcCanIWrite(IrpContext
->FileObject
, Length
, CanWait
,
995 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
)))
999 Retrying
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
);
1000 SetFlag(IrpContext
->Flags
, IRPCONTEXT_DEFERRED_WRITE
);
1002 Status
= STATUS_PENDING
;
1003 CcDeferWrite(IrpContext
->FileObject
, VfatHandleDeferredWrite
,
1004 IrpContext
, NULL
, Length
, Retrying
);
1006 DPRINT1("Dererring write!\n");
1013 Resource
= &IrpContext
->DeviceExt
->DirResource
;
1017 Resource
= &Fcb
->PagingIoResource
;
1021 Resource
= &Fcb
->MainResource
;
1026 if (!ExAcquireResourceSharedLite(Resource
, CanWait
))
1029 Status
= STATUS_PENDING
;
1035 if (!ExAcquireResourceExclusiveLite(Resource
, CanWait
))
1038 Status
= STATUS_PENDING
;
1044 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
1046 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
1048 Status
= STATUS_FILE_LOCK_CONFLICT
;
1053 if (!CanWait
&& !IsVolume
)
1055 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1057 Status
= STATUS_PENDING
;
1062 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, PagingIo
);
1064 if (!IsFAT
&& !IsVolume
&& !PagingIo
&&
1065 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
1067 LARGE_INTEGER AllocationSize
;
1069 if (!ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, CanWait
))
1071 Status
= STATUS_PENDING
;
1075 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
1076 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
1077 IrpContext
->DeviceExt
, &AllocationSize
);
1079 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
1081 if (!NT_SUCCESS (Status
))
1087 if (!NoCache
&& !PagingIo
&& !IsVolume
)
1091 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileWrites
, 1);
1092 vfatAddToStat(IrpContext
->DeviceExt
, Base
.UserFileWriteBytes
, Length
);
1096 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
1098 CcInitializeCacheMap(IrpContext
->FileObject
,
1099 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
1101 &VfatGlobalData
->CacheMgrCallbacks
,
1105 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1107 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1110 if (CcCopyWrite(IrpContext
->FileObject
,
1116 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1117 Status
= STATUS_SUCCESS
;
1121 ASSERT(FALSE
/*!CanWait*/);
1122 Status
= STATUS_UNSUCCESSFUL
;
1125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1127 Status
= _SEH2_GetExceptionCode();
1134 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1135 if (!NT_SUCCESS(Status
))
1137 Status
= STATUS_INVALID_USER_BUFFER
;
1141 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1143 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1148 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedWrites
, 1);
1149 vfatAddToStat(IrpContext
->DeviceExt
, Fat
.NonCachedWriteBytes
, Length
);
1153 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataWrites
, 1);
1154 vfatAddToStat(IrpContext
->DeviceExt
, Base
.MetaDataWriteBytes
, Length
);
1157 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
1158 if (NT_SUCCESS(Status
))
1160 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1165 if (!PagingIo
&& !IsFAT
&& !IsVolume
)
1167 if(!vfatFCBIsDirectory(Fcb
))
1169 LARGE_INTEGER SystemTime
;
1172 // set dates and times
1173 KeQuerySystemTime (&SystemTime
);
1174 if (vfatVolumeIsFatX(IrpContext
->DeviceExt
))
1176 FsdSystemTimeToDosDateTime(IrpContext
->DeviceExt
,
1177 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
1178 &Fcb
->entry
.FatX
.UpdateTime
);
1179 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
1180 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
1184 FsdSystemTimeToDosDateTime(IrpContext
->DeviceExt
,
1185 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1186 &Fcb
->entry
.Fat
.UpdateTime
);
1187 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1189 /* set date and times to dirty */
1190 Fcb
->Flags
|= FCB_IS_DIRTY
;
1192 /* Time to notify the OS */
1193 Filter
= FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1194 if (ByteOffset
.QuadPart
!= OldFileSize
.QuadPart
) Filter
|= FILE_NOTIFY_CHANGE_SIZE
;
1196 vfatReportChange(IrpContext
->DeviceExt
, Fcb
, Filter
, FILE_ACTION_MODIFIED
);
1203 ExReleaseResourceLite(Resource
);
1206 if (Status
== STATUS_PENDING
)
1208 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1209 if (NT_SUCCESS(Status
))
1211 Status
= VfatMarkIrpContextForQueue(IrpContext
);
1216 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1217 if (BooleanFlagOn(IrpContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
) &&
1218 !PagingIo
&& NT_SUCCESS(Status
))
1220 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1221 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1224 if (NT_SUCCESS(Status
))
1225 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
1227 DPRINT("%x\n", Status
);