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;
676 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
677 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
679 if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp))
681 Status = STATUS_FILE_LOCK_CONFLICT;
686 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
687 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
691 Status = STATUS_SUCCESS;
692 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
694 Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
695 Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
698 Buffer = VfatGetUserBuffer(IrpContext->Irp);
701 Status = STATUS_INVALID_USER_BUFFER;
706 if (IrpContext->FileObject->PrivateCacheMap == NULL)
709 CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
710 if (CacheSize < PAGE_SIZE)
712 CacheSize = PAGE_SIZE;
714 CcRosInitializeFileCache(IrpContext->FileObject, &Fcb->RFCB.Bcb, CacheSize);
716 if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length,
717 IrpContext->Flags & IRPCONTEXT_CANWAIT, Buffer,
718 &IrpContext->Irp->IoStatus))
720 Status = STATUS_PENDING;
724 if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
726 Status = IrpContext->Irp->IoStatus.Status;
733 if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector))
735 Length = ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart;
738 Buffer = VfatGetUserBuffer(IrpContext->Irp);
741 Status = STATUS_INVALID_USER_BUFFER;
745 Status = VfatReadFileData(IrpContext, Buffer, Length, ByteOffset, &ReturnedLength);
747 if (Status == STATUS_VERIFY_REQUIRED)
749 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
750 DeviceToVerify = IoGetDeviceToVerify(KeGetCurrentThread());
751 IoSetDeviceToVerify(KeGetCurrentThread(), NULL);
752 Status = IoVerifyVolume (DeviceToVerify, FALSE);
754 if (NT_SUCCESS(Status))
756 Status = VfatReadFileData(IrpContext, Buffer, Length,
757 ByteOffset.u.LowPart, &ReturnedLength);
761 if (NT_SUCCESS(Status))
763 IrpContext->Irp->IoStatus.Information = ReturnedLength;
770 ExReleaseResourceLite(Resource);
773 if (Status == STATUS_PENDING)
775 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
776 if (NT_SUCCESS(Status))
778 Status = VfatQueueRequest(IrpContext);
782 IrpContext->Irp->IoStatus.Status = Status;
783 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
784 VfatFreeIrpContext(IrpContext);
789 IrpContext->Irp->IoStatus.Status = Status;
790 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
791 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
792 (NT_SUCCESS(Status) || Status==STATUS_END_OF_FILE))
794 IrpContext->FileObject->CurrentByteOffset.QuadPart =
795 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
798 IoCompleteRequest(IrpContext->Irp,
799 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
800 VfatFreeIrpContext(IrpContext);
802 DPRINT("%x\n", Status);
806 NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
810 PERESOURCE Resource = NULL;
811 LARGE_INTEGER ByteOffset;
812 LARGE_INTEGER OldFileSize;
813 NTSTATUS Status = STATUS_SUCCESS;
815 ULONG OldAllocationSize;
817 ULONG BytesPerSector;
821 DPRINT("VfatWrite(IrpContext %x)\n", IrpContext);
823 assert(IrpContext->DeviceObject);
825 // This request is not allowed on the main device object
826 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
828 DPRINT("VfatWrite is called with the main device object.\n");
829 Status = STATUS_INVALID_DEVICE_REQUEST;
833 assert(IrpContext->DeviceExt);
834 assert(IrpContext->FileObject);
835 Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
840 DPRINT("<%S>\n", Fcb->PathName);
842 /* fail if file is a directory and no paged read */
843 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
845 Status = STATUS_INVALID_PARAMETER;
849 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
850 Length = IrpContext->Stack->Parameters.Write.Length;
851 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
853 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
855 Status = STATUS_INVALID_PARAMETER;
859 if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
860 1 == vfatDirEntryGetFirstCluster (IrpContext->DeviceExt, &Fcb->entry))
862 if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
864 // we can't extend the FAT, the volume or the root on FAT12/FAT16
865 Status = STATUS_END_OF_FILE;
870 if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
872 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
874 // non chached write must be sector aligned
875 Status = STATUS_INVALID_PARAMETER;
882 IrpContext->Irp->IoStatus.Information = 0;
883 Status = STATUS_SUCCESS;
887 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
889 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
891 Status = STATUS_INVALID_PARAMETER;
894 if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
896 Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
900 if (Fcb->Flags & FCB_IS_VOLUME)
902 Resource = &IrpContext->DeviceExt->DirResource;
904 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
906 Resource = &Fcb->PagingIoResource;
910 Resource = &Fcb->MainResource;
913 if (Fcb->Flags & FCB_IS_PAGE_FILE)
915 if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
918 Status = STATUS_PENDING;
924 if (!ExAcquireResourceExclusiveLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
927 Status = STATUS_PENDING;
932 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
933 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
935 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
937 Status = STATUS_FILE_LOCK_CONFLICT;
942 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
944 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
946 Status = STATUS_PENDING;
951 OldFileSize = Fcb->RFCB.FileSize;
952 OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart;
954 if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
955 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
956 ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
958 LARGE_INTEGER AllocationSize;
959 AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
960 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
961 IrpContext->DeviceExt, &AllocationSize);
962 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 Buffer = VfatGetUserBuffer(IrpContext->Irp);
979 Status = STATUS_INVALID_USER_BUFFER;
983 if (IrpContext->FileObject->PrivateCacheMap == NULL)
986 CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
987 if (CacheSize < PAGE_SIZE)
989 CacheSize = PAGE_SIZE;
991 CcRosInitializeFileCache(IrpContext->FileObject, &Fcb->RFCB.Bcb, CacheSize);
993 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
995 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
997 if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
998 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
1000 IrpContext->Irp->IoStatus.Information = Length;
1001 Status = STATUS_SUCCESS;
1005 Status = STATUS_UNSUCCESSFUL;
1014 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
1016 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
1018 Buffer = VfatGetUserBuffer(IrpContext->Irp);
1021 Status = STATUS_INVALID_USER_BUFFER;
1025 Status = VfatWriteFileData(IrpContext, Buffer, Length, ByteOffset);
1026 if (NT_SUCCESS(Status))
1028 IrpContext->Irp->IoStatus.Information = Length;
1032 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
1033 !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
1035 if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1037 LARGE_INTEGER SystemTime, LocalTime;
1038 // set dates and times
1039 KeQuerySystemTime (&SystemTime);
1040 ExSystemTimeToLocalTime (&SystemTime, &LocalTime);
1041 FsdFileTimeToDosDateTime ((TIME*)&LocalTime, &Fcb->entry.UpdateDate,
1042 &Fcb->entry.UpdateTime);
1043 Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
1044 // update dates/times and length
1045 VfatUpdateEntry (IrpContext->DeviceExt, IrpContext->FileObject);
1052 ExReleaseResourceLite(Resource);
1055 if (Status == STATUS_PENDING)
1057 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
1058 if (NT_SUCCESS(Status))
1060 Status = VfatQueueRequest(IrpContext);
1064 IrpContext->Irp->IoStatus.Status = Status;
1065 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1066 VfatFreeIrpContext(IrpContext);
1071 IrpContext->Irp->IoStatus.Status = Status;
1072 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
1073 !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
1075 IrpContext->FileObject->CurrentByteOffset.QuadPart =
1076 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
1079 IoCompleteRequest(IrpContext->Irp,
1080 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
1081 VfatFreeIrpContext(IrpContext);
1083 DPRINT("%x\n", Status);