2 /* $Id: rw.c,v 1.35 2002/01/08 00:49:01 dwelch Exp $
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/rw.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <ntos/minmax.h>
23 /* GLOBALS *******************************************************************/
25 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
26 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
28 /* FUNCTIONS *****************************************************************/
31 NextCluster(PDEVICE_EXTENSION DeviceExt
,
34 PULONG CurrentCluster
,
37 * Return the next cluster in a FAT chain, possibly extending the chain if
41 if (Fcb
!= NULL
&& Fcb
->Flags
& FCB_IS_PAGE_FILE
)
44 NextCluster
= Fcb
->FatChain
[(*CurrentCluster
)];
45 (*CurrentCluster
) = NextCluster
;
46 return(STATUS_SUCCESS
);
48 if (FirstCluster
== 1)
50 (*CurrentCluster
) += DeviceExt
->Boot
->SectorsPerCluster
;
51 return(STATUS_SUCCESS
);
56 * CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't
59 if (FirstCluster
== 0)
63 Status
= GetNextCluster(DeviceExt
, 0, CurrentCluster
,
71 Status
= GetNextCluster(DeviceExt
, (*CurrentCluster
), CurrentCluster
,
79 OffsetToCluster(PDEVICE_EXTENSION DeviceExt
,
86 * Return the cluster corresponding to an offset within a file,
87 * possibly extending the file if necessary
94 if (Fcb
!= NULL
&& Fcb
->Flags
& FCB_IS_PAGE_FILE
)
97 ULONG Offset
= FileOffset
/ DeviceExt
->BytesPerCluster
;
100 (*Cluster
) = FirstCluster
;
104 (*Cluster
) = Fcb
->FatChain
[Offset
- 1];
106 return(STATUS_SUCCESS
);
108 if (FirstCluster
== 1)
110 /* root of FAT16 or FAT12 */
111 *Cluster
= DeviceExt
->rootStart
+ FileOffset
112 / (DeviceExt
->BytesPerCluster
) * DeviceExt
->Boot
->SectorsPerCluster
;
113 return(STATUS_SUCCESS
);
117 CurrentCluster
= FirstCluster
;
118 for (i
= 0; i
< FileOffset
/ DeviceExt
->BytesPerCluster
; i
++)
120 Status
= GetNextCluster (DeviceExt
, CurrentCluster
, &CurrentCluster
,
122 if (!NT_SUCCESS(Status
))
127 *Cluster
= CurrentCluster
;
128 return(STATUS_SUCCESS
);
133 VfatReadCluster(PDEVICE_EXTENSION DeviceExt
,
136 PULONG CurrentCluster
,
138 ULONG InternalOffset
,
139 ULONG InternalLength
)
141 PVOID BaseAddress
= NULL
;
144 if (InternalLength
== DeviceExt
->BytesPerCluster
)
146 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
147 Destination
, *CurrentCluster
, 1);
151 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
152 if (BaseAddress
== NULL
)
154 return(STATUS_NO_MEMORY
);
156 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
,
157 BaseAddress
, *CurrentCluster
, 1);
158 memcpy(Destination
, BaseAddress
+ InternalOffset
, InternalLength
);
159 ExFreePool(BaseAddress
);
161 if (!NT_SUCCESS(Status
))
165 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, CurrentCluster
, FALSE
);
170 VfatReadFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
171 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
172 PULONG LengthRead
, ULONG NoCache
)
174 * FUNCTION: Reads data from a file
177 ULONG CurrentCluster
;
185 LARGE_INTEGER FileOffset
;
186 IO_STATUS_BLOCK IoStatus
;
189 assert (DeviceExt
!= NULL
);
190 assert (DeviceExt
->BytesPerCluster
!= 0);
191 assert (FileObject
!= NULL
);
192 assert (FileObject
->FsContext2
!= NULL
);
194 DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
195 "Length %d, ReadOffset 0x%x)\n", DeviceExt
, FileObject
, Buffer
,
200 Ccb
= (PVFATCCB
)FileObject
->FsContext2
;
203 // Is this a read of the FAT ?
204 if (Fcb
->Flags
& FCB_IS_FAT
)
208 DbgPrint ("Cached FAT read outside from VFATFS.SYS\n");
211 if (ReadOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| ReadOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
213 DbgPrint ("Start or end of FAT read is not on a sector boundary\n");
216 if (ReadOffset
+ Length
> Fcb
->RFCB
.FileSize
.QuadPart
)
218 Length
= Fcb
->RFCB
.FileSize
.QuadPart
- ReadOffset
;
221 Status
= VfatReadSectors(DeviceExt
->StorageDevice
,
222 DeviceExt
->FATStart
+ ReadOffset
/ BLOCKSIZE
, Length
/ BLOCKSIZE
, Buffer
);
223 if (NT_SUCCESS(Status
))
225 *LengthRead
= Length
;
229 DPRINT1("FAT reading failed, Status %x\n", Status
);
235 * Find the first cluster
237 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
240 * Truncate the read if necessary
242 if (!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
244 if (ReadOffset
>= Fcb
->entry
.FileSize
)
246 return (STATUS_END_OF_FILE
);
248 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
250 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
254 if (FirstCluster
== 1)
256 // root directory of FAT12 od FAT16
257 if (ReadOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
259 Length
= DeviceExt
->rootDirectorySectors
* BLOCKSIZE
- ReadOffset
;
263 // using the Cc-interface if possible
266 FileOffset
.QuadPart
= ReadOffset
;
267 CcCopyRead(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
, &IoStatus
);
268 *LengthRead
= IoStatus
.Information
;
269 return IoStatus
.Status
;
273 * Find the cluster to start the read from
275 if (Ccb
->LastCluster
> 0 && ReadOffset
> Ccb
->LastOffset
)
277 CurrentCluster
= Ccb
->LastCluster
;
279 Status
= OffsetToCluster(DeviceExt
,
282 ROUND_DOWN(ReadOffset
, DeviceExt
->BytesPerCluster
),
285 if (!NT_SUCCESS(Status
))
290 * If the read doesn't begin on a chunk boundary then we need special
293 if ((ReadOffset
% DeviceExt
->BytesPerCluster
) != 0 )
295 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
- (ReadOffset
% DeviceExt
->BytesPerCluster
));
296 Ccb
->LastCluster
= CurrentCluster
;
297 Ccb
->LastOffset
= ROUND_DOWN(ReadOffset
, DeviceExt
->BytesPerCluster
);
298 Status
= VfatReadCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
299 Buffer
, ReadOffset
% DeviceExt
->BytesPerCluster
,
301 if (NT_SUCCESS(Status
))
303 (*LengthRead
) = (*LengthRead
) + TempLength
;
304 Length
= Length
- TempLength
;
305 Buffer
= Buffer
+ TempLength
;
306 ReadOffset
= ReadOffset
+ TempLength
;
310 while (Length
>= DeviceExt
->BytesPerCluster
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
312 StartCluster
= CurrentCluster
;
314 // search for continous clusters
318 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
320 while (StartCluster
+ ClusterCount
== CurrentCluster
&& NT_SUCCESS(Status
) &&
321 Length
- ClusterCount
* DeviceExt
->BytesPerCluster
>= DeviceExt
->BytesPerCluster
);
322 DPRINT("Count %d, Start %x Next %x\n", ClusterCount
, StartCluster
, CurrentCluster
);
323 Ccb
->LastCluster
= StartCluster
+ (ClusterCount
- 1);
324 Ccb
->LastOffset
= ReadOffset
+ (ClusterCount
- 1) * DeviceExt
->BytesPerCluster
;
326 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, ClusterCount
);
327 if (NT_SUCCESS(Status
))
329 ClusterCount
*= DeviceExt
->BytesPerCluster
;
330 (*LengthRead
) = (*LengthRead
) + ClusterCount
;
331 Buffer
+= ClusterCount
;
332 Length
-= ClusterCount
;
333 ReadOffset
+= ClusterCount
;
337 * If the read doesn't end on a chunk boundary then we need special
340 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
342 Ccb
->LastCluster
= CurrentCluster
;
343 Ccb
->LastOffset
= ReadOffset
+ DeviceExt
->BytesPerCluster
;
345 Status
= VfatReadCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
,
347 if (NT_SUCCESS(Status
))
349 (*LengthRead
) = (*LengthRead
) + Length
;
356 VfatWriteCluster(PDEVICE_EXTENSION DeviceExt
,
360 PULONG CurrentCluster
,
362 ULONG InternalOffset
,
363 ULONG InternalLength
)
368 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
370 BaseAddress
= ExAllocatePool(NonPagedPool
, DeviceExt
->BytesPerCluster
);
371 if (BaseAddress
== NULL
)
373 return(STATUS_NO_MEMORY
);
377 BaseAddress
= Source
;
378 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
381 * If the data in the cache isn't valid or we are bypassing the
382 * cache and not writing a cluster aligned, cluster sized region
383 * then read data in to base address
385 Status
= VfatRawReadCluster(DeviceExt
, FirstCluster
, BaseAddress
,
387 if (!NT_SUCCESS(Status
))
389 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
391 ExFreePool(BaseAddress
);
395 memcpy(BaseAddress
+ InternalOffset
, Source
, InternalLength
);
398 * Write the data back to disk
400 DPRINT("Writing 0x%x\n", *CurrentCluster
);
401 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, BaseAddress
,
403 if (InternalLength
!= DeviceExt
->BytesPerCluster
)
405 ExFreePool(BaseAddress
);
407 if (!NT_SUCCESS(Status
))
411 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, CurrentCluster
, FALSE
);
416 VfatWriteFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
417 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
,
418 BOOLEAN NoCache
, BOOLEAN PageIo
)
420 * FUNCTION: Writes data to file
423 ULONG CurrentCluster
;
430 LARGE_INTEGER SystemTime
, LocalTime
;
433 LARGE_INTEGER FileOffset
;
435 DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
436 "WriteOffset %x\n", FileObject
, Buffer
, Length
, WriteOffset
);
439 pCcb
= (PVFATCCB
) (FileObject
->FsContext2
);
444 // DPRINT1("%S\n", Fcb->PathName);
448 return STATUS_SUCCESS
;
451 // Is this a write to the FAT ?
452 if (Fcb
->Flags
& FCB_IS_FAT
)
454 if (!NoCache
&& !PageIo
)
456 DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
459 if (WriteOffset
>= Fcb
->RFCB
.FileSize
.QuadPart
|| WriteOffset
% BLOCKSIZE
!= 0 || Length
% BLOCKSIZE
!= 0)
461 DbgPrint ("Start or end of FAT write is not on a sector boundary\n");
464 if (WriteOffset
+ Length
> (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
)
466 Length
= (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
- WriteOffset
;
469 for (Count
= 0; Count
< DeviceExt
->Boot
->FATCount
; Count
++)
471 Status
= VfatWriteSectors(DeviceExt
->StorageDevice
,
472 DeviceExt
->FATStart
+ (Count
* (ULONG
)Fcb
->RFCB
.FileSize
.QuadPart
+ WriteOffset
) / BLOCKSIZE
,
473 Length
/ BLOCKSIZE
, Buffer
);
474 if (!NT_SUCCESS(Status
))
476 DPRINT1("FAT writing failed, Status %x\n", Status
);
482 /* Locate the first cluster of the file */
483 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
487 if (FirstCluster
== 0)
489 return STATUS_UNSUCCESSFUL
;
494 if (FirstCluster
== 1)
496 // root directory of FAT12 od FAT16
497 if (WriteOffset
+ Length
> DeviceExt
->rootDirectorySectors
* BLOCKSIZE
)
499 DPRINT("Writing over the end of the root directory on FAT12/16\n");
500 return STATUS_END_OF_FILE
;
504 Status
= vfatExtendSpace(DeviceExt
, FileObject
, WriteOffset
+ Length
);
505 if (!NT_SUCCESS (Status
))
511 if (NoCache
|| PageIo
)
514 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
515 if (pCcb
->LastCluster
> 0 && WriteOffset
> pCcb
->LastOffset
)
517 CurrentCluster
= pCcb
->LastCluster
;
519 Status
= OffsetToCluster(DeviceExt
,
522 ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
),
525 if (!NT_SUCCESS(Status
) || CurrentCluster
== 0xffffffff)
530 pCcb
->LastCluster
= CurrentCluster
;
531 pCcb
->LastOffset
= ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
);
534 * If the offset in the cluster doesn't fall on the cluster boundary
535 * then we have to write only from the specified offset
537 Status
= STATUS_SUCCESS
;
538 if ((WriteOffset
% DeviceExt
->BytesPerCluster
) != 0)
540 TempLength
= min (Length
, DeviceExt
->BytesPerCluster
- (WriteOffset
% DeviceExt
->BytesPerCluster
));
541 Status
= VfatWriteCluster(DeviceExt
,
543 ROUND_DOWN(WriteOffset
, DeviceExt
->BytesPerCluster
),
547 WriteOffset
% DeviceExt
->BytesPerCluster
,
549 if (NT_SUCCESS(Status
))
551 Buffer
= Buffer
+ TempLength
;
552 Length
= Length
- TempLength
;
553 WriteOffset
= WriteOffset
+ TempLength
;
557 while (Length
>= DeviceExt
->BytesPerCluster
&& CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
559 StartCluster
= CurrentCluster
;
561 // search for continous clusters
565 Status
= NextCluster(DeviceExt
, Fcb
, FirstCluster
, &CurrentCluster
, FALSE
);
567 while (StartCluster
+ Count
== CurrentCluster
&& NT_SUCCESS(Status
) &&
568 Length
- Count
* DeviceExt
->BytesPerCluster
>= DeviceExt
->BytesPerCluster
);
570 pCcb
->LastCluster
= StartCluster
+ (Count
- 1);
571 pCcb
->LastOffset
= WriteOffset
+ (Count
- 1) * DeviceExt
->BytesPerCluster
;
573 Status
= VfatRawWriteCluster(DeviceExt
, FirstCluster
, Buffer
, StartCluster
, Count
);
574 if (NT_SUCCESS(Status
))
576 Count
*= DeviceExt
->BytesPerCluster
;
579 WriteOffset
+= Count
;
583 /* Write the remainder */
584 if (Length
> 0 && CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
586 Status
= VfatWriteCluster(DeviceExt
,
594 if (NT_SUCCESS(Status
))
599 if (NT_SUCCESS(Status
) && Length
)
601 if (WriteOffset
< Fcb
->RFCB
.AllocationSize
.QuadPart
)
603 DPRINT1("%d %d\n", WriteOffset
, (ULONG
)Fcb
->RFCB
.AllocationSize
.QuadPart
);
604 Status
= STATUS_DISK_FULL
; // ???????????
610 // using the Cc-interface if possible
611 FileOffset
.QuadPart
= WriteOffset
;
612 if(CcCopyWrite(FileObject
, &FileOffset
, Length
, TRUE
, Buffer
))
614 Status
= STATUS_SUCCESS
;
618 Status
= STATUS_UNSUCCESSFUL
;
625 if(!(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
627 /* set dates and times */
628 KeQuerySystemTime (&SystemTime
);
629 ExSystemTimeToLocalTime (&SystemTime
, &LocalTime
);
630 FsdFileTimeToDosDateTime ((TIME
*)&LocalTime
,
631 &Fcb
->entry
.UpdateDate
,
632 &Fcb
->entry
.UpdateTime
);
633 Fcb
->entry
.AccessDate
= Fcb
->entry
.UpdateDate
;
634 // update dates/times and length
635 updEntry (DeviceExt
, FileObject
);
642 NTSTATUS
vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt
, PFILE_OBJECT pFileObject
, ULONG NewSize
)
645 ULONG CurrentCluster
;
651 pFcb
= ((PVFATCCB
) (pFileObject
->FsContext2
))->pFcb
;
653 DPRINT ("New Size %d, AllocationSize %d, BytesPerCluster %d\n", NewSize
,
654 (ULONG
)pFcb
->RFCB
.AllocationSize
.QuadPart
, pDeviceExt
->BytesPerCluster
);
656 FirstCluster
= CurrentCluster
= vfatDirEntryGetFirstCluster (pDeviceExt
, &pFcb
->entry
);
658 if (NewSize
> pFcb
->RFCB
.AllocationSize
.QuadPart
|| FirstCluster
==0)
660 // size on disk must be extended
661 if (FirstCluster
== 0)
664 Status
= NextCluster (pDeviceExt
, pFcb
, FirstCluster
, &CurrentCluster
, TRUE
);
665 if (!NT_SUCCESS(Status
))
667 DPRINT1("NextCluster failed, Status %x\n", Status
);
670 NewCluster
= FirstCluster
= CurrentCluster
;
674 Status
= OffsetToCluster(pDeviceExt
, pFcb
, FirstCluster
,
675 pFcb
->RFCB
.AllocationSize
.QuadPart
- pDeviceExt
->BytesPerCluster
,
676 &CurrentCluster
, FALSE
);
677 if (!NT_SUCCESS(Status
))
679 DPRINT1("OffsetToCluster failed, Status %x\n", Status
);
682 if (CurrentCluster
== 0xffffffff)
684 DPRINT1("Not enough disk space.\n");
685 return STATUS_DISK_FULL
;
687 // CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
688 NewCluster
= CurrentCluster
;
689 Status
= NextCluster(pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
690 if (NewCluster
!= 0xffffffff)
692 DPRINT1("Difference between size from direntry and the FAT.\n");
696 Status
= OffsetToCluster(pDeviceExt
, pFcb
, FirstCluster
,
697 ROUND_DOWN(NewSize
-1, pDeviceExt
->BytesPerCluster
),
699 if (!NT_SUCCESS(Status
) || NewCluster
== 0xffffffff)
701 DPRINT1("Not enough free space on disk\n");
702 if (pFcb
->RFCB
.AllocationSize
.QuadPart
> 0)
704 NewCluster
= CurrentCluster
;
705 // FIXME: check status
706 NextCluster(pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
707 WriteCluster(pDeviceExt
, CurrentCluster
, 0xffffffff);
709 // free the allocated space
710 while (NewCluster
!= 0xffffffff)
712 CurrentCluster
= NewCluster
;
713 // FIXME: check status
714 NextCluster (pDeviceExt
, pFcb
, FirstCluster
, &NewCluster
, FALSE
);
715 WriteCluster (pDeviceExt
, CurrentCluster
, 0);
717 return STATUS_DISK_FULL
;
719 if (pFcb
->RFCB
.AllocationSize
.QuadPart
== 0)
721 pFcb
->entry
.FirstCluster
= FirstCluster
;
722 if(pDeviceExt
->FatType
== FAT32
)
723 pFcb
->entry
.FirstClusterHigh
= FirstCluster
>> 16;
725 pFcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(NewSize
, pDeviceExt
->BytesPerCluster
);
726 if (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
728 pFcb
->RFCB
.FileSize
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
729 pFcb
->RFCB
.ValidDataLength
.QuadPart
= pFcb
->RFCB
.AllocationSize
.QuadPart
;
733 pFcb
->entry
.FileSize
= NewSize
;
734 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
735 pFcb
->RFCB
.ValidDataLength
.QuadPart
= NewSize
;
737 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
741 if (NewSize
> pFcb
->RFCB
.FileSize
.QuadPart
)
743 // size on disk must not be extended
744 if (!(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
746 pFcb
->entry
.FileSize
= NewSize
;
747 pFcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
748 CcSetFileSizes(pFileObject
, (PCC_FILE_SIZES
)&pFcb
->RFCB
.AllocationSize
);
756 return STATUS_SUCCESS
;
759 NTSTATUS
VfatRead(PVFAT_IRP_CONTEXT IrpContext
)
763 NTSTATUS Status
= STATUS_SUCCESS
;
765 ULONG ReturnedReadLength
= 0;
766 LARGE_INTEGER ReadOffset
;
769 DPRINT ("VfatRead(IrpContext %x)\n", IrpContext
);
771 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
776 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
778 if (!ExAcquireResourceSharedLite(&Fcb
->PagingIoResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
780 return VfatQueueRequest (IrpContext
);
785 if (!ExAcquireResourceSharedLite(&Fcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
787 return VfatQueueRequest (IrpContext
);
791 ReadLength
= IrpContext
->Stack
->Parameters
.Read
.Length
;
792 ReadOffset
= IrpContext
->Stack
->Parameters
.Read
.ByteOffset
;
793 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
795 /* fail if file is a directory and no paged read */
796 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
798 Status
= STATUS_FILE_IS_A_DIRECTORY
;
802 Status
= VfatReadFile (IrpContext
->DeviceExt
, IrpContext
->FileObject
,
803 Buffer
, ReadLength
, ReadOffset
.u
.LowPart
, &ReturnedReadLength
,
804 IrpContext
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
805 || IrpContext
->Irp
->Flags
& IRP_PAGING_IO
);
808 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
810 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
814 ExReleaseResourceLite(&Fcb
->MainResource
);
817 if (NT_SUCCESS(Status
))
819 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
821 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
= ReadOffset
.QuadPart
+ ReturnedReadLength
;
823 IrpContext
->Irp
->IoStatus
.Information
= ReturnedReadLength
;
827 IrpContext
->Irp
->IoStatus
.Information
= 0;
830 IrpContext
->Irp
->IoStatus
.Status
= Status
;
831 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
832 VfatFreeIrpContext (IrpContext
);
837 NTSTATUS
VfatWrite(PVFAT_IRP_CONTEXT IrpContext
)
841 NTSTATUS Status
= STATUS_SUCCESS
;
843 LARGE_INTEGER WriteOffset
;
846 DPRINT ("VfatWrite(), %S\n", ((PVFATCCB
) IrpContext
->FileObject
->FsContext2
)->pFcb
->FileName
);
848 Ccb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
853 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
855 if (!ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
857 return VfatQueueRequest (IrpContext
);
862 if (!ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
864 return VfatQueueRequest (IrpContext
);
868 WriteLength
= IrpContext
->Stack
->Parameters
.Write
.Length
;
869 WriteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
870 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
872 /* fail if file is a directory and no paged read */
873 if (Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
875 Status
= STATUS_FILE_IS_A_DIRECTORY
;
879 Status
= VfatWriteFile (IrpContext
->DeviceExt
, IrpContext
->FileObject
,
880 Buffer
, WriteLength
, WriteOffset
.u
.LowPart
,
881 IrpContext
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
,
882 IrpContext
->Irp
->Flags
& IRP_PAGING_IO
);
885 if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
887 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
891 ExReleaseResourceLite(&Fcb
->MainResource
);
894 if (NT_SUCCESS(Status
))
896 if (IrpContext
->FileObject
->Flags
& FO_SYNCHRONOUS_IO
&& !(IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))
898 IrpContext
->FileObject
->CurrentByteOffset
.QuadPart
= WriteOffset
.QuadPart
+ WriteLength
;
900 IrpContext
->Irp
->IoStatus
.Information
= WriteLength
;
904 IrpContext
->Irp
->IoStatus
.Information
= 0;
907 IrpContext
->Irp
->IoStatus
.Status
= Status
;
908 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
909 VfatFreeIrpContext (IrpContext
);