[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:
Aleksey Bragin 2009-10-20 10:02:27 +00:00
parent 87f0ae4ac5
commit 4f4bec88a5
8 changed files with 152 additions and 1650 deletions

View file

@ -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 */

View file

@ -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 */

View file

@ -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,

View file

@ -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>

View 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;

View file

@ -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

View file

@ -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 */

View file

@ -4,7 +4,6 @@
* FILE: drivers/filesystems/fastfat/rw.c
* PURPOSE: Read/write support
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
* Alexey Vlasov
*/
/* INCLUDES *****************************************************************/