Alex Vlasov

- blockdev.c: Implement misc helper functions.
- direntry.c: Some changes to query dirents info for IRP_MJ_DIRECTORY_CONTROL, and the routine that locates a single dirent for IRP_MJ_CREATE.
- fastfat.c: Implement queuing support (FatQueueRequest / FatDequeueRequest).
- fat.c: Cleanup, use helper functions FatPin*Page.
- fcb.c: Add FCB helper routines.
- Header files: Change structures for future usage.
- Add PSEH2 library usage.

svn path=/trunk/; revision=39746
This commit is contained in:
Aleksey Bragin
2009-02-25 12:25:06 +00:00
parent bc97ce2e19
commit 228454149b
10 changed files with 1566 additions and 478 deletions

View File

@@ -3,7 +3,7 @@
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/blockdev.c
* PURPOSE: Temporary sector reading support
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
* PROGRAMMERS: Alexey Vlasov
*/
/* INCLUDES *****************************************************************/
@@ -12,5 +12,460 @@
#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;
}
PVOID
FatMapUserBuffer(
IN OUT PIRP Irp)
/*
* FUNCTION:
*
*
* ARGUMENTS:
* IrpContext = Pointer to FCB structure for the file.
* Irp = Pointer to the IRP structure
* RETURNS: Status Value.
* NOTES:
*/
{
PVOID Address;
if (Irp->MdlAddress == NULL)
return Irp->UserBuffer;
Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (Address == NULL)
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
return Address;
}
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

@@ -12,37 +12,6 @@
#include "fastfat.h"
/* PROTOTYPES ***************************************************************/
#define BYTES_PER_DIRENT_LOG 0x05
typedef struct _FAT_ENUM_DIR_CONTEXT *PFAT_ENUM_DIR_CONTEXT;
typedef ULONG (*PFAT_COPY_DIRENT_ROUTINE) (struct _FAT_ENUM_DIR_CONTEXT *, PDIR_ENTRY, PVOID);
typedef struct _FAT_ENUM_DIR_CONTEXT
{
PFILE_OBJECT FileObject;
LARGE_INTEGER PageOffset;
LONGLONG BeyondLastEntryOffset;
PVOID PageBuffer;
PBCB PageBcb;
/*
* We should always cache short file name
* because we never know if there is a long
* name for the dirent and when we find out
* that our base dirent might become unpinned.
*/
UCHAR DirentFileName[RTL_FIELD_SIZE(DIR_ENTRY, FileName) + 1];
PFAT_COPY_DIRENT_ROUTINE CopyDirent;
LONGLONG BytesPerClusterMask;
/*
* The following fields are
* set by the copy routine
*/
PULONG NextEntryOffset;
PULONG FileNameLength;
PWCHAR FileName;
} FAT_ENUM_DIR_CONTEXT;
typedef enum _FILE_TIME_INDEX
{
@@ -51,10 +20,7 @@ typedef enum _FILE_TIME_INDEX
FileLastWriteTime,
FileChangeTime
} FILE_TIME_INDEX;
VOID
FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes,
IN PDIR_ENTRY Dirent);
VOID
Fat8dot3ToUnicodeString(OUT PUNICODE_STRING FileName,
@@ -62,42 +28,427 @@ Fat8dot3ToUnicodeString(OUT PUNICODE_STRING FileName,
IN UCHAR Flags);
ULONG
FatDirentToDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer);
ULONG
FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer);
ULONG
FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer);
ULONG
FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer);
ULONG
FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer);
ULONG
FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer);
ULONG
FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
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,
@@ -280,14 +631,13 @@ Fat8dot3ToUnicodeString(OUT PUNICODE_STRING FileName,
}
ULONG
FatDirentToDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer)
{
PFILE_DIRECTORY_INFORMATION Info;
//UNICODE_STRING FileName;
Info = (PFILE_DIRECTORY_INFORMATION) Buffer;
Info->FileIndex = 0;
/* Setup Attributes */
Info->FileAttributes = Dirent->Attributes;
/* Setup times */
@@ -297,29 +647,20 @@ FatDirentToDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
Info->AllocationSize.QuadPart =
(Context->BytesPerClusterMask + Dirent->FileSize)
& ~(Context->BytesPerClusterMask);
//FileName.Buffer = Info->ShortName;
//FileName.MaximumLength = sizeof(Info->ShortName);
// FatQueryShortName(&FileName, Dirent);
// Info->ShortNameLength = (CCHAR) FileName.Length;
FatQueryFileName(Info, Dirent);
Info->NextEntryOffset = sizeof(*Info);
/* Associate LFN buffer and length pointers
* of this entry with the context.
*/
Context->NextEntryOffset = &Info->NextEntryOffset;
Context->FileName = Info->FileName;
Context->FileNameLength = &Info->FileNameLength;
return Info->NextEntryOffset;
return Info->NextEntryOffset + Info->FileNameLength;
}
ULONG
FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer)
{
PFILE_FULL_DIR_INFORMATION Info;
//UNICODE_STRING FileName;
Info = (PFILE_FULL_DIR_INFORMATION) Buffer;
Info->FileIndex = 0;
Info->EaSize = 0;
/* Setup Attributes */
Info->FileAttributes = Dirent->Attributes;
/* Setup times */
@@ -329,30 +670,21 @@ FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
Info->AllocationSize.QuadPart =
(Context->BytesPerClusterMask + Dirent->FileSize)
& ~(Context->BytesPerClusterMask);
//FileName.Buffer = Info->ShortName;
//FileName.MaximumLength = sizeof(Info->ShortName);
// FatQueryShortName(&FileName, Dirent);
// Info->ShortNameLength = (CCHAR) FileName.Length;
FatQueryFileName(Info, Dirent);
Info->NextEntryOffset = sizeof(*Info);
/*
* Associate LFN buffer and length pointers
* of this entry with the context.
*/
Context->NextEntryOffset = &Info->NextEntryOffset;
Context->FileName = Info->FileName;
Context->FileNameLength = &Info->FileNameLength;
return Info->NextEntryOffset;
return Info->NextEntryOffset + Info->FileNameLength;
}
ULONG
FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer)
{
PFILE_ID_FULL_DIR_INFORMATION Info;
//UNICODE_STRING FileName;
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 */
@@ -362,30 +694,20 @@ FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
Info->AllocationSize.QuadPart =
(Context->BytesPerClusterMask + Dirent->FileSize)
& ~(Context->BytesPerClusterMask);
//FileName.Buffer = Info->ShortName;
//FileName.MaximumLength = sizeof(Info->ShortName);
// FatQueryShortName(&FileName, Dirent);
// Info->ShortNameLength = (CCHAR) FileName.Length;
FatQueryFileName(Info, Dirent);
Info->NextEntryOffset = sizeof(*Info);
/*
* Associate LFN buffer and length pointers
* of this entry with the context.
*/
Context->NextEntryOffset = &Info->NextEntryOffset;
Context->FileName = Info->FileName;
Context->FileNameLength = &Info->FileNameLength;
return Info->NextEntryOffset;
return Info->NextEntryOffset + Info->FileNameLength;
}
ULONG
FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer)
{
PFILE_BOTH_DIR_INFORMATION Info;
UNICODE_STRING FileName;
Info = (PFILE_BOTH_DIR_INFORMATION) Buffer;
Info->FileIndex = 0;
Info->EaSize = 0;
/* Setup Attributes */
Info->FileAttributes = Dirent->Attributes;
/* Setup times */
@@ -395,29 +717,21 @@ FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
Info->AllocationSize.QuadPart =
(Context->BytesPerClusterMask + Dirent->FileSize)
& ~(Context->BytesPerClusterMask);
FileName.Buffer = Info->ShortName;
FileName.MaximumLength = sizeof(Info->ShortName);
Fat8dot3ToUnicodeString(&FileName, Dirent->FileName, Dirent->Case);
Info->ShortNameLength = (CCHAR) FileName.Length;
FatQueryBothFileName(Info, Dirent);
Info->NextEntryOffset = sizeof(*Info);
/* Associate LFN buffer and length pointers
* of this entry with the context.
*/
Context->NextEntryOffset = &Info->NextEntryOffset;
Context->FileName = Info->FileName;
Context->FileNameLength = &Info->FileNameLength;
return Info->NextEntryOffset;
return Info->NextEntryOffset + Info->FileNameLength;
}
ULONG
FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer)
{
PFILE_ID_BOTH_DIR_INFORMATION Info;
UNICODE_STRING FileName;
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 */
@@ -427,151 +741,35 @@ FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
Info->AllocationSize.QuadPart =
(Context->BytesPerClusterMask + Dirent->FileSize)
& ~(Context->BytesPerClusterMask);
FileName.Buffer = Info->ShortName;
FileName.MaximumLength = sizeof(Info->ShortName);
Fat8dot3ToUnicodeString(&FileName, Dirent->FileName, Dirent->Case);
Info->ShortNameLength = (CCHAR) FileName.Length;
FatQueryBothFileName(Info, Dirent);
Info->NextEntryOffset = sizeof(*Info);
/*
* Associate LFN buffer and length pointers
* of this entry with the context.
*/
Context->NextEntryOffset = &Info->NextEntryOffset;
Context->FileName = Info->FileName;
Context->FileNameLength = &Info->FileNameLength;
return Info->NextEntryOffset;
return Info->NextEntryOffset + Info->FileNameLength;
}
ULONG
FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context,
IN PDIR_ENTRY Dirent,
IN PVOID Buffer)
{
PFILE_NAMES_INFORMATION Info;
Info = (PFILE_NAMES_INFORMATION) Buffer;
// FatQueryShortName(&FileName, Dirent);
Info->FileIndex = 0;
FatQueryFileName(Info, Dirent);
Info->NextEntryOffset = sizeof(*Info);
/* Associate LFN buffer and length pointers
* of this entry with the context.
*/
Context->NextEntryOffset = &Info->NextEntryOffset;
Context->FileName = Info->FileName;
Context->FileNameLength = &Info->FileNameLength;
return Info->NextEntryOffset;
return Info->NextEntryOffset + Info->FileNameLength;
}
ULONG
FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
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);
}
ULONG
FatEnumerateDirents(IN OUT PFAT_ENUM_DIR_CONTEXT Context,
IN ULONG Index,
IN BOOLEAN CanWait)
{
LONGLONG PageOffset;
SIZE_T OffsetWithinPage, PageValidLength;
PUCHAR Entry, BeyondLastEntry;
/* Determine page offset and the offset within page
* for the first cluster.
*/
PageValidLength = PAGE_SIZE;
PageOffset = ((LONGLONG) Index) << BYTES_PER_DIRENT_LOG;
OffsetWithinPage = (SIZE_T) (PageOffset & (PAGE_SIZE - 1));
PageOffset -= OffsetWithinPage;
/* Check if the context already has the required page mapped.
* Map the first page is necessary.
*/
if (PageOffset != Context->PageOffset.QuadPart)
{
Context->PageOffset.QuadPart = PageOffset;
if (Context->PageBcb != NULL)
{
CcUnpinData(Context->PageBcb);
Context->PageBcb = NULL;
}
if (!CcMapData(Context->FileObject,
&Context->PageOffset,
PAGE_SIZE,
CanWait,
&Context->PageBcb,
&Context->PageBuffer))
{
Context->PageOffset.QuadPart = 0LL;
ExRaiseStatus(STATUS_CANT_WAIT);
}
}
Entry = Add2Ptr(Context->PageBuffer, OffsetWithinPage, PUCHAR);
/* Next Page Offset */
PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE;
if (PageOffset > Context->BeyondLastEntryOffset)
{
PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset
- Context->PageOffset.QuadPart);
}
BeyondLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PUCHAR);
while (TRUE)
{
do
{
if (*Entry == FAT_DIRENT_NEVER_USED)
return 0; // TODO: return something reasonable.
if (*Entry == FAT_DIRENT_DELETED)
{
continue;
}
if (Entry[0x0a] == FAT_DIRENT_ATTR_LFN)
{
PLONG_FILE_NAME_ENTRY Lfnent;
Lfnent = (PLONG_FILE_NAME_ENTRY) Entry;
}
else
{
PDIR_ENTRY Dirent;
Dirent = (PDIR_ENTRY) Entry;
RtlCopyMemory(Context->DirentFileName,
Dirent->FileName,
sizeof(Dirent->FileName));
}
} while (++Entry < BeyondLastEntry);
/* Check if this is the last available entry */
if (PageValidLength < PAGE_SIZE)
break;
/* We are getting beyond current page and
* are still in the continous run, map the next page.
*/
Context->PageOffset.QuadPart = PageOffset;
CcUnpinData(Context->PageBcb);
if (!CcMapData(Context->FileObject,
&Context->PageOffset,
PAGE_SIZE,
CanWait,
&Context->PageBcb,
&Context->PageBuffer))
{
Context->PageBcb = NULL;
Context->PageOffset.QuadPart = 0LL;
ExRaiseStatus(STATUS_CANT_WAIT);
}
Entry = (PUCHAR) Context->PageBuffer;
/* Next Page Offset */
PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE;
if (PageOffset > Context->BeyondLastEntryOffset)
{
PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset
- Context->PageOffset.QuadPart);
}
BeyondLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PUCHAR);
}
return 0;
}
/* EOF */

View File

@@ -17,6 +17,7 @@ FAT_GLOBAL_DATA FatGlobalData;
/* FUNCTIONS ****************************************************************/
NTSTATUS
NTAPI
DriverEntry(PDRIVER_OBJECT DriverObject,
@@ -110,7 +111,6 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
/* Register and reference our filesystem */
IoRegisterFileSystem(DeviceObject);
ObReferenceObject(DeviceObject);
return STATUS_SUCCESS;
}
@@ -221,5 +221,51 @@ FatCompleteRequest(PFAT_IRP_CONTEXT IrpContext OPTIONAL,
}
}
VOID
NTAPI
FatDequeueRequest(IN PVOID Context)
{
PFAT_IRP_CONTEXT IrpContext;
IrpContext = (PFAT_IRP_CONTEXT) Context;
/* Enter critical region. */
FsRtlEnterFileSystem();
/* Handle top level IRP Correctly. */
if (!FlagOn(IrpContext->Flags, IRPCONTEXT_TOPLEVEL))
IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP);
/* Enable Synchronous IO. */
SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT);
/* Invoke the handler routine. */
IrpContext->QueuedOperationHandler(IrpContext);
/* Restore top level IRP. */
IoSetTopLevelIrp(NULL);
/* Leave critical region. */
FsRtlExitFileSystem();
}
VOID
NTAPI
FatQueueRequest(IN PFAT_IRP_CONTEXT IrpContext,
IN PFAT_OPERATION_HANDLER OperationHandler)
{
/* Save the worker routine. */
IrpContext->QueuedOperationHandler = OperationHandler;
/* Indicate if top level IRP was set. */
if (IoGetTopLevelIrp() == IrpContext->Irp)
SetFlag(IrpContext->Flags, IRPCONTEXT_TOPLEVEL);
/* Initialize work item. */
ExInitializeWorkItem(&IrpContext->WorkQueueItem,
FatDequeueRequest,
IrpContext);
ExQueueWorkItem(&IrpContext->WorkQueueItem,
DelayedWorkQueue);
}
/* EOF */

View File

@@ -1,6 +1,7 @@
#include <ntifs.h>
#include <ntdddisk.h>
#include <debug.h>
#include <pseh/pseh2.h>
#ifndef TAG
#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
@@ -35,6 +36,23 @@ NTSTATUS NTAPI
FatSetVolumeInfo(PDEVICE_OBJECT DeviceObject, PIRP Irp);
/* ------------------------------------------------------ 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);
PVOID
FatMapUserBuffer(
IN OUT PIRP Irp);
/* ----------------------------------------------------------- dir.c */
@@ -46,6 +64,7 @@ FatDirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS NTAPI
FatCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp);
/* --------------------------------------------------------- close.c */
NTSTATUS NTAPI
@@ -90,6 +109,11 @@ FatBuildIrpContext(PIRP Irp, BOOLEAN CanWait);
VOID NTAPI
FatDestroyIrpContext(PFAT_IRP_CONTEXT IrpContext);
VOID
NTAPI
FatQueueRequest(IN PFAT_IRP_CONTEXT IrpContext,
IN PFAT_OPERATION_HANDLER OperationHandler);
VOID NTAPI
FatCompleteRequest(PFAT_IRP_CONTEXT IrpContext OPTIONAL,
PIRP Irp OPTIONAL,
@@ -118,6 +142,14 @@ 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
FatInitializeVcb(
@@ -152,8 +184,50 @@ FatPerformDevIoCtrl(PDEVICE_OBJECT DeviceObject,
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);
NTSTATUS
FatCreateFcb(
OUT PFCB* CreatedFcb,
IN PFAT_IRP_CONTEXT IrpContext,
IN PFCB ParentFcb,
IN PDIR_ENTRY Dirent,
IN PUNICODE_STRING FileName,
IN PUNICODE_STRING LongFileName OPTIONAL);
NTSTATUS
FatOpenFcb(
OUT PFCB* Fcb,
IN PFAT_IRP_CONTEXT IrpContext,
IN PFCB ParentFcb,
IN PUNICODE_STRING FileName);
/* ------------------------------------------------------------ rw.c */

View File

@@ -5,6 +5,7 @@
<include base="fastfatn">.</include>
<library>ntoskrnl</library>
<library>hal</library>
<library>pseh</library>
<file>blockdev.c</file>
<file>cleanup.c</file>
<file>close.c</file>

View File

@@ -28,105 +28,133 @@ typedef struct _FAT_SCAN_CONTEXT
((ULONG) ((xOffset - (xVcb)->DataArea) >> (xVcb)->BytesPerClusterLog) + 0x02)
ULONG
FatScanFat12ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
FatScanFat32ForContinousRun(IN OUT PFAT_PAGE_CONTEXT Context,
IN OUT PULONG Index,
IN BOOLEAN CanWait);
ULONG
FatSetFat12ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN BOOLEAN CanWait);
ULONG
FatScanFat12ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN ULONG IndexValue,
IN BOOLEAN CanWait);
ULONG
FatSetFat12ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN ULONG IndexValue,
IN BOOLEAN CanWait);
ULONG
FatScanFat16ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN BOOLEAN CanWait);
ULONG
FatSetFat16ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN BOOLEAN CanWait);
ULONG
FatScanFat16ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN ULONG IndexValue,
IN BOOLEAN CanWait);
ULONG
FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN ULONG IndexValue,
IN BOOLEAN CanWait);
ULONG
FatScanFat32ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN BOOLEAN CanWait);
ULONG
FatSetFat32ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN BOOLEAN CanWait);
ULONG
FatScanFat32ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN ULONG IndexValue,
IN BOOLEAN CanWait);
ULONG
FatSetFat32ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN ULONG IndexValue,
IN BOOLEAN CanWait);
BOOLEAN
NTAPI
FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb);
/* VARIABLES ****************************************************************/
FAT_METHODS Fat12Methods = {
FatScanFat12ForContinousRun,
FatSetFat12ContinousRun,
FatScanFat16ForValueRun,
FatSetFat12ValueRun
NULL,
NULL,
NULL,
NULL
};
FAT_METHODS Fat16Methods = {
FatScanFat16ForContinousRun,
FatSetFat16ContinousRun,
FatScanFat16ForValueRun,
FatSetFat16ValueRun
NULL,
NULL,
NULL,
NULL
};
FAT_METHODS Fat32Methods = {
FatScanFat32ForContinousRun,
FatSetFat32ContinousRun,
FatScanFat32ForValueRun,
FatSetFat32ValueRun
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.
*
@@ -148,83 +176,11 @@ FatPowerOfTwo(
return (((Temp + (Temp >> 3)) & 030707070707) % 63);
}
ULONG
FatScanFat12ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatSetFat12ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatScanFat12ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN ULONG IndexValue,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatSetFat12ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN ULONG IndexValue,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatScanFat16ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatSetFat16ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatScanFat16ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN OUT PULONG Index,
IN ULONG IndexValue,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
ULONG
FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
IN ULONG Index,
IN ULONG Length,
IN ULONG IndexValue,
IN BOOLEAN CanWait)
{
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
/**
* Scans FAT32 for continous chain of clusters
*
* @param Context
* Pointer to FAT_SCAN_CONTEXT.
* Pointer to FAT_PAGE_CONTEXT.
*
* @param Index
* Supplies the Index of the first cluster
@@ -241,79 +197,26 @@ FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
* Raises STATUS_CANT_WAIT race condition.
*/
ULONG
FatScanFat32ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
FatScanFat32ForContinousRun(IN OUT PFAT_PAGE_CONTEXT Context,
IN OUT PULONG Index,
IN BOOLEAN CanWait)
{
LONGLONG PageOffset;
SIZE_T OffsetWithinPage, PageValidLength;
PULONG Entry, BeyoudLastEntry;
/* Determine page offset and the offset within page
* for the first cluster.
*/
PageValidLength = PAGE_SIZE;
PageOffset = ((LONGLONG) *Index) << 0x2;
OffsetWithinPage = (SIZE_T) (PageOffset & (PAGE_SIZE - 1));
PageOffset -= OffsetWithinPage;
/* Check if the context already has the required page mapped.
* Map the first page is necessary.
*/
if (PageOffset != Context->PageOffset.QuadPart)
{
Context->PageOffset.QuadPart = PageOffset;
if (Context->PageBcb != NULL)
{
CcUnpinData(Context->PageBcb);
Context->PageBcb = NULL;
}
if (!CcMapData(Context->FileObject,
&Context->PageOffset,
PAGE_SIZE,
CanWait,
&Context->PageBcb,
&Context->PageBuffer))
{
Context->PageOffset.QuadPart = 0LL;
ExRaiseStatus(STATUS_CANT_WAIT);
}
}
Entry = Add2Ptr(Context->PageBuffer, OffsetWithinPage, PULONG);
/* Next Page Offset */
PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE;
if (PageOffset > Context->BeyondLastEntryOffset)
PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset
- Context->PageOffset.QuadPart);
BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG);
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 < BeyoudLastEntry);
} while (++Entry < EndOfPage);
/* Check if this is the last available entry */
if (PageValidLength < PAGE_SIZE)
if (FatPinIsLastPage(Context))
break;
/* We are getting beyond current page and
* are still in the continous run, map the next page.
*/
Context->PageOffset.QuadPart = PageOffset;
CcUnpinData(Context->PageBcb);
if (!CcMapData(Context->FileObject,
&Context->PageOffset, PAGE_SIZE, CanWait,
&Context->PageBcb, &Context->PageBuffer))
{
Context->PageBcb = NULL;
Context->PageOffset.QuadPart = 0LL;
ExRaiseStatus(STATUS_CANT_WAIT);
}
Entry = (PULONG) Context->PageBuffer;
/* Next Page Offset */
PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE;
if (PageOffset > Context->BeyondLastEntryOffset)
PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset
- Context->PageOffset.QuadPart);
BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG);
Entry = (PULONG) FatPinNextPage(Context);
EndOfPage = FatPinEndOfPage(Context, PULONG);
}
return (*Index - 1);
}
@@ -388,7 +291,7 @@ FatScanFat(IN PFCB Fcb,
{
LONGLONG CurrentLbo, CurrentVbo, BeyondLastVbo, CurrentLength;
ULONG Entry, NextEntry, NumberOfEntries, CurrentIndex;
FAT_SCAN_CONTEXT Context;
FAT_PAGE_CONTEXT Context;
PVCB Vcb;
/* Some often used values */
@@ -428,8 +331,11 @@ FatScanFat(IN PFCB Fcb,
CurrentIndex = 0L;
CurrentVbo = 0LL;
}
/* Initialize Context */
RtlZeroMemory(&Context, sizeof(Context));
Context.FileObject = Vcb->VolumeFileObject;
Context.FileObject = Vcb->StreamFileObject;
Context.EndOfData.QuadPart = Vcb->BeyondLastClusterInFat;
while (CurrentVbo < BeyondLastVbo)
{
/* Locate Continous run starting with the current entry */
@@ -532,6 +438,10 @@ FatiInitializeVcb(PVCB Vcb)
Vcb->BytesPerCluster = SectorsToBytes(Vcb, Vcb->Bpb.SectorsPerCluster);
Vcb->BytesPerClusterLog = FatPowerOfTwo(Vcb->BytesPerCluster);
Vcb->BeyondLastClusterInFat = ((LONGLONG) Vcb->Clusters) * Vcb->IndexDepth / 0x8;
/* Update real volume size with the real value. */
Vcb->Header.FileSize.QuadPart =
Vcb->Header.AllocationSize.QuadPart = SectorsToBytes(Vcb, Vcb->Sectors);
}
NTSTATUS
@@ -558,18 +468,19 @@ FatInitializeVcb(IN PVCB Vcb,
/* Setup Vcb fields */
Vcb->TargetDeviceObject = TargetDeviceObject;
ObReferenceObject(TargetDeviceObject);
Vcb->Vpb = Vpb;
/* Setup FCB Header */
ExInitializeFastMutex(&Vcb->HeaderMutex);
FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->HeaderMutex);
/* Create Volume File Object */
Vcb->VolumeFileObject = IoCreateStreamFileObject(NULL,
Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
Vcb->TargetDeviceObject);
/* We have to setup all FCB fields needed for CC */
Vcb->VolumeFileObject->FsContext = Vcb;
Vcb->VolumeFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
Vcb->StreamFileObject->FsContext = Vcb;
Vcb->StreamFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
/* At least full boot sector should be available */
Vcb->Header.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
@@ -578,7 +489,7 @@ FatInitializeVcb(IN PVCB Vcb,
Vcb->Header.ValidDataLength.LowPart = MAXULONG;
/* Initialize CC */
CcInitializeCacheMap(Vcb->VolumeFileObject,
CcInitializeCacheMap(Vcb->StreamFileObject,
(PCC_FILE_SIZES)&Vcb->Header.AllocationSize,
FALSE,
&FatGlobalData.CacheMgrNoopCallbacks,
@@ -592,7 +503,7 @@ FatInitializeVcb(IN PVCB Vcb,
* any of the parameters set further
* in this routine.
*/
if (CcMapData(Vcb->VolumeFileObject,
if (CcMapData(Vcb->StreamFileObject,
&Offset,
sizeof(PACKED_BOOT_SECTOR),
TRUE,
@@ -606,7 +517,7 @@ FatInitializeVcb(IN PVCB Vcb,
{
Status = STATUS_UNRECOGNIZED_VOLUME;
}
CopyUchar4(&Vpb->SerialNumber, BootSector->Id);
CopyUchar4(&Vcb->Vpb->SerialNumber, BootSector->Id);
CcUnpinData(Bcb);
}
else
@@ -641,12 +552,12 @@ FatUninitializeVcb(IN PVCB Vcb)
ZeroSize.QuadPart = 0LL;
/* Close volume file */
if (Vcb->VolumeFileObject != NULL)
if (Vcb->StreamFileObject != NULL)
{
/* Uninitialize CC. */
CcUninitializeCacheMap(Vcb->VolumeFileObject, &ZeroSize, NULL);
ObDereferenceObject(Vcb->VolumeFileObject);
Vcb->VolumeFileObject = NULL;
CcUninitializeCacheMap(Vcb->StreamFileObject, &ZeroSize, NULL);
ObDereferenceObject(Vcb->StreamFileObject);
Vcb->StreamFileObject = NULL;
}
/* Free notifications stuff */

View File

@@ -248,7 +248,7 @@ typedef struct _DIR_ENTRY
// sizeof = 0x020
typedef struct _LONG_FILE_NAME_ENTRY {
UCHAR Index;
UCHAR SeqNum;
UCHAR NameA[10];
UCHAR Attributes;
UCHAR Type;
@@ -259,7 +259,13 @@ typedef struct _LONG_FILE_NAME_ENTRY {
} LONG_FILE_NAME_ENTRY, *PLONG_FILE_NAME_ENTRY;
// sizeof = 0x020
#define FAT_FN_DIR_ENTRY_TERM_INDEX 0x40
#define FAT_LFN_NAME_LENGTH \
(RTL_FIELD_SIZE(LONG_FILE_NAME_ENTRY, NameA) \
+ RTL_FIELD_SIZE(LONG_FILE_NAME_ENTRY, NameB) \
+ RTL_FIELD_SIZE(LONG_FILE_NAME_ENTRY, NameC))
#define FAT_FN_DIR_ENTRY_LAST 0x40
#define FAT_FN_MAX_DIR_ENTIES 0x14
#define FAT_BYTES_PER_DIRENT 0x20
#define FAT_BYTES_PER_DIRENT_LOG 0x05

View File

@@ -3,8 +3,11 @@
typedef struct _FAT_SCAN_CONTEXT *PFAT_SCAN_CONTEXT;
typedef struct _FAT_IO_CONTEXT *PFAT_IO_CONTEXT;
typedef struct _FAT_IRP_CONTEXT *PFAT_IRP_CONTEXT;
typedef PVOID PBCB;
typedef NTSTATUS (*PFAT_OPERATION_HANDLER) (PFAT_IRP_CONTEXT);
typedef struct _FAT_GLOBAL_DATA
{
ERESOURCE Resource;
@@ -22,6 +25,39 @@ typedef struct _FAT_GLOBAL_DATA
LARGE_INTEGER DefaultFileTime;
} FAT_GLOBAL_DATA;
typedef struct _FAT_PAGE_CONTEXT
{
PFILE_OBJECT FileObject;
LARGE_INTEGER EndOfData;
LARGE_INTEGER Offset;
LARGE_INTEGER EndOfPage;
SIZE_T ValidLength;
PVOID Buffer;
PBCB Bcb;
BOOLEAN CanWait;
} FAT_PAGE_CONTEXT, *PFAT_PAGE_CONTEXT;
#define FatPinSetupContext(xContext, xFcb, CanWait) \
{ \
(xContext)->FileObject = (xFcb)->StreamFileObject; \
(xContext)->EndOfData = (xFcb)->Header.FileSize; \
(xContext)->Offset.QuadPart = -1LL; \
(xContext)->Bcb = NULL; \
(xContext)->CanWait = CanWait; \
}
#define FatPinCleanupContext(xContext) \
if ((xContext)->Bcb != NULL) { \
CcUnpinData((xContext)->Bcb); \
(xContext)->Bcb = NULL; \
} \
#define FatPinEndOfPage(xContext, xType) \
Add2Ptr((xContext)->Buffer, (xContext)->ValidLength, xType)
#define FatPinIsLastPage(xContext) \
((xContext)->ValidLength != PAGE_SIZE)
#define IRPCONTEXT_CANWAIT 0x0001
#define IRPCONTEXT_PENDINGRETURNED 0x0002
#define IRPCONTEXT_STACK_IO_CONTEXT 0x0004
@@ -38,18 +74,23 @@ typedef struct _FAT_IRP_CONTEXT
ULONG Flags;
struct _VCB *Vcb;
ULONG PinCount;
FAT_PAGE_CONTEXT Page;
struct _FAT_IO_CONTEXT *FatIoContext;
WORK_QUEUE_ITEM WorkQueueItem;
PFAT_OPERATION_HANDLER QueuedOperationHandler;
PIO_STACK_LOCATION Stack;
KEVENT Event;
} FAT_IRP_CONTEXT, *PFAT_IRP_CONTEXT;
} FAT_IRP_CONTEXT;
typedef struct _FAT_IO_CONTEXT
{
PMDL ZeroMdl;
PIRP MasterIrp;
LONG IrpCount;
PIRP Irp;
LONG RunCount;
SIZE_T Length;
LONGLONG Offset;
PFILE_OBJECT FileObject;
union
{
struct
@@ -57,19 +98,16 @@ typedef struct _FAT_IO_CONTEXT
PERESOURCE Resource;
PERESOURCE PagingIoResource;
ERESOURCE_THREAD ResourceThreadId;
ULONG RequestedByteCount;
PFILE_OBJECT FileObject;
BOOLEAN ReadOperation;
} Async;
KEVENT SyncEvent;
} Wait;
PIRP Irp[0];
PIRP AssociatedIrp[0];
} FAT_IO_CONTEXT;
typedef ULONG (*PFAT_SCANFAT_FOR_CONTINOUS_RUN_ROUTINE) (struct _FAT_SCAN_CONTEXT*, PULONG, BOOLEAN);
typedef ULONG (*PFAT_SETFAT_CONTINOUS_RUN_ROUTINE) (PFAT_SCAN_CONTEXT, ULONG, ULONG, BOOLEAN);
typedef ULONG (*PFAT_SCANFAT_FOR_VALUE_RUN_ROUTINE) (PFAT_SCAN_CONTEXT, PULONG, ULONG, BOOLEAN);
typedef ULONG (*PFAT_SETFAT_VALUE_RUN_ROUTINE) (PFAT_SCAN_CONTEXT, ULONG, ULONG, ULONG, BOOLEAN);
typedef ULONG (*PFAT_SCANFAT_FOR_CONTINOUS_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, PULONG, BOOLEAN);
typedef ULONG (*PFAT_SETFAT_CONTINOUS_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, ULONG, ULONG, BOOLEAN);
typedef ULONG (*PFAT_SCANFAT_FOR_VALUE_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, PULONG, ULONG, BOOLEAN);
typedef ULONG (*PFAT_SETFAT_VALUE_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, ULONG, ULONG, ULONG, BOOLEAN);
typedef struct _FAT_METHODS {
PFAT_SCANFAT_FOR_CONTINOUS_RUN_ROUTINE ScanContinousRun;
@@ -78,7 +116,7 @@ typedef struct _FAT_METHODS {
PFAT_SETFAT_VALUE_RUN_ROUTINE SetValueRun;
} FAT_METHODS, *PFAT_METHODS;
#define FAT_NTC_VCB (USHORT)TAG('F', 'V', 0, 0);
#define FAT_NTC_VCB (USHORT) TAG('F', 'V', 0, 0)
/* Volume Control Block */
typedef struct _VCB
@@ -87,9 +125,10 @@ typedef struct _VCB
FAST_MUTEX HeaderMutex;
SECTION_OBJECT_POINTERS SectionObjectPointers;
PFILE_OBJECT VolumeFileObject;
PFILE_OBJECT StreamFileObject;
PDEVICE_OBJECT TargetDeviceObject;
LIST_ENTRY VcbLinks;
PVPB Vpb;
/* Notifications support */
PNOTIFY_SYNC NotifySync;
@@ -186,10 +225,14 @@ typedef struct _FCB
FCB_NAME_LINK FileName[0x2];
/* Buffer for the short name */
WCHAR ShortNameBuffer[0xc];
/* File basic info */
FILE_BASIC_INFORMATION BasicInfo;
union
{
struct
{
/* Directory data stream (just handy to have it). */
PFILE_OBJECT StreamFileObject;
/* Bitmap to search for free dirents. */
/* RTL_BITMAP Bitmap; */
PRTL_SPLAY_LINKS SplayLinks;
@@ -197,13 +240,56 @@ typedef struct _FCB
};
} FCB, *PFCB;
typedef struct _FAT_ENUM_DIRENT_CONTEXT *PFAT_ENUM_DIRENT_CONTEXT;
typedef struct _FAT_ENUM_DIR_CONTEXT *PFAT_ENUM_DIR_CONTEXT;
typedef ULONG (*PFAT_COPY_DIRENT_ROUTINE) (PFAT_ENUM_DIR_CONTEXT, PDIR_ENTRY, PVOID);
typedef struct _FAT_ENUM_DIRENT_CONTEXT
{
FAT_PAGE_CONTEXT Page;
/* Copy dirent to dirinfo */
PFAT_COPY_DIRENT_ROUTINE CopyDirent;
LONGLONG BytesPerClusterMask;
/* Info buffer characteristics */
PVOID Buffer;
SIZE_T Offset;
SIZE_T Length;
/* Criteria */
PUNICODE_STRING FileName;
UCHAR CcbFlags;
/* Lfn buffer/length offsets */
ULONG LengthOffset;
ULONG NameOffset;
} FAT_ENUM_DIRENT_CONTEXT;
typedef struct _FAT_FIND_DIRENT_CONTEXT
{
FAT_PAGE_CONTEXT Page;
UNICODE_STRING ShortName;
WCHAR ShortNameBuffer[0x18];
/* Criteria */
PUNICODE_STRING FileName;
BOOLEAN Valid8dot3Name;
} FAT_FIND_DIRENT_CONTEXT, *PFAT_FIND_DIRENT_CONTEXT;
typedef struct _CCB
{
LARGE_INTEGER CurrentByteOffset;
ULONG Entry;
UNICODE_STRING SearchPattern;
UCHAR Flags;
} CCB, *PCCB;
#define CCB_SEARCH_RETURN_SINGLE_ENTRY 0x01
#define CCB_SEARCH_PATTERN_LEGAL_8DOT3 0x02
#define CCB_SEARCH_PATTERN_HAS_WILD_CARD 0x04
#define CCB_DASD_IO 0x10
extern FAT_GLOBAL_DATA FatGlobalData;
#endif//__STRUCT_H__

View File

@@ -1,9 +1,9 @@
/*
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/rw.c
* PURPOSE: Read/write support
* PROGRAMMERS:
* FILE: drivers/filesystems/fastfat/fcb.c
* PURPOSE: FCB manipulation routines.
* PROGRAMMERS: Alexey Vlasov
*/
/* INCLUDES *****************************************************************/
@@ -13,5 +13,316 @@
/* FUNCTIONS ****************************************************************/
/**
* Locates FCB by the supplied name in the cache trie of fcbs.
*
* @param ParentFcb
* Supplies a pointer to the parent FCB
*
* @param Name
* Supplied a name of the FCB to be located in cache.
*
* @return
* Pointer to the found FCB or NULL.
*/
PFCB
FatLookupFcbByName(
IN PFCB ParentFcb,
IN PUNICODE_STRING Name)
{
PFCB_NAME_LINK Node;
PRTL_SPLAY_LINKS Links;
/* Get sub-trie root node from the parent FCB */
Links = ParentFcb->Dcb.SplayLinks;
while (Links != NULL)
{
LONG Comparison;
Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
/*
* Compare the name stored in the node
* and determine the direction to walk.
*/
Comparison = RtlCompareUnicodeString(&Node->String, Name, TRUE);
if (Comparison > 0) {
/* Left child */
Links = RtlLeftChild(&Node->Links);
}
else if (Comparison < 0)
{
/* Right child */
Links = RtlRightChild(&Node->Links);
}
else
{
/* Strings are equal, we have found the node! */
break;
}
}
/* The case when nothing was found. */
if (Links == NULL)
return NULL;
/* Cast node to the FCB structure. */
return CONTAINING_RECORD(Links, FCB, FileName[Node->Type]);
}
/**
* Inserts FCB into FCBs cache trie.
*
* @param ParentFcb
* Supplies a pointer to the parent FCB
*
* @param Fcb
* Supplied a pointer to the being inserted FCB.
*
* @return
* TRUE if the FCB was successfully inserted,
* FASLE in the case of name collision.
*/
BOOLEAN
FatLinkFcbNames(
IN PFCB ParentFcb,
IN PFCB Fcb)
{
PFCB_NAME_LINK Name;
PRTL_SPLAY_LINKS Links;
/* None of the parameters can be NULL */
ASSERT(ParentFcb != NULL && Fcb != NULL);
/* Get root links of the parent FCB. */
Links = ParentFcb->Dcb.SplayLinks;
/*
* Get first file name
* (short name for FAT because it's always there.
*/
Name = Fcb->FileName;
/*
* Check if ParentDcb links are initialized,
* at least one child FCB is cached.
*/
if (Links == NULL)
{
ParentFcb->Dcb.SplayLinks = Links = &Name->Links;
RtlInitializeSplayLinks(Links);
/* Check if we have more names to cache. */
if ((++Name)->String.Length == 0)
return TRUE;
}
/* Lookup for the insertion point in the trie. */
do
{
LONG Comparison;
PFCB_NAME_LINK Node;
PRTL_SPLAY_LINKS PrevLinks;
PrevLinks = Links;
Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
Comparison = RtlCompareUnicodeString(&Node->String, &Name->String, TRUE);
if (Comparison > 0) {
Links = RtlLeftChild(&Node->Links);
if (Links == NULL)
{
RtlInsertAsLeftChild(PrevLinks, &Name->Links);
break;
}
}
else if (Comparison < 0)
{
Links = RtlRightChild(&Node->Links);
if (Links == NULL)
{
RtlInsertAsRightChild(PrevLinks, &Name->Links);
break;
}
}
else
{
return FALSE;
}
/* Possibly switch to the second (lfn) name and cache that. */
} while (Name == Fcb->FileName && (++Name)->String.Length > 0);
return TRUE;
}
/**
* Unlinks FCB from the FCBs cache trie.
*
* @param ParentFcb
* Supplies a pointer to the parent FCB
*
* @param Fcb
* Supplied a pointer to the being unlinked FCB.
*
* @return
* VOID
*/
VOID
FatUnlinkFcbNames(
IN PFCB ParentFcb,
IN PFCB Fcb)
{
/* See if there is an lfn and unlink that. */
if (Fcb->FileName[FcbLongName].String.Length > 0)
ParentFcb->Dcb.SplayLinks =
RtlDelete(&Fcb->FileName[FcbLongName].Links);
/* See if there is a short name and unlink that. */
if (Fcb->FileName[FcbShortName].String.Length > 0)
ParentFcb->Dcb.SplayLinks =
RtlDelete(&Fcb->FileName[FcbShortName].Links);
}
NTSTATUS
FatCreateFcb(
OUT PFCB* CreatedFcb,
IN PFAT_IRP_CONTEXT IrpContext,
IN PFCB ParentFcb,
IN PDIR_ENTRY Dirent,
IN PUNICODE_STRING FileName,
IN PUNICODE_STRING LongFileName OPTIONAL)
{
NTSTATUS Status;
PFCB Fcb;
/* Allocate FCB structure. */
Fcb = (PFCB) ExAllocateFromNPagedLookasideList(&FatGlobalData.NonPagedFcbList);
if (Fcb == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(Fcb, sizeof(FCB));
/* Setup FCB Advanced Header. */
Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
Fcb->Header.NodeByteSize = sizeof(*Fcb);
ExInitializeResourceLite(&Fcb->Resource);
Fcb->Header.Resource = &Fcb->Resource;
ExInitializeResourceLite(&Fcb->PagingIoResource);
Fcb->Header.PagingIoResource = &Fcb->PagingIoResource;
ExInitializeFastMutex(&Fcb->HeaderMutex);
FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
Fcb->Header.FileSize.QuadPart = Dirent->FileSize;
Fcb->Header.ValidDataLength.QuadPart = Dirent->FileSize;
Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
/* Setup main fields. */
FsRtlInitializeFileLock(&Fcb->Lock, NULL, NULL);
FsRtlInitializeLargeMcb(&Fcb->Mcb, PagedPool);
Fcb->Vcb = IrpContext->Vcb;
Fcb->ParentFcb = ParentFcb;
Fcb->FirstCluster = Dirent->FirstCluster
| (Dirent->FirstClusterOfFileHi << 0x10);
/* Setup basic info. */
Fcb->BasicInfo.FileAttributes = Dirent->Attributes;
FatQueryFileTimes(&Fcb->BasicInfo.CreationTime, Dirent);
/* Setup short name since always present in FAT. */
Fcb->FileName[FcbShortName].Type = FcbShortName;
Fcb->FileName[FcbShortName].String.Buffer = Fcb->ShortNameBuffer;
Fcb->FileName[FcbShortName].String.MaximumLength = 0x0c;
Fcb->FileName[FcbShortName].String.Length = FileName->Length;
RtlCopyMemory(Fcb->ShortNameBuffer, FileName->Buffer, FileName->Length);
/* Just swap optional lfn. */
if (ARGUMENT_PRESENT(LongFileName) && LongFileName->Length > 0)
{
Fcb->FileName[FcbLongName].Type = FcbLongName;
Fcb->FileName[FcbLongName].String = *LongFileName;
RtlZeroMemory(LongFileName, sizeof(UNICODE_STRING));
}
/* Put FCB into cache trie. */
if (!FatLinkFcbNames(ParentFcb, Fcb))
{
Status = STATUS_OBJECT_NAME_COLLISION;
goto FsdFatCreateFcbCleanup;
}
*CreatedFcb = Fcb;
/* We are done! */
return STATUS_SUCCESS;
FsdFatCreateFcbCleanup:
if (ARGUMENT_PRESENT(LongFileName) &&
Fcb->FileName[FcbLongName].String.Buffer != NULL)
{
/* Swap lfn back to the input parameter */
*LongFileName = Fcb->FileName[FcbLongName].String;
}
ExFreeToNPagedLookasideList(&FatGlobalData.NonPagedFcbList, Fcb);
return Status;
}
NTSTATUS
FatOpenFcb(
OUT PFCB* Fcb,
IN PFAT_IRP_CONTEXT IrpContext,
IN PFCB ParentFcb,
IN PUNICODE_STRING FileName)
{
FAT_FIND_DIRENT_CONTEXT Context;
UNICODE_STRING LongFileName;
PDIR_ENTRY Dirent;
NTSTATUS Status;
// TODO: _SEH_TRY {
if (ParentFcb->Dcb.StreamFileObject == NULL)
{
PFILE_OBJECT FileObject;
PVPB Vpb;
Vpb = IrpContext->Vcb->Vpb;
/* Create stream file object */
FileObject = IoCreateStreamFileObject(NULL, Vpb->RealDevice);
FileObject->Vpb = Vpb;
FileObject->SectionObjectPointer = &ParentFcb->SectionObjectPointers;
FileObject->FsContext = ParentFcb;
FileObject->FsContext2 = NULL;
/* Store it in parent fcb */
ParentFcb->Dcb.StreamFileObject = FileObject;
}
/* Check if cache is initialized. */
if (ParentFcb->Dcb.StreamFileObject->PrivateCacheMap == NULL )
{
CcInitializeCacheMap(ParentFcb->Dcb.StreamFileObject,
(PCC_FILE_SIZES) &ParentFcb->Header.AllocationSize,
TRUE,
&FatGlobalData.CacheMgrNoopCallbacks,
ParentFcb);
}
/* Page context */
Context.Page.FileObject = ParentFcb->Dcb.StreamFileObject;
Context.Page.EndOfData = ParentFcb->Header.FileSize;
Context.Page.Offset.QuadPart = -1LL;
Context.Page.Bcb = NULL;
Context.Page.CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
Context.Page.EndOfData = ParentFcb->Header.FileSize;
/* Search context */
Context.ShortName.Length = 0;
Context.ShortName.Buffer = Context.ShortNameBuffer;
Context.ShortName.MaximumLength = sizeof(Context.ShortNameBuffer);
Context.FileName = FileName;
Context.Valid8dot3Name = RtlIsNameLegalDOS8Dot3(FileName, NULL, NULL);
/* Locate the dirent */
FatFindDirent(&Context, &Dirent, &LongFileName);
Status = FatCreateFcb(Fcb, IrpContext, ParentFcb, Dirent,
&Context.ShortName, &LongFileName);
return Status;
}
/* EOF */

View File

@@ -112,7 +112,7 @@ FatMountVolume(PFAT_IRP_CONTEXT IrpContext,
if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup;
VolumeDevice->DeviceObject.SectorSize = DiskGeometry.BytesPerSector;
VolumeDevice->DeviceObject.SectorSize = (USHORT) DiskGeometry.BytesPerSector;
/* Signal we're done with initializing */
VolumeDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
@@ -128,7 +128,7 @@ FatMountVolume(PFAT_IRP_CONTEXT IrpContext,
VolumeDevice->Vcb.MediaChangeCount = MediaChangeCount;
/* Notify about volume mount */
FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.VolumeFileObject, FSRTL_VOLUME_MOUNT);
FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT);
/* Return success */
return STATUS_SUCCESS;