2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/rw.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
10 /* INCLUDES *****************************************************************/
16 * Uncomment to enable strict verification of cluster/offset pair
17 * caching. If this option is enabled you lose all the benefits of
18 * the caching and the read/write operations will actually be
19 * slower. It's meant only for debugging!!!
20 * - Filip Navara, 26/07/2004
22 /* #define DEBUG_VERIFY_OFFSET_CACHING */
24 /* FUNCTIONS *****************************************************************/
27 NextCluster(PDEVICE_EXTENSION DeviceExt
,
29 PULONG CurrentCluster
,
32 * Return the next cluster in a FAT chain, possibly extending the chain if
36 if (FirstCluster
== 1)
38 (*CurrentCluster
) += DeviceExt
->FatInfo
.SectorsPerCluster
;
39 return(STATUS_SUCCESS
);
44 return GetNextClusterExtend(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
46 return GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
51 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
57 * Return the cluster corresponding to an offset within a file,
58 * possibly extending the file if necessary
65 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
66 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
67 Fcb, FirstCluster, FileOffset, Cluster, Extend);
69 if (FirstCluster
== 0)
71 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
75 if (FirstCluster
== 1)
77 /* root of FAT16 or FAT12 */
78 *Cluster
= DeviceExt
->FatInfo
.rootStart
+ FileOffset
79 / (DeviceExt
->FatInfo
.BytesPerCluster
) * DeviceExt
->FatInfo
.SectorsPerCluster
;
80 return(STATUS_SUCCESS
);
84 CurrentCluster
= FirstCluster
;
87 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
89 Status
= GetNextClusterExtend (DeviceExt
, CurrentCluster
, &CurrentCluster
);
90 if (!NT_SUCCESS(Status
))
93 *Cluster
= CurrentCluster
;
97 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
99 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
);
100 if (!NT_SUCCESS(Status
))
103 *Cluster
= CurrentCluster
;
105 return(STATUS_SUCCESS
);
110 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext
,
112 LARGE_INTEGER ReadOffset
,
115 * FUNCTION: Reads data from a file
118 ULONG CurrentCluster
;
122 LARGE_INTEGER StartOffset
;
123 PDEVICE_EXTENSION DeviceExt
;
124 BOOLEAN First
= TRUE
;
129 ULONG BytesPerSector
;
130 ULONG BytesPerCluster
;
136 DeviceExt
= IrpContext
->DeviceExt
;
138 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
139 ASSERT(IrpContext
->FileObject
);
140 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
142 DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, "
143 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt
,
144 IrpContext
->FileObject
, Length
, ReadOffset
.QuadPart
);
148 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
149 Fcb
= IrpContext
->FileObject
->FsContext
;
150 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
151 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
153 ASSERT(ReadOffset
.QuadPart
+ Length
<= ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
));
154 ASSERT(ReadOffset
.u
.LowPart
% BytesPerSector
== 0);
155 ASSERT(Length
% BytesPerSector
== 0);
157 /* Is this a read of the FAT? */
158 if (Fcb
->Flags
& FCB_IS_FAT
)
160 ReadOffset
.QuadPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
161 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
163 if (NT_SUCCESS(Status
))
165 *LengthRead
= Length
;
169 DPRINT1("FAT reading failed, Status %x\n", Status
);
173 /* Is this a read of the Volume ? */
174 if (Fcb
->Flags
& FCB_IS_VOLUME
)
176 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
177 if (NT_SUCCESS(Status
))
179 *LengthRead
= Length
;
183 DPRINT1("Volume reading failed, Status %x\n", Status
);
189 * Find the first cluster
191 FirstCluster
= CurrentCluster
=
192 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
194 if (FirstCluster
== 1)
196 // Directory of FAT12/16 needs a special handling
198 if (ReadOffset
.u
.LowPart
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
)
200 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
- ReadOffset
.u
.LowPart
;
202 ReadOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
204 // Fire up the read command
206 Status
= VfatReadDiskPartial (IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
207 if (NT_SUCCESS(Status
))
209 *LengthRead
= Length
;
214 ExAcquireFastMutex(&Fcb
->LastMutex
);
215 LastCluster
= Fcb
->LastCluster
;
216 LastOffset
= Fcb
->LastOffset
;
217 ExReleaseFastMutex(&Fcb
->LastMutex
);
220 * Find the cluster to start the read from
222 if (LastCluster
> 0 && ReadOffset
.u
.LowPart
>= LastOffset
)
224 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
225 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) -
227 &CurrentCluster
, FALSE
);
228 #ifdef DEBUG_VERIFY_OFFSET_CACHING
229 /* DEBUG VERIFICATION */
231 ULONG CorrectCluster
;
232 OffsetToCluster(DeviceExt
, FirstCluster
,
233 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
234 &CorrectCluster
, FALSE
);
235 if (CorrectCluster
!= CurrentCluster
)
236 KEBUGCHECK(FAT_FILE_SYSTEM
);
242 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
243 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
244 &CurrentCluster
, FALSE
);
246 if (!NT_SUCCESS(Status
))
251 ExAcquireFastMutex(&Fcb
->LastMutex
);
252 Fcb
->LastCluster
= CurrentCluster
;
253 Fcb
->LastOffset
= ROUND_DOWN (ReadOffset
.u
.LowPart
, BytesPerCluster
);
254 ExReleaseFastMutex(&Fcb
->LastMutex
);
256 KeInitializeEvent(&IrpContext
->Event
, NotificationEvent
, FALSE
);
257 IrpContext
->RefCount
= 1;
259 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
261 StartCluster
= CurrentCluster
;
262 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
271 BytesDone
= min (Length
, BytesPerCluster
- (ReadOffset
.u
.LowPart
% BytesPerCluster
));
272 StartOffset
.QuadPart
+= ReadOffset
.u
.LowPart
% BytesPerCluster
;
277 if (Length
- BytesDone
> BytesPerCluster
)
279 BytesDone
+= BytesPerCluster
;
286 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
288 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
289 DPRINT("start %08x, next %08x, count %d\n",
290 StartCluster
, CurrentCluster
, ClusterCount
);
292 ExAcquireFastMutex(&Fcb
->LastMutex
);
293 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
294 Fcb
->LastOffset
= ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
295 ExReleaseFastMutex(&Fcb
->LastMutex
);
297 // Fire up the read command
298 Status
= VfatReadDiskPartial (IrpContext
, &StartOffset
, BytesDone
, *LengthRead
, FALSE
);
299 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
303 *LengthRead
+= BytesDone
;
305 ReadOffset
.u
.LowPart
+= BytesDone
;
307 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
309 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
311 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
315 Status
= STATUS_UNSUCCESSFUL
;
319 Status
= IrpContext
->Irp
->IoStatus
.Status
;
326 VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext
,
328 LARGE_INTEGER WriteOffset
)
330 PDEVICE_EXTENSION DeviceExt
;
335 ULONG CurrentCluster
;
339 NTSTATUS Status
= STATUS_SUCCESS
;
340 BOOLEAN First
= TRUE
;
341 ULONG BytesPerSector
;
342 ULONG BytesPerCluster
;
343 LARGE_INTEGER StartOffset
;
350 DeviceExt
= IrpContext
->DeviceExt
;
352 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
353 ASSERT(IrpContext
->FileObject
);
354 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
356 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
357 Fcb
= IrpContext
->FileObject
->FsContext
;
358 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
359 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
361 DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, "
362 "Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt
,
363 IrpContext
->FileObject
, Length
, WriteOffset
,
366 ASSERT(WriteOffset
.QuadPart
+ Length
<= Fcb
->RFCB
.AllocationSize
.QuadPart
);
367 ASSERT(WriteOffset
.u
.LowPart
% BytesPerSector
== 0);
368 ASSERT(Length
% BytesPerSector
== 0);
370 // Is this a write of the volume ?
371 if (Fcb
->Flags
& FCB_IS_VOLUME
)
373 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
374 if (!NT_SUCCESS(Status
))
376 DPRINT1("Volume writing failed, Status %x\n", Status
);
381 // Is this a write to the FAT ?
382 if (Fcb
->Flags
& FCB_IS_FAT
)
384 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
385 IrpContext
->RefCount
= 1;
386 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
388 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, FALSE
);
389 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
391 DPRINT1("FAT writing failed, Status %x\n", Status
);
394 WriteOffset
.u
.LowPart
+= Fcb
->RFCB
.FileSize
.u
.LowPart
;
396 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
398 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
400 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
402 Status
= IrpContext
->Irp
->IoStatus
.Status
;
408 * Find the first cluster
410 FirstCluster
= CurrentCluster
=
411 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
413 if (FirstCluster
== 1)
415 ASSERT(WriteOffset
.u
.LowPart
+ Length
<= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
);
416 // Directory of FAT12/16 needs a special handling
417 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
418 // Fire up the write command
419 Status
= VfatWriteDiskPartial (IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
423 ExAcquireFastMutex(&Fcb
->LastMutex
);
424 LastCluster
= Fcb
->LastCluster
;
425 LastOffset
= Fcb
->LastOffset
;
426 ExReleaseFastMutex(&Fcb
->LastMutex
);
429 * Find the cluster to start the write from
431 if (LastCluster
> 0 && WriteOffset
.u
.LowPart
>= LastOffset
)
433 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
434 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) -
436 &CurrentCluster
, FALSE
);
437 #ifdef DEBUG_VERIFY_OFFSET_CACHING
438 /* DEBUG VERIFICATION */
440 ULONG CorrectCluster
;
441 OffsetToCluster(DeviceExt
, FirstCluster
,
442 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
443 &CorrectCluster
, FALSE
);
444 if (CorrectCluster
!= CurrentCluster
)
445 KEBUGCHECK(FAT_FILE_SYSTEM
);
451 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
452 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
453 &CurrentCluster
, FALSE
);
456 if (!NT_SUCCESS(Status
))
461 ExAcquireFastMutex(&Fcb
->LastMutex
);
462 Fcb
->LastCluster
= CurrentCluster
;
463 Fcb
->LastOffset
= ROUND_DOWN (WriteOffset
.u
.LowPart
, BytesPerCluster
);
464 ExReleaseFastMutex(&Fcb
->LastMutex
);
466 IrpContext
->RefCount
= 1;
469 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
471 StartCluster
= CurrentCluster
;
472 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
481 BytesDone
= min (Length
, BytesPerCluster
- (WriteOffset
.u
.LowPart
% BytesPerCluster
));
482 StartOffset
.QuadPart
+= WriteOffset
.u
.LowPart
% BytesPerCluster
;
487 if (Length
- BytesDone
> BytesPerCluster
)
489 BytesDone
+= BytesPerCluster
;
496 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
498 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
499 DPRINT("start %08x, next %08x, count %d\n",
500 StartCluster
, CurrentCluster
, ClusterCount
);
502 ExAcquireFastMutex(&Fcb
->LastMutex
);
503 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
504 Fcb
->LastOffset
= ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
505 ExReleaseFastMutex(&Fcb
->LastMutex
);
507 // Fire up the write command
508 Status
= VfatWriteDiskPartial (IrpContext
, &StartOffset
, BytesDone
, BufferOffset
, FALSE
);
509 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
513 BufferOffset
+= BytesDone
;
515 WriteOffset
.u
.LowPart
+= BytesDone
;
517 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
519 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
521 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
525 Status
= STATUS_UNSUCCESSFUL
;
529 Status
= IrpContext
->Irp
->IoStatus
.Status
;
536 VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
541 ULONG ReturnedLength
= 0;
542 PERESOURCE Resource
= NULL
;
543 LARGE_INTEGER ByteOffset
;
545 PDEVICE_OBJECT DeviceToVerify
;
546 ULONG BytesPerSector
;
550 DPRINT("VfatRead(IrpContext %p)\n", IrpContext
);
552 ASSERT(IrpContext
->DeviceObject
);
554 // This request is not allowed on the main device object
555 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
557 DPRINT("VfatRead is called with the main device object.\n");
558 Status
= STATUS_INVALID_DEVICE_REQUEST
;
562 ASSERT(IrpContext
->DeviceExt
);
563 ASSERT(IrpContext
->FileObject
);
564 Fcb
= IrpContext
->FileObject
->FsContext
;
567 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
569 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
571 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
572 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
573 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
574 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
575 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
576 VfatFreeIrpContext(IrpContext
);
580 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
581 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
582 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
584 /* fail if file is a directory and no paged read */
585 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
587 Status
= STATUS_INVALID_PARAMETER
;
592 DPRINT("'%wZ', Offset: %d, Length %d\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
594 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
596 Status
= STATUS_INVALID_PARAMETER
;
599 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
601 IrpContext
->Irp
->IoStatus
.Information
= 0;
602 Status
= STATUS_END_OF_FILE
;
605 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
607 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
609 DPRINT("%d %d\n", ByteOffset
.u
.LowPart
, Length
);
610 // non cached read must be sector aligned
611 Status
= STATUS_INVALID_PARAMETER
;
617 IrpContext
->Irp
->IoStatus
.Information
= 0;
618 Status
= STATUS_SUCCESS
;
622 if (Fcb
->Flags
& FCB_IS_VOLUME
)
624 Resource
= &IrpContext
->DeviceExt
->DirResource
;
626 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
628 Resource
= &Fcb
->PagingIoResource
;
632 Resource
= &Fcb
->MainResource
;
634 if (!ExAcquireResourceSharedLite(Resource
,
635 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
? TRUE
: FALSE
))
638 Status
= STATUS_PENDING
;
642 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
643 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
645 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
647 Status
= STATUS_FILE_LOCK_CONFLICT
;
652 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
655 Status
= STATUS_INVALID_USER_BUFFER
;
659 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
660 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
664 Status
= STATUS_SUCCESS
;
665 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
667 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
668 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
672 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
674 #ifdef USE_ROS_CC_AND_FS
676 CacheSize
= max(IrpContext
->DeviceExt
->FatInfo
.BytesPerCluster
,
678 CcRosInitializeFileCache(IrpContext
->FileObject
, CacheSize
);
680 /* FIXME: Guard by SEH. */
681 CcInitializeCacheMap(IrpContext
->FileObject
,
682 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
684 &(VfatGlobalData
->CacheMgrCallbacks
),
688 if (!CcCopyRead(IrpContext
->FileObject
, &ByteOffset
, Length
,
689 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
), Buffer
,
690 &IrpContext
->Irp
->IoStatus
))
692 Status
= IrpContext
->Irp
->IoStatus
.Status
;//STATUS_PENDING;
696 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
698 Status
= IrpContext
->Irp
->IoStatus
.Status
;
705 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
707 Length
= (ULONG
)(ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
710 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
711 if (!NT_SUCCESS(Status
))
716 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
718 if (Status
== STATUS_VERIFY_REQUIRED
)
720 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
721 DeviceToVerify
= IoGetDeviceToVerify(PsGetCurrentThread());
722 IoSetDeviceToVerify(PsGetCurrentThread(), DeviceToVerify
);
723 Status
= IoVerifyVolume (DeviceToVerify
, FALSE
);
725 if (NT_SUCCESS(Status
))
727 Status
= VfatReadFileData(IrpContext
, Length
,
728 ByteOffset
, &ReturnedLength
);
733 if (NT_SUCCESS(Status
))
735 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
742 ExReleaseResourceLite(Resource
);
745 if (Status
== STATUS_PENDING
)
747 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
748 if (NT_SUCCESS(Status
))
750 Status
= VfatQueueRequest(IrpContext
);
754 IrpContext
->Irp
->IoStatus
.Status
= Status
;
755 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
756 VfatFreeIrpContext(IrpContext
);
761 IrpContext
->Irp
->IoStatus
.Status
= Status
;
762 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
763 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
764 (NT_SUCCESS(Status
) || Status
==STATUS_END_OF_FILE
))
766 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
767 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
770 IoCompleteRequest(IrpContext
->Irp
,
771 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
772 VfatFreeIrpContext(IrpContext
);
774 DPRINT("%x\n", Status
);
778 NTSTATUS
VfatWrite (PVFAT_IRP_CONTEXT IrpContext
)
781 PERESOURCE Resource
= NULL
;
782 LARGE_INTEGER ByteOffset
;
783 LARGE_INTEGER OldFileSize
;
784 NTSTATUS Status
= STATUS_SUCCESS
;
786 ULONG OldAllocationSize
;
788 ULONG BytesPerSector
;
792 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
794 ASSERT(IrpContext
->DeviceObject
);
796 // This request is not allowed on the main device object
797 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
799 DPRINT("VfatWrite is called with the main device object.\n");
800 Status
= STATUS_INVALID_DEVICE_REQUEST
;
804 ASSERT(IrpContext
->DeviceExt
);
805 ASSERT(IrpContext
->FileObject
);
806 Fcb
= IrpContext
->FileObject
->FsContext
;
809 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
811 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
813 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
814 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
815 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
816 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
817 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
818 VfatFreeIrpContext(IrpContext
);
822 /* fail if file is a directory and no paged read */
823 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
825 Status
= STATUS_INVALID_PARAMETER
;
829 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
830 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
831 ByteOffset
.u
.HighPart
== -1)
833 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
835 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
836 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
838 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
840 Status
= STATUS_INVALID_PARAMETER
;
844 if (Fcb
->Flags
& (FCB_IS_FAT
| FCB_IS_VOLUME
) ||
845 1 == vfatDirEntryGetFirstCluster (IrpContext
->DeviceExt
, &Fcb
->entry
))
847 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
849 // we can't extend the FAT, the volume or the root on FAT12/FAT16
850 Status
= STATUS_END_OF_FILE
;
855 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
|IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
857 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
859 // non cached write must be sector aligned
860 Status
= STATUS_INVALID_PARAMETER
;
868 * Update last write time
870 IrpContext
->Irp
->IoStatus
.Information
= 0;
871 Status
= STATUS_SUCCESS
;
875 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
877 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
879 Status
= STATUS_INVALID_PARAMETER
;
882 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
884 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
888 if (Fcb
->Flags
& FCB_IS_VOLUME
)
890 Resource
= &IrpContext
->DeviceExt
->DirResource
;
892 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
894 Resource
= &Fcb
->PagingIoResource
;
898 Resource
= &Fcb
->MainResource
;
901 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
903 if (!ExAcquireResourceSharedLite(Resource
,
904 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
907 Status
= STATUS_PENDING
;
913 if (!ExAcquireResourceExclusiveLite(Resource
,
914 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
917 Status
= STATUS_PENDING
;
922 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
923 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
925 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
927 Status
= STATUS_FILE_LOCK_CONFLICT
;
932 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
934 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
936 Status
= STATUS_PENDING
;
941 OldFileSize
= Fcb
->RFCB
.FileSize
;
942 OldAllocationSize
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
;
944 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
947 Status
= STATUS_INVALID_USER_BUFFER
;
952 if (!(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)) &&
953 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
954 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
956 LARGE_INTEGER AllocationSize
;
957 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
958 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
959 IrpContext
->DeviceExt
, &AllocationSize
);
960 if (!NT_SUCCESS (Status
))
967 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
968 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
973 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
975 #ifdef USE_ROS_CC_AND_FS
977 CacheSize
= max(IrpContext
->DeviceExt
->FatInfo
.BytesPerCluster
,
979 CcRosInitializeFileCache(IrpContext
->FileObject
, CacheSize
);
981 /* FIXME: Guard by SEH. */
982 CcInitializeCacheMap(IrpContext
->FileObject
,
983 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
985 &VfatGlobalData
->CacheMgrCallbacks
,
989 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
991 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
993 if (CcCopyWrite(IrpContext
->FileObject
, &ByteOffset
, Length
,
994 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer
))
996 IrpContext
->Irp
->IoStatus
.Information
= Length
;
997 Status
= STATUS_SUCCESS
;
1001 Status
= STATUS_UNSUCCESSFUL
;
1010 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1012 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1015 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1016 if (!NT_SUCCESS(Status
))
1021 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
1022 if (NT_SUCCESS(Status
))
1024 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1028 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
1029 !(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
1031 if(!(*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
1033 LARGE_INTEGER SystemTime
;
1034 // set dates and times
1035 KeQuerySystemTime (&SystemTime
);
1036 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1038 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
1039 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
1040 &Fcb
->entry
.FatX
.UpdateTime
);
1041 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
1042 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
1046 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
1047 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1048 &Fcb
->entry
.Fat
.UpdateTime
);
1049 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1051 /* set date and times to dirty */
1052 Fcb
->Flags
|= FCB_IS_DIRTY
;
1059 ExReleaseResourceLite(Resource
);
1062 if (Status
== STATUS_PENDING
)
1064 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1065 if (NT_SUCCESS(Status
))
1067 Status
= VfatQueueRequest(IrpContext
);
1071 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1072 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1073 VfatFreeIrpContext(IrpContext
);
1078 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1079 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
1080 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
1082 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1083 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1086 IoCompleteRequest(IrpContext
->Irp
,
1087 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
1088 VfatFreeIrpContext(IrpContext
);
1090 DPRINT("%x\n", Status
);