reactos/drivers/filesystems/fastfat_new/fastfat.c
Timo Kreuzer 5eb25b5c24 Create a branch for audio work
svn path=/branches/audio-bringup/; revision=49478
2010-11-05 11:04:48 +00:00

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