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
;
128 ULONG BytesPerSector
;
129 ULONG BytesPerCluster
;
135 DeviceExt
= IrpContext
->DeviceExt
;
137 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
138 ASSERT(IrpContext
->FileObject
);
139 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
141 DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, "
142 "Length %u, ReadOffset 0x%I64x)\n", DeviceExt
,
143 IrpContext
->FileObject
, Length
, ReadOffset
.QuadPart
);
147 Fcb
= IrpContext
->FileObject
->FsContext
;
148 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
149 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
151 ASSERT(ReadOffset
.QuadPart
+ Length
<= ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
));
152 ASSERT(ReadOffset
.u
.LowPart
% BytesPerSector
== 0);
153 ASSERT(Length
% BytesPerSector
== 0);
155 /* Is this a read of the FAT? */
156 if (Fcb
->Flags
& FCB_IS_FAT
)
158 ReadOffset
.QuadPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
159 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
161 if (NT_SUCCESS(Status
))
163 *LengthRead
= Length
;
167 DPRINT1("FAT reading failed, Status %x\n", Status
);
171 /* Is this a read of the Volume ? */
172 if (Fcb
->Flags
& FCB_IS_VOLUME
)
174 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
175 if (NT_SUCCESS(Status
))
177 *LengthRead
= Length
;
181 DPRINT1("Volume reading failed, Status %x\n", Status
);
187 * Find the first cluster
189 FirstCluster
= CurrentCluster
=
190 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
192 if (FirstCluster
== 1)
194 // Directory of FAT12/16 needs a special handling
195 if (ReadOffset
.u
.LowPart
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
)
197 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
- ReadOffset
.u
.LowPart
;
199 ReadOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
201 // Fire up the read command
203 Status
= VfatReadDiskPartial (IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
204 if (NT_SUCCESS(Status
))
206 *LengthRead
= Length
;
211 ExAcquireFastMutex(&Fcb
->LastMutex
);
212 LastCluster
= Fcb
->LastCluster
;
213 LastOffset
= Fcb
->LastOffset
;
214 ExReleaseFastMutex(&Fcb
->LastMutex
);
217 * Find the cluster to start the read from
219 if (LastCluster
> 0 && ReadOffset
.u
.LowPart
>= LastOffset
)
221 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
222 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) -
224 &CurrentCluster
, FALSE
);
225 #ifdef DEBUG_VERIFY_OFFSET_CACHING
226 /* DEBUG VERIFICATION */
228 ULONG CorrectCluster
;
229 OffsetToCluster(DeviceExt
, FirstCluster
,
230 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
231 &CorrectCluster
, FALSE
);
232 if (CorrectCluster
!= CurrentCluster
)
233 KeBugCheck(FAT_FILE_SYSTEM
);
239 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
240 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
241 &CurrentCluster
, FALSE
);
243 if (!NT_SUCCESS(Status
))
248 ExAcquireFastMutex(&Fcb
->LastMutex
);
249 Fcb
->LastCluster
= CurrentCluster
;
250 Fcb
->LastOffset
= ROUND_DOWN (ReadOffset
.u
.LowPart
, BytesPerCluster
);
251 ExReleaseFastMutex(&Fcb
->LastMutex
);
253 KeInitializeEvent(&IrpContext
->Event
, NotificationEvent
, FALSE
);
254 IrpContext
->RefCount
= 1;
256 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
258 StartCluster
= CurrentCluster
;
259 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
268 BytesDone
= min (Length
, BytesPerCluster
- (ReadOffset
.u
.LowPart
% BytesPerCluster
));
269 StartOffset
.QuadPart
+= ReadOffset
.u
.LowPart
% BytesPerCluster
;
274 if (Length
- BytesDone
> BytesPerCluster
)
276 BytesDone
+= BytesPerCluster
;
283 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
285 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
286 DPRINT("start %08x, next %08x, count %u\n",
287 StartCluster
, CurrentCluster
, ClusterCount
);
289 ExAcquireFastMutex(&Fcb
->LastMutex
);
290 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
291 Fcb
->LastOffset
= ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
292 ExReleaseFastMutex(&Fcb
->LastMutex
);
294 // Fire up the read command
295 Status
= VfatReadDiskPartial (IrpContext
, &StartOffset
, BytesDone
, *LengthRead
, FALSE
);
296 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
300 *LengthRead
+= BytesDone
;
302 ReadOffset
.u
.LowPart
+= BytesDone
;
304 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
306 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
308 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
312 Status
= STATUS_UNSUCCESSFUL
;
316 Status
= IrpContext
->Irp
->IoStatus
.Status
;
323 VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext
,
325 LARGE_INTEGER WriteOffset
)
327 PDEVICE_EXTENSION DeviceExt
;
331 ULONG CurrentCluster
;
335 NTSTATUS Status
= STATUS_SUCCESS
;
336 BOOLEAN First
= TRUE
;
337 ULONG BytesPerSector
;
338 ULONG BytesPerCluster
;
339 LARGE_INTEGER StartOffset
;
346 DeviceExt
= IrpContext
->DeviceExt
;
348 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
349 ASSERT(IrpContext
->FileObject
);
350 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
352 Fcb
= IrpContext
->FileObject
->FsContext
;
353 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
354 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
356 DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, "
357 "Length %u, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt
,
358 IrpContext
->FileObject
, Length
, WriteOffset
.QuadPart
,
361 ASSERT(WriteOffset
.QuadPart
+ Length
<= Fcb
->RFCB
.AllocationSize
.QuadPart
);
362 ASSERT(WriteOffset
.u
.LowPart
% BytesPerSector
== 0);
363 ASSERT(Length
% BytesPerSector
== 0);
365 // Is this a write of the volume ?
366 if (Fcb
->Flags
& FCB_IS_VOLUME
)
368 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
369 if (!NT_SUCCESS(Status
))
371 DPRINT1("Volume writing failed, Status %x\n", Status
);
376 // Is this a write to the FAT ?
377 if (Fcb
->Flags
& FCB_IS_FAT
)
379 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
380 IrpContext
->RefCount
= 1;
381 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
383 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, FALSE
);
384 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
386 DPRINT1("FAT writing failed, Status %x\n", Status
);
389 WriteOffset
.u
.LowPart
+= Fcb
->RFCB
.FileSize
.u
.LowPart
;
391 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
393 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
395 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
397 Status
= IrpContext
->Irp
->IoStatus
.Status
;
403 * Find the first cluster
405 FirstCluster
= CurrentCluster
=
406 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
408 if (FirstCluster
== 1)
410 ASSERT(WriteOffset
.u
.LowPart
+ Length
<= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
);
411 // Directory of FAT12/16 needs a special handling
412 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
413 // Fire up the write command
414 Status
= VfatWriteDiskPartial (IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
418 ExAcquireFastMutex(&Fcb
->LastMutex
);
419 LastCluster
= Fcb
->LastCluster
;
420 LastOffset
= Fcb
->LastOffset
;
421 ExReleaseFastMutex(&Fcb
->LastMutex
);
424 * Find the cluster to start the write from
426 if (LastCluster
> 0 && WriteOffset
.u
.LowPart
>= LastOffset
)
428 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
429 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) -
431 &CurrentCluster
, FALSE
);
432 #ifdef DEBUG_VERIFY_OFFSET_CACHING
433 /* DEBUG VERIFICATION */
435 ULONG CorrectCluster
;
436 OffsetToCluster(DeviceExt
, FirstCluster
,
437 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
438 &CorrectCluster
, FALSE
);
439 if (CorrectCluster
!= CurrentCluster
)
440 KeBugCheck(FAT_FILE_SYSTEM
);
446 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
447 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
448 &CurrentCluster
, FALSE
);
451 if (!NT_SUCCESS(Status
))
456 ExAcquireFastMutex(&Fcb
->LastMutex
);
457 Fcb
->LastCluster
= CurrentCluster
;
458 Fcb
->LastOffset
= ROUND_DOWN (WriteOffset
.u
.LowPart
, BytesPerCluster
);
459 ExReleaseFastMutex(&Fcb
->LastMutex
);
461 IrpContext
->RefCount
= 1;
464 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
466 StartCluster
= CurrentCluster
;
467 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
476 BytesDone
= min (Length
, BytesPerCluster
- (WriteOffset
.u
.LowPart
% BytesPerCluster
));
477 StartOffset
.QuadPart
+= WriteOffset
.u
.LowPart
% BytesPerCluster
;
482 if (Length
- BytesDone
> BytesPerCluster
)
484 BytesDone
+= BytesPerCluster
;
491 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
493 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
494 DPRINT("start %08x, next %08x, count %u\n",
495 StartCluster
, CurrentCluster
, ClusterCount
);
497 ExAcquireFastMutex(&Fcb
->LastMutex
);
498 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
499 Fcb
->LastOffset
= ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
500 ExReleaseFastMutex(&Fcb
->LastMutex
);
502 // Fire up the write command
503 Status
= VfatWriteDiskPartial (IrpContext
, &StartOffset
, BytesDone
, BufferOffset
, FALSE
);
504 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
508 BufferOffset
+= BytesDone
;
510 WriteOffset
.u
.LowPart
+= BytesDone
;
512 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
514 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
516 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
520 Status
= STATUS_UNSUCCESSFUL
;
524 Status
= IrpContext
->Irp
->IoStatus
.Status
;
531 VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
536 ULONG ReturnedLength
= 0;
537 PERESOURCE Resource
= NULL
;
538 LARGE_INTEGER ByteOffset
;
540 ULONG BytesPerSector
;
544 DPRINT("VfatRead(IrpContext %p)\n", IrpContext
);
546 ASSERT(IrpContext
->DeviceObject
);
548 // This request is not allowed on the main device object
549 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
551 DPRINT("VfatRead is called with the main device object.\n");
552 Status
= STATUS_INVALID_DEVICE_REQUEST
;
556 ASSERT(IrpContext
->DeviceExt
);
557 ASSERT(IrpContext
->FileObject
);
558 Fcb
= IrpContext
->FileObject
->FsContext
;
561 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
563 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
564 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
565 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
566 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
567 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
568 VfatFreeIrpContext(IrpContext
);
572 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
574 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
575 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
576 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
578 /* fail if file is a directory and no paged read */
579 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
581 Status
= STATUS_INVALID_PARAMETER
;
586 DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
588 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
590 Status
= STATUS_INVALID_PARAMETER
;
593 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
595 IrpContext
->Irp
->IoStatus
.Information
= 0;
596 Status
= STATUS_END_OF_FILE
;
599 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
601 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
603 DPRINT("%u %u\n", ByteOffset
.u
.LowPart
, Length
);
604 // non cached read must be sector aligned
605 Status
= STATUS_INVALID_PARAMETER
;
611 IrpContext
->Irp
->IoStatus
.Information
= 0;
612 Status
= STATUS_SUCCESS
;
616 if (Fcb
->Flags
& FCB_IS_VOLUME
)
618 Resource
= &IrpContext
->DeviceExt
->DirResource
;
620 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
622 Resource
= &Fcb
->PagingIoResource
;
626 Resource
= &Fcb
->MainResource
;
628 if (!ExAcquireResourceSharedLite(Resource
,
629 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
? TRUE
: FALSE
))
632 Status
= STATUS_PENDING
;
636 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
637 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
639 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
641 Status
= STATUS_FILE_LOCK_CONFLICT
;
646 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
649 Status
= STATUS_INVALID_USER_BUFFER
;
653 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
654 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
657 Status
= STATUS_SUCCESS
;
658 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
660 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
661 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
664 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
666 CcInitializeCacheMap(IrpContext
->FileObject
,
667 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
669 &(VfatGlobalData
->CacheMgrCallbacks
),
672 if (!CcCopyRead(IrpContext
->FileObject
, &ByteOffset
, Length
,
673 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
), Buffer
,
674 &IrpContext
->Irp
->IoStatus
))
676 Status
= STATUS_PENDING
;
679 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
681 Status
= IrpContext
->Irp
->IoStatus
.Status
;
687 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
689 Length
= (ULONG
)(ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
692 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
693 if (!NT_SUCCESS(Status
))
698 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
699 if (NT_SUCCESS(Status
))
701 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
708 ExReleaseResourceLite(Resource
);
711 if (Status
== STATUS_PENDING
)
713 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
714 if (NT_SUCCESS(Status
))
716 Status
= VfatQueueRequest(IrpContext
);
720 IrpContext
->Irp
->IoStatus
.Status
= Status
;
721 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
722 VfatFreeIrpContext(IrpContext
);
727 IrpContext
->Irp
->IoStatus
.Status
= Status
;
728 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
729 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
730 (NT_SUCCESS(Status
) || Status
==STATUS_END_OF_FILE
))
732 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
733 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
736 IoCompleteRequest(IrpContext
->Irp
,
737 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
738 VfatFreeIrpContext(IrpContext
);
740 DPRINT("%x\n", Status
);
744 NTSTATUS
VfatWrite (PVFAT_IRP_CONTEXT IrpContext
)
747 PERESOURCE Resource
= NULL
;
748 LARGE_INTEGER ByteOffset
;
749 LARGE_INTEGER OldFileSize
;
750 NTSTATUS Status
= STATUS_SUCCESS
;
753 ULONG BytesPerSector
;
757 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
759 ASSERT(IrpContext
->DeviceObject
);
761 // This request is not allowed on the main device object
762 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
764 DPRINT("VfatWrite is called with the main device object.\n");
765 Status
= STATUS_INVALID_DEVICE_REQUEST
;
769 ASSERT(IrpContext
->DeviceExt
);
770 ASSERT(IrpContext
->FileObject
);
771 Fcb
= IrpContext
->FileObject
->FsContext
;
774 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
776 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
777 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
778 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
779 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
780 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
781 VfatFreeIrpContext(IrpContext
);
785 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
787 /* fail if file is a directory and no paged read */
788 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
790 Status
= STATUS_INVALID_PARAMETER
;
794 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
795 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
796 ByteOffset
.u
.HighPart
== -1)
798 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
800 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
801 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
803 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
805 Status
= STATUS_INVALID_PARAMETER
;
809 if (Fcb
->Flags
& (FCB_IS_FAT
| FCB_IS_VOLUME
) ||
810 1 == vfatDirEntryGetFirstCluster (IrpContext
->DeviceExt
, &Fcb
->entry
))
812 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
814 // we can't extend the FAT, the volume or the root on FAT12/FAT16
815 Status
= STATUS_END_OF_FILE
;
820 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
|IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
822 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
824 // non cached write must be sector aligned
825 Status
= STATUS_INVALID_PARAMETER
;
833 * Update last write time
835 IrpContext
->Irp
->IoStatus
.Information
= 0;
836 Status
= STATUS_SUCCESS
;
840 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
842 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
844 Status
= STATUS_INVALID_PARAMETER
;
847 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
849 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
853 if (Fcb
->Flags
& FCB_IS_VOLUME
)
855 Resource
= &IrpContext
->DeviceExt
->DirResource
;
857 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
859 Resource
= &Fcb
->PagingIoResource
;
863 Resource
= &Fcb
->MainResource
;
866 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
868 if (!ExAcquireResourceSharedLite(Resource
,
869 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
872 Status
= STATUS_PENDING
;
878 if (!ExAcquireResourceExclusiveLite(Resource
,
879 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
882 Status
= STATUS_PENDING
;
887 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
888 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
890 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
892 Status
= STATUS_FILE_LOCK_CONFLICT
;
897 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
899 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
901 Status
= STATUS_PENDING
;
906 OldFileSize
= Fcb
->RFCB
.FileSize
;
908 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
911 Status
= STATUS_INVALID_USER_BUFFER
;
916 if (!(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)) &&
917 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
918 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
920 LARGE_INTEGER AllocationSize
;
921 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
922 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
923 IrpContext
->DeviceExt
, &AllocationSize
);
924 if (!NT_SUCCESS (Status
))
930 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
931 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
935 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
937 CcInitializeCacheMap(IrpContext
->FileObject
,
938 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
940 &VfatGlobalData
->CacheMgrCallbacks
,
943 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
945 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
947 if (CcCopyWrite(IrpContext
->FileObject
, &ByteOffset
, Length
,
948 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer
))
950 IrpContext
->Irp
->IoStatus
.Information
= Length
;
951 Status
= STATUS_SUCCESS
;
955 Status
= STATUS_UNSUCCESSFUL
;
962 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
964 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
967 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
968 if (!NT_SUCCESS(Status
))
973 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
974 if (NT_SUCCESS(Status
))
976 IrpContext
->Irp
->IoStatus
.Information
= Length
;
980 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
981 !(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
983 if(!(*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
985 LARGE_INTEGER SystemTime
;
986 // set dates and times
987 KeQuerySystemTime (&SystemTime
);
988 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
990 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
991 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
992 &Fcb
->entry
.FatX
.UpdateTime
);
993 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
994 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
998 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
999 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1000 &Fcb
->entry
.Fat
.UpdateTime
);
1001 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1003 /* set date and times to dirty */
1004 Fcb
->Flags
|= FCB_IS_DIRTY
;
1011 ExReleaseResourceLite(Resource
);
1014 if (Status
== STATUS_PENDING
)
1016 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1017 if (NT_SUCCESS(Status
))
1019 Status
= VfatQueueRequest(IrpContext
);
1023 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1024 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1025 VfatFreeIrpContext(IrpContext
);
1030 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1031 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
1032 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
1034 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1035 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1038 IoCompleteRequest(IrpContext
->Irp
,
1039 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
1040 VfatFreeIrpContext(IrpContext
);
1042 DPRINT("%x\n", Status
);