2001-01-12 21:00:08 +00:00
|
|
|
|
2003-01-11 16:01:28 +00:00
|
|
|
/* $Id: rw.c,v 1.53 2003/01/11 16:01:28 hbirr Exp $
|
1999-12-11 21:14:49 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: services/fs/vfat/rw.c
|
|
|
|
* PURPOSE: VFAT Filesystem
|
|
|
|
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2000-02-22 02:02:08 +00:00
|
|
|
#include <ddk/ntddk.h>
|
1999-12-11 21:14:49 +00:00
|
|
|
#include <wchar.h>
|
2000-06-29 23:35:53 +00:00
|
|
|
#include <ntos/minmax.h>
|
1999-12-11 21:14:49 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
2000-06-29 23:35:53 +00:00
|
|
|
#include <debug.h>
|
1999-12-11 21:14:49 +00:00
|
|
|
|
|
|
|
#include "vfat.h"
|
|
|
|
|
2001-01-01 04:42:12 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2001-01-12 21:00:08 +00:00
|
|
|
NTSTATUS
|
2001-01-08 02:14:06 +00:00
|
|
|
NextCluster(PDEVICE_EXTENSION DeviceExt,
|
2002-01-08 00:49:02 +00:00
|
|
|
PVFATFCB Fcb,
|
2001-01-08 02:14:06 +00:00
|
|
|
ULONG FirstCluster,
|
2001-01-16 09:55:02 +00:00
|
|
|
PULONG CurrentCluster,
|
|
|
|
BOOLEAN Extend)
|
|
|
|
/*
|
|
|
|
* Return the next cluster in a FAT chain, possibly extending the chain if
|
|
|
|
* necessary
|
|
|
|
*/
|
2001-01-08 02:14:06 +00:00
|
|
|
{
|
2002-01-08 00:49:02 +00:00
|
|
|
if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
|
|
|
|
{
|
2002-01-15 21:54:51 +00:00
|
|
|
ULONG i;
|
|
|
|
PULONG FatChain;
|
|
|
|
NTSTATUS Status;
|
2002-01-27 03:25:45 +00:00
|
|
|
DPRINT("NextCluster(Fcb %x, FirstCluster %x, Extend %d)\n", Fcb,
|
|
|
|
FirstCluster, Extend);
|
2002-01-15 21:54:51 +00:00
|
|
|
if (Fcb->FatChainSize == 0)
|
2002-01-27 03:25:45 +00:00
|
|
|
{
|
|
|
|
/* Paging file with zero length. */
|
|
|
|
*CurrentCluster = 0xffffffff;
|
|
|
|
if (Extend)
|
|
|
|
{
|
|
|
|
Fcb->FatChain = ExAllocatePool(NonPagedPool, sizeof(ULONG));
|
2002-08-14 20:58:39 +00:00
|
|
|
if (Fcb->FatChain == NULL)
|
2002-01-27 03:25:45 +00:00
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
return(STATUS_NO_MEMORY);
|
2002-01-27 03:25:45 +00:00
|
|
|
}
|
|
|
|
Status = GetNextCluster(DeviceExt, 0, CurrentCluster, TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ExFreePool(Fcb->FatChain);
|
2002-08-14 20:58:39 +00:00
|
|
|
return(Status);
|
2002-01-27 03:25:45 +00:00
|
|
|
}
|
|
|
|
Fcb->FatChain[0] = *CurrentCluster;
|
|
|
|
Fcb->FatChainSize = 1;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
}
|
2002-01-15 21:54:51 +00:00
|
|
|
else
|
2002-01-27 03:25:45 +00:00
|
|
|
{
|
|
|
|
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_NO_MEMORY;
|
|
|
|
}
|
|
|
|
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;
|
2002-03-19 02:29:32 +00:00
|
|
|
return STATUS_SUCCESS;
|
2002-01-27 03:25:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*CurrentCluster = Fcb->FatChain[i + 1];
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2001-01-08 02:14:06 +00:00
|
|
|
}
|
2002-01-08 00:49:02 +00:00
|
|
|
if (FirstCluster == 1)
|
2001-03-02 15:59:16 +00:00
|
|
|
{
|
2002-03-18 22:37:13 +00:00
|
|
|
(*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster;
|
2002-01-08 00:49:02 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2001-03-02 15:59:16 +00:00
|
|
|
}
|
2001-01-08 02:14:06 +00:00
|
|
|
else
|
|
|
|
{
|
2002-01-08 00:49:02 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
2001-01-08 02:14:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-12 21:00:08 +00:00
|
|
|
NTSTATUS
|
2001-10-10 22:19:51 +00:00
|
|
|
OffsetToCluster(PDEVICE_EXTENSION DeviceExt,
|
2002-01-08 00:49:02 +00:00
|
|
|
PVFATFCB Fcb,
|
2001-10-10 22:19:51 +00:00
|
|
|
ULONG FirstCluster,
|
2001-01-12 21:00:08 +00:00
|
|
|
ULONG FileOffset,
|
2001-01-16 09:55:02 +00:00
|
|
|
PULONG Cluster,
|
|
|
|
BOOLEAN Extend)
|
|
|
|
/*
|
|
|
|
* Return the cluster corresponding to an offset within a file,
|
|
|
|
* possibly extending the file if necessary
|
|
|
|
*/
|
2001-01-01 04:42:12 +00:00
|
|
|
{
|
|
|
|
ULONG CurrentCluster;
|
|
|
|
ULONG i;
|
2001-01-12 21:00:08 +00:00
|
|
|
NTSTATUS Status;
|
2002-01-15 21:54:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2001-01-01 04:42:12 +00:00
|
|
|
|
2002-01-08 00:49:02 +00:00
|
|
|
if (Fcb != NULL && Fcb->Flags & FCB_IS_PAGE_FILE)
|
|
|
|
{
|
|
|
|
ULONG NCluster;
|
2002-03-18 22:37:13 +00:00
|
|
|
ULONG Offset = FileOffset / DeviceExt->FatInfo.BytesPerCluster;
|
2002-01-15 21:54:51 +00:00
|
|
|
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;
|
|
|
|
}
|
2002-01-08 00:49:02 +00:00
|
|
|
else
|
2002-01-15 21:54:51 +00:00
|
|
|
{
|
|
|
|
if (!Extend)
|
|
|
|
{
|
|
|
|
*Cluster = 0xffffffff;
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
else
|
2002-01-08 00:49:02 +00:00
|
|
|
{
|
2002-01-15 21:54:51 +00:00
|
|
|
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;
|
2002-01-08 00:49:02 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2001-01-01 04:42:12 +00:00
|
|
|
if (FirstCluster == 1)
|
2001-10-10 22:19:51 +00:00
|
|
|
{
|
2001-01-01 04:42:12 +00:00
|
|
|
/* root of FAT16 or FAT12 */
|
2002-03-18 22:37:13 +00:00
|
|
|
*Cluster = DeviceExt->FatInfo.rootStart + FileOffset
|
|
|
|
/ (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster;
|
2001-01-12 21:00:08 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2001-01-01 04:42:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-12 21:00:08 +00:00
|
|
|
CurrentCluster = FirstCluster;
|
2002-03-18 22:37:13 +00:00
|
|
|
for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++)
|
2001-01-01 04:42:12 +00:00
|
|
|
{
|
2001-01-16 09:55:02 +00:00
|
|
|
Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster,
|
|
|
|
Extend);
|
2001-01-12 21:00:08 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2001-01-01 04:42:12 +00:00
|
|
|
}
|
2001-01-12 21:00:08 +00:00
|
|
|
*Cluster = CurrentCluster;
|
|
|
|
return(STATUS_SUCCESS);
|
2001-01-01 04:42:12 +00:00
|
|
|
}
|
|
|
|
}
|
1999-12-11 21:14:49 +00:00
|
|
|
|
2001-01-01 04:42:12 +00:00
|
|
|
NTSTATUS
|
2002-05-05 20:20:15 +00:00
|
|
|
VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, PVOID Buffer,
|
|
|
|
ULONG Length, LARGE_INTEGER ReadOffset, PULONG LengthRead)
|
2001-01-01 04:42:12 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Reads data from a file
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG CurrentCluster;
|
|
|
|
ULONG FirstCluster;
|
2001-10-10 22:19:51 +00:00
|
|
|
ULONG StartCluster;
|
|
|
|
ULONG ClusterCount;
|
2002-06-26 18:36:41 +00:00
|
|
|
LARGE_INTEGER StartOffset;
|
2002-05-05 20:20:15 +00:00
|
|
|
PDEVICE_EXTENSION DeviceExt;
|
|
|
|
BOOLEAN First = TRUE;
|
2001-01-01 04:42:12 +00:00
|
|
|
PVFATFCB Fcb;
|
2001-10-10 22:19:51 +00:00
|
|
|
PVFATCCB Ccb;
|
2001-01-12 21:00:08 +00:00
|
|
|
NTSTATUS Status;
|
2002-01-27 01:11:24 +00:00
|
|
|
ULONG BytesDone;
|
2002-06-26 18:36:41 +00:00
|
|
|
ULONG BytesPerSector;
|
|
|
|
ULONG BytesPerCluster;
|
2001-01-01 04:42:12 +00:00
|
|
|
|
|
|
|
/* PRECONDITION */
|
2002-05-05 20:20:15 +00:00
|
|
|
assert (IrpContext);
|
|
|
|
DeviceExt = IrpContext->DeviceExt;
|
|
|
|
assert (DeviceExt);
|
|
|
|
assert (DeviceExt->FatInfo.BytesPerCluster);
|
|
|
|
assert (IrpContext->FileObject);
|
|
|
|
assert (IrpContext->FileObject->FsContext2 != NULL);
|
2001-01-01 04:42:12 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT("VfatReadFileData(DeviceExt %x, FileObject %x, Buffer %x, "
|
|
|
|
"Length %d, ReadOffset 0x%I64x)\n", DeviceExt,
|
|
|
|
IrpContext->FileObject, Buffer, Length, ReadOffset.QuadPart);
|
2001-07-20 08:00:21 +00:00
|
|
|
|
|
|
|
*LengthRead = 0;
|
2001-01-01 04:42:12 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
|
2001-10-10 22:19:51 +00:00
|
|
|
Fcb = Ccb->pFcb;
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
|
|
|
|
BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-06-26 18:36:41 +00:00
|
|
|
assert(ReadOffset.QuadPart + Length <= ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector));
|
|
|
|
assert(ReadOffset.u.LowPart % BytesPerSector == 0);
|
|
|
|
assert(Length % BytesPerSector == 0);
|
2002-05-05 20:20:15 +00:00
|
|
|
|
2002-01-27 01:11:24 +00:00
|
|
|
/* Is this a read of the FAT? */
|
2001-10-10 22:19:51 +00:00
|
|
|
if (Fcb->Flags & FCB_IS_FAT)
|
2002-05-05 20:20:15 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
|
|
|
|
Status = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2001-08-08 19:04:13 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
*LengthRead = Length;
|
2001-08-08 19:04:13 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
else
|
2002-01-27 01:11:24 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT1("FAT reading failed, Status %x\n", Status);
|
2002-01-27 01:11:24 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2002-06-26 18:36:41 +00:00
|
|
|
/* Is this a read of the Volume ? */
|
2002-05-05 20:20:15 +00:00
|
|
|
if (Fcb->Flags & FCB_IS_VOLUME)
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatReadDisk(DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
|
2002-05-05 20:20:15 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2002-01-27 01:11:24 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
*LengthRead = Length;
|
2002-01-27 01:11:24 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
else
|
2002-01-27 01:11:24 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT1("Volume reading failed, Status %x\n", Status);
|
2002-01-27 01:11:24 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
return Status;
|
2002-01-27 01:11:24 +00:00
|
|
|
}
|
2001-10-10 22:19:51 +00:00
|
|
|
|
|
|
|
/*
|
2002-05-05 20:20:15 +00:00
|
|
|
* Find the first cluster
|
2001-10-10 22:19:51 +00:00
|
|
|
*/
|
2002-05-05 20:20:15 +00:00
|
|
|
FirstCluster = CurrentCluster =
|
|
|
|
vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
|
2002-01-27 01:11:24 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (FirstCluster == 1)
|
|
|
|
{
|
|
|
|
// Directory of FAT12/16 needs a special handling
|
|
|
|
CHECKPOINT;
|
2002-06-26 18:36:41 +00:00
|
|
|
if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector)
|
2002-05-05 20:20:15 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart;
|
2001-01-01 04:42:12 +00:00
|
|
|
}
|
2002-06-26 18:36:41 +00:00
|
|
|
ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
|
2001-01-16 09:55:02 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
// Fire up the read command
|
2002-06-26 18:36:41 +00:00
|
|
|
|
|
|
|
Status = VfatReadDisk (DeviceExt->StorageDevice, &ReadOffset, Length, Buffer);
|
2002-05-05 20:20:15 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
*LengthRead += Length;
|
|
|
|
}
|
|
|
|
return Status;
|
2001-08-08 19:04:13 +00:00
|
|
|
}
|
2001-01-16 09:55:02 +00:00
|
|
|
/*
|
2002-05-05 20:20:15 +00:00
|
|
|
* Find the cluster to start the read from
|
2001-01-16 09:55:02 +00:00
|
|
|
*/
|
2002-05-05 20:20:15 +00:00
|
|
|
if (Ccb->LastCluster > 0 && ReadOffset.u.LowPart > Ccb->LastOffset)
|
2001-08-08 19:04:13 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
CurrentCluster = Ccb->LastCluster;
|
2001-08-08 19:04:13 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
|
2002-06-26 18:36:41 +00:00
|
|
|
ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),
|
2002-05-05 20:20:15 +00:00
|
|
|
&CurrentCluster, FALSE);
|
2001-01-16 09:55:02 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2001-08-08 19:04:13 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
return(Status);
|
2001-08-08 19:04:13 +00:00
|
|
|
}
|
2001-01-16 09:55:02 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
Ccb->LastCluster = CurrentCluster;
|
2002-06-26 18:36:41 +00:00
|
|
|
Ccb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster);
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
|
2001-08-08 19:04:13 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
StartCluster = CurrentCluster;
|
2003-01-04 02:07:18 +00:00
|
|
|
StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
BytesDone = 0;
|
|
|
|
ClusterCount = 0;
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
do
|
2001-10-10 22:19:51 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
ClusterCount++;
|
|
|
|
if (First)
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster));
|
|
|
|
StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster;
|
2002-05-05 20:20:15 +00:00
|
|
|
First = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
if (Length - BytesDone > BytesPerCluster)
|
2002-05-05 20:20:15 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesDone += BytesPerCluster;
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BytesDone = Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
|
2001-10-10 22:19:51 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
|
|
|
|
DPRINT("start %08x, next %08x, count %d\n",
|
|
|
|
StartCluster, CurrentCluster, ClusterCount);
|
|
|
|
|
|
|
|
Ccb->LastCluster = StartCluster + (ClusterCount - 1);
|
2002-06-26 18:36:41 +00:00
|
|
|
Ccb->LastOffset = ReadOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
// Fire up the read command
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatReadDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
2001-10-10 22:19:51 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
*LengthRead += BytesDone;
|
|
|
|
Buffer += BytesDone;
|
|
|
|
Length -= BytesDone;
|
|
|
|
ReadOffset.u.LowPart += BytesDone;
|
2001-10-10 22:19:51 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
NTSTATUS VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext,
|
|
|
|
PVOID Buffer,
|
|
|
|
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;
|
|
|
|
BOOLEAN First = TRUE;
|
2002-06-26 18:36:41 +00:00
|
|
|
ULONG BytesPerSector;
|
|
|
|
ULONG BytesPerCluster;
|
|
|
|
LARGE_INTEGER StartOffset;
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
/* 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 = Ccb->pFcb;
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
|
|
|
|
BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
DPRINT("VfatWriteFileData(DeviceExt %x, FileObject %x, Buffer %x, "
|
|
|
|
"Length %d, WriteOffset 0x%I64x), '%S'\n", DeviceExt,
|
|
|
|
IrpContext->FileObject, Buffer, Length, WriteOffset,
|
|
|
|
Fcb->PathName);
|
|
|
|
|
2002-06-26 18:36:41 +00:00
|
|
|
assert(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart);
|
|
|
|
assert(WriteOffset.u.LowPart % BytesPerSector == 0);
|
|
|
|
assert(Length % BytesPerSector == 0)
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
// Is this a write of the volume ?
|
|
|
|
if (Fcb->Flags & FCB_IS_VOLUME)
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
|
2001-10-10 22:19:51 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT1("Volume writing failed, Status %x\n", Status);
|
2001-10-10 22:19:51 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
// Is this a write to the FAT ?
|
|
|
|
if (Fcb->Flags & FCB_IS_FAT)
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++)
|
2001-10-10 22:19:51 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatWriteDisk(DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
|
2002-05-05 20:20:15 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("FAT writing failed, Status %x\n", Status);
|
|
|
|
}
|
2002-06-26 18:36:41 +00:00
|
|
|
WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart;
|
2001-10-10 22:19:51 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
/*
|
|
|
|
* Find the first cluster
|
|
|
|
*/
|
|
|
|
FirstCluster = CurrentCluster =
|
|
|
|
vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
|
|
|
|
|
|
|
|
if (FirstCluster == 1)
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
assert(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector);
|
2002-05-05 20:20:15 +00:00
|
|
|
// Directory of FAT12/16 needs a special handling
|
2002-06-26 18:36:41 +00:00
|
|
|
WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
// Fire up the write command
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatWriteDisk (DeviceExt->StorageDevice, &WriteOffset, Length, Buffer);
|
2001-10-10 22:19:51 +00:00
|
|
|
return Status;
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
2001-08-07 15:38:04 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
/*
|
|
|
|
* Find the cluster to start the write from
|
|
|
|
*/
|
|
|
|
if (Ccb->LastCluster > 0 && WriteOffset.u.LowPart > Ccb->LastOffset)
|
|
|
|
{
|
|
|
|
CurrentCluster = Ccb->LastCluster;
|
|
|
|
}
|
2001-08-08 19:04:13 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
|
2002-06-26 18:36:41 +00:00
|
|
|
ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
|
2002-05-05 20:20:15 +00:00
|
|
|
&CurrentCluster, FALSE);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-10-10 22:19:51 +00:00
|
|
|
return(Status);
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
2000-12-29 23:17:12 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
Ccb->LastCluster = CurrentCluster;
|
2002-06-26 18:36:41 +00:00
|
|
|
Ccb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster);
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
while (Length > 0 && CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
|
|
|
|
{
|
2001-10-10 22:19:51 +00:00
|
|
|
StartCluster = CurrentCluster;
|
2002-06-26 18:36:41 +00:00
|
|
|
StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
BytesDone = 0;
|
|
|
|
ClusterCount = 0;
|
|
|
|
|
2001-10-10 22:19:51 +00:00
|
|
|
do
|
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
ClusterCount++;
|
|
|
|
if (First)
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster));
|
|
|
|
StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster;
|
2002-05-05 20:20:15 +00:00
|
|
|
First = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
if (Length - BytesDone > BytesPerCluster)
|
2002-05-05 20:20:15 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesDone += BytesPerCluster;
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BytesDone = Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Status = NextCluster(DeviceExt, Fcb, FirstCluster, &CurrentCluster, FALSE);
|
2001-10-10 22:19:51 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
|
|
|
|
DPRINT("start %08x, next %08x, count %d\n",
|
|
|
|
StartCluster, CurrentCluster, ClusterCount);
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
Ccb->LastCluster = StartCluster + (ClusterCount - 1);
|
2002-06-26 18:36:41 +00:00
|
|
|
Ccb->LastOffset = WriteOffset.u.LowPart + (ClusterCount - 1) * BytesPerCluster;
|
2001-10-10 22:19:51 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
// Fire up the write command
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatWriteDisk (DeviceExt->StorageDevice, &StartOffset, BytesDone, Buffer);
|
2001-10-10 22:19:51 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
Buffer += BytesDone;
|
|
|
|
Length -= BytesDone;
|
|
|
|
WriteOffset.u.LowPart += BytesDone;
|
2001-10-10 22:19:51 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
return Status;
|
1999-12-11 21:14:49 +00:00
|
|
|
}
|
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
NTSTATUS
|
2002-01-27 01:11:24 +00:00
|
|
|
VfatRead(PVFAT_IRP_CONTEXT IrpContext)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PVFATFCB Fcb;
|
|
|
|
PVFATCCB Ccb;
|
|
|
|
ULONG Length;
|
|
|
|
ULONG ReturnedLength = 0;
|
|
|
|
PERESOURCE Resource = NULL;
|
|
|
|
LARGE_INTEGER ByteOffset;
|
|
|
|
PVOID Buffer;
|
|
|
|
PDEVICE_OBJECT DeviceToVerify;
|
2002-06-26 18:36:41 +00:00
|
|
|
ULONG BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
assert(IrpContext);
|
|
|
|
|
|
|
|
DPRINT("VfatRead(IrpContext %x)\n", IrpContext);
|
|
|
|
|
|
|
|
assert(IrpContext->DeviceObject);
|
|
|
|
|
|
|
|
// This request is not allowed on the main device object
|
|
|
|
if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
|
|
|
|
{
|
|
|
|
DPRINT("VfatRead is called with the main device object.\n");
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(IrpContext->DeviceExt);
|
|
|
|
assert(IrpContext->FileObject);
|
|
|
|
Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
|
|
|
|
assert(Ccb);
|
|
|
|
Fcb = Ccb->pFcb;
|
|
|
|
assert(Fcb);
|
|
|
|
|
|
|
|
DPRINT("<%S>\n", Fcb->PathName);
|
|
|
|
|
|
|
|
ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
|
|
|
|
Length = IrpContext->Stack->Parameters.Read.Length;
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
/* 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_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DPRINT("'%S', Offset: %d, Length %d\n", Fcb->PathName, ByteOffset.u.LowPart, Length);
|
|
|
|
|
|
|
|
if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart)
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
|
|
Status = STATUS_END_OF_FILE;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
|
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT("%d %d\n", ByteOffset.u.LowPart, Length);
|
|
|
|
// non chached read must be sector aligned
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
if (Length == 0)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
goto ByeBye;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
2002-06-10 21:17:57 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (Fcb->Flags & FCB_IS_VOLUME)
|
|
|
|
{
|
|
|
|
Resource = &IrpContext->DeviceExt->DirResource;
|
|
|
|
}
|
|
|
|
else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
|
|
|
|
{
|
|
|
|
Resource = &Fcb->PagingIoResource;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Resource = &Fcb->MainResource;
|
|
|
|
}
|
|
|
|
if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
|
|
|
|
{
|
|
|
|
Resource = NULL;
|
|
|
|
Status = STATUS_PENDING;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
|
|
|
|
!(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
|
|
|
|
{
|
|
|
|
// cached read
|
|
|
|
CHECKPOINT;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
|
|
|
|
{
|
|
|
|
Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
|
|
|
|
Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
|
|
|
|
}
|
2001-11-02 22:47:36 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
Buffer = VfatGetUserBuffer(IrpContext->Irp);
|
|
|
|
if (!Buffer)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECKPOINT;
|
2002-08-17 15:15:50 +00:00
|
|
|
if (IrpContext->FileObject->PrivateCacheMap == NULL)
|
|
|
|
{
|
|
|
|
ULONG CacheSize;
|
|
|
|
CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
|
2002-10-01 19:27:25 +00:00
|
|
|
if (CacheSize < PAGE_SIZE)
|
2002-08-17 15:15:50 +00:00
|
|
|
{
|
2002-10-01 19:27:25 +00:00
|
|
|
CacheSize = PAGE_SIZE;
|
2002-08-17 15:15:50 +00:00
|
|
|
}
|
|
|
|
CcRosInitializeFileCache(IrpContext->FileObject, &Fcb->RFCB.Bcb, CacheSize);
|
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length,
|
|
|
|
IrpContext->Flags & IRPCONTEXT_CANWAIT, Buffer,
|
|
|
|
&IrpContext->Irp->IoStatus))
|
|
|
|
{
|
|
|
|
Status = STATUS_PENDING;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
CHECKPOINT;
|
|
|
|
if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
|
|
|
|
{
|
|
|
|
Status = IrpContext->Irp->IoStatus.Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
// non cached read
|
|
|
|
CHECKPOINT;
|
2002-06-26 18:36:41 +00:00
|
|
|
if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector))
|
2002-05-05 20:20:15 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
Length = ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart;
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Buffer = VfatGetUserBuffer(IrpContext->Irp);
|
|
|
|
if (!Buffer)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatReadFileData(IrpContext, Buffer, Length, ByteOffset, &ReturnedLength);
|
2002-05-05 20:20:15 +00:00
|
|
|
/*
|
|
|
|
if (Status == STATUS_VERIFY_REQUIRED)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n");
|
|
|
|
DeviceToVerify = IoGetDeviceToVerify(KeGetCurrentThread());
|
|
|
|
IoSetDeviceToVerify(KeGetCurrentThread(), NULL);
|
|
|
|
Status = IoVerifyVolume (DeviceToVerify, FALSE);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = VfatReadFileData(IrpContext, Buffer, Length,
|
|
|
|
ByteOffset.u.LowPart, &ReturnedLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Information = ReturnedLength;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
ByeBye:
|
|
|
|
if (Resource)
|
|
|
|
{
|
|
|
|
ExReleaseResourceLite(Resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = VfatQueueRequest(IrpContext);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Status = Status;
|
|
|
|
IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
|
|
|
|
VfatFreeIrpContext(IrpContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Status = Status;
|
|
|
|
if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
|
|
|
|
!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
|
|
|
|
(NT_SUCCESS(Status) || Status==STATUS_END_OF_FILE))
|
|
|
|
{
|
|
|
|
IrpContext->FileObject->CurrentByteOffset.QuadPart =
|
|
|
|
ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
|
|
|
|
}
|
|
|
|
|
|
|
|
IoCompleteRequest(IrpContext->Irp,
|
|
|
|
NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
|
|
|
|
VfatFreeIrpContext(IrpContext);
|
|
|
|
}
|
|
|
|
DPRINT("%x\n", Status);
|
|
|
|
return Status;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
|
|
|
PVFATCCB Ccb;
|
2002-05-05 20:20:15 +00:00
|
|
|
PVFATFCB Fcb;
|
|
|
|
PERESOURCE Resource = NULL;
|
|
|
|
LARGE_INTEGER ByteOffset;
|
2002-06-10 21:17:57 +00:00
|
|
|
LARGE_INTEGER OldFileSize;
|
2001-11-02 22:47:36 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2002-05-05 20:20:15 +00:00
|
|
|
ULONG Length;
|
2002-06-10 21:17:57 +00:00
|
|
|
ULONG OldAllocationSize;
|
2001-11-02 22:47:36 +00:00
|
|
|
PVOID Buffer;
|
2002-06-26 18:36:41 +00:00
|
|
|
ULONG BytesPerSector;
|
2001-11-02 22:47:36 +00:00
|
|
|
|
|
|
|
assert (IrpContext);
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
DPRINT("VfatWrite(IrpContext %x)\n", IrpContext);
|
|
|
|
|
|
|
|
assert(IrpContext->DeviceObject);
|
|
|
|
|
|
|
|
// This request is not allowed on the main device object
|
|
|
|
if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
|
|
|
|
{
|
|
|
|
DPRINT("VfatWrite is called with the main device object.\n");
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(IrpContext->DeviceExt);
|
|
|
|
assert(IrpContext->FileObject);
|
2001-11-02 22:47:36 +00:00
|
|
|
Ccb = (PVFATCCB) IrpContext->FileObject->FsContext2;
|
2002-05-05 20:20:15 +00:00
|
|
|
assert(Ccb);
|
|
|
|
Fcb = Ccb->pFcb;
|
|
|
|
assert(Fcb);
|
2001-11-02 22:47:36 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
DPRINT("<%S>\n", Fcb->PathName);
|
|
|
|
|
|
|
|
/* 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_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
|
|
|
ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
|
|
|
|
Length = IrpContext->Stack->Parameters.Write.Length;
|
2002-06-26 18:36:41 +00:00
|
|
|
BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
|
|
|
|
1 == vfatDirEntryGetFirstCluster (IrpContext->DeviceExt, &Fcb->entry))
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
// we can't extend the FAT, the volume or the root on FAT12/FAT16
|
|
|
|
Status = STATUS_END_OF_FILE;
|
|
|
|
goto ByeBye;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
|
|
|
|
if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
// non chached write must be sector aligned
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (Length == 0)
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
2001-11-02 22:47:36 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (IrpContext->Irp->Flags & IRP_PAGING_IO)
|
|
|
|
{
|
|
|
|
if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
2002-06-26 18:36:41 +00:00
|
|
|
if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
|
2002-05-05 20:20:15 +00:00
|
|
|
{
|
2002-06-26 18:36:41 +00:00
|
|
|
Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Fcb->Flags & FCB_IS_VOLUME)
|
|
|
|
{
|
|
|
|
Resource = &IrpContext->DeviceExt->DirResource;
|
|
|
|
}
|
|
|
|
else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
Resource = &Fcb->PagingIoResource;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
Resource = &Fcb->MainResource;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (Fcb->Flags & FCB_IS_PAGE_FILE)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
|
|
|
|
{
|
|
|
|
Resource = NULL;
|
|
|
|
Status = STATUS_PENDING;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
if (!ExAcquireResourceExclusiveLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
|
|
|
|
{
|
|
|
|
Resource = NULL;
|
|
|
|
Status = STATUS_PENDING;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
|
|
|
|
{
|
|
|
|
if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
|
|
|
|
{
|
|
|
|
Status = STATUS_PENDING;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 21:17:57 +00:00
|
|
|
OldFileSize = Fcb->RFCB.FileSize;
|
|
|
|
OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart;
|
|
|
|
|
2002-08-17 16:51:07 +00:00
|
|
|
if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
|
|
|
|
!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
|
|
|
|
ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-08-17 15:15:50 +00:00
|
|
|
LARGE_INTEGER AllocationSize;
|
|
|
|
AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
|
|
|
|
Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
|
|
|
|
IrpContext->DeviceExt, &AllocationSize);
|
2002-05-05 20:20:15 +00:00
|
|
|
if (!NT_SUCCESS (Status))
|
2001-11-02 22:47:36 +00:00
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
CHECKPOINT;
|
|
|
|
goto ByeBye;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 21:17:57 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
|
|
|
|
!(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
|
|
|
|
{
|
|
|
|
// cached write
|
|
|
|
CHECKPOINT;
|
|
|
|
|
|
|
|
Buffer = VfatGetUserBuffer(IrpContext->Irp);
|
|
|
|
if (!Buffer)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
CHECKPOINT;
|
2002-08-17 15:15:50 +00:00
|
|
|
if (IrpContext->FileObject->PrivateCacheMap == NULL)
|
|
|
|
{
|
|
|
|
ULONG CacheSize;
|
|
|
|
CacheSize = IrpContext->DeviceExt->FatInfo.BytesPerCluster;
|
2002-10-01 19:27:25 +00:00
|
|
|
if (CacheSize < PAGE_SIZE)
|
2002-08-17 15:15:50 +00:00
|
|
|
{
|
2002-10-01 19:27:25 +00:00
|
|
|
CacheSize = PAGE_SIZE;
|
2002-08-17 15:15:50 +00:00
|
|
|
}
|
|
|
|
CcRosInitializeFileCache(IrpContext->FileObject, &Fcb->RFCB.Bcb, CacheSize);
|
|
|
|
}
|
* Used look aside lists to allocate memory for VFATFCB, VFATCCB and VFAT_IRP_CONTEXT.
* Removed IsLastEntry, IsVolEntry, IsDeletedEntry, vfat_wstrlen, vfatGrabFCB,
vfat_initstr, vfat_wcsncat, vfat_wcsncpy, vfat_movestr, wstrcmpi and replaced
this functions with existing equivalents or functions from ntoskrnl.
* Merged GetEntryName into vfatGetNextDirEntry for reducing some overhead.
* Implemented a file name cache to speed up the searching for existing fcb.
* Removed some calls to FsdDosDateTimeToFileTime.
* Moved the call to CcZeroData behind the initializing of the cache (in VfatWrite).
* Using existing fcbs in FindFile if there is no '*?' within the search name.
svn path=/trunk/; revision=3740
2002-11-11 21:49:18 +00:00
|
|
|
if (ByteOffset.QuadPart > OldFileSize.QuadPart)
|
|
|
|
{
|
|
|
|
CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
|
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
|
|
|
|
1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Information = Length;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
CHECKPOINT;
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-05-05 20:20:15 +00:00
|
|
|
// non cached write
|
|
|
|
CHECKPOINT;
|
|
|
|
|
* Used look aside lists to allocate memory for VFATFCB, VFATCCB and VFAT_IRP_CONTEXT.
* Removed IsLastEntry, IsVolEntry, IsDeletedEntry, vfat_wstrlen, vfatGrabFCB,
vfat_initstr, vfat_wcsncat, vfat_wcsncpy, vfat_movestr, wstrcmpi and replaced
this functions with existing equivalents or functions from ntoskrnl.
* Merged GetEntryName into vfatGetNextDirEntry for reducing some overhead.
* Implemented a file name cache to speed up the searching for existing fcb.
* Removed some calls to FsdDosDateTimeToFileTime.
* Moved the call to CcZeroData behind the initializing of the cache (in VfatWrite).
* Using existing fcbs in FindFile if there is no '*?' within the search name.
svn path=/trunk/; revision=3740
2002-11-11 21:49:18 +00:00
|
|
|
if (ByteOffset.QuadPart > OldFileSize.QuadPart)
|
|
|
|
{
|
|
|
|
CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
|
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
Buffer = VfatGetUserBuffer(IrpContext->Irp);
|
|
|
|
if (!Buffer)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
|
|
goto ByeBye;
|
|
|
|
}
|
|
|
|
|
2002-06-26 18:36:41 +00:00
|
|
|
Status = VfatWriteFileData(IrpContext, Buffer, Length, ByteOffset);
|
2002-05-05 20:20:15 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Information = Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
|
|
|
|
!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
|
|
|
|
{
|
|
|
|
if(!(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
{
|
|
|
|
LARGE_INTEGER SystemTime, LocalTime;
|
|
|
|
// set dates and times
|
|
|
|
KeQuerySystemTime (&SystemTime);
|
|
|
|
ExSystemTimeToLocalTime (&SystemTime, &LocalTime);
|
|
|
|
FsdFileTimeToDosDateTime ((TIME*)&LocalTime, &Fcb->entry.UpdateDate,
|
|
|
|
&Fcb->entry.UpdateTime);
|
|
|
|
Fcb->entry.AccessDate = Fcb->entry.UpdateDate;
|
|
|
|
// update dates/times and length
|
2003-01-11 16:01:28 +00:00
|
|
|
VfatUpdateEntry (IrpContext->DeviceExt, IrpContext->FileObject);
|
2002-05-05 20:20:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ByeBye:
|
|
|
|
if (Resource)
|
|
|
|
{
|
|
|
|
ExReleaseResourceLite(Resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = VfatQueueRequest(IrpContext);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Status = Status;
|
|
|
|
IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
|
|
|
|
VfatFreeIrpContext(IrpContext);
|
|
|
|
}
|
2001-11-02 22:47:36 +00:00
|
|
|
}
|
2002-05-05 20:20:15 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
IrpContext->Irp->IoStatus.Status = Status;
|
|
|
|
if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
|
|
|
|
!(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
IrpContext->FileObject->CurrentByteOffset.QuadPart =
|
|
|
|
ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
|
|
|
|
}
|
2001-11-02 22:47:36 +00:00
|
|
|
|
2002-05-05 20:20:15 +00:00
|
|
|
IoCompleteRequest(IrpContext->Irp,
|
|
|
|
NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
|
|
|
|
VfatFreeIrpContext(IrpContext);
|
|
|
|
}
|
|
|
|
DPRINT("%x\n", Status);
|
2001-11-02 22:47:36 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|