mirror of
https://github.com/reactos/reactos.git
synced 2025-05-29 14:08:22 +00:00
[FASTFAT_NEW]
- Implement asynchronous and delayed close operations. - Fix a logical bug in FatiClose code, which led to always closing the file object (and freeing respective FCB/VCB/CCB), and then checking flags and queuing a delayed close. Instead, it should only try to close if it's not marked as a delayed close. - Support stuff added (queues, mutex for closing lists, etc). - Misc cleanup, debug silencing. svn path=/trunk/; revision=48525
This commit is contained in:
parent
8d3e4feb39
commit
e68f31b46a
7 changed files with 366 additions and 46 deletions
|
@ -11,6 +11,16 @@
|
|||
#define NDEBUG
|
||||
#include "fastfat.h"
|
||||
|
||||
VOID NTAPI
|
||||
FatQueueClose(IN PCLOSE_CONTEXT CloseContext,
|
||||
IN BOOLEAN DelayClose);
|
||||
|
||||
PCLOSE_CONTEXT NTAPI
|
||||
FatRemoveClose(PVCB Vcb OPTIONAL,
|
||||
PVCB LastVcbHint OPTIONAL);
|
||||
|
||||
const ULONG FatMaxDelayedCloseCount = 16;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
|
@ -246,8 +256,8 @@ FatiClose(IN PFAT_IRP_CONTEXT IrpContext,
|
|||
PVCB Vcb;
|
||||
PFCB Fcb;
|
||||
PCCB Ccb;
|
||||
BOOLEAN TopLevel, Wait, VcbDeleted = FALSE;
|
||||
NTSTATUS Status;
|
||||
BOOLEAN TopLevel, Wait, VcbDeleted = FALSE, DelayedClose = FALSE;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PCLOSE_CONTEXT CloseContext = NULL;
|
||||
|
||||
TopLevel = FatIsTopLevelIrp(Irp);
|
||||
|
@ -265,16 +275,57 @@ FatiClose(IN PFAT_IRP_CONTEXT IrpContext,
|
|||
/* It's possible to wait only if we are top level or not a system process */
|
||||
Wait = TopLevel && (PsGetCurrentProcess() != FatGlobalData.SystemProcess);
|
||||
|
||||
/* Call the common handler */
|
||||
Status = FatiCommonClose(Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted);
|
||||
|
||||
if (((TypeOfOpen == UserFileOpen ||
|
||||
TypeOfOpen == UserDirectoryOpen) &&
|
||||
/* Determine if it's a delayed close, by flags first */
|
||||
if ((TypeOfOpen == UserFileOpen || TypeOfOpen == UserDirectoryOpen) &&
|
||||
(Fcb->State & FCB_STATE_DELAY_CLOSE) &&
|
||||
!FatGlobalData.ShutdownStarted) ||
|
||||
Status == STATUS_PENDING)
|
||||
!FatGlobalData.ShutdownStarted)
|
||||
{
|
||||
DPRINT1("TODO: Queue a pending close request\n");
|
||||
DelayedClose = TRUE;
|
||||
}
|
||||
|
||||
/* If close is not delayed, try to perform the close operation */
|
||||
if (!DelayedClose)
|
||||
Status = FatiCommonClose(Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted);
|
||||
|
||||
/* We have to delay close if either it's defined by a flag or it was not possible
|
||||
to perform it synchronously */
|
||||
if (DelayedClose || Status == STATUS_PENDING)
|
||||
{
|
||||
DPRINT1("Queuing a pending close, Vcb %p, Fcb %p, Ccb %p\n", Vcb, Fcb, Ccb);
|
||||
|
||||
/* Check if a close context should be allocated */
|
||||
if (TypeOfOpen == VirtualVolumeFile)
|
||||
{
|
||||
ASSERT(Vcb->CloseContext != NULL);
|
||||
CloseContext = Vcb->CloseContext;
|
||||
Vcb->CloseContext = NULL;
|
||||
CloseContext->Free = TRUE;
|
||||
}
|
||||
else if (TypeOfOpen == DirectoryFile ||
|
||||
TypeOfOpen == EaFile)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
//CloseContext = FatAllocateCloseContext(Vcb);
|
||||
//ASSERT(CloseContext != NULL);
|
||||
CloseContext->Free = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: FatDeallocateCcbStrings( Ccb );
|
||||
|
||||
/* Set CloseContext to a buffer inside Ccb */
|
||||
CloseContext = &Ccb->CloseContext;
|
||||
CloseContext->Free = FALSE;
|
||||
SetFlag(Ccb->Flags, CCB_CLOSE_CONTEXT);
|
||||
}
|
||||
|
||||
/* Save all info in the close context */
|
||||
CloseContext->Vcb = Vcb;
|
||||
CloseContext->Fcb = Fcb;
|
||||
CloseContext->TypeOfOpen = TypeOfOpen;
|
||||
|
||||
/* Queue the close */
|
||||
FatQueueClose(CloseContext, (BOOLEAN)(Fcb && FlagOn(Fcb->State, FCB_STATE_DELAY_CLOSE)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -351,4 +402,250 @@ FatClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FatPendingClose(IN PVCB Vcb OPTIONAL)
|
||||
{
|
||||
PCLOSE_CONTEXT CloseContext;
|
||||
PVCB CurrentVcb = NULL;
|
||||
PVCB LastVcb = NULL;
|
||||
BOOLEAN FreeContext;
|
||||
ULONG Loops = 0;
|
||||
|
||||
/* Do the top-level IRP trick */
|
||||
if (!Vcb) IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
|
||||
|
||||
while ((CloseContext = FatRemoveClose(Vcb, LastVcb)))
|
||||
{
|
||||
if (!Vcb)
|
||||
{
|
||||
if (!FatGlobalData.ShutdownStarted)
|
||||
{
|
||||
if (CloseContext->Vcb != CurrentVcb)
|
||||
{
|
||||
Loops = 0;
|
||||
|
||||
/* Release previous VCB */
|
||||
if (CurrentVcb)
|
||||
ExReleaseResourceLite(&CurrentVcb->Resource);
|
||||
|
||||
/* Lock the new VCB */
|
||||
CurrentVcb = CloseContext->Vcb;
|
||||
(VOID)ExAcquireResourceExclusiveLite(&CurrentVcb->Resource, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try to lock */
|
||||
if (++Loops >= 20)
|
||||
{
|
||||
if (ExGetSharedWaiterCount(&CurrentVcb->Resource) +
|
||||
ExGetExclusiveWaiterCount(&CurrentVcb->Resource))
|
||||
{
|
||||
ExReleaseResourceLite(&CurrentVcb->Resource);
|
||||
(VOID)ExAcquireResourceExclusiveLite(&CurrentVcb->Resource, TRUE);
|
||||
}
|
||||
|
||||
Loops = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check open count */
|
||||
if (CurrentVcb->OpenFileCount <= 1)
|
||||
{
|
||||
ExReleaseResourceLite(&CurrentVcb->Resource);
|
||||
CurrentVcb = NULL;
|
||||
}
|
||||
}
|
||||
else if (CurrentVcb)
|
||||
{
|
||||
ExReleaseResourceLite(&CurrentVcb->Resource);
|
||||
CurrentVcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LastVcb = CurrentVcb;
|
||||
|
||||
/* Remember if we should free the context */
|
||||
FreeContext = CloseContext->Free;
|
||||
|
||||
FatiCommonClose(CloseContext->Vcb,
|
||||
CloseContext->Fcb,
|
||||
(FreeContext ? NULL : CONTAINING_RECORD(CloseContext, CCB, CloseContext)),
|
||||
CloseContext->TypeOfOpen,
|
||||
TRUE,
|
||||
NULL);
|
||||
|
||||
/* Free context if necessary */
|
||||
if (FreeContext) ExFreePool(CloseContext);
|
||||
}
|
||||
|
||||
/* Release VCB if necessary */
|
||||
if (CurrentVcb) ExReleaseResourceLite(&CurrentVcb->Resource);
|
||||
|
||||
/* Reset top level IRP */
|
||||
if (!Vcb) IoSetTopLevelIrp( NULL );
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FatCloseWorker(IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PVOID Context)
|
||||
{
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
FatPendingClose((PVCB)Context);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FatQueueClose(IN PCLOSE_CONTEXT CloseContext,
|
||||
IN BOOLEAN DelayClose)
|
||||
{
|
||||
BOOLEAN RunWorker = FALSE;
|
||||
|
||||
/* Acquire the close lists mutex */
|
||||
ExAcquireFastMutexUnsafe(&FatCloseQueueMutex);
|
||||
|
||||
/* Add it to the desired list */
|
||||
if (DelayClose)
|
||||
{
|
||||
InsertTailList(&FatGlobalData.DelayedCloseList,
|
||||
&CloseContext->GlobalLinks);
|
||||
InsertTailList(&CloseContext->Vcb->DelayedCloseList,
|
||||
&CloseContext->VcbLinks);
|
||||
|
||||
FatGlobalData.DelayedCloseCount++;
|
||||
|
||||
if (FatGlobalData.DelayedCloseCount > FatMaxDelayedCloseCount &&
|
||||
!FatGlobalData.AsyncCloseActive)
|
||||
{
|
||||
FatGlobalData.AsyncCloseActive = TRUE;
|
||||
RunWorker = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertTailList(&FatGlobalData.AsyncCloseList,
|
||||
&CloseContext->GlobalLinks);
|
||||
InsertTailList(&CloseContext->Vcb->AsyncCloseList,
|
||||
&CloseContext->VcbLinks);
|
||||
|
||||
FatGlobalData.AsyncCloseCount++;
|
||||
|
||||
if (!FatGlobalData.AsyncCloseActive)
|
||||
{
|
||||
FatGlobalData.AsyncCloseActive = TRUE;
|
||||
RunWorker = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the close lists mutex */
|
||||
ExReleaseFastMutexUnsafe(&FatCloseQueueMutex);
|
||||
|
||||
if (RunWorker)
|
||||
IoQueueWorkItem(FatGlobalData.FatCloseItem, FatCloseWorker, CriticalWorkQueue, NULL);
|
||||
}
|
||||
|
||||
PCLOSE_CONTEXT
|
||||
NTAPI
|
||||
FatRemoveClose(PVCB Vcb OPTIONAL,
|
||||
PVCB LastVcbHint OPTIONAL)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PCLOSE_CONTEXT CloseContext;
|
||||
BOOLEAN IsWorker = FALSE;
|
||||
|
||||
/* Acquire the close lists mutex */
|
||||
ExAcquireFastMutexUnsafe(&FatCloseQueueMutex);
|
||||
|
||||
if (!Vcb) IsWorker = TRUE;
|
||||
|
||||
if (Vcb == NULL && LastVcbHint != NULL)
|
||||
{
|
||||
// TODO: A very special case of overflowing the queue
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/* Usual processing from a worker thread */
|
||||
if (!Vcb)
|
||||
{
|
||||
TryToCloseAgain:
|
||||
|
||||
/* Is there anything in the async close list */
|
||||
if (!IsListEmpty(&FatGlobalData.AsyncCloseList))
|
||||
{
|
||||
Entry = RemoveHeadList(&FatGlobalData.AsyncCloseList);
|
||||
FatGlobalData.AsyncCloseCount--;
|
||||
|
||||
CloseContext = CONTAINING_RECORD(Entry,
|
||||
CLOSE_CONTEXT,
|
||||
GlobalLinks);
|
||||
|
||||
RemoveEntryList(&CloseContext->VcbLinks);
|
||||
} else if (!IsListEmpty(&FatGlobalData.DelayedCloseList) &&
|
||||
(FatGlobalData.DelayedCloseCount > FatMaxDelayedCloseCount/2 ||
|
||||
FatGlobalData.ShutdownStarted))
|
||||
{
|
||||
/* In case of a shutdown or when delayed queue is filled at half - perform closing */
|
||||
Entry = RemoveHeadList(&FatGlobalData.DelayedCloseList);
|
||||
FatGlobalData.DelayedCloseCount--;
|
||||
|
||||
CloseContext = CONTAINING_RECORD(Entry,
|
||||
CLOSE_CONTEXT,
|
||||
GlobalLinks);
|
||||
RemoveEntryList(&CloseContext->VcbLinks);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to close */
|
||||
CloseContext = NULL;
|
||||
if (IsWorker) FatGlobalData.AsyncCloseActive = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsListEmpty(&Vcb->AsyncCloseList))
|
||||
{
|
||||
/* Is there anything in the async close list */
|
||||
Entry = RemoveHeadList(&Vcb->AsyncCloseList);
|
||||
FatGlobalData.AsyncCloseCount--;
|
||||
|
||||
CloseContext = CONTAINING_RECORD(Entry,
|
||||
CLOSE_CONTEXT,
|
||||
VcbLinks);
|
||||
|
||||
RemoveEntryList(&CloseContext->GlobalLinks);
|
||||
}
|
||||
else if (!IsListEmpty(&Vcb->DelayedCloseList))
|
||||
{
|
||||
/* Process delayed close list */
|
||||
Entry = RemoveHeadList(&Vcb->DelayedCloseList);
|
||||
FatGlobalData.DelayedCloseCount--;
|
||||
|
||||
CloseContext = CONTAINING_RECORD(Entry,
|
||||
CLOSE_CONTEXT,
|
||||
VcbLinks);
|
||||
|
||||
RemoveEntryList(&CloseContext->GlobalLinks);
|
||||
}
|
||||
else if (LastVcbHint)
|
||||
{
|
||||
/* Try again */
|
||||
goto TryToCloseAgain;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to close */
|
||||
CloseContext = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the close lists mutex */
|
||||
ExReleaseFastMutexUnsafe(&FatCloseQueueMutex);
|
||||
|
||||
return CloseContext;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -111,13 +111,6 @@ FatCreateRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|||
#endif
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/* Initialize free dirent bitmap */
|
||||
RtlInitializeBitMap(&Dcb->Dcb.FreeBitmap, NULL, 0);
|
||||
|
||||
/* Fill the dirent bitmap */
|
||||
DPRINT1("Filling the free dirent bitmap is missing\n");
|
||||
//FatCheckFreeDirentBitmap( IrpContext, Dcb );
|
||||
}
|
||||
|
||||
PFCB
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
/* GLOBALS ******************************************************************/
|
||||
|
||||
FAT_GLOBAL_DATA FatGlobalData;
|
||||
FAST_MUTEX FatCloseQueueMutex;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
|
@ -109,6 +110,12 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
|
|||
/* 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);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define TAG_FCB 'BCFV'
|
||||
#define TAG_IRP 'PRIV'
|
||||
#define TAG_VFAT 'TAFV'
|
||||
#define TAG_FSD_CLOSE_CONTEXT 'CLCV'
|
||||
|
||||
|
||||
/* Global resource acquire/release */
|
||||
|
@ -183,6 +184,8 @@ FatNoopRelease(IN PVOID Context);
|
|||
|
||||
/* --------------------------------------------------------- fastfat.c */
|
||||
|
||||
extern FAST_MUTEX FatCloseQueueMutex;
|
||||
|
||||
PFAT_IRP_CONTEXT NTAPI
|
||||
FatBuildIrpContext(PIRP Irp, BOOLEAN CanWait);
|
||||
|
||||
|
|
|
@ -163,6 +163,10 @@ FatInitializeVcb(IN PFAT_IRP_CONTEXT IrpContext,
|
|||
/* Initialize VCB's resource */
|
||||
ExInitializeResourceLite(&Vcb->Resource);
|
||||
|
||||
/* Initialize close queue lists */
|
||||
InitializeListHead(&Vcb->AsyncCloseList);
|
||||
InitializeListHead(&Vcb->DelayedCloseList);
|
||||
|
||||
/* Initialize CC */
|
||||
CcInitializeCacheMap(Vcb->StreamFileObject,
|
||||
(PCC_FILE_SIZES)&Vcb->Header.AllocationSize,
|
||||
|
@ -243,6 +247,9 @@ FatUninitializeVcb(IN PVCB Vcb)
|
|||
Vcb->StreamFileObject = NULL;
|
||||
}
|
||||
|
||||
/* Free ContextClose if it's not freed up already */
|
||||
if (Vcb->CloseContext) ExFreePool(Vcb->CloseContext);
|
||||
|
||||
/* Free notifications stuff */
|
||||
FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
|
||||
|
||||
|
|
|
@ -39,6 +39,16 @@ typedef struct _FAT_GLOBAL_DATA
|
|||
/* Jan 1, 1980 System Time */
|
||||
LARGE_INTEGER DefaultFileTime;
|
||||
|
||||
/* Queued close */
|
||||
ULONG AsyncCloseCount;
|
||||
ULONG DelayedCloseCount;
|
||||
LIST_ENTRY AsyncCloseList;
|
||||
LIST_ENTRY DelayedCloseList;
|
||||
PIO_WORKITEM FatCloseItem;
|
||||
|
||||
/* Various flags */
|
||||
BOOLEAN AsyncCloseActive;
|
||||
|
||||
/* FullFAT integration */
|
||||
FF_IOMAN *Ioman;
|
||||
FF_ERROR FF_Error;
|
||||
|
@ -171,6 +181,8 @@ typedef struct _VCB
|
|||
VCB_CONDITION Condition;
|
||||
ERESOURCE Resource;
|
||||
struct _CLOSE_CONTEXT *CloseContext;
|
||||
LIST_ENTRY AsyncCloseList;
|
||||
LIST_ENTRY DelayedCloseList;
|
||||
|
||||
/* Direct volume access */
|
||||
SHARE_ACCESS ShareAccess;
|
||||
|
@ -239,6 +251,18 @@ typedef struct _VOLUME_DEVICE_OBJECT
|
|||
VCB Vcb; /* Must be the last entry! */
|
||||
};
|
||||
} VOLUME_DEVICE_OBJECT, *PVOLUME_DEVICE_OBJECT;
|
||||
|
||||
typedef enum _TYPE_OF_OPEN
|
||||
{
|
||||
UnopenedFileObject,
|
||||
UserFileOpen,
|
||||
UserDirectoryOpen,
|
||||
UserVolumeOpen,
|
||||
VirtualVolumeFile,
|
||||
DirectoryFile,
|
||||
EaFile
|
||||
} TYPE_OF_OPEN;
|
||||
|
||||
//
|
||||
// Short name always exists in FAT
|
||||
//
|
||||
|
@ -342,8 +366,6 @@ typedef struct _FCB
|
|||
PFILE_OBJECT DirectoryFile;
|
||||
/* Directory data stream (just handy to have it). */
|
||||
//PFILE_OBJECT StreamFileObject;
|
||||
/* Bitmap to search for free dirents. */
|
||||
RTL_BITMAP FreeBitmap;
|
||||
/* Names */
|
||||
PRTL_SPLAY_LINKS SplayLinksAnsi;
|
||||
PRTL_SPLAY_LINKS SplayLinksUnicode;
|
||||
|
@ -388,28 +410,6 @@ typedef struct _FAT_FIND_DIRENT_CONTEXT
|
|||
BOOLEAN Valid8dot3Name;
|
||||
} FAT_FIND_DIRENT_CONTEXT, *PFAT_FIND_DIRENT_CONTEXT;
|
||||
|
||||
typedef struct _CCB
|
||||
{
|
||||
CSHORT NodeTypeCode;
|
||||
CSHORT NodeByteSize;
|
||||
|
||||
LARGE_INTEGER CurrentByteOffset;
|
||||
ULONG Entry;
|
||||
UNICODE_STRING SearchPattern;
|
||||
UCHAR Flags;
|
||||
} CCB, *PCCB;
|
||||
|
||||
typedef enum _TYPE_OF_OPEN
|
||||
{
|
||||
UnopenedFileObject,
|
||||
UserFileOpen,
|
||||
UserDirectoryOpen,
|
||||
UserVolumeOpen,
|
||||
VirtualVolumeFile,
|
||||
DirectoryFile,
|
||||
EaFile
|
||||
} TYPE_OF_OPEN;
|
||||
|
||||
typedef struct _CLOSE_CONTEXT
|
||||
{
|
||||
LIST_ENTRY GlobalLinks;
|
||||
|
@ -421,6 +421,18 @@ typedef struct _CLOSE_CONTEXT
|
|||
BOOLEAN Free;
|
||||
} CLOSE_CONTEXT, *PCLOSE_CONTEXT;
|
||||
|
||||
typedef struct _CCB
|
||||
{
|
||||
CSHORT NodeTypeCode;
|
||||
CSHORT NodeByteSize;
|
||||
|
||||
LARGE_INTEGER CurrentByteOffset;
|
||||
ULONG Entry;
|
||||
UNICODE_STRING SearchPattern;
|
||||
UCHAR Flags;
|
||||
CLOSE_CONTEXT CloseContext;
|
||||
} CCB, *PCCB;
|
||||
|
||||
typedef enum _FILE_TIME_INDEX
|
||||
{
|
||||
FileCreationTime = 0,
|
||||
|
@ -432,9 +444,10 @@ typedef enum _FILE_TIME_INDEX
|
|||
#define CCB_SEARCH_RETURN_SINGLE_ENTRY 0x01
|
||||
#define CCB_SEARCH_PATTERN_LEGAL_8DOT3 0x02
|
||||
#define CCB_SEARCH_PATTERN_HAS_WILD_CARD 0x04
|
||||
#define CCB_DASD_IO 0x10
|
||||
#define CCB_READ_ONLY 0x20
|
||||
#define CCB_DELETE_ON_CLOSE 0x40
|
||||
#define CCB_COMPLETE_DISMOUNT 0x80
|
||||
#define CCB_DASD_IO 0x08
|
||||
#define CCB_READ_ONLY 0x10
|
||||
#define CCB_DELETE_ON_CLOSE 0x20
|
||||
#define CCB_COMPLETE_DISMOUNT 0x40
|
||||
#define CCB_CLOSE_CONTEXT 0x80
|
||||
|
||||
extern FAT_GLOBAL_DATA FatGlobalData;
|
||||
|
|
|
@ -171,7 +171,7 @@ FatUserFsCtrl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
|
|||
break;
|
||||
|
||||
default:
|
||||
DPRINT1("FatUserFsCtrl(), unhandled fs control code 0x%x\n", Code);
|
||||
DPRINT("FatUserFsCtrl(), unhandled fs control code 0x%x\n", Code);
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
FatCompleteRequest(IrpContext, Irp, Status);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue