mirror of
https://github.com/reactos/reactos.git
synced 2024-11-02 12:53:33 +00:00
b819608ed8
svn path=/branches/condrv_restructure/; revision=63104
563 lines
16 KiB
C
563 lines
16 KiB
C
/*
|
|
* PROJECT: ReactOS FAT file system driver
|
|
* LICENSE: GNU GPLv3 as published by the Free Software Foundation
|
|
* FILE: drivers/filesystems/fastfat/fastfat.c
|
|
* PURPOSE: Initialization routines
|
|
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#define NDEBUG
|
|
#include "fastfat.h"
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
FAT_GLOBAL_DATA FatGlobalData;
|
|
FAST_MUTEX FatCloseQueueMutex;
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(PDRIVER_OBJECT DriverObject,
|
|
PUNICODE_STRING RegistryPath)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Fat");
|
|
NTSTATUS Status;
|
|
|
|
/* Create a device object */
|
|
Status = IoCreateDevice(DriverObject,
|
|
0,
|
|
&DeviceName,
|
|
FILE_DEVICE_DISK_FILE_SYSTEM,
|
|
0,
|
|
FALSE,
|
|
&DeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Zero global storage */
|
|
RtlZeroMemory(&FatGlobalData, sizeof(FAT_GLOBAL_DATA));
|
|
FatGlobalData.DriverObject = DriverObject;
|
|
FatGlobalData.DiskDeviceObject = DeviceObject;
|
|
FatGlobalData.SystemProcess = PsGetCurrentProcess();
|
|
|
|
/* Fill major function handlers */
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FatClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = FatCreate;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = FatRead;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = FatWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FatFileSystemControl;
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = FatQueryInformation;
|
|
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = FatSetInformation;
|
|
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = FatDirectoryControl;
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = FatQueryVolumeInfo;
|
|
DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = FatSetVolumeInfo;
|
|
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FatShutdown;
|
|
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = FatLockControl;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FatDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FatCleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = FatFlushBuffers;
|
|
//DriverObject->MajorFunction[IRP_MJ_QUERY_EA]
|
|
//DriverObject->MajorFunction[IRP_MJ_SET_EA]
|
|
//DriverObject->MajorFunction[IRP_MJ_PNP]
|
|
|
|
DriverObject->DriverUnload = NULL;
|
|
|
|
/* Initialize cache manager callbacks */
|
|
FatGlobalData.CacheMgrCallbacks.AcquireForLazyWrite = FatAcquireForLazyWrite;
|
|
FatGlobalData.CacheMgrCallbacks.ReleaseFromLazyWrite = FatReleaseFromLazyWrite;
|
|
FatGlobalData.CacheMgrCallbacks.AcquireForReadAhead = FatAcquireForReadAhead;
|
|
FatGlobalData.CacheMgrCallbacks.ReleaseFromReadAhead = FatReleaseFromReadAhead;
|
|
|
|
FatGlobalData.CacheMgrNoopCallbacks.AcquireForLazyWrite = FatNoopAcquire;
|
|
FatGlobalData.CacheMgrNoopCallbacks.ReleaseFromLazyWrite = FatNoopRelease;
|
|
FatGlobalData.CacheMgrNoopCallbacks.AcquireForReadAhead = FatNoopAcquire;
|
|
FatGlobalData.CacheMgrNoopCallbacks.ReleaseFromReadAhead = FatNoopRelease;
|
|
|
|
/* Initialize Fast I/O dispatchers */
|
|
FatInitFastIoRoutines(&FatGlobalData.FastIoDispatch);
|
|
DriverObject->FastIoDispatch = &FatGlobalData.FastIoDispatch;
|
|
|
|
/* Initialize lookaside lists */
|
|
ExInitializeNPagedLookasideList(&FatGlobalData.NonPagedFcbList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
sizeof(FCB),
|
|
TAG_FCB,
|
|
0);
|
|
|
|
ExInitializeNPagedLookasideList(&FatGlobalData.ResourceList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
sizeof(ERESOURCE),
|
|
TAG_CCB,
|
|
0);
|
|
|
|
ExInitializeNPagedLookasideList(&FatGlobalData.IrpContextList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
sizeof(FAT_IRP_CONTEXT),
|
|
TAG_IRP,
|
|
0);
|
|
|
|
/* Initialize synchronization resource for the global data */
|
|
ExInitializeResourceLite(&FatGlobalData.Resource);
|
|
|
|
/* Initialize queued close stuff */
|
|
InitializeListHead(&FatGlobalData.AsyncCloseList);
|
|
InitializeListHead(&FatGlobalData.DelayedCloseList);
|
|
FatGlobalData.FatCloseItem = IoAllocateWorkItem(DeviceObject);
|
|
ExInitializeFastMutex(&FatCloseQueueMutex);
|
|
|
|
/* Initialize global VCB list */
|
|
InitializeListHead(&FatGlobalData.VcbListHead);
|
|
|
|
/* Register and reference our filesystem */
|
|
IoRegisterFileSystem(DeviceObject);
|
|
ObReferenceObject(DeviceObject);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PFAT_IRP_CONTEXT
|
|
NTAPI
|
|
FatBuildIrpContext(PIRP Irp,
|
|
BOOLEAN CanWait)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PFAT_IRP_CONTEXT IrpContext;
|
|
PVOLUME_DEVICE_OBJECT VolumeObject;
|
|
|
|
/* Get current IRP stack location */
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* Allocate memory for the Irp context */
|
|
IrpContext = ExAllocateFromNPagedLookasideList(&FatGlobalData.IrpContextList);
|
|
|
|
/* Zero init memory */
|
|
RtlZeroMemory(IrpContext, sizeof(FAT_IRP_CONTEXT));
|
|
|
|
/* Save IRP, MJ and MN */
|
|
IrpContext->Irp = Irp;
|
|
IrpContext->Stack = IrpSp;
|
|
IrpContext->MajorFunction = IrpSp->MajorFunction;
|
|
IrpContext->MinorFunction = IrpSp->MinorFunction;
|
|
|
|
/* Set DeviceObject */
|
|
if (IrpSp->FileObject)
|
|
{
|
|
IrpContext->DeviceObject = IrpSp->FileObject->DeviceObject;
|
|
|
|
/* Save VCB pointer */
|
|
VolumeObject = (PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject;
|
|
IrpContext->Vcb = &VolumeObject->Vcb;
|
|
|
|
/* TODO: Handle write-through */
|
|
}
|
|
else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)
|
|
{
|
|
/* Handle FSCTRL case */
|
|
IrpContext->DeviceObject = IrpSp->Parameters.MountVolume.Vpb->RealDevice;
|
|
}
|
|
|
|
/* Set Wait flag */
|
|
if (CanWait) IrpContext->Flags |= IRPCONTEXT_CANWAIT;
|
|
|
|
/* Return prepared context */
|
|
return IrpContext;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FatDestroyIrpContext(PFAT_IRP_CONTEXT IrpContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* Make sure it has no pinned stuff */
|
|
ASSERT(IrpContext->PinCount == 0);
|
|
|
|
/* If there is a FatIo context associated with it - free it */
|
|
if (IrpContext->FatIoContext)
|
|
{
|
|
if (!(IrpContext->Flags & IRPCONTEXT_STACK_IO_CONTEXT))
|
|
{
|
|
/* If a zero mdl was allocated - free it */
|
|
if (IrpContext->FatIoContext->ZeroMdl)
|
|
IoFreeMdl(IrpContext->FatIoContext->ZeroMdl);
|
|
|
|
/* Free memory of FatIo context */
|
|
ExFreePool(IrpContext->FatIoContext);
|
|
}
|
|
}
|
|
|
|
/* Free memory */
|
|
ExFreeToNPagedLookasideList(&FatGlobalData.IrpContextList, IrpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FatCompleteRequest(PFAT_IRP_CONTEXT IrpContext OPTIONAL,
|
|
PIRP Irp OPTIONAL,
|
|
NTSTATUS Status)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (IrpContext)
|
|
{
|
|
/* TODO: Unpin repinned BCBs */
|
|
//ASSERT(IrpContext->Repinned.Bcb[0] == NULL);
|
|
//FatUnpinRepinnedBcbs( IrpContext );
|
|
|
|
/* Destroy IRP context */
|
|
FatDestroyIrpContext(IrpContext);
|
|
}
|
|
|
|
/* Complete the IRP */
|
|
if (Irp)
|
|
{
|
|
/* Cleanup IoStatus.Information in case of error input operation */
|
|
if (NT_ERROR(Status) && (Irp->Flags & IRP_INPUT_OPERATION))
|
|
{
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
/* Save status and complete this IRP */
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
TYPE_OF_OPEN
|
|
NTAPI
|
|
FatDecodeFileObject(IN PFILE_OBJECT FileObject,
|
|
OUT PVCB *Vcb,
|
|
OUT PFCB *FcbOrDcb,
|
|
OUT PCCB *Ccb)
|
|
{
|
|
TYPE_OF_OPEN TypeOfOpen = UnopenedFileObject;
|
|
PVOID FsContext = FileObject->FsContext;
|
|
PVOID FsContext2 = FileObject->FsContext2;
|
|
|
|
/* If FsContext is NULL, then everything is NULL */
|
|
if (!FsContext)
|
|
{
|
|
*Ccb = NULL;
|
|
*FcbOrDcb = NULL;
|
|
*Vcb = NULL;
|
|
|
|
return TypeOfOpen;
|
|
}
|
|
|
|
/* CCB is always stored in FsContext2 */
|
|
*Ccb = FsContext2;
|
|
|
|
/* Switch according to the NodeType */
|
|
switch (FatNodeType(FsContext))
|
|
{
|
|
/* Volume */
|
|
case FAT_NTC_VCB:
|
|
*FcbOrDcb = NULL;
|
|
*Vcb = FsContext;
|
|
|
|
TypeOfOpen = ( *Ccb == NULL ? VirtualVolumeFile : UserVolumeOpen );
|
|
|
|
break;
|
|
|
|
/* Root or normal directory*/
|
|
case FAT_NTC_ROOT_DCB:
|
|
case FAT_NTC_DCB:
|
|
*FcbOrDcb = FsContext;
|
|
*Vcb = (*FcbOrDcb)->Vcb;
|
|
|
|
TypeOfOpen = (*Ccb == NULL ? DirectoryFile : UserDirectoryOpen);
|
|
|
|
DPRINT("Referencing a directory: %wZ\n", &(*FcbOrDcb)->FullFileName);
|
|
break;
|
|
|
|
/* File */
|
|
case FAT_NTC_FCB:
|
|
*FcbOrDcb = FsContext;
|
|
*Vcb = (*FcbOrDcb)->Vcb;
|
|
|
|
TypeOfOpen = (*Ccb == NULL ? EaFile : UserFileOpen);
|
|
|
|
DPRINT("Referencing a file: %wZ\n", &(*FcbOrDcb)->FullFileName);
|
|
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unknown node type %x\n", FatNodeType(FsContext));
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return TypeOfOpen;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FatSetFileObject(PFILE_OBJECT FileObject,
|
|
TYPE_OF_OPEN TypeOfOpen,
|
|
PVOID Fcb,
|
|
PCCB Ccb)
|
|
{
|
|
if (Fcb)
|
|
{
|
|
/* Check Fcb's type */
|
|
if (FatNodeType(Fcb) == FAT_NTC_VCB)
|
|
{
|
|
FileObject->Vpb = ((PVCB)Fcb)->Vpb;
|
|
}
|
|
else
|
|
{
|
|
FileObject->Vpb = ((PFCB)Fcb)->Vcb->Vpb;
|
|
}
|
|
}
|
|
|
|
/* Set FsContext */
|
|
if (FileObject)
|
|
{
|
|
FileObject->FsContext = Fcb;
|
|
FileObject->FsContext2 = Ccb;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
FatAcquireExclusiveVcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb)
|
|
{
|
|
/* Acquire VCB's resource if possible */
|
|
if (ExAcquireResourceExclusiveLite(&Vcb->Resource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
FatAcquireSharedVcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb)
|
|
{
|
|
/* Acquire VCB's resource if possible */
|
|
if (ExAcquireResourceSharedLite(&Vcb->Resource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FatReleaseVcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb)
|
|
{
|
|
/* Release VCB's resource */
|
|
ExReleaseResourceLite(&Vcb->Resource);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
FatAcquireExclusiveFcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb)
|
|
{
|
|
RetryLockingE:
|
|
/* Try to acquire the exclusive lock*/
|
|
if (ExAcquireResourceExclusiveLite(Fcb->Header.Resource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
/* Wait same way MS's FASTFAT wait, i.e.
|
|
checking that there are outstanding async writes,
|
|
or someone is waiting on it*/
|
|
if (Fcb->OutstandingAsyncWrites &&
|
|
((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
|
|
!FlagOn(IrpContext->Irp->Flags, IRP_NOCACHE) ||
|
|
ExGetSharedWaiterCount(Fcb->Header.Resource) ||
|
|
ExGetExclusiveWaiterCount(Fcb->Header.Resource)))
|
|
{
|
|
KeWaitForSingleObject(Fcb->OutstandingAsyncEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
/* Release the lock */
|
|
FatReleaseFcb(IrpContext, Fcb);
|
|
|
|
/* Retry */
|
|
goto RetryLockingE;
|
|
}
|
|
|
|
/* Return success */
|
|
return TRUE;
|
|
}
|
|
|
|
/* Return failure */
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
FatAcquireSharedFcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb)
|
|
{
|
|
RetryLockingS:
|
|
/* Try to acquire the shared lock*/
|
|
if (ExAcquireResourceSharedLite(Fcb->Header.Resource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
/* Wait same way MS's FASTFAT wait, i.e.
|
|
checking that there are outstanding async writes,
|
|
or someone is waiting on it*/
|
|
if (Fcb->OutstandingAsyncWrites &&
|
|
((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
|
|
!FlagOn(IrpContext->Irp->Flags, IRP_NOCACHE) ||
|
|
ExGetSharedWaiterCount(Fcb->Header.Resource) ||
|
|
ExGetExclusiveWaiterCount(Fcb->Header.Resource)))
|
|
{
|
|
KeWaitForSingleObject(Fcb->OutstandingAsyncEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
/* Release the lock */
|
|
FatReleaseFcb(IrpContext, Fcb);
|
|
|
|
/* Retry */
|
|
goto RetryLockingS;
|
|
}
|
|
|
|
/* Return success */
|
|
return TRUE;
|
|
}
|
|
|
|
/* Return failure */
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FatReleaseFcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb)
|
|
{
|
|
/* Release FCB's resource */
|
|
ExReleaseResourceLite(Fcb->Header.Resource);
|
|
}
|
|
|
|
PVOID
|
|
FASTCALL
|
|
FatMapUserBuffer(PIRP Irp)
|
|
{
|
|
if (!Irp->MdlAddress)
|
|
return Irp->UserBuffer;
|
|
else
|
|
return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
FatIsTopLevelIrp(IN PIRP Irp)
|
|
{
|
|
if (!IoGetTopLevelIrp())
|
|
{
|
|
IoSetTopLevelIrp(Irp);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FatNotifyReportChange(IN PFAT_IRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFCB Fcb,
|
|
IN ULONG Filter,
|
|
IN ULONG Action)
|
|
{
|
|
if (Fcb->FullFileName.Buffer == NULL)
|
|
FatSetFullFileNameInFcb(IrpContext, Fcb);
|
|
|
|
ASSERT(Fcb->FullFileName.Length != 0 );
|
|
ASSERT(Fcb->FileNameLength != 0 );
|
|
ASSERT(Fcb->FullFileName.Length > Fcb->FileNameLength );
|
|
ASSERT(Fcb->FullFileName.Buffer[(Fcb->FullFileName.Length - Fcb->FileNameLength)/sizeof(WCHAR) - 1] == L'\\' );
|
|
|
|
FsRtlNotifyFullReportChange(Vcb->NotifySync,
|
|
&Vcb->NotifyList,
|
|
(PSTRING)&Fcb->FullFileName,
|
|
(USHORT)(Fcb->FullFileName.Length -
|
|
Fcb->FileNameLength),
|
|
NULL,
|
|
NULL,
|
|
Filter,
|
|
Action,
|
|
NULL);
|
|
}
|
|
|
|
/* EOF */
|