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 /* FUNCTIONS *****************************************************************/
26 NextCluster(PDEVICE_EXTENSION DeviceExt,
29 PULONG CurrentCluster,
32 * Return the next cluster in a FAT chain, possibly extending the chain if
36 if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
41 DPRINT("NextCluster(Fcb %x, FirstCluster %x, Extend %d)\n", Fcb,
42 FirstCluster, Extend);
43 if (Fcb->FatChainSize == 0)
45 /* Paging file with zero length. */
46 *CurrentCluster = 0xffffffff;
49 Fcb->FatChain = ExAllocatePool(NonPagedPool, sizeof(ULONG));
50 if (Fcb->FatChain == NULL)
52 return(STATUS_NO_MEMORY);
54 Status = GetNextCluster(DeviceExt, 0, CurrentCluster, TRUE);
55 if (!NT_SUCCESS(Status))
57 ExFreePool(Fcb->FatChain);
60 Fcb->FatChain[0] = *CurrentCluster;
61 Fcb->FatChainSize = 1;
66 return STATUS_UNSUCCESSFUL;
71 for (i = 0; i < Fcb->FatChainSize; i++)
73 if (Fcb->FatChain[i] == *CurrentCluster)
76 if (i >= Fcb->FatChainSize)
78 return STATUS_UNSUCCESSFUL;
80 if (i == Fcb->FatChainSize - 1)
84 FatChain = ExAllocatePool(NonPagedPool,
85 (i + 2) * sizeof(ULONG));
88 *CurrentCluster = 0xffffffff;
89 return STATUS_NO_MEMORY;
91 Status = GetNextCluster(DeviceExt, *CurrentCluster,
92 CurrentCluster, TRUE);
93 if (NT_SUCCESS(Status) && *CurrentCluster != 0xffffffff)
95 memcpy(FatChain, Fcb->FatChain, (i + 1) * sizeof(ULONG));
96 FatChain[i + 1] = *CurrentCluster;
97 ExFreePool(Fcb->FatChain);
98 Fcb->FatChain = FatChain;
99 Fcb->FatChainSize = i + 2;
103 ExFreePool(FatChain);
109 *CurrentCluster = 0xffffffff;
110 return STATUS_SUCCESS;
113 *CurrentCluster = Fcb->FatChain[i + 1];
114 return STATUS_SUCCESS;
117 if (FirstCluster == 1)
119 (*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster;
120 return(STATUS_SUCCESS);
125 * CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't
128 if (FirstCluster == 0)
132 Status = GetNextCluster(DeviceExt, 0, CurrentCluster,
140 Status = GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster,
148 OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
155 * Return the cluster corresponding to an offset within a file,
156 * possibly extending the file if necessary
159 ULONG CurrentCluster;
162 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
163 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
164 Fcb, FirstCluster, FileOffset, Cluster, Extend);
165 if (FirstCluster == 0)
167 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
171 if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
174 ULONG Offset = FileOffset / DeviceExt->FatInfo.BytesPerCluster;
177 if (Fcb->FatChainSize == 0)
179 DbgPrint("OffsetToCluster is called with FirstCluster = %x"
180 " and Fcb->FatChainSize = 0!\n", FirstCluster);
183 if (Offset < Fcb->FatChainSize)
185 *Cluster = Fcb->FatChain[Offset];
186 return STATUS_SUCCESS;
192 *Cluster = 0xffffffff;
193 return STATUS_UNSUCCESSFUL;
197 FatChain = ExAllocatePool(NonPagedPool, (Offset + 1) * sizeof(ULONG));
200 *Cluster = 0xffffffff;
201 return STATUS_UNSUCCESSFUL;
204 CurrentCluster = Fcb->FatChain[Fcb->FatChainSize - 1];
205 FatChain[Fcb->FatChainSize - 1] = CurrentCluster;
206 for (i = Fcb->FatChainSize; i < Offset + 1; i++)
208 Status = GetNextCluster(DeviceExt, CurrentCluster, &CurrentCluster, TRUE);
209 if (!NT_SUCCESS(Status) || CurrentCluster == 0xFFFFFFFF)
211 while (i >= Fcb->FatChainSize)
213 WriteCluster(DeviceExt, FatChain[i - 1], 0xFFFFFFFF);
216 *Cluster = 0xffffffff;
217 ExFreePool(FatChain);
218 if (!NT_SUCCESS(Status))
220 return STATUS_UNSUCCESSFUL;
222 FatChain[i] = CurrentCluster;
224 memcpy (FatChain, Fcb->FatChain, Fcb->FatChainSize * sizeof(ULONG));
225 ExFreePool(Fcb->FatChain);
226 Fcb->FatChain = FatChain;
227 Fcb->FatChainSize = Offset + 1;
230 *Cluster = CurrentCluster;
231 return(STATUS_SUCCESS);
233 if (FirstCluster == 1)
235 /* root of FAT16 or FAT12 */
236 *Cluster = DeviceExt->FatInfo.rootStart + FileOffset
237 / (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster;
238 return(STATUS_SUCCESS);
242 CurrentCluster = FirstCluster;
243 for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
245 Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster,
247 if (!NT_SUCCESS(Status))
252 *Cluster = CurrentCluster;
253 return(STATUS_SUCCESS);
258 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
259 ULONG Length, LARGE_INTEGER ReadOffset, PULONG LengthRead)
261 * FUNCTION: Reads data from a file
264 ULONG CurrentCluster;
268 LARGE_INTEGER StartOffset;
269 PDEVICE_EXTENSION DeviceExt;
270 BOOLEAN First = TRUE;
275 ULONG BytesPerSector;
276 ULONG BytesPerCluster;
280 DeviceExt = IrpContext->DeviceExt;
282 assert (DeviceExt->FatInfo.BytesPerCluster);
283 assert (IrpContext->FileObject);
284 assert (IrpContext->FileObject->FsContext2 != NULL);
286 DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, Buffer %x, "
287 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt,
288 IrpContext->FileObject, Buffer, Length, ReadOffset.QuadPart);
292 Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
294 BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
295 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
297 assert(ReadOffset.QuadPart + Length <= ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector));
298 assert(ReadOffset.u.LowPart % BytesPerSector == 0);
299 assert(Length % BytesPerSector == 0);
301 /* Is this a read of the FAT? */
302 if (Fcb->Flags & FCB_IS_FAT)
304 ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
305 Status = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
307 if (NT_SUCCESS(Status))
309 *LengthRead = Length;
313 DPRINT1("FAT reading failed, Status %x\n", Status);
317 /* Is this a read of the Volume ? */
318 if (Fcb->Flags & FCB_IS_VOLUME)
320 Status = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
321 if (NT_SUCCESS(Status))
323 *LengthRead = Length;
327 DPRINT1("Volume reading failed, Status %x\n", Status);
333 * Find the first cluster
335 FirstCluster = CurrentCluster =
336 vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
338 if (FirstCluster == 1)
340 // Directory of FAT12/16 needs a special handling
342 if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector)
344 Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart;
346 ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
348 // Fire up the read command
350 Status = VfatReadDisk (DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
351 if (NT_SUCCESS(Status))
353 *LengthRead += Length;
358 * Find the cluster to start the read from
360 if (Ccb->LastCluster > 0 && ReadOffset.u.LowPart > Ccb->LastOffset)
362 CurrentCluster = Ccb->LastCluster;
364 Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
365 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
366 &CurrentCluster, FALSE);
367 if (!NT_SUCCESS(Status))
372 Ccb->LastCluster = CurrentCluster;
373 Ccb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster);
375 while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
377 StartCluster = CurrentCluster;
378 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
387 BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster));
388 StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster;
393 if (Length - BytesDone > BytesPerCluster)
395 BytesDone += BytesPerCluster;
402 Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
404 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
405 DPRINT("start %08x, next %08x, count %d\n",
406 StartCluster, CurrentCluster, ClusterCount);
408 Ccb->LastCluster = StartCluster + (ClusterCount - 1);
409 Ccb->LastOffset = ReadOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
411 // Fire up the read command
412 Status = VfatReadDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
414 if (NT_SUCCESS(Status))
416 *LengthRead += BytesDone;
419 ReadOffset.u.LowPart += BytesDone;
425 NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
428 LARGE_INTEGER WriteOffset)
430 PDEVICE_EXTENSION DeviceExt;
435 ULONG CurrentCluster;
440 BOOLEAN First = TRUE;
441 ULONG BytesPerSector;
442 ULONG BytesPerCluster;
443 LARGE_INTEGER StartOffset;
447 DeviceExt = IrpContext->DeviceExt;
449 assert (DeviceExt->FatInfo.BytesPerCluster);
450 assert (IrpContext->FileObject);
451 assert (IrpContext->FileObject->FsContext2 != NULL);
453 Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
455 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
456 BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
458 DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, Buffer %x, "
459 "Length %d, WriteOffset 0x%I64x), '%S'\n", DeviceExt,
460 IrpContext->FileObject, Buffer, Length, WriteOffset,
463 assert(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart);
464 assert(WriteOffset.u.LowPart % BytesPerSector == 0);
465 assert(Length % BytesPerSector == 0)
467 // Is this a write of the volume ?
468 if (Fcb->Flags & FCB_IS_VOLUME)
470 Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
471 if (!NT_SUCCESS(Status))
473 DPRINT1("Volume writing failed, Status %x\n", Status);
478 // Is this a write to the FAT ?
479 if (Fcb->Flags & FCB_IS_FAT)
481 WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
482 for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++)
484 Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
485 if (!NT_SUCCESS(Status))
487 DPRINT1("FAT writing failed, Status %x\n", Status);
489 WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart;
495 * Find the first cluster
497 FirstCluster = CurrentCluster =
498 vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
500 if (FirstCluster == 1)
502 assert(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector);
503 // Directory of FAT12/16 needs a special handling
504 WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
505 // Fire up the write command
506 Status = VfatWriteDisk (DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
511 * Find the cluster to start the write from
513 if (Ccb->LastCluster > 0 && WriteOffset.u.LowPart > Ccb->LastOffset)
515 CurrentCluster = Ccb->LastCluster;
518 Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
519 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
520 &CurrentCluster, FALSE);
522 if (!NT_SUCCESS(Status))
527 Ccb->LastCluster = CurrentCluster;
528 Ccb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster);
530 while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
532 StartCluster = CurrentCluster;
533 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
542 BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster));
543 StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster;
548 if (Length - BytesDone > BytesPerCluster)
550 BytesDone += BytesPerCluster;
557 Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
559 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
560 DPRINT("start %08x, next %08x, count %d\n",
561 StartCluster, CurrentCluster, ClusterCount);
563 Ccb->LastCluster = StartCluster + (ClusterCount - 1);
564 Ccb->LastOffset = WriteOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
566 // Fire up the write command
567 Status = VfatWriteDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
568 if (NT_SUCCESS(Status))
572 WriteOffset.u.LowPart += BytesDone;
579 VfatRead(PVFAT_IRP_CONTEXT IrpContext)
585 ULONG ReturnedLength = 0;
586 PERESOURCE Resource = NULL;
587 LARGE_INTEGER ByteOffset;
589 PDEVICE_OBJECT DeviceToVerify;
590 ULONG BytesPerSector;
594 DPRINT("VfatRead(IrpContext %x)\n", IrpContext);
596 assert(IrpContext->DeviceObject);
598 // This request is not allowed on the main device object
599 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
601 DPRINT("VfatRead is called with the main device object.\n");
602 Status = STATUS_INVALID_DEVICE_REQUEST;
606 assert(IrpContext->DeviceExt);
607 assert(IrpContext->FileObject);
608 Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
613 DPRINT("<%S>\n", Fcb->PathName);
615 ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
616 Length = IrpContext->Stack->Parameters.Read.Length;
617 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
619 /* fail if file is a directory and no paged read */
620 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
622 Status = STATUS_INVALID_PARAMETER;
627 DPRINT("'%S', Offset: %d, Length %d\n", Fcb->PathName, ByteOffset.u.LowPart, Length);
629 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
631 Status = STATUS_INVALID_PARAMETER;
634 if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart)
636 IrpContext->Irp->IoStatus.Information = 0;
637 Status = STATUS_END_OF_FILE;
640 if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
642 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
644 DPRINT("%d %d\n", ByteOffset.u.LowPart, Length);
645 // non chached read must be sector aligned
646 Status = STATUS_INVALID_PARAMETER;
652 IrpContext->Irp->IoStatus.Information = 0;
653 Status = STATUS_SUCCESS;
657 if (Fcb->Flags & FCB_IS_VOLUME)
659 Resource = &IrpContext->DeviceExt->DirResource;
661 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
663 Resource = &Fcb->PagingIoResource;
667 Resource = &Fcb->MainResource;
669 if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
672 Status = STATUS_PENDING;
675 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
676 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
680 Status = STATUS_SUCCESS;
681 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
683 Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
684 Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
687 Buffer = VfatGetUserBuffer(IrpContext->Irp);
690 Status = STATUS_INVALID_USER_BUFFER;
695 if (IrpContext->FileObject->PrivateCacheMap == NULL)
698 CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
699 if (CacheSize < PAGE_SIZE)
701 CacheSize = PAGE_SIZE;
703 CcRosInitializeFileCache(IrpContext->FileObject, &Fcb->RFCB.Bcb, CacheSize);
705 if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length,
706 IrpContext->Flags & IRPCONTEXT_CANWAIT, Buffer,
707 &IrpContext->Irp->IoStatus))
709 Status = STATUS_PENDING;
713 if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
715 Status = IrpContext->Irp->IoStatus.Status;
722 if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector))
724 Length = ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart;
727 Buffer = VfatGetUserBuffer(IrpContext->Irp);
730 Status = STATUS_INVALID_USER_BUFFER;
734 Status = VfatReadFileData(IrpContext, Buffer, Length, ByteOffset, &ReturnedLength);
736 if (Status == STATUS_VERIFY_REQUIRED)
738 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
739 DeviceToVerify = IoGetDeviceToVerify(KeGetCurrentThread());
740 IoSetDeviceToVerify(KeGetCurrentThread(), NULL);
741 Status = IoVerifyVolume (DeviceToVerify, FALSE);
743 if (NT_SUCCESS(Status))
745 Status = VfatReadFileData(IrpContext, Buffer, Length,
746 ByteOffset.u.LowPart, &ReturnedLength);
750 if (NT_SUCCESS(Status))
752 IrpContext->Irp->IoStatus.Information = ReturnedLength;
759 ExReleaseResourceLite(Resource);
762 if (Status == STATUS_PENDING)
764 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
765 if (NT_SUCCESS(Status))
767 Status = VfatQueueRequest(IrpContext);
771 IrpContext->Irp->IoStatus.Status = Status;
772 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
773 VfatFreeIrpContext(IrpContext);
778 IrpContext->Irp->IoStatus.Status = Status;
779 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
780 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
781 (NT_SUCCESS(Status) || Status==STATUS_END_OF_FILE))
783 IrpContext->FileObject->CurrentByteOffset.QuadPart =
784 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
787 IoCompleteRequest(IrpContext->Irp,
788 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
789 VfatFreeIrpContext(IrpContext);
791 DPRINT("%x\n", Status);
795 NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
799 PERESOURCE Resource = NULL;
800 LARGE_INTEGER ByteOffset;
801 LARGE_INTEGER OldFileSize;
802 NTSTATUS Status = STATUS_SUCCESS;
804 ULONG OldAllocationSize;
806 ULONG BytesPerSector;
810 DPRINT("VfatWrite(IrpContext %x)\n", IrpContext);
812 assert(IrpContext->DeviceObject);
814 // This request is not allowed on the main device object
815 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
817 DPRINT("VfatWrite is called with the main device object.\n");
818 Status = STATUS_INVALID_DEVICE_REQUEST;
822 assert(IrpContext->DeviceExt);
823 assert(IrpContext->FileObject);
824 Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
829 DPRINT("<%S>\n", Fcb->PathName);
831 /* fail if file is a directory and no paged read */
832 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
834 Status = STATUS_INVALID_PARAMETER;
838 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
839 Length = IrpContext->Stack->Parameters.Write.Length;
840 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
842 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
844 Status = STATUS_INVALID_PARAMETER;
848 if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
849 1 == vfatDirEntryGetFirstCluster (IrpContext->DeviceExt, &Fcb->entry))
851 if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
853 // we can't extend the FAT, the volume or the root on FAT12/FAT16
854 Status = STATUS_END_OF_FILE;
859 if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
861 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
863 // non chached write must be sector aligned
864 Status = STATUS_INVALID_PARAMETER;
871 IrpContext->Irp->IoStatus.Information = 0;
872 Status = STATUS_SUCCESS;
876 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
878 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
880 Status = STATUS_INVALID_PARAMETER;
883 if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
885 Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
889 if (Fcb->Flags & FCB_IS_VOLUME)
891 Resource = &IrpContext->DeviceExt->DirResource;
893 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
895 Resource = &Fcb->PagingIoResource;
899 Resource = &Fcb->MainResource;
902 if (Fcb->Flags & FCB_IS_PAGE_FILE)
904 if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
907 Status = STATUS_PENDING;
913 if (!ExAcquireResourceExclusiveLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
916 Status = STATUS_PENDING;
921 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
923 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
925 Status = STATUS_PENDING;
930 OldFileSize = Fcb->RFCB.FileSize;
931 OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart;
933 if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
934 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
935 ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
937 LARGE_INTEGER AllocationSize;
938 AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
939 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
940 IrpContext->DeviceExt, &AllocationSize);
941 if (!NT_SUCCESS (Status))
948 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
950 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
953 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
954 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
959 Buffer = VfatGetUserBuffer(IrpContext->Irp);
962 Status = STATUS_INVALID_USER_BUFFER;
966 if (IrpContext->FileObject->PrivateCacheMap == NULL)
969 CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
970 if (CacheSize < PAGE_SIZE)
972 CacheSize = PAGE_SIZE;
974 CcRosInitializeFileCache(IrpContext->FileObject, &Fcb->RFCB.Bcb, CacheSize);
976 if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
977 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
979 IrpContext->Irp->IoStatus.Information = Length;
980 Status = STATUS_SUCCESS;
984 Status = STATUS_UNSUCCESSFUL;
993 Buffer = VfatGetUserBuffer(IrpContext->Irp);
996 Status = STATUS_INVALID_USER_BUFFER;
1000 Status = VfatWriteFileData(IrpContext, Buffer, Length, ByteOffset);
1001 if (NT_SUCCESS(Status))
1003 IrpContext->Irp->IoStatus.Information = Length;
1007 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
1008 !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
1010 if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1012 LARGE_INTEGER SystemTime, LocalTime;
1013 // set dates and times
1014 KeQuerySystemTime (&SystemTime);
1015 ExSystemTimeToLocalTime (&SystemTime, &LocalTime);
1016 FsdFileTimeToDosDateTime ((TIME*)&LocalTime, &Fcb->entry.UpdateDate,
1017 &Fcb->entry.UpdateTime);
1018 Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
1019 // update dates/times and length
1020 if (OldAllocationSize != Fcb->RFCB.AllocationSize.u.LowPart)
1022 VfatUpdateEntry (IrpContext->DeviceExt, IrpContext->FileObject);
1023 Fcb->Flags &= ~FCB_UPDATE_DIRENTRY;
1026 Fcb->Flags |= FCB_UPDATE_DIRENTRY;
1033 ExReleaseResourceLite(Resource);
1036 if (Status == STATUS_PENDING)
1038 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
1039 if (NT_SUCCESS(Status))
1041 Status = VfatQueueRequest(IrpContext);
1045 IrpContext->Irp->IoStatus.Status = Status;
1046 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1047 VfatFreeIrpContext(IrpContext);
1052 IrpContext->Irp->IoStatus.Status = Status;
1053 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
1054 !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
1056 IrpContext->FileObject->CurrentByteOffset.QuadPart =
1057 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
1060 IoCompleteRequest(IrpContext->Irp,
1061 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
1062 VfatFreeIrpContext(IrpContext);
1064 DPRINT("%x\n", Status);