-/* $Id: rw.c,v 1.25 2001/07/20 08:00:20 ekohl Exp $
+/* $Id: rw.c,v 1.36 2002/01/15 21:54:51 hbirr Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
NTSTATUS
NextCluster(PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB Fcb,
ULONG FirstCluster,
PULONG CurrentCluster,
BOOLEAN Extend)
* necessary
*/
{
+ if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
+ {
+ ULONG i;
+ PULONG FatChain;
+ NTSTATUS Status;
+ DPRINT("NextCluster(Fcb %x, FirstCluster %x, Extend %d)\n", Fcb, FirstCluster, Extend);
+ if (Fcb->FatChainSize == 0)
+ {
+ // paging file with zero length
+ *CurrentCluster = 0xffffffff;
+ if (Extend)
+ {
+ Fcb->FatChain = ExAllocatePool(NonPagedPool, sizeof(ULONG));
+ if (!Fcb->FatChain)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ Status = GetNextCluster(DeviceExt, 0, CurrentCluster, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(Fcb->FatChain);
+ return Status;
+ }
+ Fcb->FatChain[0] = *CurrentCluster;
+ Fcb->FatChainSize = 1;
+ return Status;
+ }
+ else
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ else
+ {
+ for (i = 0; i < Fcb->FatChainSize; i++)
+ {
+ if (Fcb->FatChain[i] == *CurrentCluster)
+ break;
+ }
+ if (i >= Fcb->FatChainSize)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ if (i == Fcb->FatChainSize - 1)
+ {
+ if (Extend)
+ {
+ FatChain = ExAllocatePool(NonPagedPool, (i + 2) * sizeof(ULONG));
+ if (!FatChain)
+ {
+ *CurrentCluster = 0xffffffff;
+ return STATUS_UNSUCCESSFUL;
+ }
+ Status = GetNextCluster(DeviceExt, *CurrentCluster, CurrentCluster, TRUE);
+ if (NT_SUCCESS(Status) && *CurrentCluster != 0xffffffff)
+ {
+ memcpy(FatChain, Fcb->FatChain, (i + 1) * sizeof(ULONG));
+ FatChain[i + 1] = *CurrentCluster;
+ ExFreePool(Fcb->FatChain);
+ Fcb->FatChain = FatChain;
+ Fcb->FatChainSize = i + 2;
+ }
+ else
+ ExFreePool(FatChain);
+ return Status;
+ }
+ else
+ {
+ *CurrentCluster = 0xffffffff;
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ *CurrentCluster = Fcb->FatChain[i + 1];
+ return STATUS_SUCCESS;
+ }
+ }
if (FirstCluster == 1)
{
(*CurrentCluster) += DeviceExt->Boot->SectorsPerCluster;
return(STATUS_SUCCESS);
}
else
- /* CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't initialized when 0*/
- if (FirstCluster == 0)
{
- NTSTATUS Status;
-
- Status = GetNextCluster(DeviceExt, 0, CurrentCluster,
- Extend);
- return(Status);
- }
- else
- {
- NTSTATUS Status;
-
- Status = GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster,
- Extend);
- return(Status);
+ /*
+ * CN: FIXME: Real bug here or in dirwr, where CurrentCluster isn't
+ * initialized when 0
+ */
+ if (FirstCluster == 0)
+ {
+ NTSTATUS Status;
+
+ Status = GetNextCluster(DeviceExt, 0, CurrentCluster,
+ Extend);
+ return(Status);
+ }
+ else
+ {
+ NTSTATUS Status;
+
+ Status = GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster,
+ Extend);
+ return(Status);
+ }
}
}
NTSTATUS
-OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
- ULONG FirstCluster,
+OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB Fcb,
+ ULONG FirstCluster,
ULONG FileOffset,
PULONG Cluster,
BOOLEAN Extend)
ULONG CurrentCluster;
ULONG i;
NTSTATUS Status;
+ DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x,"
+ " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt,
+ Fcb, FirstCluster, FileOffset, Cluster, Extend);
+ if (FirstCluster == 0)
+ {
+ DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n");
+ KeBugCheck(0);
+ }
+ if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
+ {
+ ULONG NCluster;
+ ULONG Offset = FileOffset / DeviceExt->BytesPerCluster;
+ PULONG FatChain;
+ int i;
+ if (Fcb->FatChainSize == 0)
+ {
+ DbgPrint("OffsetToCluster is called with FirstCluster = %x"
+ " and Fcb->FatChainSize = 0!\n", FirstCluster);
+ KeBugCheck(0);
+ }
+ if (Offset < Fcb->FatChainSize)
+ {
+ *Cluster = Fcb->FatChain[Offset];
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ if (!Extend)
+ {
+ *Cluster = 0xffffffff;
+ return STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ FatChain = ExAllocatePool(NonPagedPool, (Offset + 1) * sizeof(ULONG));
+ if (!FatChain)
+ {
+ *Cluster = 0xffffffff;
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ CurrentCluster = Fcb->FatChain[Fcb->FatChainSize - 1];
+ FatChain[Fcb->FatChainSize - 1] = CurrentCluster;
+ for (i = Fcb->FatChainSize; i < Offset + 1; i++)
+ {
+ Status = GetNextCluster(DeviceExt, CurrentCluster, &CurrentCluster, TRUE);
+ if (!NT_SUCCESS(Status) || CurrentCluster == 0xFFFFFFFF)
+ {
+ while (i >= Fcb->FatChainSize)
+ {
+ WriteCluster(DeviceExt, FatChain[i - 1], 0xFFFFFFFF);
+ i--;
+ }
+ *Cluster = 0xffffffff;
+ ExFreePool(FatChain);
+ if (!NT_SUCCESS(Status))
+ return Status;
+ return STATUS_UNSUCCESSFUL;
+ }
+ FatChain[i] = CurrentCluster;
+ }
+ memcpy (FatChain, Fcb->FatChain, Fcb->FatChainSize * sizeof(ULONG));
+ ExFreePool(Fcb->FatChain);
+ Fcb->FatChain = FatChain;
+ Fcb->FatChainSize = Offset + 1;
+ }
+ }
+ *Cluster = CurrentCluster;
+ return(STATUS_SUCCESS);
+ }
if (FirstCluster == 1)
- {
+ {
/* root of FAT16 or FAT12 */
*Cluster = DeviceExt->rootStart + FileOffset
/ (DeviceExt->BytesPerCluster) * DeviceExt->Boot->SectorsPerCluster;
}
NTSTATUS
-VfatReadBigCluster(PDEVICE_EXTENSION DeviceExt,
+VfatReadCluster(PDEVICE_EXTENSION DeviceExt,
PVFATFCB Fcb,
- ULONG StartOffset,
ULONG FirstCluster,
PULONG CurrentCluster,
PVOID Destination,
- ULONG NoCache,
ULONG InternalOffset,
ULONG InternalLength)
{
- BOOLEAN Valid;
PVOID BaseAddress = NULL;
- PCACHE_SEGMENT CacheSeg = NULL;
- NTSTATUS Status;
-
- /*
- * In this case the size of a cache segment is the same as a cluster
- */
-
- if (!NoCache)
- {
- Status = CcRosRequestCacheSegment(Fcb->RFCB.Bcb,
- StartOffset,
- &BaseAddress,
- &Valid,
- &CacheSeg);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- }
- else
- {
- Valid = FALSE;
- if (InternalOffset == 0)
- {
- BaseAddress = Destination;
- }
- else
- {
- BaseAddress = ExAllocatePool(NonPagedPool,
- DeviceExt->BytesPerCluster);
- if (BaseAddress == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
- }
- }
-
- if (!Valid)
- {
- /*
- * If necessary read the cluster from the disk
- */
- Status = VfatRawReadCluster(DeviceExt, FirstCluster, BaseAddress,
- *CurrentCluster);
- if (!NT_SUCCESS(Status))
- {
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, FALSE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(Status);
- }
- }
- /*
- * Copy the data from the cache to the caller
- */
- if (InternalOffset != 0 || !NoCache)
- {
- memcpy(Destination, BaseAddress + InternalOffset, InternalLength);
- }
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, TRUE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
-
- Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- return(STATUS_SUCCESS);
-}
-
-NTSTATUS
-VfatReadSmallCluster(PDEVICE_EXTENSION DeviceExt,
- PVFATFCB Fcb,
- ULONG StartOffset,
- ULONG FirstCluster,
- PULONG CurrentCluster,
- PVOID Destination,
- ULONG NoCache,
- ULONG InternalOffset,
- ULONG InternalLength)
-{
- BOOLEAN Valid;
- PVOID BaseAddress = NULL;
- PCACHE_SEGMENT CacheSeg = NULL;
- NTSTATUS Status;
- ULONG i;
-
- /*
- * Otherwise we read a page of clusters together
- */
- if (!NoCache)
- {
- Status = CcRosRequestCacheSegment(Fcb->RFCB.Bcb,
- StartOffset,
- &BaseAddress,
- &Valid,
- &CacheSeg);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- }
- else
- {
- Valid = FALSE;
- if (InternalOffset == 0)
- {
- BaseAddress = Destination;
- }
- else
- {
- BaseAddress = ExAllocatePool(NonPagedPool, PAGESIZE);
- if (BaseAddress == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
- }
- }
-
- /*
- * If necessary read all the data for the page, unfortunately the
- * file length may not be page aligned in which case the page will
- * only be partially filled.
- * FIXME: So zero fill the rest?
- */
- if (!Valid)
- {
- for (i = 0; i < (PAGESIZE / DeviceExt->BytesPerCluster); i++)
- {
- Status = VfatRawReadCluster(DeviceExt,
- FirstCluster,
- BaseAddress +
- (i * DeviceExt->BytesPerCluster),
- *CurrentCluster);
- if (!NT_SUCCESS(Status))
- {
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, FALSE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(Status);
- }
- Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
- if ((*CurrentCluster) == 0xFFFFFFFF)
- {
- break;
- }
- }
- }
- else
- {
- /*
- * Otherwise just move onto the next cluster
- */
- for (i = 0; i < (PAGESIZE / DeviceExt->BytesPerCluster); i++)
- {
- NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
- if ((*CurrentCluster) == 0xFFFFFFFF)
- {
- break;
- }
- }
- }
- /*
- * Copy the data from the cache to the caller
- */
- if (InternalOffset != 0 || !NoCache)
- {
- memcpy(Destination, BaseAddress + InternalOffset, InternalLength);
- }
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, TRUE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(STATUS_SUCCESS);
-}
+ NTSTATUS Status;
-NTSTATUS
-VfatReadCluster(PDEVICE_EXTENSION DeviceExt,
- PVFATFCB Fcb,
- ULONG StartOffset,
- ULONG FirstCluster,
- PULONG CurrentCluster,
- PVOID Destination,
- ULONG NoCache,
- ULONG InternalOffset,
- ULONG InternalLength)
-{
- if (DeviceExt->BytesPerCluster >= PAGESIZE)
- {
- return(VfatReadBigCluster(DeviceExt,
- Fcb,
- StartOffset,
- FirstCluster,
- CurrentCluster,
- Destination,
- NoCache,
- InternalOffset,
- InternalLength));
- }
+ if (InternalLength == DeviceExt->BytesPerCluster)
+ {
+ Status = VfatRawReadCluster(DeviceExt, FirstCluster,
+ Destination, *CurrentCluster, 1);
+ }
else
+ {
+ BaseAddress = ExAllocatePool(NonPagedPool, DeviceExt->BytesPerCluster);
+ if (BaseAddress == NULL)
{
- return(VfatReadSmallCluster(DeviceExt,
- Fcb,
- StartOffset,
- FirstCluster,
- CurrentCluster,
- Destination,
- NoCache,
- InternalOffset,
- InternalLength));
+ return(STATUS_NO_MEMORY);
}
- return(STATUS_SUCCESS);
+ Status = VfatRawReadCluster(DeviceExt, FirstCluster,
+ BaseAddress, *CurrentCluster, 1);
+ memcpy(Destination, BaseAddress + InternalOffset, InternalLength);
+ ExFreePool(BaseAddress);
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, CurrentCluster, FALSE);
+ return(Status);
}
NTSTATUS
VfatReadFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
- PVOID Buffer, ULONG Length, ULONG ReadOffset,
+ PVOID Buffer, ULONG Length, ULONG ReadOffset,
PULONG LengthRead, ULONG NoCache)
/*
* FUNCTION: Reads data from a file
{
ULONG CurrentCluster;
ULONG FirstCluster;
+ ULONG StartCluster;
+ ULONG ClusterCount;
PVFATFCB Fcb;
- ULONG ChunkSize;
+ PVFATCCB Ccb;
NTSTATUS Status;
ULONG TempLength;
+ LARGE_INTEGER FileOffset;
+ IO_STATUS_BLOCK IoStatus;
/* PRECONDITION */
assert (DeviceExt != NULL);
assert (DeviceExt->BytesPerCluster != 0);
assert (FileObject != NULL);
- assert (FileObject->FsContext != NULL);
+ assert (FileObject->FsContext2 != NULL);
DPRINT("VfatReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
- "Length %d, ReadOffset 0x%x)\n", DeviceExt, FileObject, Buffer,
- Length, ReadOffset);
+ "Length %d, ReadOffset 0x%x)\n", DeviceExt, FileObject, Buffer,
+ Length, ReadOffset);
*LengthRead = 0;
- Fcb = ((PVFATCCB)FileObject->FsContext2)->pFcb;
+ Ccb = (PVFATCCB)FileObject->FsContext2;
+ Fcb = Ccb->pFcb;
+
+ // Is this a read of the FAT ?
+ if (Fcb->Flags & FCB_IS_FAT)
+ {
+ if (!NoCache)
+ {
+ DbgPrint ("Cached FAT read outside from VFATFS.SYS\n");
+ KeBugCheck (0);
+ }
+ if (ReadOffset >= Fcb->RFCB.FileSize.QuadPart || ReadOffset % BLOCKSIZE != 0 || Length % BLOCKSIZE != 0)
+ {
+ DbgPrint ("Start or end of FAT read is not on a sector boundary\n");
+ KeBugCheck (0);
+ }
+ if (ReadOffset + Length > Fcb->RFCB.FileSize.QuadPart)
+ {
+ Length = Fcb->RFCB.FileSize.QuadPart - ReadOffset;
+ }
+
+ Status = VfatReadSectors(DeviceExt->StorageDevice,
+ DeviceExt->FATStart + ReadOffset / BLOCKSIZE, Length / BLOCKSIZE, Buffer);
+ if (NT_SUCCESS(Status))
+ {
+ *LengthRead = Length;
+ }
+ else
+ {
+ DPRINT1("FAT reading failed, Status %x\n", Status);
+ }
+ return Status;
+ }
/*
* Find the first cluster
*/
- if (DeviceExt->FatType == FAT32)
- CurrentCluster = Fcb->entry.FirstCluster
- + Fcb->entry.FirstClusterHigh * 65536;
- else
- CurrentCluster = Fcb->entry.FirstCluster;
- FirstCluster = CurrentCluster;
- DPRINT( "FirstCluster = %x\n", FirstCluster );
+ FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
+
/*
* Truncate the read if necessary
*/
if (!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ if (ReadOffset >= Fcb->entry.FileSize)
{
- if (ReadOffset >= Fcb->entry.FileSize)
- {
- return (STATUS_END_OF_FILE);
- }
- if ((ReadOffset + Length) > Fcb->entry.FileSize)
- {
- Length = Fcb->entry.FileSize - ReadOffset;
- }
+ return (STATUS_END_OF_FILE);
}
-
- /*
- * Select an appropiate size for reads
- */
- if (DeviceExt->BytesPerCluster >= PAGESIZE)
+ if ((ReadOffset + Length) > Fcb->entry.FileSize)
{
- ChunkSize = DeviceExt->BytesPerCluster;
+ Length = Fcb->entry.FileSize - ReadOffset;
}
- else
+ }
+
+ if (FirstCluster == 1)
+ {
+ // root directory of FAT12 od FAT16
+ if (ReadOffset + Length > DeviceExt->rootDirectorySectors * BLOCKSIZE)
{
- ChunkSize = PAGESIZE;
+ Length = DeviceExt->rootDirectorySectors * BLOCKSIZE - ReadOffset;
}
+ }
+
+ // using the Cc-interface if possible
+ if (!NoCache)
+ {
+ FileOffset.QuadPart = ReadOffset;
+ CcCopyRead(FileObject, &FileOffset, Length, TRUE, Buffer, &IoStatus);
+ *LengthRead = IoStatus.Information;
+ return IoStatus.Status;
+ }
/*
* Find the cluster to start the read from
- * FIXME: Optimize by remembering the last cluster read and using if
- * possible.
*/
+ if (Ccb->LastCluster > 0 && ReadOffset > Ccb->LastOffset)
+ {
+ CurrentCluster = Ccb->LastCluster;
+ }
Status = OffsetToCluster(DeviceExt,
+ Fcb,
FirstCluster,
- ROUND_DOWN(ReadOffset, ChunkSize),
+ ROUND_DOWN(ReadOffset, DeviceExt->BytesPerCluster),
&CurrentCluster,
FALSE);
if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
+ {
+ return(Status);
+ }
/*
* If the read doesn't begin on a chunk boundary then we need special
* handling
*/
- if ((ReadOffset % ChunkSize) != 0 )
- {
- TempLength = min (Length, ChunkSize - (ReadOffset % ChunkSize));
- VfatReadCluster(DeviceExt, Fcb, ROUND_DOWN(ReadOffset, ChunkSize),
- FirstCluster, &CurrentCluster, Buffer, NoCache,
- ReadOffset % ChunkSize, TempLength);
-
+ if ((ReadOffset % DeviceExt->BytesPerCluster) != 0 )
+ {
+ TempLength = min (Length, DeviceExt->BytesPerCluster - (ReadOffset % DeviceExt->BytesPerCluster));
+ Ccb->LastCluster = CurrentCluster;
+ Ccb->LastOffset = ROUND_DOWN(ReadOffset, DeviceExt->BytesPerCluster);
+ Status = VfatReadCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster,
+ Buffer, ReadOffset % DeviceExt->BytesPerCluster,
+ TempLength);
+ if (NT_SUCCESS(Status))
+ {
(*LengthRead) = (*LengthRead) + TempLength;
Length = Length - TempLength;
Buffer = Buffer + TempLength;
ReadOffset = ReadOffset + TempLength;
}
+ }
+
+ while (Length >= DeviceExt->BytesPerCluster && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+ {
+ StartCluster = CurrentCluster;
+ ClusterCount = 0;
+ // search for continous clusters
+ do
+ {
+ ClusterCount++;
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
+ }
+ while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) &&
+ Length - ClusterCount * DeviceExt->BytesPerCluster >= DeviceExt->BytesPerCluster);
+ DPRINT("Count %d, Start %x Next %x\n", ClusterCount, StartCluster, CurrentCluster);
+ Ccb->LastCluster = StartCluster + (ClusterCount - 1);
+ Ccb->LastOffset = ReadOffset + (ClusterCount - 1) * DeviceExt->BytesPerCluster;
- while (Length >= ChunkSize && CurrentCluster)
+ Status = VfatRawReadCluster(DeviceExt, FirstCluster, Buffer, StartCluster, ClusterCount);
+ if (NT_SUCCESS(Status))
{
- VfatReadCluster(DeviceExt, Fcb, ReadOffset,
- FirstCluster, &CurrentCluster, Buffer, NoCache, 0,
- ChunkSize);
-
- (*LengthRead) = (*LengthRead) + ChunkSize;
- Buffer = Buffer + ChunkSize;
- Length = Length - ChunkSize;
- ReadOffset = ReadOffset + ChunkSize;
+ ClusterCount *= DeviceExt->BytesPerCluster;
+ (*LengthRead) = (*LengthRead) + ClusterCount;
+ Buffer += ClusterCount;
+ Length -= ClusterCount;
+ ReadOffset += ClusterCount;
}
- if (Length > 0 && CurrentCluster)
+ }
+ /*
+ * If the read doesn't end on a chunk boundary then we need special
+ * handling
+ */
+ if (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+ {
+ Ccb->LastCluster = CurrentCluster;
+ Ccb->LastOffset = ReadOffset + DeviceExt->BytesPerCluster;
+
+ Status = VfatReadCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster,
+ Buffer, 0, Length);
+ if (NT_SUCCESS(Status))
{
- VfatReadCluster(DeviceExt, Fcb, ReadOffset,
- FirstCluster, &CurrentCluster, Buffer, NoCache, 0,
- Length);
(*LengthRead) = (*LengthRead) + Length;
}
- return (STATUS_SUCCESS);
+ }
+ return Status;
}
NTSTATUS
-VfatWriteBigCluster(PDEVICE_EXTENSION DeviceExt,
- PVFATFCB Fcb,
+VfatWriteCluster(PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB Fcb,
ULONG StartOffset,
ULONG FirstCluster,
PULONG CurrentCluster,
PVOID Source,
- ULONG NoCache,
ULONG InternalOffset,
- ULONG InternalLength,
- BOOLEAN Extend)
+ ULONG InternalLength)
{
- BOOLEAN Valid;
PVOID BaseAddress;
- PCACHE_SEGMENT CacheSeg;
NTSTATUS Status;
- /*
- * In this case the size of a cache segment is the same as a cluster
- */
- if (!NoCache)
- {
- Status = CcRosRequestCacheSegment(Fcb->RFCB.Bcb,
- StartOffset,
- &BaseAddress,
- &Valid,
- &CacheSeg);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- }
+ if (InternalLength != DeviceExt->BytesPerCluster)
+ {
+ BaseAddress = ExAllocatePool(NonPagedPool, DeviceExt->BytesPerCluster);
+ if (BaseAddress == NULL)
+ {
+ return(STATUS_NO_MEMORY);
+ }
+ }
else
- {
- Valid = FALSE;
- /*
- * If we are bypassing the cache and not writing starting on
- * cluster boundary then allocate a temporary buffer
- */
- if (InternalOffset != 0)
- {
- BaseAddress = ExAllocatePool(NonPagedPool,
- DeviceExt->BytesPerCluster);
- if (BaseAddress == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
- }
- }
- if (!Valid && InternalLength != DeviceExt->BytesPerCluster)
- {
- /*
- * If the data in the cache isn't valid or we are bypassing the
- * cache and not writing a cluster aligned, cluster sized region
- * then read data in to base address
- */
- Status = VfatRawReadCluster(DeviceExt, FirstCluster, BaseAddress,
- *CurrentCluster);
- if (!NT_SUCCESS(Status))
- {
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, FALSE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(Status);
- }
- }
- if (!NoCache || InternalLength != DeviceExt->BytesPerCluster)
- {
- /*
- * If we are writing into the cache or we are writing from a
- * temporary buffer then copy the data over
- */
- DPRINT("InternalOffset 0x%x InternalLength 0x%x BA %x\n",
- InternalOffset, InternalLength, BaseAddress);
- memcpy(BaseAddress + InternalOffset, Source, InternalLength);
- }
+ BaseAddress = Source;
+ if (InternalLength != DeviceExt->BytesPerCluster)
+ {
+ /*
+ * If the data in the cache isn't valid or we are bypassing the
+ * cache and not writing a cluster aligned, cluster sized region
+ * then read data in to base address
+ */
+ Status = VfatRawReadCluster(DeviceExt, FirstCluster, BaseAddress,
+ *CurrentCluster, 1);
+ if (!NT_SUCCESS(Status))
+ {
+ if (InternalLength != DeviceExt->BytesPerCluster)
+ {
+ ExFreePool(BaseAddress);
+ }
+ return(Status);
+ }
+ memcpy(BaseAddress + InternalOffset, Source, InternalLength);
+ }
/*
* Write the data back to disk
*/
DPRINT("Writing 0x%x\n", *CurrentCluster);
Status = VfatRawWriteCluster(DeviceExt, FirstCluster, BaseAddress,
- *CurrentCluster);
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, TRUE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
-
- Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, Extend);
+ *CurrentCluster, 1);
+ if (InternalLength != DeviceExt->BytesPerCluster)
+ {
+ ExFreePool(BaseAddress);
+ }
if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- return(STATUS_SUCCESS);
-}
-
-NTSTATUS
-VfatWriteSmallCluster(PDEVICE_EXTENSION DeviceExt,
- PVFATFCB Fcb,
- ULONG StartOffset,
- ULONG FirstCluster,
- PULONG CurrentCluster,
- PVOID Source,
- ULONG NoCache,
- ULONG InternalOffset,
- ULONG InternalLength,
- BOOLEAN Extend)
-{
- BOOLEAN Valid;
- PVOID BaseAddress;
- PCACHE_SEGMENT CacheSeg;
- NTSTATUS Status;
- ULONG NCluster;
- ULONG i;
-
- /*
- * Otherwise we read a page of clusters together
- */
-
- if (!NoCache)
- {
- Status = CcRosRequestCacheSegment(Fcb->RFCB.Bcb,
- StartOffset,
- &BaseAddress,
- &Valid,
- &CacheSeg);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- }
- else
- {
- Valid = FALSE;
- if (InternalOffset != 0)
- {
- BaseAddress = ExAllocatePool(NonPagedPool, PAGESIZE);
- if (BaseAddress == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
- }
- else
- {
- BaseAddress = Source;
- }
- }
-
- /*
- * If necessary read all the data for the page, unfortunately the
- * file length may not be page aligned in which case the page will
- * only be partially filled.
- * FIXME: So zero fill the rest?
- */
- if (!Valid || InternalLength != PAGESIZE)
- {
- NCluster = *CurrentCluster;
-
- for (i = 0; i < (PAGESIZE / DeviceExt->BytesPerCluster); i++)
- {
- Status = VfatRawReadCluster(DeviceExt,
- FirstCluster,
- BaseAddress +
- (i * DeviceExt->BytesPerCluster),
- NCluster);
- if (!NT_SUCCESS(Status))
- {
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, FALSE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(Status);
- }
- Status = NextCluster(DeviceExt, FirstCluster, &NCluster, Extend);
- if (NCluster == 0xFFFFFFFF)
- {
- break;
- }
- }
- }
- else
- {
- /*
- * Otherwise just move onto the next cluster
- */
- for (i = 0; i < (PAGESIZE / DeviceExt->BytesPerCluster); i++)
- {
- NextCluster(DeviceExt, FirstCluster, &NCluster, Extend);
- if (NCluster == 0xFFFFFFFF)
- {
- break;
- }
- }
- }
-
- if (!NoCache || InternalLength != PAGESIZE)
- {
- /*
- * Copy the caller's data if we are using the cache or writing
- * from temporary buffer
- */
- memcpy(BaseAddress + InternalOffset, Source, InternalLength);
- }
-
- /*
- * Write the data to the disk
- */
- NCluster = *CurrentCluster;
-
- for (i = 0; i < (PAGESIZE / DeviceExt->BytesPerCluster); i++)
- {
- Status = VfatRawWriteCluster(DeviceExt,
- FirstCluster,
- BaseAddress +
- (i * DeviceExt->BytesPerCluster),
- NCluster);
- if (!NT_SUCCESS(Status))
- {
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, FALSE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(Status);
- }
- Status = NextCluster(DeviceExt, FirstCluster, &NCluster, Extend);
- if (NCluster == 0xFFFFFFFF)
- {
- break;
- }
- }
- *CurrentCluster = NCluster;
-
- if (!NoCache)
- {
- CcRosReleaseCacheSegment(Fcb->RFCB.Bcb, CacheSeg, TRUE);
- }
- else if (InternalOffset != 0)
- {
- ExFreePool(BaseAddress);
- }
- return(STATUS_SUCCESS);
-}
-
-NTSTATUS
-VfatWriteCluster(PDEVICE_EXTENSION DeviceExt,
- PVFATFCB Fcb,
- ULONG StartOffset,
- ULONG FirstCluster,
- PULONG CurrentCluster,
- PVOID Source,
- ULONG NoCache,
- ULONG InternalOffset,
- ULONG InternalLength,
- BOOLEAN Extend)
-{
-
-
- if (DeviceExt->BytesPerCluster >= PAGESIZE)
- {
- return(VfatWriteBigCluster(DeviceExt,
- Fcb,
- StartOffset,
- FirstCluster,
- CurrentCluster,
- Source,
- NoCache,
- InternalOffset,
- InternalLength,
- Extend));
- }
- else
- {
- return(VfatWriteSmallCluster(DeviceExt,
- Fcb,
- StartOffset,
- FirstCluster,
- CurrentCluster,
- Source,
- NoCache,
- InternalOffset,
- InternalLength,
- Extend));
- }
+ {
+ return Status;
+ }
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, CurrentCluster, FALSE);
+ return(Status);
}
NTSTATUS
VfatWriteFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
PVOID Buffer, ULONG Length, ULONG WriteOffset,
- ULONG NoCache)
+ BOOLEAN NoCache, BOOLEAN PageIo)
/*
* FUNCTION: Writes data to file
*/
{
ULONG CurrentCluster;
ULONG FirstCluster;
+ ULONG StartCluster;
+ ULONG Count;
PVFATFCB Fcb;
PVFATCCB pCcb;
ULONG TempLength;
LARGE_INTEGER SystemTime, LocalTime;
- ULONG ChunkSize;
NTSTATUS Status;
BOOLEAN Extend;
+ LARGE_INTEGER FileOffset;
DPRINT ("VfatWriteFile(FileObject %x, Buffer %x, Length %x, "
- "WriteOffset %x\n", FileObject, Buffer, Length, WriteOffset);
+ "WriteOffset %x\n", FileObject, Buffer, Length, WriteOffset);
- /* Locate the first cluster of the file */
assert (FileObject);
pCcb = (PVFATCCB) (FileObject->FsContext2);
assert (pCcb);
Fcb = pCcb->pFcb;
assert (Fcb);
- if (DeviceExt->BytesPerCluster >= PAGESIZE)
+// DPRINT1("%S\n", Fcb->PathName);
+
+ if (Length == 0)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ // Is this a write to the FAT ?
+ if (Fcb->Flags & FCB_IS_FAT)
+ {
+ if (!NoCache && !PageIo)
{
- ChunkSize = DeviceExt->BytesPerCluster;
+ DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
+ KeBugCheck (0);
}
- else
+ if (WriteOffset >= Fcb->RFCB.FileSize.QuadPart || WriteOffset % BLOCKSIZE != 0 || Length % BLOCKSIZE != 0)
+ {
+ DbgPrint ("Start or end of FAT write is not on a sector boundary\n");
+ KeBugCheck (0);
+ }
+ if (WriteOffset + Length > (ULONG)Fcb->RFCB.FileSize.QuadPart)
{
- ChunkSize = PAGESIZE;
+ Length = (ULONG)Fcb->RFCB.FileSize.QuadPart - WriteOffset;
}
- if (DeviceExt->FatType == FAT32)
+ for (Count = 0; Count < DeviceExt->Boot->FATCount; Count++)
{
- CurrentCluster =
- Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
+ Status = VfatWriteSectors(DeviceExt->StorageDevice,
+ DeviceExt->FATStart + (Count * (ULONG)Fcb->RFCB.FileSize.QuadPart + WriteOffset) / BLOCKSIZE,
+ Length / BLOCKSIZE, Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("FAT writing failed, Status %x\n", Status);
+ }
}
- else
+ return Status;
+ }
+
+ /* Locate the first cluster of the file */
+ FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
+
+ if (PageIo)
+ {
+ if (FirstCluster == 0)
{
- CurrentCluster = Fcb->entry.FirstCluster;
+ return STATUS_UNSUCCESSFUL;
}
- FirstCluster = CurrentCluster;
-
- /* Find the cluster according to the offset in the file */
- if (CurrentCluster == 0)
+ }
+ else
+ {
+ if (FirstCluster == 1)
{
- /*
- * File of size zero
- */
- Status = NextCluster (DeviceExt, FirstCluster, &CurrentCluster,
- TRUE);
- if (DeviceExt->FatType == FAT32)
- {
- Fcb->entry.FirstClusterHigh = CurrentCluster >> 16;
- Fcb->entry.FirstCluster = CurrentCluster;
- }
- else
- {
- Fcb->entry.FirstCluster = CurrentCluster;
- }
- FirstCluster = CurrentCluster;
+ // root directory of FAT12 od FAT16
+ if (WriteOffset + Length > DeviceExt->rootDirectorySectors * BLOCKSIZE)
+ {
+ DPRINT("Writing over the end of the root directory on FAT12/16\n");
+ return STATUS_END_OF_FILE;
+ }
}
- Status = OffsetToCluster(DeviceExt, FirstCluster, WriteOffset,
- &CurrentCluster, TRUE);
-
- if (WriteOffset + Length > Fcb->entry.FileSize &&
- !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+
+ Status = vfatExtendSpace(DeviceExt, FileObject, WriteOffset + Length);
+ if (!NT_SUCCESS (Status))
{
- Fcb->entry.FileSize = WriteOffset + Length;
+ return Status;
}
+ }
- /*
- * If the offset in the cluster doesn't fall on the cluster boundary
- * then we have to write only from the specified offset
- */
+ if (NoCache || PageIo)
+ {
- if ((WriteOffset % ChunkSize) != 0)
+ FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
+ if (pCcb->LastCluster > 0 && WriteOffset > pCcb->LastOffset)
{
- TempLength = min (Length, ChunkSize - (WriteOffset % ChunkSize));
- if ((Length - TempLength) > 0)
- {
- Extend = TRUE;
- }
- else
- {
- Extend = FALSE;
- }
- Status = VfatWriteCluster(DeviceExt,
- Fcb,
- ROUND_DOWN(WriteOffset, ChunkSize),
- FirstCluster,
- &CurrentCluster,
- Buffer,
- NoCache,
- WriteOffset % ChunkSize,
- TempLength,
- Extend);
- Buffer = Buffer + TempLength;
- Length = Length - TempLength;
- WriteOffset = WriteOffset + TempLength;
+ CurrentCluster = pCcb->LastCluster;
}
+ Status = OffsetToCluster(DeviceExt,
+ Fcb,
+ FirstCluster,
+ ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster),
+ &CurrentCluster,
+ FALSE);
+ if (!NT_SUCCESS(Status) || CurrentCluster == 0xffffffff)
+ {
+ DPRINT1("????\n");
+ return(Status);
+ }
+ pCcb->LastCluster = CurrentCluster;
+ pCcb->LastOffset = ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster);
- while (Length >= ChunkSize)
+ /*
+ * If the offset in the cluster doesn't fall on the cluster boundary
+ * then we have to write only from the specified offset
+ */
+ Status = STATUS_SUCCESS;
+ if ((WriteOffset % DeviceExt->BytesPerCluster) != 0)
{
- if ((Length - ChunkSize) > 0)
- {
- Extend = TRUE;
- }
- else
- {
- Extend = FALSE;
- }
+ TempLength = min (Length, DeviceExt->BytesPerCluster - (WriteOffset % DeviceExt->BytesPerCluster));
Status = VfatWriteCluster(DeviceExt,
Fcb,
- ROUND_DOWN(WriteOffset, ChunkSize),
- FirstCluster,
- &CurrentCluster,
- Buffer,
- NoCache,
- 0,
- ChunkSize,
- Extend);
- Buffer = Buffer + ChunkSize;
- Length = Length - ChunkSize;
- WriteOffset = WriteOffset + ChunkSize;
+ ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster),
+ FirstCluster,
+ &CurrentCluster,
+ Buffer,
+ WriteOffset % DeviceExt->BytesPerCluster,
+ TempLength);
+ if (NT_SUCCESS(Status))
+ {
+ Buffer = Buffer + TempLength;
+ Length = Length - TempLength;
+ WriteOffset = WriteOffset + TempLength;
+ }
}
- /* Write the remainder */
- if (Length > 0)
+ while (Length >= DeviceExt->BytesPerCluster && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+ {
+ StartCluster = CurrentCluster;
+ Count = 0;
+ // search for continous clusters
+ do
+ {
+ Count++;
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
+ }
+ while (StartCluster + Count == CurrentCluster && NT_SUCCESS(Status) &&
+ Length - Count * DeviceExt->BytesPerCluster >= DeviceExt->BytesPerCluster);
+
+ pCcb->LastCluster = StartCluster + (Count - 1);
+ pCcb->LastOffset = WriteOffset + (Count - 1) * DeviceExt->BytesPerCluster;
+
+ Status = VfatRawWriteCluster(DeviceExt, FirstCluster, Buffer, StartCluster, Count);
+ if (NT_SUCCESS(Status))
+ {
+ Count *= DeviceExt->BytesPerCluster;
+ Buffer += Count;
+ Length -= Count;
+ WriteOffset += Count;
+ }
+ }
+
+ /* Write the remainder */
+ if (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
{
Status = VfatWriteCluster(DeviceExt,
Fcb,
- ROUND_DOWN(WriteOffset, ChunkSize),
- FirstCluster,
- &CurrentCluster,
- Buffer,
- NoCache,
- 0,
- Length,
- FALSE);
+ WriteOffset,
+ FirstCluster,
+ &CurrentCluster,
+ Buffer,
+ 0,
+ Length);
+ if (NT_SUCCESS(Status))
+ {
+ Length = 0;
+ }
+ }
+ if (NT_SUCCESS(Status) && Length)
+ {
+ if (WriteOffset < Fcb->RFCB.AllocationSize.QuadPart)
+ {
+ DPRINT1("%d %d\n", WriteOffset, (ULONG)Fcb->RFCB.AllocationSize.QuadPart);
+ Status = STATUS_DISK_FULL; // ???????????
+ }
+ }
+ }
+ else
+ {
+ // using the Cc-interface if possible
+ FileOffset.QuadPart = WriteOffset;
+ if(CcCopyWrite(FileObject, &FileOffset, Length, TRUE, Buffer))
+ {
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ Status = STATUS_UNSUCCESSFUL;
}
+ }
- /* set dates and times */
- if (!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+ if (!PageIo)
+ {
+ if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
{
+ /* set dates and times */
KeQuerySystemTime (&SystemTime);
ExSystemTimeToLocalTime (&SystemTime, &LocalTime);
FsdFileTimeToDosDateTime ((TIME*)&LocalTime,
- &Fcb->entry.UpdateDate,
- &Fcb->entry.UpdateTime);
+ &Fcb->entry.UpdateDate,
+ &Fcb->entry.UpdateTime);
Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
+ // update dates/times and length
updEntry (DeviceExt, FileObject);
}
+ }
- return (STATUS_SUCCESS);
+ return Status;
}
-NTSTATUS STDCALL
-VfatWrite (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Write to a file
- */
+NTSTATUS vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt, PFILE_OBJECT pFileObject, ULONG NewSize)
{
- ULONG Length;
- PVOID Buffer;
- ULONG Offset;
- PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation (Irp);
- PFILE_OBJECT FileObject = Stack->FileObject;
- PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
+ ULONG FirstCluster;
+ ULONG CurrentCluster;
+ ULONG NewCluster;
NTSTATUS Status;
- ULONG NoCache;
+ PVFATFCB pFcb;
+
+
+ pFcb = ((PVFATCCB) (pFileObject->FsContext2))->pFcb;
- DPRINT ("VfatWrite(DeviceObject %x Irp %x)\n", DeviceObject, Irp);
+ DPRINT ("New Size %d, AllocationSize %d, BytesPerCluster %d\n", NewSize,
+ (ULONG)pFcb->RFCB.AllocationSize.QuadPart, pDeviceExt->BytesPerCluster);
- Length = Stack->Parameters.Write.Length;
- Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
- Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
+ FirstCluster = CurrentCluster = vfatDirEntryGetFirstCluster (pDeviceExt, &pFcb->entry);
- if (Irp->Flags & IRP_PAGING_IO ||
- FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
+ if (NewSize > pFcb->RFCB.AllocationSize.QuadPart || FirstCluster==0)
+ {
+ // size on disk must be extended
+ if (FirstCluster == 0)
{
- NoCache = TRUE;
+ // file of size zero
+ Status = NextCluster (pDeviceExt, pFcb, FirstCluster, &CurrentCluster, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NextCluster failed, Status %x\n", Status);
+ return Status;
+ }
+ NewCluster = FirstCluster = CurrentCluster;
+ }
+ else
+ {
+ Status = OffsetToCluster(pDeviceExt, pFcb, FirstCluster,
+ pFcb->RFCB.AllocationSize.QuadPart - pDeviceExt->BytesPerCluster,
+ &CurrentCluster, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("OffsetToCluster failed, Status %x\n", Status);
+ return Status;
+ }
+ if (CurrentCluster == 0xffffffff)
+ {
+ DPRINT1("Not enough disk space.\n");
+ return STATUS_DISK_FULL;
+ }
+ // CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
+ NewCluster = CurrentCluster;
+ Status = NextCluster(pDeviceExt, pFcb, FirstCluster, &NewCluster, FALSE);
+ if (NewCluster != 0xffffffff)
+ {
+ DPRINT1("Difference between size from direntry and the FAT.\n");
+ }
}
+
+ Status = OffsetToCluster(pDeviceExt, pFcb, FirstCluster,
+ ROUND_DOWN(NewSize-1, pDeviceExt->BytesPerCluster),
+ &NewCluster, TRUE);
+ if (!NT_SUCCESS(Status) || NewCluster == 0xffffffff)
+ {
+ DPRINT1("Not enough free space on disk\n");
+ if (pFcb->RFCB.AllocationSize.QuadPart > 0)
+ {
+ NewCluster = CurrentCluster;
+ // FIXME: check status
+ NextCluster(pDeviceExt, pFcb, FirstCluster, &NewCluster, FALSE);
+ WriteCluster(pDeviceExt, CurrentCluster, 0xffffffff);
+ }
+ // free the allocated space
+ while (NewCluster != 0xffffffff)
+ {
+ CurrentCluster = NewCluster;
+ // FIXME: check status
+ NextCluster (pDeviceExt, pFcb, FirstCluster, &NewCluster, FALSE);
+ WriteCluster (pDeviceExt, CurrentCluster, 0);
+ }
+ return STATUS_DISK_FULL;
+ }
+ if (pFcb->RFCB.AllocationSize.QuadPart == 0)
+ {
+ pFcb->entry.FirstCluster = FirstCluster;
+ if(pDeviceExt->FatType == FAT32)
+ pFcb->entry.FirstClusterHigh = FirstCluster >> 16;
+ }
+ pFcb->RFCB.AllocationSize.QuadPart = ROUND_UP(NewSize, pDeviceExt->BytesPerCluster);
+ if (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ pFcb->RFCB.FileSize.QuadPart = pFcb->RFCB.AllocationSize.QuadPart;
+ pFcb->RFCB.ValidDataLength.QuadPart = pFcb->RFCB.AllocationSize.QuadPart;
+ }
+ else
+ {
+ pFcb->entry.FileSize = NewSize;
+ pFcb->RFCB.FileSize.QuadPart = NewSize;
+ pFcb->RFCB.ValidDataLength.QuadPart = NewSize;
+ }
+ CcSetFileSizes(pFileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
+ }
else
+ {
+ if (NewSize > pFcb->RFCB.FileSize.QuadPart)
+ {
+ // size on disk must not be extended
+ if (!(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ pFcb->entry.FileSize = NewSize;
+ pFcb->RFCB.FileSize.QuadPart = NewSize;
+ CcSetFileSizes(pFileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
+ }
+ }
+ else
{
- NoCache = FALSE;
+ // nothing to do
}
+ }
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VfatRead(PVFAT_IRP_CONTEXT IrpContext)
+{
+ PVFATFCB Fcb;
+ PVFATCCB Ccb;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG ReadLength;
+ ULONG ReturnedReadLength = 0;
+ LARGE_INTEGER ReadOffset;
+ PVOID Buffer;
- Status = VfatWriteFile (DeviceExt, FileObject, Buffer, Length, Offset,
- NoCache);
+ DPRINT ("VfatRead(IrpContext %x)\n", IrpContext);
+ assert (IrpContext);
+ Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
+ assert (Ccb);
+ Fcb = Ccb->pFcb;
+ assert (Fcb);
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = Length;
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
+ if (IrpContext->Irp->Flags & IRP_PAGING_IO)
+ {
+ if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
+ {
+ return VfatQueueRequest (IrpContext);
+ }
+ }
+ else
+ {
+ if (!ExAcquireResourceSharedLite(&Fcb->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
+ {
+ return VfatQueueRequest (IrpContext);
+ }
+ }
- return (Status);
+ ReadLength = IrpContext->Stack->Parameters.Read.Length;
+ ReadOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
+ Buffer = MmGetSystemAddressForMdl (IrpContext->Irp->MdlAddress);
+
+ /* fail if file is a directory and no paged read */
+ if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
+ {
+ Status = STATUS_FILE_IS_A_DIRECTORY;
+ }
+ else
+ {
+ Status = VfatReadFile (IrpContext->DeviceExt, IrpContext->FileObject,
+ Buffer, ReadLength, ReadOffset.u.LowPart, &ReturnedReadLength,
+ IrpContext->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING
+ || IrpContext->Irp->Flags & IRP_PAGING_IO);
+ }
+
+ if (IrpContext->Irp->Flags & IRP_PAGING_IO)
+ {
+ ExReleaseResourceLite(&Fcb->PagingIoResource);
+ }
+ else
+ {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
+ {
+ IrpContext->FileObject->CurrentByteOffset.QuadPart = ReadOffset.QuadPart + ReturnedReadLength;
+ }
+ IrpContext->Irp->IoStatus.Information = ReturnedReadLength;
+ }
+ else
+ {
+ IrpContext->Irp->IoStatus.Information = 0;
+ }
+
+ IrpContext->Irp->IoStatus.Status = Status;
+ IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
+ VfatFreeIrpContext (IrpContext);
+
+ return Status;
}
-NTSTATUS STDCALL
-VfatRead (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Read from a file
- */
+NTSTATUS VfatWrite(PVFAT_IRP_CONTEXT IrpContext)
{
- ULONG Length;
- PVOID Buffer;
- ULONG Offset;
- PIO_STACK_LOCATION Stack;
- PFILE_OBJECT FileObject;
- PDEVICE_EXTENSION DeviceExt;
- NTSTATUS Status;
- ULONG LengthRead;
- PVFATFCB Fcb;
- ULONG NoCache;
+ PVFATFCB Fcb;
+ PVFATCCB Ccb;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG WriteLength;
+ LARGE_INTEGER WriteOffset;
+ PVOID Buffer;
- DPRINT ("VfatRead(DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
+ DPRINT ("VfatWrite(), %S\n", ((PVFATCCB) IrpContext->FileObject->FsContext2)->pFcb->FileName);
+ assert (IrpContext);
+ Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
+ assert (Ccb);
+ Fcb = Ccb->pFcb;
+ assert (Fcb);
- /* Precondition / Initialization */
- assert (Irp != NULL);
- Stack = IoGetCurrentIrpStackLocation (Irp);
- assert (Stack != NULL);
- FileObject = Stack->FileObject;
- assert (FileObject != NULL);
- DeviceExt = DeviceObject->DeviceExtension;
- assert (DeviceExt != NULL);
+ if (IrpContext->Irp->Flags & IRP_PAGING_IO)
+ {
+ if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
+ {
+ return VfatQueueRequest (IrpContext);
+ }
+ }
+ else
+ {
+ if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
+ {
+ return VfatQueueRequest (IrpContext);
+ }
+ }
- Length = Stack->Parameters.Read.Length;
- Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
- Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
-
- if (Irp->Flags & IRP_PAGING_IO ||
- FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
- {
- NoCache = TRUE;
- }
- else
- {
- NoCache = FALSE;
- }
+ WriteLength = IrpContext->Stack->Parameters.Write.Length;
+ WriteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
+ Buffer = MmGetSystemAddressForMdl (IrpContext->Irp->MdlAddress);
- /* fail if file is a directory */
- Fcb = ((PVFATCCB) (FileObject->FsContext2))->pFcb;
- if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
- {
+ /* fail if file is a directory and no paged read */
+ if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
+ {
Status = STATUS_FILE_IS_A_DIRECTORY;
- }
- else
- {
- Status = VfatReadFile (DeviceExt,
- FileObject, Buffer, Length, Offset, &LengthRead,
- NoCache);
- }
+ }
+ else
+ {
+ Status = VfatWriteFile (IrpContext->DeviceExt, IrpContext->FileObject,
+ Buffer, WriteLength, WriteOffset.u.LowPart,
+ IrpContext->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING,
+ IrpContext->Irp->Flags & IRP_PAGING_IO);
+ }
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = LengthRead;
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
+ if (IrpContext->Irp->Flags & IRP_PAGING_IO)
+ {
+ ExReleaseResourceLite(&Fcb->PagingIoResource);
+ }
+ else
+ {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
- return (Status);
+ if (NT_SUCCESS(Status))
+ {
+ if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
+ {
+ IrpContext->FileObject->CurrentByteOffset.QuadPart = WriteOffset.QuadPart + WriteLength;
+ }
+ IrpContext->Irp->IoStatus.Information = WriteLength;
+ }
+ else
+ {
+ IrpContext->Irp->IoStatus.Information = 0;
+ }
+
+ IrpContext->Irp->IoStatus.Status = Status;
+ IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
+ VfatFreeIrpContext (IrpContext);
+ return Status;
}
+
+