mirror of
https://github.com/reactos/reactos.git
synced 2026-07-07 04:44:26 +08:00
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:
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user