4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: drivers/fs/vfat/rw.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
13 /* 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 /* FUNCTIONS *****************************************************************/
30 NextCluster(PDEVICE_EXTENSION DeviceExt
,
32 PULONG CurrentCluster
,
35 * Return the next cluster in a FAT chain, possibly extending the chain if
39 if (FirstCluster
== 1)
41 (*CurrentCluster
) += DeviceExt
->FatInfo
.SectorsPerCluster
;
42 return(STATUS_SUCCESS
);
47 return GetNextClusterExtend(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
49 return GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
);
54 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
60 * Return the cluster corresponding to an offset within a file,
61 * possibly extending the file if necessary
68 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
69 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
70 Fcb, FirstCluster, FileOffset, Cluster, Extend);
72 if (FirstCluster
== 0)
74 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
78 if (FirstCluster
== 1)
80 /* root of FAT16 or FAT12 */
81 *Cluster
= DeviceExt
->FatInfo
.rootStart
+ FileOffset
82 / (DeviceExt
->FatInfo
.BytesPerCluster
) * DeviceExt
->FatInfo
.SectorsPerCluster
;
83 return(STATUS_SUCCESS
);
87 CurrentCluster
= FirstCluster
;
90 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
92 Status
= GetNextClusterExtend (DeviceExt
, CurrentCluster
, &CurrentCluster
);
93 if (!NT_SUCCESS(Status
))
96 *Cluster
= CurrentCluster
;
100 for (i
= 0; i
< FileOffset
/ DeviceExt
->FatInfo
.BytesPerCluster
; i
++)
102 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
);
103 if (!NT_SUCCESS(Status
))
106 *Cluster
= CurrentCluster
;
108 return(STATUS_SUCCESS
);
113 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext
,
115 LARGE_INTEGER ReadOffset
,
118 * FUNCTION: Reads data from a file
121 ULONG CurrentCluster
;
125 LARGE_INTEGER StartOffset
;
126 PDEVICE_EXTENSION DeviceExt
;
127 BOOLEAN First
= TRUE
;
132 ULONG BytesPerSector
;
133 ULONG BytesPerCluster
;
139 DeviceExt
= IrpContext
->DeviceExt
;
141 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
142 ASSERT(IrpContext
->FileObject
);
143 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
145 DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, "
146 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt
,
147 IrpContext
->FileObject
, Length
, ReadOffset
.QuadPart
);
151 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
152 Fcb
= IrpContext
->FileObject
->FsContext
;
153 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
154 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
156 ASSERT(ReadOffset
.QuadPart
+ Length
<= ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
));
157 ASSERT(ReadOffset
.u
.LowPart
% BytesPerSector
== 0);
158 ASSERT(Length
% BytesPerSector
== 0);
160 /* Is this a read of the FAT? */
161 if (Fcb
->Flags
& FCB_IS_FAT
)
163 ReadOffset
.QuadPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
164 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
166 if (NT_SUCCESS(Status
))
168 *LengthRead
= Length
;
172 DPRINT1("FAT reading failed, Status %x\n", Status
);
176 /* Is this a read of the Volume ? */
177 if (Fcb
->Flags
& FCB_IS_VOLUME
)
179 Status
= VfatReadDiskPartial(IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
180 if (NT_SUCCESS(Status
))
182 *LengthRead
= Length
;
186 DPRINT1("Volume reading failed, Status %x\n", Status
);
192 * Find the first cluster
194 FirstCluster
= CurrentCluster
=
195 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
197 if (FirstCluster
== 1)
199 // Directory of FAT12/16 needs a special handling
201 if (ReadOffset
.u
.LowPart
+ Length
> DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
)
203 Length
= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
- ReadOffset
.u
.LowPart
;
205 ReadOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
207 // Fire up the read command
209 Status
= VfatReadDiskPartial (IrpContext
, &ReadOffset
, Length
, 0, TRUE
);
210 if (NT_SUCCESS(Status
))
212 *LengthRead
= Length
;
217 ExAcquireFastMutex(&Fcb
->LastMutex
);
218 LastCluster
= Fcb
->LastCluster
;
219 LastOffset
= Fcb
->LastOffset
;
220 ExReleaseFastMutex(&Fcb
->LastMutex
);
223 * Find the cluster to start the read from
225 if (LastCluster
> 0 && ReadOffset
.u
.LowPart
>= LastOffset
)
227 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
228 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
) -
230 &CurrentCluster
, FALSE
);
231 #ifdef DEBUG_VERIFY_OFFSET_CACHING
232 /* DEBUG VERIFICATION */
234 ULONG CorrectCluster
;
235 OffsetToCluster(DeviceExt
, FirstCluster
,
236 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
237 &CorrectCluster
, FALSE
);
238 if (CorrectCluster
!= CurrentCluster
)
239 KEBUGCHECK(FAT_FILE_SYSTEM
);
245 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
246 ROUND_DOWN(ReadOffset
.u
.LowPart
, BytesPerCluster
),
247 &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 %d\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
;
310 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
312 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
314 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
318 Status
= STATUS_UNSUCCESSFUL
;
322 Status
= IrpContext
->Irp
->IoStatus
.Status
;
329 VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext
,
331 LARGE_INTEGER WriteOffset
)
333 PDEVICE_EXTENSION DeviceExt
;
338 ULONG CurrentCluster
;
342 NTSTATUS Status
= STATUS_SUCCESS
;
343 BOOLEAN First
= TRUE
;
344 ULONG BytesPerSector
;
345 ULONG BytesPerCluster
;
346 LARGE_INTEGER StartOffset
;
353 DeviceExt
= IrpContext
->DeviceExt
;
355 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
);
356 ASSERT(IrpContext
->FileObject
);
357 ASSERT(IrpContext
->FileObject
->FsContext2
!= NULL
);
359 Ccb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
360 Fcb
= IrpContext
->FileObject
->FsContext
;
361 BytesPerCluster
= DeviceExt
->FatInfo
.BytesPerCluster
;
362 BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
364 DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, "
365 "Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt
,
366 IrpContext
->FileObject
, Length
, WriteOffset
,
369 ASSERT(WriteOffset
.QuadPart
+ Length
<= Fcb
->RFCB
.AllocationSize
.QuadPart
);
370 ASSERT(WriteOffset
.u
.LowPart
% BytesPerSector
== 0);
371 ASSERT(Length
% BytesPerSector
== 0);
373 // Is this a write of the volume ?
374 if (Fcb
->Flags
& FCB_IS_VOLUME
)
376 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
377 if (!NT_SUCCESS(Status
))
379 DPRINT1("Volume writing failed, Status %x\n", Status
);
384 // Is this a write to the FAT ?
385 if (Fcb
->Flags
& FCB_IS_FAT
)
387 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.FATStart
* BytesPerSector
;
388 IrpContext
->RefCount
= 1;
389 for (Count
= 0; Count
< DeviceExt
->FatInfo
.FATCount
; Count
++)
391 Status
= VfatWriteDiskPartial(IrpContext
, &WriteOffset
, Length
, 0, FALSE
);
392 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
394 DPRINT1("FAT writing failed, Status %x\n", Status
);
397 WriteOffset
.u
.LowPart
+= Fcb
->RFCB
.FileSize
.u
.LowPart
;
399 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
401 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
403 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
405 Status
= IrpContext
->Irp
->IoStatus
.Status
;
411 * Find the first cluster
413 FirstCluster
= CurrentCluster
=
414 vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
416 if (FirstCluster
== 1)
418 ASSERT(WriteOffset
.u
.LowPart
+ Length
<= DeviceExt
->FatInfo
.rootDirectorySectors
* BytesPerSector
);
419 // Directory of FAT12/16 needs a special handling
420 WriteOffset
.u
.LowPart
+= DeviceExt
->FatInfo
.rootStart
* BytesPerSector
;
421 // Fire up the write command
422 Status
= VfatWriteDiskPartial (IrpContext
, &WriteOffset
, Length
, 0, TRUE
);
426 ExAcquireFastMutex(&Fcb
->LastMutex
);
427 LastCluster
= Fcb
->LastCluster
;
428 LastOffset
= Fcb
->LastOffset
;
429 ExReleaseFastMutex(&Fcb
->LastMutex
);
432 * Find the cluster to start the write from
434 if (LastCluster
> 0 && WriteOffset
.u
.LowPart
>= LastOffset
)
436 Status
= OffsetToCluster(DeviceExt
, LastCluster
,
437 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) -
439 &CurrentCluster
, FALSE
);
440 #ifdef DEBUG_VERIFY_OFFSET_CACHING
441 /* DEBUG VERIFICATION */
443 ULONG CorrectCluster
;
444 OffsetToCluster(DeviceExt
, FirstCluster
,
445 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
446 &CorrectCluster
, FALSE
);
447 if (CorrectCluster
!= CurrentCluster
)
448 KEBUGCHECK(FAT_FILE_SYSTEM
);
454 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
455 ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
),
456 &CurrentCluster
, FALSE
);
459 if (!NT_SUCCESS(Status
))
464 ExAcquireFastMutex(&Fcb
->LastMutex
);
465 Fcb
->LastCluster
= CurrentCluster
;
466 Fcb
->LastOffset
= ROUND_DOWN (WriteOffset
.u
.LowPart
, BytesPerCluster
);
467 ExReleaseFastMutex(&Fcb
->LastMutex
);
469 IrpContext
->RefCount
= 1;
472 while (Length
> 0 && CurrentCluster
!= 0xffffffff)
474 StartCluster
= CurrentCluster
;
475 StartOffset
.QuadPart
= ClusterToSector(DeviceExt
, StartCluster
) * BytesPerSector
;
484 BytesDone
= min (Length
, BytesPerCluster
- (WriteOffset
.u
.LowPart
% BytesPerCluster
));
485 StartOffset
.QuadPart
+= WriteOffset
.u
.LowPart
% BytesPerCluster
;
490 if (Length
- BytesDone
> BytesPerCluster
)
492 BytesDone
+= BytesPerCluster
;
499 Status
= NextCluster(DeviceExt
, FirstCluster
, &CurrentCluster
, FALSE
);
501 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) && Length
> BytesDone
);
502 DPRINT("start %08x, next %08x, count %d\n",
503 StartCluster
, CurrentCluster
, ClusterCount
);
505 ExAcquireFastMutex(&Fcb
->LastMutex
);
506 Fcb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
507 Fcb
->LastOffset
= ROUND_DOWN(WriteOffset
.u
.LowPart
, BytesPerCluster
) + (ClusterCount
- 1) * BytesPerCluster
;
508 ExReleaseFastMutex(&Fcb
->LastMutex
);
510 // Fire up the write command
511 Status
= VfatWriteDiskPartial (IrpContext
, &StartOffset
, BytesDone
, BufferOffset
, FALSE
);
512 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PENDING
)
516 BufferOffset
+= BytesDone
;
518 WriteOffset
.u
.LowPart
+= BytesDone
;
520 if (0 != InterlockedDecrement((PLONG
)&IrpContext
->RefCount
))
522 KeWaitForSingleObject(&IrpContext
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
524 if (NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
528 Status
= STATUS_UNSUCCESSFUL
;
532 Status
= IrpContext
->Irp
->IoStatus
.Status
;
539 VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
544 ULONG ReturnedLength
= 0;
545 PERESOURCE Resource
= NULL
;
546 LARGE_INTEGER ByteOffset
;
548 PDEVICE_OBJECT DeviceToVerify
;
549 ULONG BytesPerSector
;
553 DPRINT("VfatRead(IrpContext %x)\n", IrpContext
);
555 ASSERT(IrpContext
->DeviceObject
);
557 // This request is not allowed on the main device object
558 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
560 DPRINT("VfatRead is called with the main device object.\n");
561 Status
= STATUS_INVALID_DEVICE_REQUEST
;
565 ASSERT(IrpContext
->DeviceExt
);
566 ASSERT(IrpContext
->FileObject
);
567 Fcb
= IrpContext
->FileObject
->FsContext
;
570 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
572 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
574 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
575 IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
576 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
577 DPRINT("Read from page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Read
.ByteOffset
.QuadPart
);
578 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
579 VfatFreeIrpContext(IrpContext
);
583 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
584 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
585 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
587 /* fail if file is a directory and no paged read */
588 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
590 Status
= STATUS_INVALID_PARAMETER
;
595 DPRINT("'%wZ', Offset: %d, Length %d\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
597 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
599 Status
= STATUS_INVALID_PARAMETER
;
602 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
604 IrpContext
->Irp
->IoStatus
.Information
= 0;
605 Status
= STATUS_END_OF_FILE
;
608 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
610 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
612 DPRINT("%d %d\n", ByteOffset
.u
.LowPart
, Length
);
613 // non cached read must be sector aligned
614 Status
= STATUS_INVALID_PARAMETER
;
620 IrpContext
->Irp
->IoStatus
.Information
= 0;
621 Status
= STATUS_SUCCESS
;
625 if (Fcb
->Flags
& FCB_IS_VOLUME
)
627 Resource
= &IrpContext
->DeviceExt
->DirResource
;
629 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
631 Resource
= &Fcb
->PagingIoResource
;
635 Resource
= &Fcb
->MainResource
;
637 if (!ExAcquireResourceSharedLite(Resource
,
638 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
? TRUE
: FALSE
))
641 Status
= STATUS_PENDING
;
645 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
646 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
648 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
650 Status
= STATUS_FILE_LOCK_CONFLICT
;
655 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
658 Status
= STATUS_INVALID_USER_BUFFER
;
662 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
663 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
667 Status
= STATUS_SUCCESS
;
668 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
670 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
671 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
675 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
677 #ifdef USE_ROS_CC_AND_FS
679 CacheSize
= max(IrpContext
->DeviceExt
->FatInfo
.BytesPerCluster
,
681 CcRosInitializeFileCache(IrpContext
->FileObject
, CacheSize
);
683 /* FIXME: Guard by SEH. */
684 CcInitializeCacheMap(IrpContext
->FileObject
,
685 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
687 &(VfatGlobalData
->CacheMgrCallbacks
),
691 if (!CcCopyRead(IrpContext
->FileObject
, &ByteOffset
, Length
,
692 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
), Buffer
,
693 &IrpContext
->Irp
->IoStatus
))
695 Status
= STATUS_PENDING
;
699 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
701 Status
= IrpContext
->Irp
->IoStatus
.Status
;
708 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
710 Length
= (ULONG
)(ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
713 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
714 if (!NT_SUCCESS(Status
))
719 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
721 if (Status
== STATUS_VERIFY_REQUIRED
)
723 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
724 DeviceToVerify
= IoGetDeviceToVerify(PsGetCurrentThread());
725 IoSetDeviceToVerify(PsGetCurrentThread(), DeviceToVerify
);
726 Status
= IoVerifyVolume (DeviceToVerify
, FALSE
);
728 if (NT_SUCCESS(Status
))
730 Status
= VfatReadFileData(IrpContext
, Length
,
731 ByteOffset
, &ReturnedLength
);
736 if (NT_SUCCESS(Status
))
738 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
745 ExReleaseResourceLite(Resource
);
748 if (Status
== STATUS_PENDING
)
750 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
751 if (NT_SUCCESS(Status
))
753 Status
= VfatQueueRequest(IrpContext
);
757 IrpContext
->Irp
->IoStatus
.Status
= Status
;
758 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
759 VfatFreeIrpContext(IrpContext
);
764 IrpContext
->Irp
->IoStatus
.Status
= Status
;
765 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
766 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
767 (NT_SUCCESS(Status
) || Status
==STATUS_END_OF_FILE
))
769 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
770 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
773 IoCompleteRequest(IrpContext
->Irp
,
774 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
775 VfatFreeIrpContext(IrpContext
);
777 DPRINT("%x\n", Status
);
781 NTSTATUS
VfatWrite (PVFAT_IRP_CONTEXT IrpContext
)
784 PERESOURCE Resource
= NULL
;
785 LARGE_INTEGER ByteOffset
;
786 LARGE_INTEGER OldFileSize
;
787 NTSTATUS Status
= STATUS_SUCCESS
;
789 ULONG OldAllocationSize
;
791 ULONG BytesPerSector
;
795 DPRINT("VfatWrite(IrpContext %x)\n", IrpContext
);
797 ASSERT(IrpContext
->DeviceObject
);
799 // This request is not allowed on the main device object
800 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
802 DPRINT("VfatWrite is called with the main device object.\n");
803 Status
= STATUS_INVALID_DEVICE_REQUEST
;
807 ASSERT(IrpContext
->DeviceExt
);
808 ASSERT(IrpContext
->FileObject
);
809 Fcb
= IrpContext
->FileObject
->FsContext
;
812 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
814 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
816 PFATINFO FatInfo
= &IrpContext
->DeviceExt
->FatInfo
;
817 IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
+= FatInfo
->dataStart
* FatInfo
->BytesPerSector
;
818 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
819 DPRINT("Write to page file, disk offset %I64x\n", IrpContext
->Stack
->Parameters
.Write
.ByteOffset
.QuadPart
);
820 Status
= IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
821 VfatFreeIrpContext(IrpContext
);
825 /* fail if file is a directory and no paged read */
826 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
828 Status
= STATUS_INVALID_PARAMETER
;
832 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
833 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
834 ByteOffset
.u
.HighPart
== -1)
836 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
838 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
839 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
841 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
843 Status
= STATUS_INVALID_PARAMETER
;
847 if (Fcb
->Flags
& (FCB_IS_FAT
| FCB_IS_VOLUME
) ||
848 1 == vfatDirEntryGetFirstCluster (IrpContext
->DeviceExt
, &Fcb
->entry
))
850 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
852 // we can't extend the FAT, the volume or the root on FAT12/FAT16
853 Status
= STATUS_END_OF_FILE
;
858 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
|IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
860 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
862 // non cached write must be sector aligned
863 Status
= STATUS_INVALID_PARAMETER
;
871 * Update last write time
873 IrpContext
->Irp
->IoStatus
.Information
= 0;
874 Status
= STATUS_SUCCESS
;
878 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
880 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
882 Status
= STATUS_INVALID_PARAMETER
;
885 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
887 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
891 if (Fcb
->Flags
& FCB_IS_VOLUME
)
893 Resource
= &IrpContext
->DeviceExt
->DirResource
;
895 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
897 Resource
= &Fcb
->PagingIoResource
;
901 Resource
= &Fcb
->MainResource
;
904 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
906 if (!ExAcquireResourceSharedLite(Resource
,
907 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
910 Status
= STATUS_PENDING
;
916 if (!ExAcquireResourceExclusiveLite(Resource
,
917 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
920 Status
= STATUS_PENDING
;
925 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
926 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
928 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
930 Status
= STATUS_FILE_LOCK_CONFLICT
;
935 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
937 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
939 Status
= STATUS_PENDING
;
944 OldFileSize
= Fcb
->RFCB
.FileSize
;
945 OldAllocationSize
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
;
947 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
950 Status
= STATUS_INVALID_USER_BUFFER
;
955 if (!(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)) &&
956 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
957 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
959 LARGE_INTEGER AllocationSize
;
960 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
961 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
962 IrpContext
->DeviceExt
, &AllocationSize
);
963 if (!NT_SUCCESS (Status
))
970 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
971 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
976 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
978 #ifdef USE_ROS_CC_AND_FS
980 CacheSize
= max(IrpContext
->DeviceExt
->FatInfo
.BytesPerCluster
,
982 CcRosInitializeFileCache(IrpContext
->FileObject
, CacheSize
);
984 /* FIXME: Guard by SEH. */
985 CcInitializeCacheMap(IrpContext
->FileObject
,
986 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
988 &VfatGlobalData
->CacheMgrCallbacks
,
992 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
994 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
996 if (CcCopyWrite(IrpContext
->FileObject
, &ByteOffset
, Length
,
997 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer
))
999 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1000 Status
= STATUS_SUCCESS
;
1004 Status
= STATUS_UNSUCCESSFUL
;
1013 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
1015 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
1018 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1019 if (!NT_SUCCESS(Status
))
1024 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
1025 if (NT_SUCCESS(Status
))
1027 IrpContext
->Irp
->IoStatus
.Information
= Length
;
1031 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
1032 !(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
1034 if(!(*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
1036 LARGE_INTEGER SystemTime
;
1037 // set dates and times
1038 KeQuerySystemTime (&SystemTime
);
1039 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1041 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
1042 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
1043 &Fcb
->entry
.FatX
.UpdateTime
);
1044 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
1045 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
1049 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
1050 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
1051 &Fcb
->entry
.Fat
.UpdateTime
);
1052 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
1054 /* set date and times to dirty */
1055 Fcb
->Flags
|= FCB_IS_DIRTY
;
1062 ExReleaseResourceLite(Resource
);
1065 if (Status
== STATUS_PENDING
)
1067 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
1068 if (NT_SUCCESS(Status
))
1070 Status
= VfatQueueRequest(IrpContext
);
1074 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1075 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1076 VfatFreeIrpContext(IrpContext
);
1081 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1082 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
1083 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
1085 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1086 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1089 IoCompleteRequest(IrpContext
->Irp
,
1090 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
1091 VfatFreeIrpContext(IrpContext
);
1093 DPRINT("%x\n", Status
);