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 %d, 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 %d\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 %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt
,
358 IrpContext
->FileObject
, Length
, WriteOffset
,
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 %d\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 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
563 ByteOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
564 Length
= IrpContext
->Stack
->Parameters
.Read
.Length
;
565 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
567 /* fail if file is a directory and no paged read */
568 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
570 Status
= STATUS_INVALID_PARAMETER
;
575 DPRINT("'%wZ', Offset: %d, Length %d\n", &Fcb
->PathNameU
, ByteOffset
.u
.LowPart
, Length
);
577 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
579 Status
= STATUS_INVALID_PARAMETER
;
582 if (ByteOffset
.QuadPart
>= Fcb
->RFCB
.FileSize
.QuadPart
)
584 IrpContext
->Irp
->IoStatus
.Information
= 0;
585 Status
= STATUS_END_OF_FILE
;
588 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
590 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
592 DPRINT("%d %d\n", ByteOffset
.u
.LowPart
, Length
);
593 // non cached read must be sector aligned
594 Status
= STATUS_INVALID_PARAMETER
;
600 IrpContext
->Irp
->IoStatus
.Information
= 0;
601 Status
= STATUS_SUCCESS
;
605 if (Fcb
->Flags
& FCB_IS_VOLUME
)
607 Resource
= &IrpContext
->DeviceExt
->DirResource
;
609 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
611 Resource
= &Fcb
->PagingIoResource
;
615 Resource
= &Fcb
->MainResource
;
617 if (!ExAcquireResourceSharedLite(Resource
,
618 IrpContext
->Flags
& IRPCONTEXT_CANWAIT
? TRUE
: FALSE
))
621 Status
= STATUS_PENDING
;
625 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
626 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
628 if (!FsRtlCheckLockForReadAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
630 Status
= STATUS_FILE_LOCK_CONFLICT
;
635 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
638 Status
= STATUS_INVALID_USER_BUFFER
;
642 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
643 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
646 Status
= STATUS_SUCCESS
;
647 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
649 Length
= Fcb
->RFCB
.FileSize
.u
.LowPart
- ByteOffset
.u
.LowPart
;
650 Status
= /*STATUS_END_OF_FILE*/STATUS_SUCCESS
;
653 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
655 CcInitializeCacheMap(IrpContext
->FileObject
,
656 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
658 &(VfatGlobalData
->CacheMgrCallbacks
),
661 if (!CcCopyRead(IrpContext
->FileObject
, &ByteOffset
, Length
,
662 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
), Buffer
,
663 &IrpContext
->Irp
->IoStatus
))
665 Status
= STATUS_PENDING
;
668 if (!NT_SUCCESS(IrpContext
->Irp
->IoStatus
.Status
))
670 Status
= IrpContext
->Irp
->IoStatus
.Status
;
676 if (ByteOffset
.QuadPart
+ Length
> ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
))
678 Length
= (ULONG
)(ROUND_UP(Fcb
->RFCB
.FileSize
.QuadPart
, BytesPerSector
) - ByteOffset
.QuadPart
);
681 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
682 if (!NT_SUCCESS(Status
))
687 Status
= VfatReadFileData(IrpContext
, Length
, ByteOffset
, &ReturnedLength
);
688 if (NT_SUCCESS(Status
))
690 IrpContext
->Irp
->IoStatus
.Information
= ReturnedLength
;
697 ExReleaseResourceLite(Resource
);
700 if (Status
== STATUS_PENDING
)
702 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoWriteAccess
);
703 if (NT_SUCCESS(Status
))
705 Status
= VfatQueueRequest(IrpContext
);
709 IrpContext
->Irp
->IoStatus
.Status
= Status
;
710 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
711 VfatFreeIrpContext(IrpContext
);
716 IrpContext
->Irp
->IoStatus
.Status
= Status
;
717 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
718 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
719 (NT_SUCCESS(Status
) || Status
==STATUS_END_OF_FILE
))
721 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
722 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
725 IoCompleteRequest(IrpContext
->Irp
,
726 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
727 VfatFreeIrpContext(IrpContext
);
729 DPRINT("%x\n", Status
);
733 NTSTATUS
VfatWrite (PVFAT_IRP_CONTEXT IrpContext
)
736 PERESOURCE Resource
= NULL
;
737 LARGE_INTEGER ByteOffset
;
738 LARGE_INTEGER OldFileSize
;
739 NTSTATUS Status
= STATUS_SUCCESS
;
742 ULONG BytesPerSector
;
746 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext
);
748 ASSERT(IrpContext
->DeviceObject
);
750 // This request is not allowed on the main device object
751 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
753 DPRINT("VfatWrite is called with the main device object.\n");
754 Status
= STATUS_INVALID_DEVICE_REQUEST
;
758 ASSERT(IrpContext
->DeviceExt
);
759 ASSERT(IrpContext
->FileObject
);
760 Fcb
= IrpContext
->FileObject
->FsContext
;
763 DPRINT("<%wZ>\n", &Fcb
->PathNameU
);
765 /* fail if file is a directory and no paged read */
766 if (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
768 Status
= STATUS_INVALID_PARAMETER
;
772 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
773 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
774 ByteOffset
.u
.HighPart
== -1)
776 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
778 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
779 BytesPerSector
= IrpContext
->DeviceExt
->FatInfo
.BytesPerSector
;
781 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
783 Status
= STATUS_INVALID_PARAMETER
;
787 if (Fcb
->Flags
& (FCB_IS_FAT
| FCB_IS_VOLUME
) ||
788 1 == vfatDirEntryGetFirstCluster (IrpContext
->DeviceExt
, &Fcb
->entry
))
790 if (ByteOffset
.QuadPart
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
792 // we can't extend the FAT, the volume or the root on FAT12/FAT16
793 Status
= STATUS_END_OF_FILE
;
798 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
|IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
))
800 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
802 // non cached write must be sector aligned
803 Status
= STATUS_INVALID_PARAMETER
;
811 * Update last write time
813 IrpContext
->Irp
->IoStatus
.Information
= 0;
814 Status
= STATUS_SUCCESS
;
818 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
820 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
822 Status
= STATUS_INVALID_PARAMETER
;
825 if (ByteOffset
.u
.LowPart
+ Length
> ROUND_UP(Fcb
->RFCB
.AllocationSize
.u
.LowPart
, BytesPerSector
))
827 Length
= ROUND_UP(Fcb
->RFCB
.FileSize
.u
.LowPart
, BytesPerSector
) - ByteOffset
.u
.LowPart
;
831 if (Fcb
->Flags
& FCB_IS_VOLUME
)
833 Resource
= &IrpContext
->DeviceExt
->DirResource
;
835 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
837 Resource
= &Fcb
->PagingIoResource
;
841 Resource
= &Fcb
->MainResource
;
844 if (Fcb
->Flags
& FCB_IS_PAGE_FILE
)
846 if (!ExAcquireResourceSharedLite(Resource
,
847 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
850 Status
= STATUS_PENDING
;
856 if (!ExAcquireResourceExclusiveLite(Resource
,
857 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
860 Status
= STATUS_PENDING
;
865 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
866 FsRtlAreThereCurrentFileLocks(&Fcb
->FileLock
))
868 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLock
, IrpContext
->Irp
))
870 Status
= STATUS_FILE_LOCK_CONFLICT
;
875 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
877 if (ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
879 Status
= STATUS_PENDING
;
884 OldFileSize
= Fcb
->RFCB
.FileSize
;
886 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
889 Status
= STATUS_INVALID_USER_BUFFER
;
894 if (!(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)) &&
895 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
896 ByteOffset
.u
.LowPart
+ Length
> Fcb
->RFCB
.FileSize
.u
.LowPart
)
898 LARGE_INTEGER AllocationSize
;
899 AllocationSize
.QuadPart
= ByteOffset
.u
.LowPart
+ Length
;
900 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
, Fcb
,
901 IrpContext
->DeviceExt
, &AllocationSize
);
902 if (!NT_SUCCESS (Status
))
908 if (!(IrpContext
->Irp
->Flags
& (IRP_NOCACHE
|IRP_PAGING_IO
)) &&
909 !(Fcb
->Flags
& (FCB_IS_PAGE_FILE
|FCB_IS_VOLUME
)))
913 if (IrpContext
->FileObject
->PrivateCacheMap
== NULL
)
915 CcInitializeCacheMap(IrpContext
->FileObject
,
916 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
918 &VfatGlobalData
->CacheMgrCallbacks
,
921 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
923 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
925 if (CcCopyWrite(IrpContext
->FileObject
, &ByteOffset
, Length
,
926 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer
))
928 IrpContext
->Irp
->IoStatus
.Information
= Length
;
929 Status
= STATUS_SUCCESS
;
933 Status
= STATUS_UNSUCCESSFUL
;
940 if (ByteOffset
.QuadPart
> OldFileSize
.QuadPart
)
942 CcZeroData(IrpContext
->FileObject
, &OldFileSize
, &ByteOffset
, TRUE
);
945 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
946 if (!NT_SUCCESS(Status
))
951 Status
= VfatWriteFileData(IrpContext
, Length
, ByteOffset
);
952 if (NT_SUCCESS(Status
))
954 IrpContext
->Irp
->IoStatus
.Information
= Length
;
958 if (!(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) &&
959 !(Fcb
->Flags
& (FCB_IS_FAT
|FCB_IS_VOLUME
)))
961 if(!(*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
963 LARGE_INTEGER SystemTime
;
964 // set dates and times
965 KeQuerySystemTime (&SystemTime
);
966 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
968 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
969 &SystemTime
, &Fcb
->entry
.FatX
.UpdateDate
,
970 &Fcb
->entry
.FatX
.UpdateTime
);
971 Fcb
->entry
.FatX
.AccessDate
= Fcb
->entry
.FatX
.UpdateDate
;
972 Fcb
->entry
.FatX
.AccessTime
= Fcb
->entry
.FatX
.UpdateTime
;
976 FsdSystemTimeToDosDateTime (IrpContext
->DeviceExt
,
977 &SystemTime
, &Fcb
->entry
.Fat
.UpdateDate
,
978 &Fcb
->entry
.Fat
.UpdateTime
);
979 Fcb
->entry
.Fat
.AccessDate
= Fcb
->entry
.Fat
.UpdateDate
;
981 /* set date and times to dirty */
982 Fcb
->Flags
|= FCB_IS_DIRTY
;
989 ExReleaseResourceLite(Resource
);
992 if (Status
== STATUS_PENDING
)
994 Status
= VfatLockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
995 if (NT_SUCCESS(Status
))
997 Status
= VfatQueueRequest(IrpContext
);
1001 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1002 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1003 VfatFreeIrpContext(IrpContext
);
1008 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1009 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&&
1010 !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
) && NT_SUCCESS(Status
))
1012 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
=
1013 ByteOffset
.QuadPart
+ IrpContext
->Irp
->IoStatus
.Information
;
1016 IoCompleteRequest(IrpContext
->Irp
,
1017 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
1018 VfatFreeIrpContext(IrpContext
);
1020 DPRINT("%x\n", Status
);