-/* $Id: rw.c,v 1.33 2001/10/11 15:39:51 hbirr 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 (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)
+ if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
{
+ ULONG i;
+ PULONG FatChain;
NTSTATUS Status;
-
- Status = GetNextCluster(DeviceExt, 0, CurrentCluster,
- Extend);
- return(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
{
- 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,
+ PVFATFCB Fcb,
ULONG FirstCluster,
ULONG FileOffset,
PULONG Cluster,
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 */
NTSTATUS
VfatReadCluster(PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB Fcb,
ULONG FirstCluster,
PULONG CurrentCluster,
PVOID Destination,
{
return(Status);
}
- Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, CurrentCluster, FALSE);
return(Status);
}
CurrentCluster = Ccb->LastCluster;
}
Status = OffsetToCluster(DeviceExt,
+ Fcb,
FirstCluster,
ROUND_DOWN(ReadOffset, DeviceExt->BytesPerCluster),
&CurrentCluster,
TempLength = min (Length, DeviceExt->BytesPerCluster - (ReadOffset % DeviceExt->BytesPerCluster));
Ccb->LastCluster = CurrentCluster;
Ccb->LastOffset = ROUND_DOWN(ReadOffset, DeviceExt->BytesPerCluster);
- Status = VfatReadCluster(DeviceExt, FirstCluster, &CurrentCluster, Buffer,
- ReadOffset % DeviceExt->BytesPerCluster, TempLength);
+ Status = VfatReadCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster,
+ Buffer, ReadOffset % DeviceExt->BytesPerCluster,
+ TempLength);
if (NT_SUCCESS(Status))
{
(*LengthRead) = (*LengthRead) + TempLength;
do
{
ClusterCount++;
- Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
}
while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) &&
Length - ClusterCount * DeviceExt->BytesPerCluster >= DeviceExt->BytesPerCluster);
Ccb->LastCluster = CurrentCluster;
Ccb->LastOffset = ReadOffset + DeviceExt->BytesPerCluster;
- Status = VfatReadCluster(DeviceExt, FirstCluster, &CurrentCluster,
+ Status = VfatReadCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster,
Buffer, 0, Length);
if (NT_SUCCESS(Status))
{
NTSTATUS
VfatWriteCluster(PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB Fcb,
ULONG StartOffset,
ULONG FirstCluster,
PULONG CurrentCluster,
{
return Status;
}
- Status = NextCluster(DeviceExt, FirstCluster, CurrentCluster, FALSE);
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, CurrentCluster, FALSE);
return(Status);
}
// Is this a write to the FAT ?
if (Fcb->Flags & FCB_IS_FAT)
{
- if (!NoCache)
+ if (!NoCache && !PageIo)
{
DbgPrint ("Cached FAT write outside from VFATFS.SYS\n");
KeBugCheck (0);
CurrentCluster = pCcb->LastCluster;
}
Status = OffsetToCluster(DeviceExt,
+ Fcb,
FirstCluster,
ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster),
&CurrentCluster,
{
TempLength = min (Length, DeviceExt->BytesPerCluster - (WriteOffset % DeviceExt->BytesPerCluster));
Status = VfatWriteCluster(DeviceExt,
+ Fcb,
ROUND_DOWN(WriteOffset, DeviceExt->BytesPerCluster),
FirstCluster,
&CurrentCluster,
do
{
Count++;
- Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
+ Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
}
while (StartCluster + Count == CurrentCluster && NT_SUCCESS(Status) &&
Length - Count * DeviceExt->BytesPerCluster >= DeviceExt->BytesPerCluster);
if (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
{
Status = VfatWriteCluster(DeviceExt,
+ Fcb,
WriteOffset,
FirstCluster,
&CurrentCluster,
return Status;
}
-NTSTATUS STDCALL
-VfatWrite (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Write to a file
- */
-{
- ULONG Length;
- PVOID Buffer;
- ULONG Offset;
- PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation (Irp);
- PFILE_OBJECT FileObject = Stack->FileObject;
- PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
- NTSTATUS Status;
- ULONG NoCache;
-
- DPRINT ("VfatWrite(DeviceObject %x Irp %x)\n", DeviceObject, Irp);
-
- Length = Stack->Parameters.Write.Length;
- Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
- Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
-
- if (Irp->Flags & IRP_PAGING_IO ||
- FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
- {
- NoCache = TRUE;
- }
- else
- {
- NoCache = FALSE;
- }
-
- Status = VfatWriteFile (DeviceExt, FileObject, Buffer, Length, Offset,
- NoCache, Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
-
- if (!(Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
- {
- FileObject->CurrentByteOffset.QuadPart = Offset + Length;
- }
-
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = Length;
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
-
- return (Status);
-}
-
-NTSTATUS STDCALL
-VfatRead (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-/*
- * FUNCTION: Read from a file
- */
-{
- ULONG Length;
- PVOID Buffer;
- ULONG Offset;
- PIO_STACK_LOCATION Stack;
- PFILE_OBJECT FileObject;
- PDEVICE_EXTENSION DeviceExt;
- NTSTATUS Status;
- ULONG LengthRead;
- PVFATFCB Fcb;
- ULONG NoCache;
-
- DPRINT ("VfatRead(DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
-
- /* Precondition / Initialization */
- assert (Irp != NULL);
- Stack = IoGetCurrentIrpStackLocation (Irp);
- assert (Stack != NULL);
- FileObject = Stack->FileObject;
- assert (FileObject != NULL);
- DeviceExt = DeviceObject->DeviceExtension;
- assert (DeviceExt != NULL);
-
- 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;
- }
-
- Fcb = ((PVFATCCB) (FileObject->FsContext2))->pFcb;
- /* fail if file is a directory and no paged read */
- if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY && !(Irp->Flags & IRP_PAGING_IO))
- {
- Status = STATUS_FILE_IS_A_DIRECTORY;
- }
- else
- {
- Status = VfatReadFile (DeviceExt, FileObject, Buffer, Length,
- Offset, &LengthRead, NoCache);
- }
-
- if (!(Irp->Flags & IRP_PAGING_IO))
- {
- // update the file pointer
- FileObject->CurrentByteOffset.QuadPart = Offset + LengthRead;
- }
-
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = LengthRead;
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
-
- return (Status);
-}
-
NTSTATUS vfatExtendSpace (PDEVICE_EXTENSION pDeviceExt, PFILE_OBJECT pFileObject, ULONG NewSize)
{
ULONG FirstCluster;
if (FirstCluster == 0)
{
// file of size zero
- Status = NextCluster (pDeviceExt, FirstCluster, &CurrentCluster, TRUE);
+ Status = NextCluster (pDeviceExt, pFcb, FirstCluster, &CurrentCluster, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("NextCluster failed, Status %x\n", Status);
}
else
{
- Status = OffsetToCluster(pDeviceExt, FirstCluster,
+ Status = OffsetToCluster(pDeviceExt, pFcb, FirstCluster,
pFcb->RFCB.AllocationSize.QuadPart - pDeviceExt->BytesPerCluster,
&CurrentCluster, FALSE);
if (!NT_SUCCESS(Status))
}
// CurrentCluster zeigt jetzt auf den letzten Cluster in der Kette
NewCluster = CurrentCluster;
- Status = NextCluster(pDeviceExt, FirstCluster, &NewCluster, FALSE);
+ Status = NextCluster(pDeviceExt, pFcb, FirstCluster, &NewCluster, FALSE);
if (NewCluster != 0xffffffff)
{
DPRINT1("Difference between size from direntry and the FAT.\n");
}
}
- Status = OffsetToCluster(pDeviceExt, FirstCluster,
+ Status = OffsetToCluster(pDeviceExt, pFcb, FirstCluster,
ROUND_DOWN(NewSize-1, pDeviceExt->BytesPerCluster),
&NewCluster, TRUE);
if (!NT_SUCCESS(Status) || NewCluster == 0xffffffff)
{
NewCluster = CurrentCluster;
// FIXME: check status
- NextCluster(pDeviceExt, FirstCluster, &NewCluster, FALSE);
+ NextCluster(pDeviceExt, pFcb, FirstCluster, &NewCluster, FALSE);
WriteCluster(pDeviceExt, CurrentCluster, 0xffffffff);
}
// free the allocated space
{
CurrentCluster = NewCluster;
// FIXME: check status
- NextCluster (pDeviceExt, FirstCluster, &NewCluster, FALSE);
+ NextCluster (pDeviceExt, pFcb, FirstCluster, &NewCluster, FALSE);
WriteCluster (pDeviceExt, CurrentCluster, 0);
}
return STATUS_DISK_FULL;
}
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;
+
+ DPRINT ("VfatRead(IrpContext %x)\n", IrpContext);
+ assert (IrpContext);
+ Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
+ assert (Ccb);
+ Fcb = Ccb->pFcb;
+ assert (Fcb);
+
+ 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);
+ }
+ }
+
+ 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 VfatWrite(PVFAT_IRP_CONTEXT IrpContext)
+{
+ PVFATFCB Fcb;
+ PVFATCCB Ccb;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG WriteLength;
+ LARGE_INTEGER WriteOffset;
+ PVOID Buffer;
+
+ DPRINT ("VfatWrite(), %S\n", ((PVFATCCB) IrpContext->FileObject->FsContext2)->pFcb->FileName);
+ assert (IrpContext);
+ Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
+ assert (Ccb);
+ Fcb = Ccb->pFcb;
+ assert (Fcb);
+
+ 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);
+ }
+ }
+
+ WriteLength = IrpContext->Stack->Parameters.Write.Length;
+ WriteOffset = IrpContext->Stack->Parameters.Write.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 = VfatWriteFile (IrpContext->DeviceExt, IrpContext->FileObject,
+ Buffer, WriteLength, WriteOffset.u.LowPart,
+ 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 = 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;
+}
+
+