diff --git a/build/VStudio/testing/memfs.vcxproj b/build/VStudio/testing/memfs.vcxproj
index 65db905d..80b0a4f9 100644
--- a/build/VStudio/testing/memfs.vcxproj
+++ b/build/VStudio/testing/memfs.vcxproj
@@ -101,7 +101,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MEMFS_STANDALONE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
..\..\..\src;..\..\..\inc
MultiThreaded
@@ -117,7 +117,7 @@
Level3
Disabled
- _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MEMFS_STANDALONE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
..\..\..\src;..\..\..\inc
MultiThreaded
@@ -135,7 +135,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MEMFS_STANDALONE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
..\..\..\src;..\..\..\inc
MultiThreaded
@@ -155,7 +155,7 @@
MaxSpeed
true
true
- NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MEMFS_STANDALONE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
..\..\..\src;..\..\..\inc
MultiThreaded
diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h
index cdd4914e..353bf5fb 100644
--- a/inc/winfsp/fsctl.h
+++ b/inc/winfsp/fsctl.h
@@ -176,7 +176,8 @@ enum
UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\
UINT32 WslFeatures:1; /* support features required for WSLinux */\
UINT32 DirectoryMarkerAsNextOffset:1; /* directory marker is next offset instead of last name */\
- UINT32 KmReservedFlags:4;\
+ UINT32 RejectIrpPriorToTransact0:1; /* reject IRP's prior to FspFsctlTransact with 0 buffers */\
+ UINT32 KmReservedFlags:3;\
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
diff --git a/src/dll/fs.c b/src/dll/fs.c
index 5b68e546..e2c36804 100644
--- a/src/dll/fs.c
+++ b/src/dll/fs.c
@@ -273,6 +273,11 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
OperationContext.Response = Response;
TlsSetValue(FspFileSystemTlsKey, &OperationContext);
+ Result = FspFsctlTransact(FileSystem->VolumeHandle, 0, 0, 0, 0, FALSE);
+ /* send a Transact0 to inform the FSD that the dispatcher is ready */
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
memset(Response, 0, sizeof *Response);
for (;;)
{
diff --git a/src/sys/create.c b/src/sys/create.c
index bbcd3344..4b34372d 100644
--- a/src/sys/create.c
+++ b/src/sys/create.c
@@ -284,6 +284,11 @@ static NTSTATUS FspFsvolCreateNoLock(
return STATUS_SUCCESS;
}
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+ if (!FspFsvolDeviceReadyToAcceptIrp(FsvolDeviceObject))
+ return STATUS_CANCELLED;
+#endif
+
PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
ULONG CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0xff;
ULONG CreateOptions = IrpSp->Parameters.Create.Options;
diff --git a/src/sys/driver.h b/src/sys/driver.h
index 85164a7f..b6da6824 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -1028,6 +1028,7 @@ NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLen
#define FspStatisticsAdd(S,F,V) ((S)->F += (V))
/* device management */
+#define FSP_DEVICE_REJECT_EARLY_IRP
enum
{
FspFsvolDeviceSecurityCacheCapacity = 100,
@@ -1082,6 +1083,9 @@ typedef struct
FSP_FSEXT_PROVIDER *Provider;
UNICODE_STRING VolumePrefix;
UNICODE_PREFIX_TABLE_ENTRY VolumePrefixEntry;
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+ LONG ReadyToAcceptIrp;
+#endif
FSP_IOQ *Ioq;
FSP_META_CACHE *SecurityCache;
FSP_META_CACHE *DirInfoCache;
@@ -1181,6 +1185,24 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+static inline
+BOOLEAN FspFsvolDeviceReadyToAcceptIrp(PDEVICE_OBJECT DeviceObject)
+{
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
+ if (!FsvolDeviceExtension->VolumeParams.RejectIrpPriorToTransact0)
+ return TRUE;
+ return 0 != InterlockedCompareExchange(&FsvolDeviceExtension->ReadyToAcceptIrp, 0, 0);
+}
+static inline
+VOID FspFsvolDeviceSetReadyToAcceptIrp(PDEVICE_OBJECT DeviceObject)
+{
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
+ if (!FsvolDeviceExtension->VolumeParams.RejectIrpPriorToTransact0)
+ return;
+ InterlockedExchange(&FsvolDeviceExtension->ReadyToAcceptIrp, 1);
+}
+#endif
static inline
BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING String)
{
diff --git a/src/sys/volinfo.c b/src/sys/volinfo.c
index c82b8e63..4ffda23e 100644
--- a/src/sys/volinfo.c
+++ b/src/sys/volinfo.c
@@ -286,6 +286,11 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
{
PAGED_CODE();
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+ if (!FspFsvolDeviceReadyToAcceptIrp(FsvolDeviceObject))
+ return STATUS_CANCELLED;
+#endif
+
NTSTATUS Result;
PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer;
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryVolume.Length;
@@ -414,6 +419,11 @@ static NTSTATUS FspFsvolSetVolumeInformation(
{
PAGED_CODE();
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+ if (!FspFsvolDeviceReadyToAcceptIrp(FsvolDeviceObject))
+ return STATUS_CANCELLED;
+#endif
+
NTSTATUS Result;
FS_INFORMATION_CLASS FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
diff --git a/src/sys/volume.c b/src/sys/volume.c
index a597a16c..992552df 100644
--- a/src/sys/volume.c
+++ b/src/sys/volume.c
@@ -277,6 +277,10 @@ static NTSTATUS FspVolumeCreateNoLock(
RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName,
FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf);
RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName);
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+ if (!FsvolDeviceExtension->VolumeParams.RejectIrpPriorToTransact0)
+ FsvolDeviceExtension->ReadyToAcceptIrp = 1;
+#endif
Result = FspDeviceInitialize(FsvolDeviceObject);
if (NT_SUCCESS(Result))
{
@@ -767,6 +771,11 @@ NTSTATUS FspVolumeTransact(
if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED;
+#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
+ if (0 == InputBufferLength && 0 == OutputBufferLength)
+ FspFsvolDeviceSetReadyToAcceptIrp(FsvolDeviceObject);
+#endif
+
NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PUINT8 BufferEnd;
diff --git a/tst/memfs/memfs.cpp b/tst/memfs/memfs.cpp
index efd86a35..1cc3ba7e 100644
--- a/tst/memfs/memfs.cpp
+++ b/tst/memfs/memfs.cpp
@@ -34,6 +34,12 @@
FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
"MEMFS_MAX_PATH must be greater than MAX_PATH.");
+/*
+ * Define the MEMFS_STANDALONE macro when building MEMFS as a standalone file system.
+ * This macro should be defined in the Visual Studio project settings, Makefile, etc.
+ */
+//#define MEMFS_STANDALONE
+
/*
* Define the MEMFS_NAME_NORMALIZATION macro to include name normalization support.
*/
@@ -74,7 +80,15 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
*/
#define MEMFS_WSL
- /*
+/*
+ * Define the MEMFS_REJECT_EARLY_IRP macro to reject IRP's sent
+ * to the file system prior to the dispatcher being started.
+ */
+#if defined(MEMFS_STANDALONE)
+#define MEMFS_REJECT_EARLY_IRP
+#endif
+
+/*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only.
*
@@ -2387,6 +2401,9 @@ NTSTATUS MemfsCreateFunnel(
VolumeParams.WslFeatures = 1;
#endif
VolumeParams.AllowOpenInKernelMode = 1;
+#if defined(MEMFS_REJECT_EARLY_IRP)
+ VolumeParams.RejectIrpPriorToTransact0 = 1;
+#endif
if (0 != VolumePrefix)
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),