📄 rw.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/fs/vfat/rw.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
*
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
#include "vfat.h"
/*
* Uncomment to enable strict verification of cluster/offset pair
* caching. If this option is enabled you lose all the benefits of
* the caching and the read/write operations will actually be
* slower. It's meant only for debugging!!!
* - Filip Navara, 26/07/2004
*/
/* #define DEBUG_VERIFY_OFFSET_CACHING */
/* FUNCTIONS *****************************************************************/
NTSTATUS
NextCluster(PDEVICE_EXTENSION DeviceExt,
ULONG FirstCluster,
PULONG CurrentCluster,
BOOLEAN Extend)
/*
* Return the next cluster in a FAT chain, possibly extending the chain if
* necessary
*/
{
if (FirstCluster == 1)
{
(*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster;
return(STATUS_SUCCESS);
}
else
{
if (Extend)
return GetNextClusterExtend(DeviceExt, (*CurrentCluster), CurrentCluster);
else
return GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster);
}
}
NTSTATUS
OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
ULONG FirstCluster,
ULONG FileOffset,
PULONG Cluster,
BOOLEAN Extend)
/*
* Return the cluster corresponding to an offset within a file,
* possibly extending the file if necessary
*/
{
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 (FirstCluster == 1)
{
/* root of FAT16 or FAT12 */
*Cluster = DeviceExt->FatInfo.rootStart + FileOffset
/ (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster;
return(STATUS_SUCCESS);
}
else
{
CurrentCluster = FirstCluster;
if (Extend)
{
for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
{
Status = GetNextClusterExtend (DeviceExt, CurrentCluster, &CurrentCluster);
if (!NT_SUCCESS(Status))
return(Status);
}
*Cluster = CurrentCluster;
}
else
{
for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
{
Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster);
if (!NT_SUCCESS(Status))
return(Status);
}
*Cluster = CurrentCluster;
}
return(STATUS_SUCCESS);
}
}
static NTSTATUS
VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext,
ULONG Length,
LARGE_INTEGER ReadOffset,
PULONG LengthRead)
/*
* FUNCTION: Reads data from a file
*/
{
ULONG CurrentCluster;
ULONG FirstCluster;
ULONG StartCluster;
ULONG ClusterCount;
LARGE_INTEGER StartOffset;
PDEVICE_EXTENSION DeviceExt;
BOOLEAN First = TRUE;
PVFATFCB Fcb;
PVFATCCB Ccb;
NTSTATUS Status;
ULONG BytesDone;
ULONG BytesPerSector;
ULONG BytesPerCluster;
ULONG LastCluster;
ULONG LastOffset;
/* PRECONDITION */
ASSERT(IrpContext);
DeviceExt = IrpContext->DeviceExt;
ASSERT(DeviceExt);
ASSERT(DeviceExt->FatInfo.BytesPerCluster);
ASSERT(IrpContext->FileObject);
ASSERT(IrpContext->FileObject->FsContext2 != NULL);
DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, "
"Length %d, ReadOffset 0x%I64x)\n", DeviceExt,
IrpContext->FileObject, Length, ReadOffset.QuadPart);
*LengthRead = 0;
Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
Fcb = IrpContext->FileObject->FsContext;
BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
ASSERT(ReadOffset.QuadPart + Length <= ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector));
ASSERT(ReadOffset.u.LowPart % BytesPerSector == 0);
ASSERT(Length % BytesPerSector == 0);
/* Is this a read of the FAT? */
if (Fcb->Flags & FCB_IS_FAT)
{
ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE);
if (NT_SUCCESS(Status))
{
*LengthRead = Length;
}
else
{
DPRINT1("FAT reading failed, Status %x\n", Status);
}
return Status;
}
/* Is this a read of the Volume ? */
if (Fcb->Flags & FCB_IS_VOLUME)
{
Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE);
if (NT_SUCCESS(Status))
{
*LengthRead = Length;
}
else
{
DPRINT1("Volume reading failed, Status %x\n", Status);
}
return Status;
}
/*
* Find the first cluster
*/
FirstCluster = CurrentCluster =
vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
if (FirstCluster == 1)
{
// Directory of FAT12/16 needs a special handling
CHECKPOINT;
if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector)
{
Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart;
}
ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
// Fire up the read command
Status = VfatReadDiskPartial (IrpContext, &ReadOffset, Length, 0, TRUE);
if (NT_SUCCESS(Status))
{
*LengthRead = Length;
}
return Status;
}
ExAcquireFastMutex(&Fcb->LastMutex);
LastCluster = Fcb->LastCluster;
LastOffset = Fcb->LastOffset;
ExReleaseFastMutex(&Fcb->LastMutex);
/*
* Find the cluster to start the read from
*/
if (LastCluster > 0 && ReadOffset.u.LowPart >= LastOffset)
{
Status = OffsetToCluster(DeviceExt, LastCluster,
ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) -
LastOffset,
&CurrentCluster, FALSE);
#ifdef DEBUG_VERIFY_OFFSET_CACHING
/* DEBUG VERIFICATION */
{
ULONG CorrectCluster;
OffsetToCluster(DeviceExt, FirstCluster,
ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
&CorrectCluster, FALSE);
if (CorrectCluster != CurrentCluster)
KEBUGCHECK(FAT_FILE_SYSTEM);
}
#endif
}
else
{
Status = OffsetToCluster(DeviceExt, FirstCluster,
ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
&CurrentCluster, FALSE);
}
if (!NT_SUCCESS(Status))
{
return(Status);
}
ExAcquireFastMutex(&Fcb->LastMutex);
Fcb->LastCluster = CurrentCluster;
Fcb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster);
ExReleaseFastMutex(&Fcb->LastMutex);
KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
IrpContext->RefCount = 1;
while (Length > 0 && CurrentCluster != 0xffffffff)
{
StartCluster = CurrentCluster;
StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
BytesDone = 0;
ClusterCount = 0;
do
{
ClusterCount++;
if (First)
{
BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster));
StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster;
First = FALSE;
}
else
{
if (Length - BytesDone > BytesPerCluster)
{
BytesDone += BytesPerCluster;
}
else
{
BytesDone = Length;
}
}
Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
}
while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
DPRINT("start %08x, next %08x, count %d\n",
StartCluster, CurrentCluster, ClusterCount);
ExAcquireFastMutex(&Fcb->LastMutex);
Fcb->LastCluster = StartCluster + (ClusterCount - 1);
Fcb->LastOffset = ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster;
ExReleaseFastMutex(&Fcb->LastMutex);
// Fire up the read command
Status = VfatReadDiskPartial (IrpContext, &StartOffset, BytesDone, *LengthRead, FALSE);
if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
break;
}
*LengthRead += BytesDone;
Length -= BytesDone;
ReadOffset.u.LowPart += BytesDone;
}
if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount))
{
KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
}
if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
{
if (Length > 0)
{
Status = STATUS_UNSUCCESSFUL;
}
else
{
Status = IrpContext->Irp->IoStatus.Status;
}
}
return Status;
}
static NTSTATUS
VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
ULONG Length,
LARGE_INTEGER WriteOffset)
{
PDEVICE_EXTENSION DeviceExt;
PVFATFCB Fcb;
PVFATCCB Ccb;
ULONG Count;
ULONG FirstCluster;
ULONG CurrentCluster;
ULONG BytesDone;
ULONG StartCluster;
ULONG ClusterCount;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN First = TRUE;
ULONG BytesPerSector;
ULONG BytesPerCluster;
LARGE_INTEGER StartOffset;
ULONG BufferOffset;
ULONG LastCluster;
ULONG LastOffset;
/* PRECONDITION */
ASSERT(IrpContext);
DeviceExt = IrpContext->DeviceExt;
ASSERT(DeviceExt);
ASSERT(DeviceExt->FatInfo.BytesPerCluster);
ASSERT(IrpContext->FileObject);
ASSERT(IrpContext->FileObject->FsContext2 != NULL);
Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
Fcb = IrpContext->FileObject->FsContext;
BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, "
"Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt,
IrpContext->FileObject, Length, WriteOffset,
&Fcb->PathNameU);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -