mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00
[fastfat_new]
- Cleanup the source code from parts which aren't needed anymore (after switching to FullFAT library usage). About 40kb of source code removed. svn path=/trunk/; revision=43641
This commit is contained in:
parent
87f0ae4ac5
commit
4f4bec88a5
8 changed files with 152 additions and 1650 deletions
|
@ -1,447 +0,0 @@
|
|||
/*
|
||||
* PROJECT: ReactOS FAT file system driver
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: drivers/filesystems/fastfat/blockdev.c
|
||||
* PURPOSE: Temporary sector reading support
|
||||
* PROGRAMMERS: Alexey Vlasov
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
#include "fastfat.h"
|
||||
|
||||
/* FUNCTIONS ***************************************************************/
|
||||
//FIXME: There is a conflicting function FatPerformDevIoCtrl doing same thing!
|
||||
NTSTATUS
|
||||
FatDiskIoControl_(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG IoCtlCode,
|
||||
IN PVOID InputBuffer,
|
||||
IN ULONG InputBufferSize,
|
||||
IN OUT PVOID OutputBuffer,
|
||||
IN OUT PULONG OutputBufferSize OPTIONAL)
|
||||
{
|
||||
PIRP Irp;
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
ULONG OutBufferSize;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
|
||||
/* Set out buffer size if it was supplied. */
|
||||
OutBufferSize = (ARGUMENT_PRESENT(OutputBufferSize)
|
||||
? 0 : *OutputBufferSize);
|
||||
|
||||
/* Initialize event if the operation will be pended. */
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
/* Build the Irp. */
|
||||
Irp = IoBuildDeviceIoControlRequest(IoCtlCode, DeviceObject,
|
||||
InputBuffer, InputBufferSize, OutputBuffer, OutBufferSize,
|
||||
FALSE, &Event, &IoStatus);
|
||||
if (Irp == NULL)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* Send IRP to Disk Device */
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatus.Status;
|
||||
}
|
||||
|
||||
/* Return output buffer length if required. */
|
||||
if (ARGUMENT_PRESENT(OutputBufferSize))
|
||||
*OutputBufferSize = IoStatus.Information;
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FatLockUserBuffer (
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN LOCK_OPERATION Operation,
|
||||
IN ULONG BufferLength)
|
||||
/*
|
||||
* FUNCTION:
|
||||
*
|
||||
*
|
||||
* ARGUMENTS:
|
||||
* IrpContext = Pointer to FCB structure for the file.
|
||||
* Operation = Type of lock operation.
|
||||
* BufferLength = Buffer length to be locked.
|
||||
* RETURNS: Status Value.
|
||||
* NOTES:
|
||||
*/
|
||||
{
|
||||
PMDL Mdl;
|
||||
PIRP Irp;
|
||||
NTSTATUS Status;
|
||||
|
||||
Mdl = NULL;
|
||||
Irp = IrpContext->Irp;
|
||||
Status = STATUS_SUCCESS;
|
||||
if (Irp->MdlAddress == NULL)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
Mdl = IoAllocateMdl(Irp->UserBuffer,
|
||||
BufferLength, FALSE, FALSE, Irp);
|
||||
if (Mdl == NULL)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
_SEH2_TRY
|
||||
{
|
||||
MmProbeAndLockPages(Mdl,
|
||||
Irp->RequestorMode, Operation);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
IoFreeMdl( Mdl );
|
||||
Irp->MdlAddress = NULL;
|
||||
} _SEH2_END
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FatIoSyncCompletionRoutine(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context)
|
||||
{
|
||||
PFAT_IO_CONTEXT IoContext;
|
||||
|
||||
IoContext = (PFAT_IO_CONTEXT) Context;
|
||||
|
||||
/* Check if this is an associated irp. */
|
||||
if (Irp != IoContext->Irp)
|
||||
{
|
||||
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
||||
IoContext->Irp->IoStatus = Irp->IoStatus;
|
||||
IoFreeMdl(Irp->MdlAddress);
|
||||
IoFreeIrp(Irp);
|
||||
if (InterlockedDecrement(&IoContext->RunCount) != 0)
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
/* This was the last run, update master irp. */
|
||||
if (NT_SUCCESS(IoContext->Irp->IoStatus.Status))
|
||||
IoContext->Irp->IoStatus.Information = IoContext->Length;
|
||||
}
|
||||
|
||||
/* This is the last associated irp or a single irp IO. */
|
||||
if (NT_SUCCESS(IoContext->Irp->IoStatus.Status) &&
|
||||
!FlagOn(IoContext->Irp->Flags, IRP_PAGING_IO))
|
||||
{
|
||||
/* Maintain FileObject CurrentByteOffset */
|
||||
IoContext->FileObject->CurrentByteOffset.QuadPart =
|
||||
IoContext->Offset + IoContext->Irp->IoStatus.Information;
|
||||
}
|
||||
|
||||
/* Signal about completion. */
|
||||
KeSetEvent(&IoContext->Wait.SyncEvent, 0, FALSE);
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FatIoAsyncCompletionRoutine(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context)
|
||||
{
|
||||
PFAT_IO_CONTEXT IoContext;
|
||||
|
||||
IoContext = (PFAT_IO_CONTEXT) Context;
|
||||
|
||||
/* Check if this is an associated irp. */
|
||||
if (Irp != IoContext->Irp)
|
||||
{
|
||||
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
||||
IoContext->Irp->IoStatus = Irp->IoStatus;
|
||||
IoFreeMdl(Irp->MdlAddress);
|
||||
IoFreeIrp(Irp);
|
||||
if (InterlockedDecrement(&IoContext->RunCount) != 0)
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
/* This was the last run, update master irp. */
|
||||
if (NT_SUCCESS(IoContext->Irp->IoStatus.Status))
|
||||
IoContext->Irp->IoStatus.Information = IoContext->Length;
|
||||
}
|
||||
|
||||
|
||||
/* This is the last associated irp or a single irp IO. */
|
||||
if (NT_SUCCESS(IoContext->Irp->IoStatus.Status) &&
|
||||
!FlagOn(IoContext->Irp->Flags, IRP_PAGING_IO))
|
||||
{
|
||||
/* Maintain FileObject Flags */
|
||||
if (IoGetCurrentIrpStackLocation(IoContext->Irp)->MajorFunction
|
||||
== IRP_MJ_READ)
|
||||
{
|
||||
SetFlag(IoContext->FileObject->Flags, FO_FILE_FAST_IO_READ);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFlag(IoContext->FileObject->Flags, FO_FILE_MODIFIED);
|
||||
}
|
||||
}
|
||||
if (IoContext->Wait.Async.Resource != NULL)
|
||||
ExReleaseResourceForThreadLite(
|
||||
IoContext->Wait.Async.Resource,
|
||||
IoContext->Wait.Async.ResourceThreadId);
|
||||
|
||||
if (IoContext->Wait.Async.PagingIoResource != NULL)
|
||||
ExReleaseResourceForThreadLite(
|
||||
IoContext->Wait.Async.PagingIoResource,
|
||||
IoContext->Wait.Async.ResourceThreadId);
|
||||
|
||||
IoMarkIrpPending(Irp);
|
||||
ExFreePool(Context);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
FatPerformLboIo(
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN PLARGE_INTEGER Offset,
|
||||
IN SIZE_T Length)
|
||||
{
|
||||
BOOLEAN CanWait, ReadOperation;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
|
||||
ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ);
|
||||
|
||||
/* Allocate completion context */
|
||||
IrpContext->FatIoContext = FsRtlAllocatePoolWithTag(
|
||||
NonPagedPool, sizeof(FAT_IO_CONTEXT), (ULONG) 'xCoI');
|
||||
|
||||
if (IrpContext->FatIoContext == NULL)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
RtlZeroMemory(IrpContext->FatIoContext,
|
||||
sizeof(FAT_IO_CONTEXT));
|
||||
|
||||
/* Initialize event if we are supposed to wait. */
|
||||
if (CanWait)
|
||||
{
|
||||
KeInitializeEvent(
|
||||
&IrpContext->FatIoContext->Wait.SyncEvent,
|
||||
NotificationEvent, FALSE);
|
||||
}
|
||||
|
||||
/* Set the completion routine depending on wait semantics. */
|
||||
IoSetCompletionRoutine(IrpContext->Irp,
|
||||
(CanWait
|
||||
? FatIoSyncCompletionRoutine
|
||||
: FatIoAsyncCompletionRoutine),
|
||||
IrpContext->FatIoContext, TRUE, TRUE, TRUE);
|
||||
|
||||
/* Setup stack location. */
|
||||
IoStack = IoGetNextIrpStackLocation(IrpContext->Irp);
|
||||
IoStack->MajorFunction = IrpContext->MajorFunction;
|
||||
IoStack->Parameters.Read.Length = (ULONG) Length;
|
||||
IoStack->Parameters.Read.ByteOffset = *Offset;
|
||||
if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH))
|
||||
SetFlag(IoStack->Flags, SL_WRITE_THROUGH);
|
||||
|
||||
IoCallDriver(
|
||||
IrpContext->Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
if (CanWait)
|
||||
{
|
||||
KeWaitForSingleObject(
|
||||
&IrpContext->FatIoContext->Wait.SyncEvent,
|
||||
Executive, KernelMode, FALSE, NULL);
|
||||
return IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS
|
||||
FatPerformVirtualNonCachedIo(
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN PLARGE_INTEGER Offset,
|
||||
IN SIZE_T Length)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
LONGLONG Vbo, Lbo, RunLength;
|
||||
ULONG RunCount, CleanupIndex, FirstIndex, BeyoundLastIndex;
|
||||
BOOLEAN CanWait, ReadOperation;
|
||||
PIRP* RunIrp;
|
||||
PMDL Mdl;
|
||||
|
||||
ASSERT(IrpContext->FatIoContext == NULL);
|
||||
|
||||
|
||||
FirstIndex = CleanupIndex = 0;
|
||||
CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
|
||||
ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ);
|
||||
Status = FatLockUserBuffer(IrpContext,
|
||||
(ReadOperation ? IoWriteAccess : IoReadAccess),
|
||||
Length);
|
||||
if (!NT_SUCCESS(Status))
|
||||
goto FatIoPerformNonCachedCleanup;
|
||||
Vbo = Offset->QuadPart;
|
||||
RunLength = Length;
|
||||
_SEH2_TRY
|
||||
{
|
||||
BeyoundLastIndex = FatScanFat(Fcb, Vbo,
|
||||
&Lbo, &RunLength, &FirstIndex, CanWait);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
_SEH2_YIELD(goto FatIoPerformNonCachedCleanup;)
|
||||
}_SEH2_END
|
||||
RunCount = BeyoundLastIndex - FirstIndex;
|
||||
if (RunCount == 0)
|
||||
{
|
||||
Status = STATUS_END_OF_FILE;
|
||||
goto FatIoPerformNonCachedCleanup;
|
||||
}
|
||||
Length = sizeof(FAT_IO_CONTEXT);
|
||||
if (RunCount > 0x1)
|
||||
Length += RunCount * sizeof(PIRP);
|
||||
IrpContext->FatIoContext = FsRtlAllocatePoolWithTag(
|
||||
NonPagedPool, Length, (ULONG) 'xCoI');
|
||||
if (IrpContext->FatIoContext == NULL)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto FatIoPerformNonCachedCleanup;
|
||||
}
|
||||
RtlZeroMemory(IrpContext->FatIoContext, Length);
|
||||
if (CanWait)
|
||||
{
|
||||
KeInitializeEvent(
|
||||
&IrpContext->FatIoContext->Wait.SyncEvent,
|
||||
NotificationEvent, FALSE);
|
||||
}
|
||||
if (RunCount == 0x1)
|
||||
{
|
||||
IoSetCompletionRoutine(IrpContext->Irp,
|
||||
(CanWait ? FatIoSyncCompletionRoutine
|
||||
: FatIoAsyncCompletionRoutine),
|
||||
IrpContext->FatIoContext, TRUE, TRUE, TRUE);
|
||||
IoStack = IoGetNextIrpStackLocation(IrpContext->Irp);
|
||||
IoStack->MajorFunction = IrpContext->Stack->MajorFunction;
|
||||
IoStack->Parameters.Read.Length = (ULONG) RunLength;
|
||||
IoStack->Parameters.Read.ByteOffset.QuadPart = Lbo;
|
||||
IoStack->Flags = FlagOn(
|
||||
IrpContext->Stack->Flags,
|
||||
SL_WRITE_THROUGH);
|
||||
Status = IoCallDriver(
|
||||
IrpContext->Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
goto FatIoPerformNonCachedComplete;
|
||||
}
|
||||
/*
|
||||
* We already have the first run retrieved by FatiScanFat.
|
||||
*/
|
||||
for (RunIrp = &IrpContext->FatIoContext->Irp,
|
||||
CleanupIndex = FirstIndex;
|
||||
CleanupIndex < BeyoundLastIndex;
|
||||
CleanupIndex ++, RunIrp ++)
|
||||
{
|
||||
#if DBG
|
||||
LONGLONG NextVbo = Vbo + RunLength;
|
||||
BOOLEAN RunExists;
|
||||
#endif
|
||||
/*
|
||||
* Allocate Irp for the run.
|
||||
*/
|
||||
*RunIrp = IoMakeAssociatedIrp(IrpContext->Irp,
|
||||
(CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1));
|
||||
if (*RunIrp == NULL)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto FatIoPerformNonCachedCleanup;
|
||||
}
|
||||
CleanupIndex ++;
|
||||
/*
|
||||
* Build Mdl for the run range.
|
||||
*/
|
||||
Mdl = IoAllocateMdl(
|
||||
Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID),
|
||||
(ULONG) RunLength, FALSE, FALSE, *RunIrp);
|
||||
if (Mdl == NULL)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto FatIoPerformNonCachedCleanup;
|
||||
}
|
||||
IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Mdl,
|
||||
Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID),
|
||||
(ULONG) RunLength);
|
||||
/*
|
||||
* Setup IRP for each run.
|
||||
*/
|
||||
IoSetCompletionRoutine(IrpContext->Irp,
|
||||
(CanWait ? FatIoSyncCompletionRoutine
|
||||
: FatIoAsyncCompletionRoutine),
|
||||
IrpContext->FatIoContext, TRUE, TRUE, TRUE);
|
||||
IoStack = IoGetNextIrpStackLocation(*RunIrp);
|
||||
IoStack->MajorFunction = IrpContext->Stack->MajorFunction;
|
||||
IoStack->Parameters.Read.Length = (ULONG) RunLength;
|
||||
IoStack->Parameters.Read.ByteOffset.QuadPart = Lbo;
|
||||
|
||||
/*
|
||||
* Propagate write-through to the associated IRPs
|
||||
*/
|
||||
if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH))
|
||||
SetFlag(IoStack->Flags, SL_WRITE_THROUGH);
|
||||
/*
|
||||
* Prepare for next iteration:
|
||||
*/
|
||||
#if DBG
|
||||
RunExists =
|
||||
#endif
|
||||
FsRtlGetNextLargeMcbEntry(&Fcb->Mcb, CleanupIndex, &Vbo, &Lbo, &RunLength);
|
||||
ASSERT(RunExists);
|
||||
ASSERT(NextVbo == Vbo);
|
||||
}
|
||||
/*
|
||||
* Send all IRPs to the volume device, we don't need to check
|
||||
* status code because cleanup will be done
|
||||
* by the completion routine in any case.
|
||||
*/
|
||||
for (RunIrp = &IrpContext->FatIoContext->Irp,
|
||||
CleanupIndex = FirstIndex;
|
||||
CleanupIndex < BeyoundLastIndex;
|
||||
CleanupIndex ++, RunIrp ++)
|
||||
{
|
||||
IoCallDriver(IrpContext->Vcb->TargetDeviceObject, *RunIrp);
|
||||
}
|
||||
|
||||
FatIoPerformNonCachedComplete:
|
||||
if (CanWait)
|
||||
{
|
||||
KeWaitForSingleObject(
|
||||
&IrpContext->FatIoContext->Wait.SyncEvent,
|
||||
Executive, KernelMode, FALSE, NULL);
|
||||
return IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT);
|
||||
return STATUS_PENDING;
|
||||
/*
|
||||
* The following block of code implements unwind logic
|
||||
*/
|
||||
FatIoPerformNonCachedCleanup:
|
||||
if (IrpContext->FatIoContext != NULL)
|
||||
{
|
||||
RunIrp = &IrpContext->FatIoContext->Irp;
|
||||
while (FirstIndex < CleanupIndex)
|
||||
{
|
||||
if ((*RunIrp)->MdlAddress != NULL)
|
||||
IoFreeMdl((*RunIrp)->MdlAddress);
|
||||
IoFreeIrp(*RunIrp);
|
||||
FirstIndex ++;
|
||||
RunIrp ++;
|
||||
}
|
||||
ExFreePool(IrpContext->FatIoContext);
|
||||
IrpContext->FatIoContext = NULL;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -1,775 +0,0 @@
|
|||
/*
|
||||
* PROJECT: ReactOS FAT file system driver
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: drivers/filesystems/fastfat/direntry.c
|
||||
* PURPOSE: Directory entries
|
||||
* PROGRAMMERS: Alexey Vlasov
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
#include "fastfat.h"
|
||||
|
||||
/* PROTOTYPES ***************************************************************/
|
||||
|
||||
typedef enum _FILE_TIME_INDEX
|
||||
{
|
||||
FileCreationTime = 0,
|
||||
FileLastAccessTime,
|
||||
FileLastWriteTime,
|
||||
FileChangeTime
|
||||
} FILE_TIME_INDEX;
|
||||
|
||||
|
||||
VOID
|
||||
Fat8dot3ToUnicodeString(OUT PUNICODE_STRING FileName,
|
||||
IN PUCHAR ShortName,
|
||||
IN UCHAR Flags);
|
||||
|
||||
ULONG
|
||||
FatDirentToDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
ULONG
|
||||
FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
ULONG
|
||||
FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
ULONG
|
||||
FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
ULONG
|
||||
FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
ULONG
|
||||
FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
ULONG
|
||||
FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer);
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
#define FatQueryFileName(xInfo, xDirent) \
|
||||
{ \
|
||||
UNICODE_STRING FileName; \
|
||||
if (Info->FileNameLength == 0) \
|
||||
{ \
|
||||
FileName.Buffer = Info->FileName; \
|
||||
FileName.MaximumLength = 0x18; \
|
||||
Fat8dot3ToUnicodeString(&FileName, \
|
||||
(xDirent)->FileName, (xDirent)->Case); \
|
||||
Info->FileNameLength = FileName.Length; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FatQueryBothFileName(xInfo, xDirent) \
|
||||
{ \
|
||||
UNICODE_STRING FileName; \
|
||||
FileName.MaximumLength = 0x18; \
|
||||
if (Info->FileNameLength == 0) \
|
||||
{ \
|
||||
FileName.Buffer = Info->FileName; \
|
||||
Fat8dot3ToUnicodeString(&FileName, \
|
||||
(xDirent)->FileName, (xDirent)->Case); \
|
||||
Info->FileNameLength = FileName.Length; \
|
||||
Info->ShortNameLength = 0; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
FileName.Buffer = Info->ShortName; \
|
||||
Fat8dot3ToUnicodeString(&FileName, \
|
||||
(xDirent)->FileName, (xDirent)->Case); \
|
||||
Info->ShortNameLength = (CCHAR) FileName.Length; \
|
||||
} \
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
UCHAR
|
||||
FatLfnChecksum(
|
||||
PUCHAR Buffer
|
||||
)
|
||||
{
|
||||
UCHAR Index, Chksum;
|
||||
|
||||
for (Index = 0x1, Chksum = *Buffer;
|
||||
Index < RTL_FIELD_SIZE(DIR_ENTRY, FileName);
|
||||
Index ++)
|
||||
{
|
||||
Chksum = (((Chksum & 0x1) << 0x7) | (Chksum >> 0x1))
|
||||
+ Buffer[Index];
|
||||
}
|
||||
return Chksum;
|
||||
}
|
||||
|
||||
VOID
|
||||
FatFindDirent(IN OUT PFAT_FIND_DIRENT_CONTEXT Context,
|
||||
OUT PDIR_ENTRY* Dirent,
|
||||
OUT PUNICODE_STRING LongFileName OPTIONAL)
|
||||
{
|
||||
PDIR_ENTRY Entry, EndOfPage;
|
||||
UCHAR SeqNum = 0, Checksum = 0;
|
||||
PUNICODE_STRING FileName;
|
||||
|
||||
/* Pin first page. */
|
||||
Entry = (PDIR_ENTRY) FatPinPage(&Context->Page, 0);
|
||||
EndOfPage = FatPinEndOfPage(&Context->Page, PDIR_ENTRY);
|
||||
|
||||
/* Run dirents. */
|
||||
FileName = NULL;
|
||||
while (TRUE)
|
||||
{
|
||||
/* Check if we have entered the area of never used dirents */
|
||||
if (Entry->FileName[0] == FAT_DIRENT_NEVER_USED)
|
||||
ExRaiseStatus(STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
|
||||
/* Just ignore entries marked as deleted */
|
||||
if (Entry->FileName[0] == FAT_DIRENT_DELETED)
|
||||
goto FatFindDirentNext;
|
||||
|
||||
/* Check if it's an lfn */
|
||||
if (Entry->Attributes == FAT_DIRENT_ATTR_LFN)
|
||||
{
|
||||
PLONG_FILE_NAME_ENTRY LfnEntry;
|
||||
|
||||
FileName = LongFileName;
|
||||
LfnEntry = (PLONG_FILE_NAME_ENTRY) Entry;
|
||||
|
||||
/* Run lfns and collect file name if required */
|
||||
do {
|
||||
PWSTR Lfn;
|
||||
|
||||
/* Check if we just running lfn */
|
||||
if (FileName == NULL)
|
||||
goto FatFindDirentRunLfn;
|
||||
|
||||
/* Check for cluster index to be zero. */
|
||||
if (LfnEntry->Reserved != 0)
|
||||
{
|
||||
FileName = NULL;
|
||||
goto FatFindDirentRunLfn;
|
||||
}
|
||||
|
||||
/* Check if this is the last lfn entry. */
|
||||
if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST))
|
||||
{
|
||||
SeqNum = (LfnEntry->SeqNum & ~FAT_FN_DIR_ENTRY_LAST);
|
||||
Checksum = LfnEntry->Checksum;
|
||||
|
||||
/* Check if we exceed max number of lfns */
|
||||
if (SeqNum > (FAT_FN_MAX_DIR_ENTIES + 1))
|
||||
{
|
||||
FileName = NULL;
|
||||
goto FatFindDirentRunLfn;
|
||||
}
|
||||
|
||||
/* Setup maximal expected lfn length */
|
||||
FileName->Length = (SeqNum * FAT_LFN_NAME_LENGTH);
|
||||
|
||||
/* Extend lfn buffer if needed */
|
||||
if (FileName->Length > FileName->MaximumLength)
|
||||
{
|
||||
Lfn = ExAllocatePoolWithTag(PagedPool,
|
||||
LongFileName->Length, TAG_VFAT);
|
||||
if (Lfn == NULL)
|
||||
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
||||
if (FileName->Buffer != NULL)
|
||||
ExFreePool(FileName->Buffer);
|
||||
FileName->Buffer = Lfn;
|
||||
FileName->MaximumLength = FileName->Length;
|
||||
}
|
||||
}
|
||||
else if (!(LfnEntry->SeqNum == SeqNum
|
||||
&& LfnEntry->Checksum == Checksum))
|
||||
{
|
||||
/* Wrong SeqNum or CheckSum. */
|
||||
FileName = NULL;
|
||||
goto FatFindDirentRunLfn;
|
||||
}
|
||||
/* Gather file name */
|
||||
Lfn = Add2Ptr(FileName->Buffer, (SeqNum * FAT_LFN_NAME_LENGTH)
|
||||
- sizeof(LfnEntry->NameC), PWSTR);
|
||||
RtlCopyMemory(Lfn, LfnEntry->NameC, sizeof(LfnEntry->NameC));
|
||||
Lfn -= (sizeof(LfnEntry->NameB) / sizeof(WCHAR));
|
||||
RtlCopyMemory(Lfn, LfnEntry->NameB, sizeof(LfnEntry->NameB));
|
||||
Lfn -= (sizeof(LfnEntry->NameA) / sizeof(WCHAR));
|
||||
RtlCopyMemory(Lfn, LfnEntry->NameA, sizeof(LfnEntry->NameA));
|
||||
|
||||
/* If last lfn determine exact lfn length. */
|
||||
if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST))
|
||||
{
|
||||
PWSTR LfnEnd = Add2Ptr(FileName->Buffer,
|
||||
(FileName->Length - sizeof(WCHAR)), PWSTR);
|
||||
|
||||
/* Trim trailing 0xffff's */
|
||||
while (LfnEnd > Lfn && *LfnEnd == 0xffff) --LfnEnd;
|
||||
|
||||
/* Trim 0 terminator is the one is there. */
|
||||
if (*LfnEnd == 0x0) --LfnEnd;
|
||||
|
||||
/* Set correct lfn size */
|
||||
FileName->Length = (USHORT)PtrOffset(FileName->Buffer, LfnEnd);
|
||||
}
|
||||
/* Setup validation for the next iteration */
|
||||
SeqNum = LfnEntry->SeqNum - 0x1;
|
||||
Checksum = LfnEntry->Checksum;
|
||||
|
||||
FatFindDirentRunLfn:
|
||||
/* Get next dirent */
|
||||
LfnEntry ++;
|
||||
if (LfnEntry > (PLONG_FILE_NAME_ENTRY) EndOfPage)
|
||||
{
|
||||
if (FatPinIsLastPage(&Context->Page))
|
||||
ExRaiseStatus(STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
LfnEntry = (PLONG_FILE_NAME_ENTRY) FatPinNextPage(&Context->Page);
|
||||
EndOfPage = FatPinEndOfPage(&Context->Page, PDIR_ENTRY);
|
||||
}
|
||||
}
|
||||
while (LfnEntry->Attributes == FAT_DIRENT_ATTR_LFN);
|
||||
Entry = (PDIR_ENTRY) LfnEntry;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we've got here then this is a normal dirent */
|
||||
if (FileName != NULL && FileName->Length > 0)
|
||||
{
|
||||
/* Check if we have a correct lfn collected. */
|
||||
if (FatLfnChecksum(Entry->FileName) != Checksum)
|
||||
{
|
||||
FileName = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* See if we were looking for this dirent. */
|
||||
if (!Context->Valid8dot3Name &&
|
||||
FsRtlAreNamesEqual(FileName, Context->FileName, TRUE, NULL))
|
||||
{
|
||||
Fat8dot3ToUnicodeString(&Context->ShortName, Entry->FileName, Entry->Case);
|
||||
*Dirent = Entry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We surely have a short name, check if we were looking for that. */
|
||||
if (Context->Valid8dot3Name)
|
||||
{
|
||||
Fat8dot3ToUnicodeString(&Context->ShortName,
|
||||
Entry->FileName, Entry->Case);
|
||||
if (FsRtlAreNamesEqual(&Context->ShortName, Context->FileName, TRUE, NULL))
|
||||
{
|
||||
if (ARGUMENT_PRESENT(LongFileName) && FileName == NULL)
|
||||
LongFileName->Length = 0;
|
||||
*Dirent = Entry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
FileName = NULL;
|
||||
|
||||
FatFindDirentNext:
|
||||
Entry ++;
|
||||
if (Entry > EndOfPage)
|
||||
{
|
||||
if (FatPinIsLastPage(&Context->Page))
|
||||
ExRaiseStatus(STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
Entry = (PDIR_ENTRY) FatPinNextPage(&Context->Page);
|
||||
EndOfPage = FatPinEndOfPage(&Context->Page, PDIR_ENTRY);
|
||||
}
|
||||
}
|
||||
/* Should never get here! */
|
||||
ASSERT(TRUE);
|
||||
}
|
||||
|
||||
VOID
|
||||
FatEnumerateDirents(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN SIZE_T Offset)
|
||||
{
|
||||
PUCHAR Entry, EndOfPage;
|
||||
PWSTR FileName;
|
||||
USHORT FileNameLength;
|
||||
USHORT FileNameMaximumLength;
|
||||
PVOID InfoEntry;
|
||||
UCHAR SeqNum = 0;
|
||||
UCHAR Checksum = 0;
|
||||
|
||||
/* Pin first page. */
|
||||
Entry = (PUCHAR)FatPinPage(&Context->Page, Offset);
|
||||
EndOfPage = FatPinEndOfPage(&Context->Page, PUCHAR);
|
||||
|
||||
/* Iterate dirents. */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Check if we have entered the area of never used dirents */
|
||||
if (*Entry == FAT_DIRENT_NEVER_USED)
|
||||
ExRaiseStatus(STATUS_NO_MORE_FILES);
|
||||
|
||||
/* Just ignore entries marked as deleted */
|
||||
if (*Entry == FAT_DIRENT_DELETED)
|
||||
goto FatEnumerateDirentsNext;
|
||||
|
||||
/* Get info pointer. */
|
||||
InfoEntry = Add2Ptr(Context->Buffer, Context->Offset, PVOID);
|
||||
|
||||
/* Check if info class has file name */
|
||||
if (Context->NameOffset == Context->LengthOffset)
|
||||
{
|
||||
FileName = NULL;
|
||||
FileNameMaximumLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileName = Add2Ptr(InfoEntry, Context->NameOffset, PWSTR);
|
||||
FileNameMaximumLength = (USHORT) (Context->Length
|
||||
- Context->Offset + Context->NameOffset);
|
||||
}
|
||||
FileNameLength = 0;
|
||||
|
||||
/* Check if it's an lfn */
|
||||
while (Entry[0xb] == FAT_DIRENT_ATTR_LFN)
|
||||
{
|
||||
PWSTR Lfn;
|
||||
PLONG_FILE_NAME_ENTRY LfnEntry;
|
||||
|
||||
/* Check if we just running lfn */
|
||||
if (FileNameMaximumLength == 0)
|
||||
goto FatEnumerateDirentsRunLfn;
|
||||
|
||||
LfnEntry = (PLONG_FILE_NAME_ENTRY) Entry;
|
||||
|
||||
/* Check for cluster index to be zero. */
|
||||
if (LfnEntry->Reserved != 0)
|
||||
{
|
||||
FileNameMaximumLength = 0;
|
||||
goto FatEnumerateDirentsRunLfn;
|
||||
}
|
||||
|
||||
/* Check if this is the last lfn entry. */
|
||||
if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST))
|
||||
{
|
||||
SeqNum = (LfnEntry->SeqNum & ~FAT_FN_DIR_ENTRY_LAST);
|
||||
Checksum = LfnEntry->Checksum;
|
||||
|
||||
/* Check if we exceed max number of lfns */
|
||||
if (SeqNum > (FAT_FN_MAX_DIR_ENTIES + 1))
|
||||
{
|
||||
FileNameMaximumLength = 0;
|
||||
goto FatEnumerateDirentsRunLfn;
|
||||
}
|
||||
|
||||
/* Setup maximal expected lfn length */
|
||||
FileNameLength = SeqNum * FAT_LFN_NAME_LENGTH;
|
||||
|
||||
/* Validate the maximal expected lfn length */
|
||||
if (FileNameLength > FileNameMaximumLength)
|
||||
goto FatEnumerateDirentsRunLfn;
|
||||
}
|
||||
else if (!(LfnEntry->SeqNum == SeqNum
|
||||
&& LfnEntry->Checksum == Checksum))
|
||||
{
|
||||
/* Wrong SeqNum or CheckSum. */
|
||||
FileNameMaximumLength = 0;
|
||||
goto FatEnumerateDirentsRunLfn;
|
||||
}
|
||||
/* Gather file name */
|
||||
Lfn = Add2Ptr(FileName, (SeqNum * FAT_LFN_NAME_LENGTH)
|
||||
- sizeof(LfnEntry->NameC), PWSTR);
|
||||
RtlCopyMemory(Lfn, LfnEntry->NameC, sizeof(LfnEntry->NameC));
|
||||
Lfn -= (sizeof(LfnEntry->NameB) / sizeof(WCHAR));
|
||||
RtlCopyMemory(Lfn, LfnEntry->NameB, sizeof(LfnEntry->NameB));
|
||||
Lfn -= (sizeof(LfnEntry->NameA) / sizeof(WCHAR));
|
||||
RtlCopyMemory(Lfn, LfnEntry->NameA, sizeof(LfnEntry->NameA));
|
||||
|
||||
/* If last lfn determine exact lfn length. */
|
||||
if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST))
|
||||
{
|
||||
PWSTR LfnEnd = Add2Ptr(FileName, FileNameLength
|
||||
- sizeof(WCHAR), PWSTR);
|
||||
|
||||
/* Trim trailing 0xffff's */
|
||||
while (LfnEnd > Lfn && *LfnEnd == 0xffff) --LfnEnd;
|
||||
|
||||
/* Trim 0 terminator is the one is there. */
|
||||
if (*LfnEnd == 0x0) --LfnEnd;
|
||||
|
||||
/* Set correct lfn size */
|
||||
FileNameLength = (USHORT)PtrOffset(FileName, LfnEnd);
|
||||
}
|
||||
/* Setup vaidation for the next iteration */
|
||||
SeqNum = LfnEntry->SeqNum - 0x1;
|
||||
Checksum = LfnEntry->Checksum;
|
||||
FatEnumerateDirentsRunLfn:
|
||||
Entry = Add2Ptr(Entry, sizeof(DIR_ENTRY), PUCHAR);
|
||||
if (Entry > EndOfPage)
|
||||
{
|
||||
if (FatPinIsLastPage(&Context->Page))
|
||||
ExRaiseStatus(STATUS_NO_MORE_FILES);
|
||||
Entry = (PUCHAR) FatPinNextPage(&Context->Page);
|
||||
EndOfPage = FatPinEndOfPage(&Context->Page, PUCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
/* if lfn was found, validate and commit. */
|
||||
if (FileNameLength > 0 && FatLfnChecksum(Entry) == Checksum)
|
||||
{
|
||||
*Add2Ptr(InfoEntry, Context->LengthOffset, PULONG) = FileNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
*Add2Ptr(InfoEntry, Context->LengthOffset, PULONG) = 0;
|
||||
}
|
||||
/* TODO: Implement Filtering using Context->FileName & Context->CcbFlags. */
|
||||
|
||||
/* Copy the entry values. */
|
||||
Context->Offset += Context->CopyDirent((PFAT_ENUM_DIR_CONTEXT)Context, (PDIR_ENTRY) Entry, InfoEntry);
|
||||
|
||||
FatEnumerateDirentsNext:
|
||||
/* Get next entry */
|
||||
Entry = Add2Ptr(Entry, sizeof(DIR_ENTRY), PUCHAR);
|
||||
if (Entry > EndOfPage)
|
||||
{
|
||||
if (FatPinIsLastPage(&Context->Page))
|
||||
ExRaiseStatus(STATUS_NO_MORE_FILES);
|
||||
Entry = (PUCHAR) FatPinNextPage(&Context->Page);
|
||||
EndOfPage = FatPinEndOfPage(&Context->Page, PUCHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
FatDateTimeToSystemTime(OUT PLARGE_INTEGER SystemTime,
|
||||
IN PFAT_DATETIME FatDateTime,
|
||||
IN UCHAR TenMs OPTIONAL)
|
||||
{
|
||||
TIME_FIELDS TimeFields;
|
||||
|
||||
/* Setup time fields */
|
||||
TimeFields.Year = FatDateTime->Date.Year + 1980;
|
||||
TimeFields.Month = FatDateTime->Date.Month;
|
||||
TimeFields.Day = FatDateTime->Date.Day;
|
||||
TimeFields.Hour = FatDateTime->Time.Hour;
|
||||
TimeFields.Minute = FatDateTime->Time.Minute;
|
||||
TimeFields.Second = (FatDateTime->Time.DoubleSeconds << 1);
|
||||
|
||||
/* Adjust up to 10 milliseconds
|
||||
* if the parameter was supplied
|
||||
*/
|
||||
if (ARGUMENT_PRESENT(TenMs))
|
||||
{
|
||||
TimeFields.Second += TenMs / 100;
|
||||
TimeFields.Milliseconds = (TenMs % 100) * 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeFields.Milliseconds = 0;
|
||||
}
|
||||
|
||||
/* Fix seconds value that might get beyoud the bound */
|
||||
if (TimeFields.Second > 59) TimeFields.Second = 0;
|
||||
|
||||
/* Perform ceonversion to system time if possible */
|
||||
if (RtlTimeFieldsToTime(&TimeFields, SystemTime))
|
||||
{
|
||||
/* Convert to system time */
|
||||
ExLocalTimeToSystemTime(SystemTime, SystemTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set to default time if conversion failed */
|
||||
*SystemTime = FatGlobalData.DefaultFileTime;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes,
|
||||
IN PDIR_ENTRY Dirent)
|
||||
{
|
||||
/* Convert LastWriteTime */
|
||||
FatDateTimeToSystemTime(&FileTimes[FileLastWriteTime],
|
||||
&Dirent->LastWriteDateTime,
|
||||
0);
|
||||
/* All other time fileds are valid (according to MS)
|
||||
* only if Win31 compatability mode is set.
|
||||
*/
|
||||
if (FatGlobalData.Win31FileSystem)
|
||||
{
|
||||
/* We can avoid calling conversion routine
|
||||
* if time in dirent is 0 or equals to already
|
||||
* known time (LastWriteTime).
|
||||
*/
|
||||
if (Dirent->CreationDateTime.Value == 0)
|
||||
{
|
||||
/* Set it to default time */
|
||||
FileTimes[FileCreationTime] = FatGlobalData.DefaultFileTime;
|
||||
}
|
||||
else if (Dirent->CreationDateTime.Value
|
||||
== Dirent->LastWriteDateTime.Value)
|
||||
{
|
||||
/* Assign the already known time */
|
||||
FileTimes[FileCreationTime] = FileTimes[FileLastWriteTime];
|
||||
/* Adjust milliseconds from extra dirent field */
|
||||
FileTimes[FileCreationTime].QuadPart
|
||||
+= (ULONG) Dirent->CreationTimeTenMs * 100000;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform conversion */
|
||||
FatDateTimeToSystemTime(&FileTimes[FileCreationTime],
|
||||
&Dirent->CreationDateTime,
|
||||
Dirent->CreationTimeTenMs);
|
||||
}
|
||||
if (Dirent->LastAccessDate.Value == 0)
|
||||
{
|
||||
/* Set it to default time */
|
||||
FileTimes[FileLastAccessTime] = FatGlobalData.DefaultFileTime;
|
||||
}
|
||||
else if (Dirent->LastAccessDate.Value
|
||||
== Dirent->LastWriteDateTime.Date.Value)
|
||||
{
|
||||
/* Assign the already known time */
|
||||
FileTimes[FileLastAccessTime] = FileTimes[FileLastWriteTime];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform conversion */
|
||||
FAT_DATETIME LastAccessDateTime;
|
||||
|
||||
LastAccessDateTime.Date.Value = Dirent->LastAccessDate.Value;
|
||||
LastAccessDateTime.Time.Value = 0;
|
||||
FatDateTimeToSystemTime(&FileTimes[FileLastAccessTime],
|
||||
&LastAccessDateTime,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
Fat8dot3ToUnicodeString(OUT PUNICODE_STRING FileName,
|
||||
IN PUCHAR ShortName,
|
||||
IN UCHAR Flags)
|
||||
{
|
||||
PCHAR Name;
|
||||
UCHAR Index, Ext = 0;
|
||||
OEM_STRING Oem;
|
||||
|
||||
Name = Add2Ptr(FileName->Buffer, 0x0c, PCHAR);
|
||||
RtlCopyMemory(Name, ShortName, 0x0b);
|
||||
|
||||
/* Restore the name byte used to mark deleted entries */
|
||||
if (Name[0] == 0x05)
|
||||
Name[0] |= 0xe0;
|
||||
|
||||
/* Locate the end of name part */
|
||||
for (Index = 0; Index < 0x08
|
||||
&& Name[Index] != 0x20; Index++);
|
||||
|
||||
/* Locate the end of extension part */
|
||||
if (Name[0x08] != 0x20)
|
||||
{
|
||||
Ext = 0x2;
|
||||
Name[Index++] = 0x2e;
|
||||
Name[Index++] = Name[0x08];
|
||||
if ((Name[Index] = Name[0x09]) != 0x20)
|
||||
{
|
||||
Index ++; Ext ++;
|
||||
}
|
||||
if ((Name[Index] = Name[0x0a]) != 0x20)
|
||||
{
|
||||
Index ++; Ext ++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform Oem to Unicode conversion. */
|
||||
Oem.Buffer = Name;
|
||||
Oem.Length = Index;
|
||||
Oem.MaximumLength = Index;
|
||||
RtlOemStringToUnicodeString(FileName, &Oem, FALSE);
|
||||
Index = FlagOn(Flags, FAT_CASE_LOWER_BASE|FAT_CASE_LOWER_EXT);
|
||||
if (Index > 0)
|
||||
{
|
||||
/* Downcase the whole name */
|
||||
if (Index == (FAT_CASE_LOWER_BASE|FAT_CASE_LOWER_EXT))
|
||||
{
|
||||
RtlUpcaseUnicodeString(FileName, FileName, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Index == FAT_CASE_LOWER_EXT)
|
||||
{
|
||||
/* Set extension for downcase */
|
||||
Oem.Length = Ext * sizeof(WCHAR);
|
||||
Oem.Buffer = Add2Ptr(FileName->Buffer,
|
||||
FileName->Length - Oem.Length,
|
||||
PSTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set base name for downcase */
|
||||
Oem.Buffer = (PSTR) FileName->Buffer;
|
||||
Oem.Length = FileName->Length - Ext * sizeof(WCHAR);
|
||||
}
|
||||
Oem.MaximumLength = Oem.Length;
|
||||
RtlUpcaseUnicodeString((PUNICODE_STRING)&Oem,
|
||||
(PUNICODE_STRING)&Oem,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_DIRECTORY_INFORMATION Info;
|
||||
Info = (PFILE_DIRECTORY_INFORMATION) Buffer;
|
||||
Info->FileIndex = 0;
|
||||
/* Setup Attributes */
|
||||
Info->FileAttributes = Dirent->Attributes;
|
||||
/* Setup times */
|
||||
FatQueryFileTimes(&Info->CreationTime, Dirent);
|
||||
/* Setup sizes */
|
||||
Info->EndOfFile.QuadPart = Dirent->FileSize;
|
||||
Info->AllocationSize.QuadPart =
|
||||
(Context->BytesPerClusterMask + Dirent->FileSize)
|
||||
& ~(Context->BytesPerClusterMask);
|
||||
FatQueryFileName(Info, Dirent);
|
||||
Info->NextEntryOffset = sizeof(*Info);
|
||||
return Info->NextEntryOffset + Info->FileNameLength;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_FULL_DIR_INFORMATION Info;
|
||||
Info = (PFILE_FULL_DIR_INFORMATION) Buffer;
|
||||
Info->FileIndex = 0;
|
||||
Info->EaSize = 0;
|
||||
/* Setup Attributes */
|
||||
Info->FileAttributes = Dirent->Attributes;
|
||||
/* Setup times */
|
||||
FatQueryFileTimes(&Info->CreationTime, Dirent);
|
||||
/* Setup sizes */
|
||||
Info->EndOfFile.QuadPart = Dirent->FileSize;
|
||||
Info->AllocationSize.QuadPart =
|
||||
(Context->BytesPerClusterMask + Dirent->FileSize)
|
||||
& ~(Context->BytesPerClusterMask);
|
||||
FatQueryFileName(Info, Dirent);
|
||||
Info->NextEntryOffset = sizeof(*Info);
|
||||
return Info->NextEntryOffset + Info->FileNameLength;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_ID_FULL_DIR_INFORMATION Info;
|
||||
Info = (PFILE_ID_FULL_DIR_INFORMATION) Buffer;
|
||||
Info->FileId.QuadPart = 0;
|
||||
Info->FileIndex = 0;
|
||||
Info->EaSize = 0;
|
||||
/* Setup Attributes */
|
||||
Info->FileAttributes = Dirent->Attributes;
|
||||
/* Setup times */
|
||||
FatQueryFileTimes(&Info->CreationTime, Dirent);
|
||||
/* Setup sizes */
|
||||
Info->EndOfFile.QuadPart = Dirent->FileSize;
|
||||
Info->AllocationSize.QuadPart =
|
||||
(Context->BytesPerClusterMask + Dirent->FileSize)
|
||||
& ~(Context->BytesPerClusterMask);
|
||||
FatQueryFileName(Info, Dirent);
|
||||
Info->NextEntryOffset = sizeof(*Info);
|
||||
return Info->NextEntryOffset + Info->FileNameLength;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_BOTH_DIR_INFORMATION Info;
|
||||
Info = (PFILE_BOTH_DIR_INFORMATION) Buffer;
|
||||
Info->FileIndex = 0;
|
||||
Info->EaSize = 0;
|
||||
/* Setup Attributes */
|
||||
Info->FileAttributes = Dirent->Attributes;
|
||||
/* Setup times */
|
||||
FatQueryFileTimes(&Info->CreationTime, Dirent);
|
||||
/* Setup sizes */
|
||||
Info->EndOfFile.QuadPart = Dirent->FileSize;
|
||||
Info->AllocationSize.QuadPart =
|
||||
(Context->BytesPerClusterMask + Dirent->FileSize)
|
||||
& ~(Context->BytesPerClusterMask);
|
||||
FatQueryBothFileName(Info, Dirent);
|
||||
Info->NextEntryOffset = sizeof(*Info);
|
||||
return Info->NextEntryOffset + Info->FileNameLength;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_ID_BOTH_DIR_INFORMATION Info;
|
||||
Info = (PFILE_ID_BOTH_DIR_INFORMATION) Buffer;
|
||||
Info->FileId.QuadPart = 0;
|
||||
Info->FileIndex = 0;
|
||||
Info->EaSize = 0;
|
||||
/* Setup Attributes */
|
||||
Info->FileAttributes = Dirent->Attributes;
|
||||
/* Setup times */
|
||||
FatQueryFileTimes(&Info->CreationTime, Dirent);
|
||||
/* Setup sizes */
|
||||
Info->EndOfFile.QuadPart = Dirent->FileSize;
|
||||
Info->AllocationSize.QuadPart =
|
||||
(Context->BytesPerClusterMask + Dirent->FileSize)
|
||||
& ~(Context->BytesPerClusterMask);
|
||||
FatQueryBothFileName(Info, Dirent);
|
||||
Info->NextEntryOffset = sizeof(*Info);
|
||||
return Info->NextEntryOffset + Info->FileNameLength;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_NAMES_INFORMATION Info;
|
||||
Info = (PFILE_NAMES_INFORMATION) Buffer;
|
||||
Info->FileIndex = 0;
|
||||
FatQueryFileName(Info, Dirent);
|
||||
Info->NextEntryOffset = sizeof(*Info);
|
||||
return Info->NextEntryOffset + Info->FileNameLength;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN PDIR_ENTRY Dirent,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PFILE_OBJECTID_INFORMATION Info;
|
||||
Info = (PFILE_OBJECTID_INFORMATION) Buffer;
|
||||
Info->FileReference = 0;
|
||||
((PLONGLONG)Info->ObjectId)[0] = 0LL;
|
||||
((PLONGLONG)Info->ObjectId)[1] = 0LL;
|
||||
return sizeof(*Info);
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -66,21 +66,6 @@ FatReadStreamFile(PVCB Vcb,
|
|||
PBCB *Bcb,
|
||||
PVOID *Buffer);
|
||||
|
||||
/* ------------------------------------------------------ blockdev.c */
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
FatPerformLboIo(
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN PLARGE_INTEGER Offset,
|
||||
IN SIZE_T Length);
|
||||
|
||||
NTSTATUS
|
||||
FatPerformVirtualNonCachedIo(
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN PLARGE_INTEGER Offset,
|
||||
IN SIZE_T Length);
|
||||
|
||||
/* ----------------------------------------------------------- dir.c */
|
||||
|
||||
NTSTATUS NTAPI
|
||||
|
@ -215,6 +200,10 @@ FatWriteBlocks(FF_T_UINT8 *pBuffer, FF_T_UINT32 SectorAddress, FF_T_UINT32 Count
|
|||
FF_T_SINT32
|
||||
FatReadBlocks(FF_T_UINT8 *pBuffer, FF_T_UINT32 SectorAddress, FF_T_UINT32 Count, void *pParam);
|
||||
|
||||
VOID NTAPI
|
||||
FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes,
|
||||
IN PDIR_ENTRY Dirent);
|
||||
|
||||
/* --------------------------------------------------------- lock.c */
|
||||
|
||||
NTSTATUS NTAPI
|
||||
|
@ -249,34 +238,17 @@ NTAPI
|
|||
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
|
||||
|
||||
/* ----------------------------------------------------------- fat.c */
|
||||
PVOID
|
||||
FatPinPage(
|
||||
PFAT_PAGE_CONTEXT Context,
|
||||
LONGLONG ByteOffset);
|
||||
|
||||
PVOID
|
||||
FatPinNextPage(
|
||||
PFAT_PAGE_CONTEXT Context);
|
||||
|
||||
NTSTATUS
|
||||
NTSTATUS NTAPI
|
||||
FatInitializeVcb(
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PDEVICE_OBJECT TargetDeviceObject,
|
||||
IN PVPB Vpb);
|
||||
|
||||
VOID
|
||||
VOID NTAPI
|
||||
FatUninitializeVcb(
|
||||
IN PVCB Vcb);
|
||||
|
||||
ULONG
|
||||
FatScanFat(
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG Vbo, OUT PLONGLONG Lbo,
|
||||
IN OUT PLONGLONG Length,
|
||||
OUT PULONG Index,
|
||||
IN BOOLEAN CanWait);
|
||||
|
||||
/* ------------------------------------------------------ device.c */
|
||||
|
||||
NTSTATUS NTAPI
|
||||
|
@ -291,36 +263,7 @@ FatPerformDevIoCtrl(PDEVICE_OBJECT DeviceObject,
|
|||
ULONG OutputBufferSize,
|
||||
BOOLEAN Override);
|
||||
|
||||
/* ------------------------------------------------------ direntry.c */
|
||||
VOID
|
||||
FatFindDirent(IN OUT PFAT_FIND_DIRENT_CONTEXT Context,
|
||||
OUT PDIR_ENTRY* Dirent,
|
||||
OUT PUNICODE_STRING LongFileName OPTIONAL);
|
||||
|
||||
VOID
|
||||
FatEnumerateDirents(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
|
||||
IN SIZE_T Offset);
|
||||
|
||||
VOID
|
||||
FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes,
|
||||
IN PDIR_ENTRY Dirent);
|
||||
|
||||
/* ----------------------------------------------------------- fcb.c */
|
||||
PFCB
|
||||
FatLookupFcbByName(
|
||||
IN PFCB ParentFcb,
|
||||
IN PUNICODE_STRING Name);
|
||||
|
||||
BOOLEAN
|
||||
FatLinkFcbNames(
|
||||
IN PFCB ParentFcb,
|
||||
IN PFCB Fcb);
|
||||
|
||||
VOID
|
||||
FatUnlinkFcbNames(
|
||||
IN PFCB ParentFcb,
|
||||
IN PFCB Fcb);
|
||||
|
||||
PFCB NTAPI
|
||||
FatCreateFcb(
|
||||
IN PFAT_IRP_CONTEXT IrpContext,
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<library>pseh</library>
|
||||
<file>blockdev.c</file>
|
||||
<file>cleanup.c</file>
|
||||
<file>close.c</file>
|
||||
<file>create.c</file>
|
||||
<file>device.c</file>
|
||||
<file>dir.c</file>
|
||||
<file>direntry.c</file>
|
||||
<file>ea.c</file>
|
||||
<file>fastfat.c</file>
|
||||
<file>fat.c</file>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: drivers/filesystems/fastfat/fat.c
|
||||
* PURPOSE: FAT support routines
|
||||
* PROGRAMMERS: Alexey Vlasov
|
||||
* PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
@ -12,370 +12,12 @@
|
|||
#include "fastfat.h"
|
||||
|
||||
/* PROTOTYPES ***************************************************************/
|
||||
typedef struct _FAT_SCAN_CONTEXT
|
||||
{
|
||||
PFILE_OBJECT FileObject;
|
||||
LARGE_INTEGER PageOffset;
|
||||
LONGLONG BeyondLastEntryOffset;
|
||||
PVOID PageBuffer;
|
||||
PBCB PageBcb;
|
||||
} FAT_SCAN_CONTEXT;
|
||||
|
||||
#define FatEntryToDataOffset(xEntry, xVcb) \
|
||||
((xVcb)->DataArea + (((LONGLONG) ((xEntry) - 0x02)) << (xVcb)->BytesPerClusterLog))
|
||||
|
||||
#define FatDataOffsetToEntry(xOffset, xVcb) \
|
||||
((ULONG) ((xOffset - (xVcb)->DataArea) >> (xVcb)->BytesPerClusterLog) + 0x02)
|
||||
|
||||
ULONG
|
||||
FatScanFat32ForContinousRun(IN OUT PFAT_PAGE_CONTEXT Context,
|
||||
IN OUT PULONG Index,
|
||||
IN BOOLEAN CanWait);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb);
|
||||
|
||||
/* VARIABLES ****************************************************************/
|
||||
FAT_METHODS Fat12Methods = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
FAT_METHODS Fat16Methods = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
FAT_METHODS Fat32Methods = {
|
||||
FatScanFat32ForContinousRun,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
/**
|
||||
* Pins the page containing ByteOffset byte.
|
||||
*
|
||||
* @param Context
|
||||
* Keeps current BCB, Buffer pointer
|
||||
* and maintains current and next page offset.
|
||||
*
|
||||
* @param ByteOffset
|
||||
* Offset from the beginning of the data stream to be pinned.
|
||||
*
|
||||
* @return
|
||||
* Pointer to the buffer starting with the specified ByteOffset.
|
||||
*/
|
||||
PVOID
|
||||
FatPinPage(
|
||||
PFAT_PAGE_CONTEXT Context,
|
||||
LONGLONG ByteOffset)
|
||||
{
|
||||
SIZE_T OffsetWithinPage;
|
||||
|
||||
OffsetWithinPage = (SIZE_T) (ByteOffset & (PAGE_SIZE - 1));
|
||||
ByteOffset -= OffsetWithinPage;
|
||||
if (ByteOffset != Context->Offset.QuadPart)
|
||||
{
|
||||
Context->Offset.QuadPart = ByteOffset;
|
||||
if (Context->Bcb != NULL)
|
||||
{
|
||||
CcUnpinData(Context->Bcb);
|
||||
Context->Bcb = NULL;
|
||||
}
|
||||
if (!CcMapData(Context->FileObject,
|
||||
&Context->Offset,
|
||||
PAGE_SIZE,
|
||||
Context->CanWait,
|
||||
&Context->Bcb,
|
||||
&Context->Buffer))
|
||||
{
|
||||
Context->Offset.QuadPart = 0LL;
|
||||
ExRaiseStatus(STATUS_CANT_WAIT);
|
||||
}
|
||||
}
|
||||
Context->EndOfPage.QuadPart =
|
||||
Context->Offset.QuadPart + PAGE_SIZE;
|
||||
if (Context->EndOfPage.QuadPart
|
||||
> Context->EndOfData.QuadPart)
|
||||
{
|
||||
Context->ValidLength = (SIZE_T)
|
||||
(Context->EndOfData.QuadPart
|
||||
- Context->Offset.QuadPart);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context->ValidLength = PAGE_SIZE;
|
||||
}
|
||||
return Add2Ptr(Context->Buffer, OffsetWithinPage, PVOID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins the next page of data stream.
|
||||
*
|
||||
* @param Context
|
||||
* Keeps current BCB, Buffer pointer
|
||||
* and maintains current and next page offset.
|
||||
*
|
||||
* @return
|
||||
* Pointer to the buffer starting with the beginning of the next page.
|
||||
*/
|
||||
PVOID
|
||||
FatPinNextPage(
|
||||
PFAT_PAGE_CONTEXT Context)
|
||||
{
|
||||
ASSERT ((Context->Offset.QuadPart % PAGE_SIZE)
|
||||
!= (Context->EndOfPage.QuadPart % PAGE_SIZE)
|
||||
&& Context->Bcb != NULL);
|
||||
|
||||
ASSERT (Context->ValidLength == PAGE_SIZE);
|
||||
|
||||
Context->Offset = Context->EndOfPage;
|
||||
CcUnpinData(Context->Bcb);
|
||||
if (!CcMapData(Context->FileObject,
|
||||
&Context->Offset,
|
||||
PAGE_SIZE,
|
||||
Context->CanWait,
|
||||
&Context->Bcb,
|
||||
&Context->Buffer))
|
||||
{
|
||||
Context->Bcb = NULL;
|
||||
Context->Offset.QuadPart = 0LL;
|
||||
ExRaiseStatus(STATUS_CANT_WAIT);
|
||||
}
|
||||
Context->EndOfPage.QuadPart =
|
||||
Context->Offset.QuadPart + PAGE_SIZE;
|
||||
return Context->Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the index of the set bit.
|
||||
*
|
||||
* @param Number
|
||||
* Number having a single bit set.
|
||||
*
|
||||
* @return
|
||||
* Index of the set bit.
|
||||
*/
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
FatPowerOfTwo(
|
||||
ULONG Number)
|
||||
{
|
||||
ULONG Temp;
|
||||
Temp = Number
|
||||
- ((Number >> 1) & 033333333333)
|
||||
- ((Number >> 2) & 011111111111);
|
||||
return (((Temp + (Temp >> 3)) & 030707070707) % 63);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans FAT32 for continous chain of clusters
|
||||
*
|
||||
* @param Context
|
||||
* Pointer to FAT_PAGE_CONTEXT.
|
||||
*
|
||||
* @param Index
|
||||
* Supplies the Index of the first cluster
|
||||
* and receves the last index after the last
|
||||
* cluster in the chain.
|
||||
*
|
||||
* @param CanWait
|
||||
* Indicates if the context allows blocking.
|
||||
*
|
||||
* @return
|
||||
* Value of the last claster terminated the scan.
|
||||
*
|
||||
* @note
|
||||
* Raises STATUS_CANT_WAIT race condition.
|
||||
*/
|
||||
ULONG
|
||||
FatScanFat32ForContinousRun(IN OUT PFAT_PAGE_CONTEXT Context,
|
||||
IN OUT PULONG Index,
|
||||
IN BOOLEAN CanWait)
|
||||
{
|
||||
PULONG Entry, EndOfPage;
|
||||
|
||||
Entry = FatPinPage(Context, ((LONGLONG) *Index) << 0x2);
|
||||
EndOfPage = FatPinEndOfPage(Context, PULONG);
|
||||
while (TRUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if ((*Entry & FAT_CLUSTER_LAST) != ++(*Index))
|
||||
return (*Entry & FAT_CLUSTER_LAST);
|
||||
} while (++Entry < EndOfPage);
|
||||
/* Check if this is the last available entry */
|
||||
if (FatPinIsLastPage(Context))
|
||||
break;
|
||||
Entry = (PULONG) FatPinNextPage(Context);
|
||||
EndOfPage = FatPinEndOfPage(Context, PULONG);
|
||||
}
|
||||
return (*Index - 1);
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatSetFat32ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
|
||||
IN ULONG Index,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN CanWait)
|
||||
{
|
||||
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatScanFat32ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
|
||||
IN OUT PULONG Index,
|
||||
IN ULONG IndexValue,
|
||||
IN BOOLEAN CanWait)
|
||||
{
|
||||
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
ULONG
|
||||
FatSetFat32ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
|
||||
IN ULONG Index,
|
||||
IN ULONG Length,
|
||||
IN ULONG IndexValue,
|
||||
IN BOOLEAN CanWait)
|
||||
{
|
||||
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries file MCB for the specified region [Vbo, Vbo + Length],
|
||||
* returns the number of runs in the region as well as the first
|
||||
* run of the range itself.
|
||||
* If the specified region is not fully cached in MCB the routine
|
||||
* scans FAT for the file and fills the MCB until the file offset
|
||||
* (defined as Vbo + Length) is reached.
|
||||
*
|
||||
* @param Fcb
|
||||
* Pointer to FCB structure for the file.
|
||||
*
|
||||
* @param Vbo
|
||||
* Virtual Byte Offset in the file.
|
||||
*
|
||||
* @param Lbo
|
||||
* Receives the Value of Logical Byte offset corresponding
|
||||
* to supplied Vbo Value.
|
||||
*
|
||||
* @param Length
|
||||
* Supplies file range length to be examined and receives
|
||||
* the length of first run.
|
||||
*
|
||||
* @param OutIndex
|
||||
* Receives the index (in MCB cache) of first run.
|
||||
*
|
||||
* @return
|
||||
* Incremented index of the last run (+1).
|
||||
*
|
||||
* @note
|
||||
* Should be called by I/O routines to split the I/O operation
|
||||
* into sequential or parallel I/O operations.
|
||||
*/
|
||||
ULONG
|
||||
FatScanFat(IN PFCB Fcb,
|
||||
IN LONGLONG Vbo,
|
||||
OUT PLONGLONG Lbo,
|
||||
IN OUT PLONGLONG Length,
|
||||
OUT PULONG Index,
|
||||
IN BOOLEAN CanWait)
|
||||
{
|
||||
LONGLONG CurrentLbo, CurrentVbo, BeyondLastVbo, CurrentLength;
|
||||
ULONG Entry, NextEntry, NumberOfEntries, CurrentIndex;
|
||||
FAT_PAGE_CONTEXT Context;
|
||||
PVCB Vcb;
|
||||
|
||||
/* Some often used values */
|
||||
Vcb = Fcb->Vcb;
|
||||
CurrentIndex = 0;
|
||||
BeyondLastVbo = Vbo + *Length;
|
||||
CurrentLength = ((LONGLONG) Vcb->Clusters) << Vcb->BytesPerClusterLog;
|
||||
if (BeyondLastVbo > CurrentLength)
|
||||
BeyondLastVbo = CurrentLength;
|
||||
/* Try to locate first run */
|
||||
if (FsRtlLookupLargeMcbEntry(&Fcb->Mcb, Vbo, Lbo, Length, NULL, NULL, Index))
|
||||
{
|
||||
/* Check if we have a single mapped run */
|
||||
if (Vbo >= BeyondLastVbo)
|
||||
goto FatScanFcbFatExit;
|
||||
} else {
|
||||
*Length = 0L;
|
||||
}
|
||||
/* Get the first scan startup values */
|
||||
if (FsRtlLookupLastLargeMcbEntryAndIndex(
|
||||
&Fcb->Mcb, &CurrentVbo, &CurrentLbo, &CurrentIndex))
|
||||
{
|
||||
Entry = FatDataOffsetToEntry(CurrentLbo, Vcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Map is empty, set up initial values */
|
||||
Entry = Fcb->FirstCluster;
|
||||
if (Entry <= 0x2)
|
||||
ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
|
||||
if (Entry >= Vcb->Clusters)
|
||||
{
|
||||
if (Entry < FAT_CLUSTER_LAST)
|
||||
ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
|
||||
BeyondLastVbo = 0LL;
|
||||
}
|
||||
CurrentIndex = 0L;
|
||||
CurrentVbo = 0LL;
|
||||
}
|
||||
/* Initialize Context */
|
||||
RtlZeroMemory(&Context, sizeof(Context));
|
||||
Context.FileObject = Vcb->StreamFileObject;
|
||||
Context.EndOfData.QuadPart = Vcb->BeyondLastClusterInFat;
|
||||
|
||||
while (CurrentVbo < BeyondLastVbo)
|
||||
{
|
||||
/* Locate Continous run starting with the current entry */
|
||||
NumberOfEntries = Entry;
|
||||
NextEntry = Vcb->Methods.ScanContinousRun(
|
||||
&Context, &NumberOfEntries, CanWait);
|
||||
NumberOfEntries -= Entry;
|
||||
/* Check value that terminated the for being valid for FAT */
|
||||
if (NextEntry <= 0x2)
|
||||
ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
|
||||
if (NextEntry >= Vcb->Clusters)
|
||||
{
|
||||
if (NextEntry < FAT_CLUSTER_LAST)
|
||||
ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
|
||||
break;
|
||||
}
|
||||
/* Add new run */
|
||||
CurrentLength = ((LONGLONG) NumberOfEntries)
|
||||
<< Vcb->BytesPerClusterLog;
|
||||
FsRtlAddLargeMcbEntry(&Fcb->Mcb,
|
||||
CurrentVbo,
|
||||
FatEntryToDataOffset(Entry, Vcb),
|
||||
CurrentLength);
|
||||
/* Setup next iteration */
|
||||
Entry = NextEntry;
|
||||
CurrentVbo += CurrentLength;
|
||||
CurrentIndex ++;
|
||||
}
|
||||
if (*Length == 0LL && CurrentIndex > 0)
|
||||
{
|
||||
if (!FsRtlLookupLargeMcbEntry(&Fcb->Mcb,
|
||||
Vbo, Lbo, Length, NULL, NULL, Index))
|
||||
{
|
||||
*Index = 0L;
|
||||
*Lbo = 0LL;
|
||||
}
|
||||
}
|
||||
FatScanFcbFatExit:
|
||||
return CurrentIndex;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
|
@ -400,7 +42,29 @@ FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb)
|
|||
&& (Bpb->SectorsPerFat > 0 || !Bpb->MirrorDisabled));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the index of the set bit.
|
||||
*
|
||||
* @param Number
|
||||
* Number having a single bit set.
|
||||
*
|
||||
* @return
|
||||
* Index of the set bit.
|
||||
*/
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
FatPowerOfTwo(
|
||||
ULONG Number)
|
||||
{
|
||||
ULONG Temp;
|
||||
Temp = Number
|
||||
- ((Number >> 1) & 033333333333)
|
||||
- ((Number >> 2) & 011111111111);
|
||||
return (((Temp + (Temp >> 3)) & 030707070707) % 63);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FatiInitializeVcb(PVCB Vcb)
|
||||
{
|
||||
ULONG ClustersCapacity;
|
||||
|
@ -420,17 +84,17 @@ FatiInitializeVcb(PVCB Vcb)
|
|||
if (Vcb->BytesPerClusterLog < 4087)
|
||||
{
|
||||
Vcb->IndexDepth = 0x0c;
|
||||
Vcb->Methods = Fat12Methods;
|
||||
//Vcb->Methods = Fat12Methods;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vcb->IndexDepth = 0x10;
|
||||
Vcb->Methods = Fat16Methods;
|
||||
//Vcb->Methods = Fat16Methods;
|
||||
}
|
||||
/* Large Sectors are used for FAT32 */
|
||||
if (Vcb->Bpb.Sectors == 0) {
|
||||
Vcb->IndexDepth = 0x20;
|
||||
Vcb->Methods = Fat32Methods;
|
||||
//Vcb->Methods = Fat32Methods;
|
||||
}
|
||||
ClustersCapacity = (SectorsToBytes(Vcb, Vcb->Sectors) * 0x8 / Vcb->IndexDepth) - 1;
|
||||
if (Vcb->Clusters > ClustersCapacity)
|
||||
|
@ -445,6 +109,7 @@ FatiInitializeVcb(PVCB Vcb)
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
FatInitializeVcb(IN PFAT_IRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PDEVICE_OBJECT TargetDeviceObject,
|
||||
|
@ -558,6 +223,7 @@ FatInitializeVcbCleanup:
|
|||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FatUninitializeVcb(IN PVCB Vcb)
|
||||
{
|
||||
LARGE_INTEGER ZeroSize;
|
||||
|
|
|
@ -388,6 +388,14 @@ typedef enum _TYPE_OF_OPEN
|
|||
EaFile
|
||||
} TYPE_OF_OPEN;
|
||||
|
||||
typedef enum _FILE_TIME_INDEX
|
||||
{
|
||||
FileCreationTime = 0,
|
||||
FileLastAccessTime,
|
||||
FileLastWriteTime,
|
||||
FileChangeTime
|
||||
} FILE_TIME_INDEX;
|
||||
|
||||
#define CCB_SEARCH_RETURN_SINGLE_ENTRY 0x01
|
||||
#define CCB_SEARCH_PATTERN_LEGAL_8DOT3 0x02
|
||||
#define CCB_SEARCH_PATTERN_HAS_WILD_CARD 0x04
|
||||
|
|
|
@ -100,4 +100,114 @@ FF_FILE *FF_OpenW(FF_IOMAN *pIoman, PUNICODE_STRING pathW, FF_T_UINT8 Mode, FF_E
|
|||
return FF_Open(pIoman, AnsiName.Buffer, Mode, pError);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
FatDateTimeToSystemTime(OUT PLARGE_INTEGER SystemTime,
|
||||
IN PFAT_DATETIME FatDateTime,
|
||||
IN UCHAR TenMs OPTIONAL)
|
||||
{
|
||||
TIME_FIELDS TimeFields;
|
||||
|
||||
/* Setup time fields */
|
||||
TimeFields.Year = FatDateTime->Date.Year + 1980;
|
||||
TimeFields.Month = FatDateTime->Date.Month;
|
||||
TimeFields.Day = FatDateTime->Date.Day;
|
||||
TimeFields.Hour = FatDateTime->Time.Hour;
|
||||
TimeFields.Minute = FatDateTime->Time.Minute;
|
||||
TimeFields.Second = (FatDateTime->Time.DoubleSeconds << 1);
|
||||
|
||||
/* Adjust up to 10 milliseconds
|
||||
* if the parameter was supplied
|
||||
*/
|
||||
if (ARGUMENT_PRESENT(TenMs))
|
||||
{
|
||||
TimeFields.Second += TenMs / 100;
|
||||
TimeFields.Milliseconds = (TenMs % 100) * 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeFields.Milliseconds = 0;
|
||||
}
|
||||
|
||||
/* Fix seconds value that might get beyoud the bound */
|
||||
if (TimeFields.Second > 59) TimeFields.Second = 0;
|
||||
|
||||
/* Perform ceonversion to system time if possible */
|
||||
if (RtlTimeFieldsToTime(&TimeFields, SystemTime))
|
||||
{
|
||||
/* Convert to system time */
|
||||
ExLocalTimeToSystemTime(SystemTime, SystemTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set to default time if conversion failed */
|
||||
*SystemTime = FatGlobalData.DefaultFileTime;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make it a helper around FullFAT library
|
||||
VOID
|
||||
NTAPI
|
||||
FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes,
|
||||
IN PDIR_ENTRY Dirent)
|
||||
{
|
||||
/* Convert LastWriteTime */
|
||||
FatDateTimeToSystemTime(&FileTimes[FileLastWriteTime],
|
||||
&Dirent->LastWriteDateTime,
|
||||
0);
|
||||
/* All other time fileds are valid (according to MS)
|
||||
* only if Win31 compatability mode is set.
|
||||
*/
|
||||
if (FatGlobalData.Win31FileSystem)
|
||||
{
|
||||
/* We can avoid calling conversion routine
|
||||
* if time in dirent is 0 or equals to already
|
||||
* known time (LastWriteTime).
|
||||
*/
|
||||
if (Dirent->CreationDateTime.Value == 0)
|
||||
{
|
||||
/* Set it to default time */
|
||||
FileTimes[FileCreationTime] = FatGlobalData.DefaultFileTime;
|
||||
}
|
||||
else if (Dirent->CreationDateTime.Value
|
||||
== Dirent->LastWriteDateTime.Value)
|
||||
{
|
||||
/* Assign the already known time */
|
||||
FileTimes[FileCreationTime] = FileTimes[FileLastWriteTime];
|
||||
/* Adjust milliseconds from extra dirent field */
|
||||
FileTimes[FileCreationTime].QuadPart
|
||||
+= (ULONG) Dirent->CreationTimeTenMs * 100000;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform conversion */
|
||||
FatDateTimeToSystemTime(&FileTimes[FileCreationTime],
|
||||
&Dirent->CreationDateTime,
|
||||
Dirent->CreationTimeTenMs);
|
||||
}
|
||||
if (Dirent->LastAccessDate.Value == 0)
|
||||
{
|
||||
/* Set it to default time */
|
||||
FileTimes[FileLastAccessTime] = FatGlobalData.DefaultFileTime;
|
||||
}
|
||||
else if (Dirent->LastAccessDate.Value
|
||||
== Dirent->LastWriteDateTime.Date.Value)
|
||||
{
|
||||
/* Assign the already known time */
|
||||
FileTimes[FileLastAccessTime] = FileTimes[FileLastWriteTime];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform conversion */
|
||||
FAT_DATETIME LastAccessDateTime;
|
||||
|
||||
LastAccessDateTime.Date.Value = Dirent->LastAccessDate.Value;
|
||||
LastAccessDateTime.Time.Value = 0;
|
||||
FatDateTimeToSystemTime(&FileTimes[FileLastAccessTime],
|
||||
&LastAccessDateTime,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* FILE: drivers/filesystems/fastfat/rw.c
|
||||
* PURPOSE: Read/write support
|
||||
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
|
||||
* Alexey Vlasov
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
|
Loading…
Reference in a new issue