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>
25 /* FUNCTIONS *****************************************************************/
28 NextCluster(PDEVICE_EXTENSION DeviceExt,
30 PULONG CurrentCluster,
33 * Return the next cluster in a FAT chain, possibly extending the chain if
37 if (FirstCluster == 1)
39 (*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster;
40 return(STATUS_SUCCESS);
45 * CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't
48 if (FirstCluster == 0)
52 Status = GetNextCluster(DeviceExt, 0, CurrentCluster,
60 Status = GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster,
68 OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
74 * Return the cluster corresponding to an offset within a file,
75 * possibly extending the file if necessary
82 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
83 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
84 Fcb, FirstCluster, FileOffset, Cluster, Extend);
86 if (FirstCluster == 0)
88 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
92 if (FirstCluster == 1)
94 /* root of FAT16 or FAT12 */
95 *Cluster = DeviceExt->FatInfo.rootStart + FileOffset
96 / (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster;
97 return(STATUS_SUCCESS);
101 CurrentCluster = FirstCluster;
102 for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
104 Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster,
106 if (!NT_SUCCESS(Status))
111 *Cluster = CurrentCluster;
112 return(STATUS_SUCCESS);
117 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
118 ULONG Length, LARGE_INTEGER ReadOffset, PULONG LengthRead)
120 * FUNCTION: Reads data from a file
123 ULONG CurrentCluster;
127 LARGE_INTEGER StartOffset;
128 PDEVICE_EXTENSION DeviceExt;
129 BOOLEAN First = TRUE;
134 ULONG BytesPerSector;
135 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, Buffer %x, "
146 "Length %d, ReadOffset 0x%I64x)\n", DeviceExt,
147 IrpContext->FileObject, Buffer, 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 = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
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 = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
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 = VfatReadDisk (DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
210 if (NT_SUCCESS(Status))
212 *LengthRead += Length;
217 * Find the cluster to start the read from
219 if (Ccb->LastCluster > 0 && ReadOffset.u.LowPart > Ccb->LastOffset)
221 CurrentCluster = Ccb->LastCluster;
223 Status = OffsetToCluster(DeviceExt, FirstCluster,
224 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
225 &CurrentCluster, FALSE);
226 if (!NT_SUCCESS(Status))
231 Ccb->LastCluster = CurrentCluster;
232 Ccb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster);
234 while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
236 StartCluster = CurrentCluster;
237 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
246 BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster));
247 StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster;
252 if (Length - BytesDone > BytesPerCluster)
254 BytesDone += BytesPerCluster;
261 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
263 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
264 DPRINT("start %08x, next %08x, count %d\n",
265 StartCluster, CurrentCluster, ClusterCount);
267 Ccb->LastCluster = StartCluster + (ClusterCount - 1);
268 Ccb->LastOffset = ReadOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
270 // Fire up the read command
271 Status = VfatReadDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
273 if (NT_SUCCESS(Status))
275 *LengthRead += BytesDone;
276 /* GCC allows arithmetics on the void type. Conforming compilers do not. */
281 char* pBuf = (char*)Buffer + BytesDone;
282 Buffer = (PVOID)pBuf;
286 ReadOffset.u.LowPart += BytesDone;
292 NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
295 LARGE_INTEGER WriteOffset)
297 PDEVICE_EXTENSION DeviceExt;
302 ULONG CurrentCluster;
307 BOOLEAN First = TRUE;
308 ULONG BytesPerSector;
309 ULONG BytesPerCluster;
310 LARGE_INTEGER StartOffset;
314 DeviceExt = IrpContext->DeviceExt;
316 assert (DeviceExt->FatInfo.BytesPerCluster);
317 assert (IrpContext->FileObject);
318 assert (IrpContext->FileObject->FsContext2 != NULL);
320 Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
321 Fcb = IrpContext->FileObject->FsContext;
322 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
323 BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
325 DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, Buffer %x, "
326 "Length %d, WriteOffset 0x%I64x), '%S'\n", DeviceExt,
327 IrpContext->FileObject, Buffer, Length, WriteOffset,
330 assert(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart);
331 assert(WriteOffset.u.LowPart % BytesPerSector == 0);
332 assert(Length % BytesPerSector == 0)
334 // Is this a write of the volume ?
335 if (Fcb->Flags & FCB_IS_VOLUME)
337 Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
338 if (!NT_SUCCESS(Status))
340 DPRINT1("Volume writing failed, Status %x\n", Status);
345 // Is this a write to the FAT ?
346 if (Fcb->Flags & FCB_IS_FAT)
348 WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
349 for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++)
351 Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
352 if (!NT_SUCCESS(Status))
354 DPRINT1("FAT writing failed, Status %x\n", Status);
356 WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart;
362 * Find the first cluster
364 FirstCluster = CurrentCluster =
365 vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
367 if (FirstCluster == 1)
369 assert(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector);
370 // Directory of FAT12/16 needs a special handling
371 WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
372 // Fire up the write command
373 Status = VfatWriteDisk (DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
378 * Find the cluster to start the write from
380 if (Ccb->LastCluster > 0 && WriteOffset.u.LowPart > Ccb->LastOffset)
382 CurrentCluster = Ccb->LastCluster;
385 Status = OffsetToCluster(DeviceExt, FirstCluster,
386 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
387 &CurrentCluster, FALSE);
389 if (!NT_SUCCESS(Status))
394 Ccb->LastCluster = CurrentCluster;
395 Ccb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster);
397 while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
399 StartCluster = CurrentCluster;
400 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
409 BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster));
410 StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster;
415 if (Length - BytesDone > BytesPerCluster)
417 BytesDone += BytesPerCluster;
424 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
426 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
427 DPRINT("start %08x, next %08x, count %d\n",
428 StartCluster, CurrentCluster, ClusterCount);
430 Ccb->LastCluster = StartCluster + (ClusterCount - 1);
431 Ccb->LastOffset = WriteOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
433 // Fire up the write command
434 Status = VfatWriteDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
435 if (NT_SUCCESS(Status))
437 /* GCC allows arithmetics on the void type. Conforming compilers do not. */
442 char* pBuf = (char*)Buffer + BytesDone;
443 Buffer = (PVOID)pBuf;
447 WriteOffset.u.LowPart += BytesDone;
454 VfatRead(PVFAT_IRP_CONTEXT IrpContext)
459 ULONG ReturnedLength = 0;
460 PERESOURCE Resource = NULL;
461 LARGE_INTEGER ByteOffset;
463 /*PDEVICE_OBJECT DeviceToVerify;*/
464 ULONG BytesPerSector;
468 DPRINT("VfatRead(IrpContext %x)\n", IrpContext);
470 assert(IrpContext->DeviceObject);
472 // This request is not allowed on the main device object
473 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
475 DPRINT("VfatRead is called with the main device object.\n");
476 Status = STATUS_INVALID_DEVICE_REQUEST;
480 assert(IrpContext->DeviceExt);
481 assert(IrpContext->FileObject);
482 Fcb = IrpContext->FileObject->FsContext;
485 DPRINT("<%S>\n", Fcb->PathName);
487 if (Fcb->Flags & FCB_IS_PAGE_FILE)
489 PIO_STACK_LOCATION Stack;
490 PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
491 IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
492 Stack = IoGetNextIrpStackLocation(IrpContext->Irp);
493 Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
494 DPRINT("Read from page file, disk offset %I64x\n", Stack->Parameters.Read.ByteOffset.QuadPart);
495 Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
496 VfatFreeIrpContext(IrpContext);
500 ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
501 Length = IrpContext->Stack->Parameters.Read.Length;
502 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
504 /* fail if file is a directory and no paged read */
505 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
507 Status = STATUS_INVALID_PARAMETER;
512 DPRINT("'%S', Offset: %d, Length %d\n", Fcb->PathName, ByteOffset.u.LowPart, Length);
514 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
516 Status = STATUS_INVALID_PARAMETER;
519 if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart)
521 IrpContext->Irp->IoStatus.Information = 0;
522 Status = STATUS_END_OF_FILE;
525 if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
527 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
529 DPRINT("%d %d\n", ByteOffset.u.LowPart, Length);
530 // non chached read must be sector aligned
531 Status = STATUS_INVALID_PARAMETER;
537 IrpContext->Irp->IoStatus.Information = 0;
538 Status = STATUS_SUCCESS;
542 if (Fcb->Flags & FCB_IS_VOLUME)
544 Resource = &IrpContext->DeviceExt->DirResource;
546 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
548 Resource = &Fcb->PagingIoResource;
552 Resource = &Fcb->MainResource;
554 if (!ExAcquireResourceSharedLite(Resource,
555 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
558 Status = STATUS_PENDING;
562 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
563 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
565 if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp))
567 Status = STATUS_FILE_LOCK_CONFLICT;
572 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
573 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
577 Status = STATUS_SUCCESS;
578 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
580 Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
581 Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
584 Buffer = VfatGetUserBuffer(IrpContext->Irp);
587 Status = STATUS_INVALID_USER_BUFFER;
592 if (IrpContext->FileObject->PrivateCacheMap == NULL)
595 CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
596 if (CacheSize < PAGE_SIZE)
598 CacheSize = PAGE_SIZE;
600 CcRosInitializeFileCache(IrpContext->FileObject, CacheSize);
602 if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length,
603 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT), Buffer,
604 &IrpContext->Irp->IoStatus))
606 Status = STATUS_PENDING;
610 if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
612 Status = IrpContext->Irp->IoStatus.Status;
619 if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector))
621 Length = (ULONG)(ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart);
624 Buffer = VfatGetUserBuffer(IrpContext->Irp);
627 Status = STATUS_INVALID_USER_BUFFER;
631 Status = VfatReadFileData(IrpContext, Buffer, Length, ByteOffset, &ReturnedLength);
633 if (Status == STATUS_VERIFY_REQUIRED)
635 DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
636 DeviceToVerify = IoGetDeviceToVerify(KeGetCurrentThread());
637 IoSetDeviceToVerify(KeGetCurrentThread(), NULL);
638 Status = IoVerifyVolume (DeviceToVerify, FALSE);
640 if (NT_SUCCESS(Status))
642 Status = VfatReadFileData(IrpContext, Buffer, Length,
643 ByteOffset.u.LowPart, &ReturnedLength);
647 if (NT_SUCCESS(Status))
649 IrpContext->Irp->IoStatus.Information = ReturnedLength;
656 ExReleaseResourceLite(Resource);
659 if (Status == STATUS_PENDING)
661 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
662 if (NT_SUCCESS(Status))
664 Status = VfatQueueRequest(IrpContext);
668 IrpContext->Irp->IoStatus.Status = Status;
669 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
670 VfatFreeIrpContext(IrpContext);
675 IrpContext->Irp->IoStatus.Status = Status;
676 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
677 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
678 (NT_SUCCESS(Status) || Status==STATUS_END_OF_FILE))
680 IrpContext->FileObject->CurrentByteOffset.QuadPart =
681 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
684 IoCompleteRequest(IrpContext->Irp,
685 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
686 VfatFreeIrpContext(IrpContext);
688 DPRINT("%x\n", Status);
692 NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
695 PERESOURCE Resource = NULL;
696 LARGE_INTEGER ByteOffset;
697 LARGE_INTEGER OldFileSize;
698 NTSTATUS Status = STATUS_SUCCESS;
700 ULONG OldAllocationSize;
702 ULONG BytesPerSector;
706 DPRINT("VfatWrite(IrpContext %x)\n", IrpContext);
708 assert(IrpContext->DeviceObject);
710 // This request is not allowed on the main device object
711 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
713 DPRINT("VfatWrite is called with the main device object.\n");
714 Status = STATUS_INVALID_DEVICE_REQUEST;
718 assert(IrpContext->DeviceExt);
719 assert(IrpContext->FileObject);
720 Fcb = IrpContext->FileObject->FsContext;
723 DPRINT("<%S>\n", Fcb->PathName);
725 if (Fcb->Flags & FCB_IS_PAGE_FILE)
727 PIO_STACK_LOCATION Stack;
728 PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
729 IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
730 Stack = IoGetNextIrpStackLocation(IrpContext->Irp);
731 Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
732 DPRINT("Write to page file, disk offset %I64x\n", Stack->Parameters.Write.ByteOffset.QuadPart);
733 Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
734 VfatFreeIrpContext(IrpContext);
738 /* fail if file is a directory and no paged read */
739 if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
741 Status = STATUS_INVALID_PARAMETER;
745 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
746 Length = IrpContext->Stack->Parameters.Write.Length;
747 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
749 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
751 Status = STATUS_INVALID_PARAMETER;
755 if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
756 1 == vfatDirEntryGetFirstCluster (IrpContext->DeviceExt, &Fcb->entry))
758 if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
760 // we can't extend the FAT, the volume or the root on FAT12/FAT16
761 Status = STATUS_END_OF_FILE;
766 if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
768 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
770 // non chached write must be sector aligned
771 Status = STATUS_INVALID_PARAMETER;
778 IrpContext->Irp->IoStatus.Information = 0;
779 Status = STATUS_SUCCESS;
783 if (IrpContext->Irp->Flags & IRP_PAGING_IO)
785 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
787 Status = STATUS_INVALID_PARAMETER;
790 if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
792 Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
796 if (Fcb->Flags & FCB_IS_VOLUME)
798 Resource = &IrpContext->DeviceExt->DirResource;
800 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
802 Resource = &Fcb->PagingIoResource;
806 Resource = &Fcb->MainResource;
809 if (Fcb->Flags & FCB_IS_PAGE_FILE)
811 if (!ExAcquireResourceSharedLite(Resource,
812 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
815 Status = STATUS_PENDING;
821 if (!ExAcquireResourceExclusiveLite(Resource,
822 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
825 Status = STATUS_PENDING;
830 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
831 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
833 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
835 Status = STATUS_FILE_LOCK_CONFLICT;
840 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
842 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
844 Status = STATUS_PENDING;
849 OldFileSize = Fcb->RFCB.FileSize;
850 OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart;
852 if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
853 !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
854 ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
856 LARGE_INTEGER AllocationSize;
857 AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
858 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
859 IrpContext->DeviceExt, &AllocationSize);
860 if (!NT_SUCCESS (Status))
868 if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
869 !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
874 Buffer = VfatGetUserBuffer(IrpContext->Irp);
877 Status = STATUS_INVALID_USER_BUFFER;
881 if (IrpContext->FileObject->PrivateCacheMap == NULL)
884 CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
885 if (CacheSize < PAGE_SIZE)
887 CacheSize = PAGE_SIZE;
889 CcRosInitializeFileCache(IrpContext->FileObject, CacheSize);
891 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
893 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
895 if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
896 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
898 IrpContext->Irp->IoStatus.Information = Length;
899 Status = STATUS_SUCCESS;
903 Status = STATUS_UNSUCCESSFUL;
912 if (ByteOffset.QuadPart > OldFileSize.QuadPart)
914 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
916 Buffer = VfatGetUserBuffer(IrpContext->Irp);
919 Status = STATUS_INVALID_USER_BUFFER;
923 Status = VfatWriteFileData(IrpContext, Buffer, Length, ByteOffset);
924 if (NT_SUCCESS(Status))
926 IrpContext->Irp->IoStatus.Information = Length;
930 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
931 !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
933 if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
935 LARGE_INTEGER SystemTime, LocalTime;
936 // set dates and times
937 KeQuerySystemTime (&SystemTime);
938 ExSystemTimeToLocalTime (&SystemTime, &LocalTime);
939 FsdFileTimeToDosDateTime ((TIME*)&LocalTime, &Fcb->entry.UpdateDate,
940 &Fcb->entry.UpdateTime);
941 Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
942 // update dates/times and length
943 VfatUpdateEntry (IrpContext->DeviceExt, IrpContext->FileObject);
950 ExReleaseResourceLite(Resource);
953 if (Status == STATUS_PENDING)
955 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
956 if (NT_SUCCESS(Status))
958 Status = VfatQueueRequest(IrpContext);
962 IrpContext->Irp->IoStatus.Status = Status;
963 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
964 VfatFreeIrpContext(IrpContext);
969 IrpContext->Irp->IoStatus.Status = Status;
970 if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
971 !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
973 IrpContext->FileObject->CurrentByteOffset.QuadPart =
974 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
977 IoCompleteRequest(IrpContext->Irp,
978 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
979 VfatFreeIrpContext(IrpContext);
981 DPRINT("%x\n", Status);