Compare commits

..

32 Commits
v1.7 ... v1.8

Author SHA1 Message Date
2be71fa425 build,changelog: version 2020.2 Gold 2020-10-30 14:02:26 -07:00
c77690e59d update changelog and version number 2020-10-01 17:13:43 -07:00
32a5b2bc64 tst: winfsp-tests: rename_backslash_test 2020-10-01 11:46:55 -07:00
5045403d85 sys: FspFsvolSetRenameInformation: tolerate trailing backslash on target name 2020-09-28 16:01:38 -07:00
13a52c4ab4 tools: parselog: parse winfsp logs 2020-08-26 18:30:30 -07:00
c18d4f1508 tools: parselog: parse winfsp logs 2020-08-26 16:01:14 -07:00
fcfebb968f tools: parselog: parse winfsp logs 2020-08-26 14:52:53 -07:00
10053bc759 tst: memfs-fuse3: Makefile: fix build under Cygwin gcc 2020-08-20 16:03:46 -07:00
7985827c73 build: update version number 2020-08-08 10:13:31 -07:00
13146e4854 update Changelog 2020-08-08 10:09:00 -07:00
84e0744c28 sys: FspVolumeTransact: FSP_FSCTL_TRANSACT_INTERNAL
Zero out OutputBuffer on error to avoid confusion for fsext providers.
2020-07-29 22:51:17 -07:00
20e19cb0fc update Changelog 2020-07-24 12:56:24 -07:00
2326521ef8 appveyor: disable cygfuse x86 build
This improves slow builds.
2020-07-22 15:45:04 -07:00
0296502f24 sys: FspFsvolReadNonCached: acquire FileNode shared
See GitHub issue #291 for discussion
2020-07-22 15:42:06 -07:00
5d0b10d0b6 Changelog: add missing changes for v1.7 2020-07-07 13:56:53 -07:00
5fac25d200 update Changelog 2020-07-04 15:43:34 -07:00
b82aeeadbd tools: deploy.bat 2020-06-14 14:46:13 -07:00
dcaa24bc52 tools: deploy.bat, debug.bat 2020-06-09 18:09:56 -07:00
7e37fc57f9 doc: container support doc: fix version typo 2020-06-08 23:04:55 -07:00
8efe1f3a1f doc: container support doc 2020-06-08 22:49:01 -07:00
aa3beba928 sys: silo support 2020-06-05 15:47:19 -07:00
899cd5595d sys: FspIsNtDdiVersionAvailable 2020-06-01 23:11:33 -07:00
6bcbfd5380 tst: winfsp-tests: disable query_winfsp_tests over --external 2020-05-25 12:58:20 -07:00
a197b99960 tst: winfsp-tests: disable query_winfsp_tests over shares 2020-05-25 11:49:36 -07:00
2ffb8a1c97 sys: FSP_FSCTL_QUERY_WINFSP
The FSP_FSCTL_QUERY_WINFSP code provides a simple method to determine if
the file system backing a file is a WinFsp file system. To use issue a

    DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &Bytes, 0)

If the return value is TRUE this is a WinFsp file system.
2020-05-24 21:04:28 -07:00
fc18b70a00 tools: deploy: winfsp checkpoint 2020-05-24 00:18:57 -07:00
191c98bd41 tools: vcvarsall.bat: minor fix 2020-05-21 18:59:01 -07:00
5360f5ca6e tools: vcvarsall.bat: minor fix 2020-05-21 18:05:21 -07:00
89aaf33b62 tools: deploy: hyper-v support 2020-05-22 01:33:02 +01:00
675ecf2e51 tools: switch default build to latest Visual Studio 2020-05-21 15:51:32 -07:00
b663cfdca5 tools: update ntstatus.bat, winerror.bat for latest SDK's 2020-05-21 15:23:21 -07:00
dcf83b6d64 build: version.properties bump version to 2020.2 Beta2 2020-05-21 15:09:37 -07:00
30 changed files with 1369 additions and 162 deletions

View File

@ -1,5 +1,96 @@
= Changelog
v1.8 (2020.2)::
Changes since v1.7:
* [FSD] WinFsp now supports Windows containers. See the link:doc/WinFsp-Container-Support.asciidoc[WinFsp Container Support] document for details.
* [FSD] The `FSP_FSCTL_QUERY_WINFSP` code provides a simple method to determine if
the file system backing a file is a WinFsp file system. To use issue a
+
----
DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &Bytes, 0)
----
+
If the return value is TRUE this is a WinFsp file system.
* [FSD] A fix regarding concurrency of READs on the same file: WinFsp was supposed to allow concurrent READ requests on the same file (e.g. two concurrent overlapped `ReadFile` requests on the same `HANDLE`) to be handled concurrently by the file system; unfortunately due to a problem in recent versions of WinFsp READ requests on the same file were serialized. This problem has now been fixed. See GitHub issue #291 for more details.
** *NOTE*: It may be that some file system was inadvertently relying on WinFsp's implicit serialization of READs in this case. Please test your file system thoroughly against this version, especially with regard to READ serialization. Related XKCD: https://imgs.xkcd.com/comics/workflow.png
* [FSD] When renaming files or directories NTFS allows the target name to contain a backslash at the end (even for files!) whereas WinFsp did not. This problem has been fixed and a test has been added in `winfsp-tests`.
v1.8B3 (2020.2 B2)::
Changes since v1.7:
* [FSD] WinFsp now supports Windows containers. See the link:doc/WinFsp-Container-Support.asciidoc[WinFsp Container Support] document for details.
* [FSD] The `FSP_FSCTL_QUERY_WINFSP` code provides a simple method to determine if
the file system backing a file is a WinFsp file system. To use issue a
+
----
DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &Bytes, 0)
----
+
If the return value is TRUE this is a WinFsp file system.
* [FSD] A fix regarding concurrency of READs on the same file: WinFsp was supposed to allow concurrent READ requests on the same file (e.g. two concurrent overlapped `ReadFile` requests on the same `HANDLE`) to be handled concurrently by the file system; unfortunately due to a problem in recent versions of WinFsp READ requests on the same file were serialized. This problem has now been fixed. See GitHub issue #291 for more details.
** *NOTE*: It may be that some file system was inadvertently relying on WinFsp's implicit serialization of READs in this case. Please test your file system thoroughly against this version, especially with regard to READ serialization. Related XKCD: https://imgs.xkcd.com/comics/workflow.png
* [FSD] When renaming files or directories NTFS allows the target name to contain a backslash at the end (even for files!) whereas WinFsp did not. This problem has been fixed and a test has been added in `winfsp-tests`.
v1.8B2 (2020.2 B2)::
Changes since v1.7:
* [FSD] WinFsp now supports Windows containers. See the link:doc/WinFsp-Container-Support.asciidoc[WinFsp Container Support] document for details.
* [FSD] The `FSP_FSCTL_QUERY_WINFSP` code provides a simple method to determine if
the file system backing a file is a WinFsp file system. To use issue a
+
----
DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &Bytes, 0)
----
+
If the return value is TRUE this is a WinFsp file system.
* [FSD] A fix regarding concurrency of READs on the same file: WinFsp was supposed to allow concurrent READ requests on the same file (e.g. two concurrent overlapped `ReadFile` requests on the same `HANDLE`) to be handled concurrently by the file system; unfortunately due to a problem in recent versions of WinFsp READ requests on the same file were serialized. This problem has now been fixed. See GitHub issue #291 for more details.
** *NOTE*: It may be that some file system was inadvertently relying on WinFsp's implicit serialization of READs in this case. Please test your file system thoroughly against this version, especially with regard to READ serialization. Related XKCD: https://imgs.xkcd.com/comics/workflow.png
v1.8B1 (2020.2 B1)::
Changes since v1.7:
* [FSD] WinFsp now supports Windows containers. See the link:doc/WinFsp-Container-Support.asciidoc[WinFsp Container Support] document for details.
* [FSD] The `FSP_FSCTL_QUERY_WINFSP` code provides a simple method to determine if
the file system backing a file is a WinFsp file system. To use issue a
+
----
DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &Bytes, 0)
----
+
If the return value is TRUE this is a WinFsp file system.
v1.7 (2020.1)::
Changes since v1.6:
* [FUSE] FUSE invalid directory entries no longer break the entire directory listing. Such invalid directory entries are logged. (GitHub PR #292.)
* [LAUNCH] The Launcher can now restart file systems that have crashed. Set `Recovery=1` in the file system's registry entry.
* [LAUNCH] The Launcher can now redirect file system standard error output. Set `Stderr=PATH` in the file system's registry entry.
* [FIX] Work around a problem in CreateProcess/CreateSection that allowed a faulty or malicious file system to bugcheck Windows.
* [FIX] Work around an incompatibility with Avast Antivirus.
** Native and .NET file systems that experience this problem should set the flag `RejectIrpPriorToTransact0` in `FSP_FSCTL_VOLUME_PARAMS` to `1`. This is only required when mounting on a directory with Avast Antivirus present.
** FUSE file systems do not need to do anything special as this flag is always enabled.
* [FIX] Fix junction (mount point reparse point) handling. (GitHub issue #269.)
v1.7B2 (2020.1 B2)::
Changes since v1.6:

View File

@ -35,8 +35,8 @@ build_script:
# build cygfuse
- C:\cygwin64\setup-x86_64.exe -qnNd -P cygport
- C:\cygwin64\bin\bash --login -c "make -C '%CD%\opt\cygfuse' dist"
- C:\cygwin\setup-x86.exe -qnNd -P cygport
- C:\cygwin\bin\bash --login -c "make -C '%CD%\opt\cygfuse' dist"
#- C:\cygwin\setup-x86.exe -qnNd -P cygport
#- C:\cygwin\bin\bash --login -c "make -C '%CD%\opt\cygfuse' dist"
# build winfsp
- tools\build.bat %CONFIGURATION%

View File

@ -16,9 +16,9 @@
<MyCompanyName>Navimatics LLC</MyCompanyName>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<MyCanonicalVersion>1.7</MyCanonicalVersion>
<MyCanonicalVersion>1.8</MyCanonicalVersion>
<MyProductVersion>2020.1</MyProductVersion>
<MyProductVersion>2020.2</MyProductVersion>
<MyProductStage>Gold</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>

View File

@ -185,6 +185,7 @@
<ClCompile Include="..\..\src\sys\read.c" />
<ClCompile Include="..\..\src\sys\security.c" />
<ClCompile Include="..\..\src\sys\shutdown.c" />
<ClCompile Include="..\..\src\sys\silo.c" />
<ClCompile Include="..\..\src\sys\statistics.c" />
<ClCompile Include="..\..\src\sys\util.c" />
<ClCompile Include="..\..\src\sys\volinfo.c" />

View File

@ -122,6 +122,9 @@
<ClCompile Include="..\..\src\shared\ku\uuid5.c">
<Filter>Source\shared\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sys\silo.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h">

View File

@ -0,0 +1,73 @@
= WinFsp Container Support
WinFsp gained support for Windows Containers in release 2020.2 B1. This document discusses this new functionality and explains how user mode file systems can take advantage of it.
NOTE: WinFsp support for Windows Containers is at this time highly experimental. It may change substantially in the future or eliminated altogether.
== Windows Containers
Containers are a technology for deployment and execution of applications in an isolated environment. Applications deployed inside a container cannot be affected by or affect applications in other containers or in the host operating system.
Containers on Windows provide isolation via one of two modes:
- The _Hyper-V_ isolation mode where a container runs in its own virtual machine and has its own kernel.
- The _process_ isolation mode where a container runs in a "silo" inside the host operating system's kernel. This is the same model used in containers for Linux.
WinFsp supports containers that use the process isolation mode in versions of Windows 10 1809 and later.
=== Server Silos
Containers using the process isolation mode are called _server silos_. Server silos are built on top of kernel job objects that have been extended with additional capabities useful for containers. Most importantly each server silo has its own object namespace root directory that is distinct from the host's object namespace root directory. This allows for all named kernel objects inside a server silo to be isolated from named objects in other server silos or the host.
The Windows kernel provides a number of DDI's (Device Driver Interfaces) to enable kernel drivers to work with server silos. The WinFsp FSD uses these DDI's to monitor silo creation and termination and manage its own devices within the silo's object namespace.
=== Docker
In order to manage containers on Windows a version of Docker for Windows is needed. In order to use server silos and process isolation with Docker the switch `--isolation=process` must be used when creating a container:
----
docker run --isolation=process ...
----
== Containerized User Mode File Systems
The WinFsp 2020.2 B1 release gained the ability for user mode file systems to run inside a server silo container and expose a file system either within the container or to the host operating system. This allows for user mode file systems to be containerized.
There are a few considerations that must be taken into account when deploying a user mode file system in a container:
* When using WinFsp with containers the process isolation mode must be used.
* WinFsp currently supports the Windows Server Core and Windows base images. Work is underway for Nano Server compatibility.
* User mode file systems that run in a container cannot start the FSD, because containers disallow driver loading. (Usually the WinFsp DLL automatically starts the WinFsp FSD when it is not already running, but this is not possible within a container.)
+
To work around this problem start the FSD outside the container. For example, the FSD can be started in the host using the `sc.exe` utility.
+
----
sc.exe start winfsp
----
+
Once the FSD has been started it will monitor server silo creation and termination and will set things up so that containerized user mode file systems will be able to interface with it.
* WinFsp file systems typically use the registry to locate and load the WinFsp DLL (see `FspLoad` in `winfsp/winfsp.h`). However the registry inside a container does not contain any WinFsp entries. The easiest workaround is to hardcode the location of the WinFsp installation within the container, which will also hardcode the location of the WinFsp DLL.
* During development it is sometimes useful to bind mount the WinFsp installation directory into the container. For example:
+
----
docker run -it --rm --isolation=process "-vC:\Program Files (x86)\WinFsp:C:\Program Files (x86)\WinFsp:RO" mcr.microsoft.com/windows/servercore:2004 cmd.exe
----
* When a WinFsp based file system is mounted as a disk file system within a container, it is only visible within that container. For example, the drive `Z:` below and associated file system volume will be accessible only within the container:
+
----
memfs-x64 -i -F NTFS -m Z:
----
* When a WinFsp based file system is mounted as a network file system within a container, the file system becomes accessible **outside** the container via its UNC prefix. For example, while the drive `Y:` below will be accessible only within the container, the file system volume will be accessible from both the container and the host via the UNC prefix `\\memfs\share`.
+
----
memfs-x64 -i -F NTFS -m Y: -u \memfs\share
----
+
The reason that this happens is that server silo containers share the same MUP device object with the host. The MUP (Multiple UNC Provider) is the Windows kernel component responsible for resolving UNC prefixes. It is unclear at this time whether this "leak" from the container to the host via the shared MUP is intentional or whether it is an unintended consequence. I note that the server silo MUP entry in the object namespace is a symbolic link, which suggests that the shared MUP device object was a conscious decision by Microsoft.

View File

@ -71,6 +71,10 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_TRANSACT_INTERNAL \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'I', METHOD_NEITHER, FILE_ANY_ACCESS)
/* fsvol device codes */
#define FSP_FSCTL_QUERY_WINFSP \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + '?', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))

View File

@ -242,6 +242,22 @@ static NTSTATUS FspFsctlStartService(VOID)
DWORD LastError;
NTSTATUS Result;
/* Determine if we are running inside container.
*
* See https://github.com/microsoft/perfview/blob/V1.9.65/src/TraceEvent/TraceEventSession.cs#L525
* See https://stackoverflow.com/a/50748300
*/
LastError = RegGetValueW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control",
L"ContainerType",
RRF_RT_REG_DWORD, 0,
0, 0);
if (ERROR_SUCCESS == LastError)
{
Result = STATUS_SUCCESS;
goto exit;
}
ScmHandle = OpenSCManagerW(0, 0, 0);
if (0 == ScmHandle)
{

View File

@ -21,26 +21,16 @@
#include <sys/driver.h>
/*
* Define the following macro to include FspUnload.
*
* Note that this driver is no longer unloadable.
* See the comments in DriverEntry as to why!
*/
//#define FSP_UNLOAD
DRIVER_INITIALIZE DriverEntry;
static VOID FspDriverMultiVersionInitialize(VOID);
#if defined(FSP_UNLOAD)
DRIVER_UNLOAD FspUnload;
#endif
static NTSTATUS FspDriverInitializeDevices(VOID);
static VOID FspDriverFinalizeDevices(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(INIT, FspDriverMultiVersionInitialize)
#if defined(FSP_UNLOAD)
#pragma alloc_text(PAGE, FspUnload)
#endif
#pragma alloc_text(PAGE, FspDriverInitializeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevices)
#endif
NTSTATUS DriverEntry(
@ -49,9 +39,6 @@ NTSTATUS DriverEntry(
FSP_ENTER_DRV();
/* setup the driver object */
#if defined(FSP_UNLOAD)
DriverObject->DriverUnload = FspUnload;
#endif
DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose;
DriverObject->MajorFunction[IRP_MJ_READ] = FspRead;
@ -133,94 +120,41 @@ NTSTATUS DriverEntry(
#pragma prefast(suppress:28175, "We are a filesystem: ok to access FastIoDispatch")
DriverObject->FastIoDispatch = &FspFastIoDispatch;
BOOLEAN InitDoneGRes = FALSE, InitDonePsBuf = FALSE;
UNICODE_STRING DeviceSddl;
UNICODE_STRING DeviceName;
BOOLEAN InitDoneGRes = FALSE, InitDoneSilo = FALSE, InitDonePsBuf = FALSE,
InitDoneDevices = FALSE;
FspDriverObject = DriverObject;
FspDriverMultiVersionInitialize();
ExInitializeResourceLite(&FspDeviceGlobalResource);
InitDoneGRes = TRUE;
FspDriverMultiVersionInitialize();
Result = FspSiloInitialize(FspDriverInitializeDevices, FspDriverFinalizeDevices);
if (!NT_SUCCESS(Result))
goto exit;
InitDoneSilo = TRUE;
Result = FspProcessBufferInitialize();
if (!NT_SUCCESS(Result))
goto exit;
InitDonePsBuf = TRUE;
/* create the file system control device objects */
RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL);
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&FspFsctlDiskDeviceObject);
Result = FspDriverInitializeDevices();
if (!NT_SUCCESS(Result))
goto exit;
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&FspFsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0,
FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE,
&FspFsmupDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
#if DBG
/*
* Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes
* to GitHub user @thinkport.
*
* On debug builds set DO_LOW_PRIORITY_FILESYSTEM to place the file system
* at the end of the file system list during IoRegisterFileSystem below.
* This allows us to test the behavior of our Fsvrt devices when foreign
* file systems attempt to use them for mounting.
*/
SetFlag(FspFsctlDiskDeviceObject->Flags, DO_LOW_PRIORITY_FILESYSTEM);
#endif
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsmupDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME);
Result = FsRtlRegisterUncProviderEx(&FspMupHandle,
&DeviceName, FspFsmupDeviceObject, 0);
if (!NT_SUCCESS(Result))
goto exit;
/*
* Register our "disk" device as a file system. We do not register our "net" device
* as a file system; we register with the MUP instead.
*
* Please note that the call below makes our driver unloadable. In fact the driver
* remains unloadable even if we issue an IoUnregisterFileSystem() call immediately
* after our IoRegisterFileSystem() call! Some system component appears to keep an
* extra reference to our device somewhere.
*/
IoRegisterFileSystem(FspFsctlDiskDeviceObject);
InitDoneDevices = TRUE;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (0 != FspFsmupDeviceObject)
FspDeviceDelete(FspFsmupDeviceObject);
if (0 != FspFsctlNetDeviceObject)
FspDeviceDelete(FspFsctlNetDeviceObject);
if (0 != FspFsctlDiskDeviceObject)
FspDeviceDelete(FspFsctlDiskDeviceObject);
if (InitDoneDevices)
FspDriverFinalizeDevices();
if (InitDonePsBuf)
FspProcessBufferFinalize();
if (InitDoneSilo)
FspSiloFinalize();
if (InitDoneGRes)
ExDeleteResourceLite(&FspDeviceGlobalResource);
}
@ -237,7 +171,7 @@ static VOID FspDriverMultiVersionInitialize(VOID)
#pragma prefast(suppress:30035, "FspDriverMultiVersionInitialize is called from DriverEntry")
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
if (FspIsNtDdiVersionAvailable(NTDDI_WIN7))
{
UNICODE_STRING Name;
@ -246,42 +180,164 @@ static VOID FspDriverMultiVersionInitialize(VOID)
(FSP_MV_CcCoherencyFlushAndPurgeCache *)(UINT_PTR)MmGetSystemRoutineAddress(&Name);
}
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN8))
if (FspIsNtDdiVersionAvailable(NTDDI_WIN8))
FspMvMdlMappingNoWrite = MdlMappingNoWrite;
if (RtlIsNtDdiVersionAvailable(0x0A000005/*NTDDI_WIN10_RS4*/))
if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS4))
FspHasReparsePointCaseSensitivityFix = TRUE;
}
#if defined(FSP_UNLOAD)
VOID FspUnload(
PDRIVER_OBJECT DriverObject)
static NTSTATUS FspDriverInitializeDevices(VOID)
{
FSP_ENTER_VOID(PAGED_CODE());
PAGED_CODE();
FsRtlDeregisterUncProvider(FspMupHandle);
FSP_SILO_GLOBALS *Globals;
UNICODE_STRING DeviceSddl;
UNICODE_STRING DeviceName;
GUID Guid;
NTSTATUS Result;
FspFsctlDiskDeviceObject = 0;
FspFsctlNetDeviceObject = 0;
FspFsmupDeviceObject = 0;
//FspDeviceDeleteAll();
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
ExDeleteResourceLite(&FspDeviceGlobalResource);
FspDriverObject = 0;
/* create the file system control device objects */
RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL);
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlDiskDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0,
FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE,
&Globals->FsmupDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
FspProcessBufferFinalize();
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
&DriverObject->DriverName);
}
#if DBG
/*
* Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes
* to GitHub user @thinkport.
*
* On debug builds set DO_LOW_PRIORITY_FILESYSTEM to place the file system
* at the end of the file system list during IoRegisterFileSystem below.
* This allows us to test the behavior of our Fsvrt devices when foreign
* file systems attempt to use them for mounting.
*/
SetFlag(Globals->FsctlDiskDeviceObject->Flags, DO_LOW_PRIORITY_FILESYSTEM);
#endif
Result = FspDeviceInitialize(Globals->FsctlDiskDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(Globals->FsctlNetDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(Globals->FsmupDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
FspSiloGetContainerId(&Guid);
RtlInitEmptyUnicodeString(&DeviceName,
Globals->FsmupDeviceNameBuf, sizeof Globals->FsmupDeviceNameBuf);
Result = RtlUnicodeStringPrintf(&DeviceName,
0 == ((PULONG)&Guid)[0] && 0 == ((PULONG)&Guid)[1] &&
0 == ((PULONG)&Guid)[2] && 0 == ((PULONG)&Guid)[3] ?
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME :
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
Guid.Data1, Guid.Data2, Guid.Data3,
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
ASSERT(NT_SUCCESS(Result));
DeviceName.MaximumLength = DeviceName.Length;
Result = FsRtlRegisterUncProviderEx(&Globals->MupHandle,
&DeviceName, Globals->FsmupDeviceObject, 0);
if (!NT_SUCCESS(Result))
{
Globals->MupHandle = 0;
goto exit;
}
/*
* Register our "disk" device as a file system. We do not register our "net" device
* as a file system; we register with the MUP instead.
*/
IoRegisterFileSystem(Globals->FsctlDiskDeviceObject);
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (0 != Globals->MupHandle)
{
FsRtlDeregisterUncProvider(Globals->MupHandle);
Globals->MupHandle = 0;
}
if (0 != Globals->FsmupDeviceObject)
{
FspDeviceDelete(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
}
if (0 != Globals->FsctlNetDeviceObject)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
}
if (0 != Globals->FsctlDiskDeviceObject)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0;
}
}
FspSiloDereferenceGlobals(Globals);
return Result;
}
static VOID FspDriverFinalizeDevices(VOID)
{
PAGED_CODE();
FSP_SILO_GLOBALS *Globals;
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
if (0 != Globals->MupHandle)
{
FsRtlDeregisterUncProvider(Globals->MupHandle);
Globals->MupHandle = 0;
}
if (0 != Globals->FsmupDeviceObject)
{
FspDeviceDelete(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
}
if (0 != Globals->FsctlNetDeviceObject)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
}
if (0 != Globals->FsctlDiskDeviceObject)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0;
}
FspSiloDereferenceGlobals(Globals);
}
PDRIVER_OBJECT FspDriverObject;
PDEVICE_OBJECT FspFsctlDiskDeviceObject;
PDEVICE_OBJECT FspFsctlNetDeviceObject;
PDEVICE_OBJECT FspFsmupDeviceObject;
HANDLE FspMupHandle;
FAST_IO_DISPATCH FspFastIoDispatch;
CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;

View File

@ -503,6 +503,7 @@ NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUI
/* utility */
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
BOOLEAN FspIsNtDdiVersionAvailable(ULONG RequestedVersion);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
@ -651,6 +652,23 @@ VOID FspIrpHookReset(PIRP Irp);
PVOID FspIrpHookContext(PVOID Context);
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
/* silos */
typedef struct
{
PDEVICE_OBJECT FsctlDiskDeviceObject;
PDEVICE_OBJECT FsctlNetDeviceObject;
PDEVICE_OBJECT FsmupDeviceObject;
HANDLE MupHandle;
WCHAR FsmupDeviceNameBuf[64];
} FSP_SILO_GLOBALS;
typedef NTSTATUS (*FSP_SILO_INIT_CALLBACK)(VOID);
typedef VOID (*FSP_SILO_FINI_CALLBACK)(VOID);
NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals);
VOID FspSiloDereferenceGlobals(FSP_SILO_GLOBALS *Globals);
VOID FspSiloGetContainerId(GUID *ContainerId);
NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini);
VOID FspSiloFinalize(VOID);
/* process buffers */
#define FspProcessBufferSizeMax (64 * 1024)
NTSTATUS FspProcessBufferInitialize(VOID);
@ -1068,6 +1086,7 @@ typedef struct
KSPIN_LOCK SpinLock;
LONG RefCount;
UINT32 Kind;
GUID SiloContainerId;
} FSP_DEVICE_EXTENSION;
typedef struct
{
@ -1694,10 +1713,6 @@ FSP_MV_CcCoherencyFlushAndPurgeCache(
/* extern */
extern PDRIVER_OBJECT FspDriverObject;
extern PDEVICE_OBJECT FspFsctlDiskDeviceObject;
extern PDEVICE_OBJECT FspFsctlNetDeviceObject;
extern PDEVICE_OBJECT FspFsmupDeviceObject;
extern HANDLE FspMupHandle;
extern FAST_IO_DISPATCH FspFastIoDispatch;
extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[];

View File

@ -1589,6 +1589,10 @@ retry:
Suffix.Length = (USHORT)Info->FileNameLength;
Suffix.Buffer = Info->FileName;
/* remove any trailing backslash; NTFS allows it for both directories AND files! */
if (sizeof(WCHAR) * 2/* not empty or root */ <= Suffix.Length &&
L'\\' == Suffix.Buffer[Suffix.Length / sizeof(WCHAR) - 1])
Suffix.Length -= sizeof(WCHAR);
/* if there is a backslash anywhere in the NewFileName get its suffix */
for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++)
if (L'\\' == *P)

View File

@ -698,6 +698,10 @@ static NTSTATUS FspFsvolFileSystemControl(
case FSP_FSCTL_WORK_BEST_EFFORT:
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_QUERY_WINFSP:
Irp->IoStatus.Information = 0;
Result = STATUS_SUCCESS;
break;
case FSCTL_GET_REPARSE_POINT:
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, FALSE);
break;

View File

@ -249,9 +249,9 @@ static NTSTATUS FspFsvolReadNonCached(
if (!NT_SUCCESS(Result))
return Result;
/* acquire FileNode exclusive Full */
/* acquire FileNode shared Full */
Success = DEBUGTEST(90) &&
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
FspFileNodeTryAcquireSharedF(FileNode, FspFileNodeAcquireFull, CanWait);
if (!Success)
return FspWqRepostIrpWorkItem(Irp, FspFsvolReadNonCached, 0);
@ -280,21 +280,21 @@ static NTSTATUS FspFsvolReadNonCached(
/* if this is a non-cached transfer on a cached file then flush the file */
if (!PagingIo && 0 != FileObject->SectionObjectPointer->DataSectionObject)
{
FspFileNodeRelease(FileNode, Full);
if (!CanWait)
{
FspFileNodeRelease(FileNode, Full);
return FspWqRepostIrpWorkItem(Irp, FspFsvolReadNonCached, 0);
}
/* need to acquire exclusive for flushing */
FspFileNodeAcquireExclusive(FileNode, Full);
Result = FspFileNodeFlushAndPurgeCache(FileNode,
IrpSp->Parameters.Read.ByteOffset.QuadPart,
IrpSp->Parameters.Read.Length,
FALSE);
FspFileNodeRelease(FileNode, Full);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
FspFileNodeAcquireShared(FileNode, Full);
}
/* trim ReadLength during CreateProcess; resolve bugcheck for filesystem that reports incorrect size */
@ -310,9 +310,6 @@ static NTSTATUS FspFsvolReadNonCached(
ReadLength = (ULONG)(FileInfo.FileSize - ReadOffset.QuadPart);
}
/* convert FileNode to shared */
FspFileNodeConvertExclusiveToShared(FileNode, Full);
Request = FspIrpRequest(Irp);
if (0 == Request)
{

325
src/sys/silo.c Normal file
View File

@ -0,0 +1,325 @@
/**
* @file sys/silo.c
*
* @copyright 2015-2020 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include <sys/driver.h>
NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, FspSiloInitialize)
#endif
typedef PEJOB FSP_PESILO;
typedef PVOID FSP_PSILO_MONITOR;
typedef NTSTATUS (NTAPI *FSP_SILO_MONITOR_CREATE_CALLBACK)(FSP_PESILO Silo);
typedef VOID (NTAPI *FSP_SILO_MONITOR_TERMINATE_CALLBACK)(FSP_PESILO Silo);
typedef VOID (NTAPI *FSP_SILO_CONTEXT_CLEANUP_CALLBACK)(PVOID SiloContext);
#pragma warning(push)
#pragma warning(disable:4201) /* nameless struct/union */
typedef struct _FSP_SILO_MONITOR_REGISTRATION
{
UCHAR Version;
BOOLEAN MonitorHost;
BOOLEAN MonitorExistingSilos;
UCHAR Reserved[5];
union
{
PUNICODE_STRING DriverObjectName;
PUNICODE_STRING ComponentName;
};
FSP_SILO_MONITOR_CREATE_CALLBACK CreateCallback;
FSP_SILO_MONITOR_TERMINATE_CALLBACK TerminateCallback;
} FSP_SILO_MONITOR_REGISTRATION;
#pragma warning(pop)
typedef NTSTATUS FSP_SILO_PsRegisterSiloMonitor(
FSP_SILO_MONITOR_REGISTRATION *Registration,
FSP_PSILO_MONITOR *ReturnedMonitor);
typedef NTSTATUS FSP_SILO_PsStartSiloMonitor(
FSP_PSILO_MONITOR Monitor);
typedef VOID FSP_SILO_PsUnregisterSiloMonitor(
FSP_PSILO_MONITOR Monitor);
typedef ULONG FSP_SILO_PsGetSiloMonitorContextSlot(
FSP_PSILO_MONITOR Monitor);
typedef NTSTATUS FSP_SILO_PsCreateSiloContext(
FSP_PESILO Silo,
ULONG Size,
POOL_TYPE PoolType,
FSP_SILO_CONTEXT_CLEANUP_CALLBACK ContextCleanupCallback,
PVOID *ReturnedSiloContext);
typedef VOID FSP_SILO_PsDereferenceSiloContext(
PVOID SiloContext);
typedef NTSTATUS FSP_SILO_PsInsertSiloContext(
FSP_PESILO Silo,
ULONG ContextSlot,
PVOID SiloContext);
typedef NTSTATUS FSP_SILO_PsRemoveSiloContext(
FSP_PESILO Silo,
ULONG ContextSlot,
PVOID *RemovedSiloContext);
typedef NTSTATUS FSP_SILO_PsGetSiloContext(
FSP_PESILO Silo,
ULONG ContextSlot,
PVOID *ReturnedSiloContext);
typedef FSP_PESILO FSP_SILO_PsAttachSiloToCurrentThread(
FSP_PESILO Silo);
typedef VOID FSP_SILO_PsDetachSiloFromCurrentThread(
FSP_PESILO PreviousSilo);
typedef FSP_PESILO FSP_SILO_PsGetCurrentServerSilo(
VOID);
typedef GUID* FSP_SILO_PsGetSiloContainerId(
FSP_PESILO Silo);
static FSP_SILO_PsRegisterSiloMonitor *FspSiloPsRegisterSiloMonitor;
static FSP_SILO_PsStartSiloMonitor *FspSiloPsStartSiloMonitor;
static FSP_SILO_PsUnregisterSiloMonitor *FspSiloPsUnregisterSiloMonitor;
static FSP_SILO_PsGetSiloMonitorContextSlot *FspSiloPsGetSiloMonitorContextSlot;
static FSP_SILO_PsCreateSiloContext *FspSiloPsCreateSiloContext;
static FSP_SILO_PsDereferenceSiloContext *FspSiloPsDereferenceSiloContext;
static FSP_SILO_PsInsertSiloContext *FspSiloPsInsertSiloContext;
static FSP_SILO_PsRemoveSiloContext *FspSiloPsRemoveSiloContext;
static FSP_SILO_PsGetSiloContext *FspSiloPsGetSiloContext;
static FSP_SILO_PsAttachSiloToCurrentThread *FspSiloPsAttachSiloToCurrentThread;
static FSP_SILO_PsDetachSiloFromCurrentThread *FspSiloPsDetachSiloFromCurrentThread;
static FSP_SILO_PsGetCurrentServerSilo *FspSiloPsGetCurrentServerSilo;
static FSP_SILO_PsGetSiloContainerId *FspSiloPsGetSiloContainerId;
static FSP_PSILO_MONITOR FspSiloMonitor;
static FSP_SILO_INIT_CALLBACK FspSiloInitCallback;
static FSP_SILO_FINI_CALLBACK FspSiloFiniCallback;
static BOOLEAN FspSiloInitDone = FALSE;
static FSP_SILO_GLOBALS FspSiloHostGlobals;
#define FSP_SILO_MONITOR_REGISTRATION_VERSION 1
#define LOAD(n) \
{ \
UNICODE_STRING Name; \
RtlInitUnicodeString(&Name, L"" #n);\
FspSilo ## n = \
(FSP_SILO_ ## n *)(UINT_PTR)MmGetSystemRoutineAddress(&Name);\
if (0 == FspSilo ## n) \
Fail++; \
}
#define CALL(n) (FspSilo ## n)
NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals)
{
FSP_PESILO Silo;
ULONG ContextSlot;
FSP_SILO_GLOBALS *Globals;
NTSTATUS Result;
if (!FspSiloInitDone ||
0 == (Silo = CALL(PsGetCurrentServerSilo)()))
{
*PGlobals = &FspSiloHostGlobals;
return STATUS_SUCCESS;
}
ContextSlot = CALL(PsGetSiloMonitorContextSlot)(FspSiloMonitor);
Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals);
if (!NT_SUCCESS(Result))
{
*PGlobals = 0;
return Result;
}
*PGlobals = Globals;
return STATUS_SUCCESS;
}
VOID FspSiloDereferenceGlobals(FSP_SILO_GLOBALS *Globals)
{
if (&FspSiloHostGlobals == Globals)
return;
CALL(PsDereferenceSiloContext)(Globals);
}
VOID FspSiloGetContainerId(GUID *ContainerId)
{
FSP_PESILO Silo;
GUID *Guid;
if (!FspSiloInitDone ||
0 == (Silo = CALL(PsGetCurrentServerSilo)()) ||
0 == (Guid = CALL(PsGetSiloContainerId)(Silo)))
{
RtlZeroMemory(ContainerId, sizeof *ContainerId);
return;
}
RtlCopyMemory(ContainerId, Guid, sizeof *ContainerId);
}
static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
{
ULONG ContextSlot;
FSP_SILO_GLOBALS *Globals = 0;
BOOLEAN Inserted = FALSE;
NTSTATUS Result;
ASSERT(0 != Silo);
ContextSlot = CALL(PsGetSiloMonitorContextSlot)(FspSiloMonitor);
Result = CALL(PsCreateSiloContext)(Silo, sizeof(FSP_SILO_GLOBALS), NonPagedPoolNx, 0, &Globals);
if (!NT_SUCCESS(Result))
goto exit;
RtlZeroMemory(Globals, sizeof(FSP_SILO_GLOBALS));
/* PsInsertSiloContext adds reference to Globals */
Result = CALL(PsInsertSiloContext)(Silo, ContextSlot, Globals);
if (!NT_SUCCESS(Result))
goto exit;
Inserted = TRUE;
if (0 != FspSiloInitCallback)
{
FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo);
Result = FspSiloInitCallback();
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
}
exit:
if (!NT_SUCCESS(Result))
{
if (Inserted)
CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0);
}
if (0 != Globals)
CALL(PsDereferenceSiloContext)(Globals);
/*
* Ignore errors and return success. There are two reasons for this:
*
* - Returning an error will disallow container creation.
* - In some cases returning an error will crash Windows with an
* unexpected page fault in wcifs.sys.
*/
return STATUS_SUCCESS;
}
static VOID NTAPI FspSiloMonitorTerminateCallback(FSP_PESILO Silo)
{
ULONG ContextSlot;
FSP_SILO_GLOBALS *Globals;
NTSTATUS Result;
ASSERT(0 != Silo);
ContextSlot = CALL(PsGetSiloMonitorContextSlot)(FspSiloMonitor);
/* if we cannot get the Globals, it must mean that we failed in Create callback */
Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals);
if (!NT_SUCCESS(Result))
return;
CALL(PsDereferenceSiloContext)(Globals);
Globals = 0;
if (0 != FspSiloFiniCallback)
{
FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo);
FspSiloFiniCallback();
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
}
/* PsRemoveSiloContext removes reference to Globals (possibly freeing it) */
CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0);
}
NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini)
{
NTSTATUS Result = STATUS_SUCCESS;
if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS5))
{
ULONG Fail = 0;
LOAD(PsRegisterSiloMonitor);
LOAD(PsStartSiloMonitor);
LOAD(PsUnregisterSiloMonitor);
LOAD(PsGetSiloMonitorContextSlot);
LOAD(PsCreateSiloContext);
LOAD(PsDereferenceSiloContext);
LOAD(PsInsertSiloContext);
LOAD(PsRemoveSiloContext);
LOAD(PsGetSiloContext);
LOAD(PsAttachSiloToCurrentThread);
LOAD(PsDetachSiloFromCurrentThread);
LOAD(PsGetCurrentServerSilo);
LOAD(PsGetSiloContainerId);
if (0 == Fail)
{
FSP_SILO_MONITOR_REGISTRATION Registration =
{
.Version = FSP_SILO_MONITOR_REGISTRATION_VERSION,
.MonitorHost = FALSE,
.MonitorExistingSilos = TRUE,
.DriverObjectName = 0,
.CreateCallback = FspSiloMonitorCreateCallback,
.TerminateCallback = FspSiloMonitorTerminateCallback,
};
FSP_PSILO_MONITOR Monitor = 0;
UNICODE_STRING DriverName;
RtlInitUnicodeString(&DriverName, L"" DRIVER_NAME);
Registration.DriverObjectName = &DriverName;
Result = CALL(PsRegisterSiloMonitor)(&Registration, &Monitor);
if (!NT_SUCCESS(Result))
goto exit;
Result = CALL(PsStartSiloMonitor)(Monitor);
if (!NT_SUCCESS(Result))
goto exit;
FspSiloMonitor = Monitor;
FspSiloInitCallback = Init;
FspSiloFiniCallback = Fini;
FspSiloInitDone = TRUE;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (0 != Monitor)
CALL(PsUnregisterSiloMonitor)(Monitor);
}
}
}
return Result;
}
VOID FspSiloFinalize(VOID)
{
if (!FspSiloInitDone)
return;
CALL(PsUnregisterSiloMonitor)(FspSiloMonitor);
}

View File

@ -21,6 +21,7 @@
#include <sys/driver.h>
BOOLEAN FspIsNtDdiVersionAvailable(ULONG Version);
NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
@ -132,6 +133,7 @@ PVOID FspIrpHookContext(PVOID Context);
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspIsNtDdiVersionAvailable)
#pragma alloc_text(PAGE, FspCreateGuid)
#pragma alloc_text(PAGE, FspGetDeviceObjectPointer)
#pragma alloc_text(PAGE, FspRegistryGetValue)
@ -223,6 +225,75 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize)
}
}
BOOLEAN FspIsNtDdiVersionAvailable(ULONG RequestedVersion)
{
PAGED_CODE();
static ULONG Version;
if (0 == Version)
{
RTL_OSVERSIONINFOEXW VersionInfo;
ULONG TempVersion;
RtlZeroMemory(&VersionInfo, sizeof VersionInfo);
VersionInfo.dwOSVersionInfoSize = sizeof VersionInfo;
RtlGetVersion((PVOID)&VersionInfo);
TempVersion =
((UINT8)VersionInfo.dwMajorVersion << 24) |
((UINT8)VersionInfo.dwMinorVersion << 16) |
((UINT8)VersionInfo.wServicePackMajor << 8);
if (10 <= VersionInfo.dwMajorVersion)
{
/* see https://docs.microsoft.com/en-us/windows/release-information/ */
static struct
{
ULONG BuildNumber;
ULONG Subver;
} Builds[] =
{
{ 10240, SUBVER(NTDDI_WIN10) },
{ 10586, SUBVER(NTDDI_WIN10_TH2) },
{ 14393, SUBVER(NTDDI_WIN10_RS1) },
{ 15063, SUBVER(NTDDI_WIN10_RS2) },
{ 16299, SUBVER(NTDDI_WIN10_RS3) },
{ 17134, SUBVER(NTDDI_WIN10_RS4) },
{ 17763, SUBVER(NTDDI_WIN10_RS5) },
{ 18362, SUBVER(NTDDI_WIN10_19H1) },
{ 18363, SUBVER(NTDDI_WIN10_19H1) },
{ 19041, 9 },
{ (ULONG)-1, 10 },
};
int Lo = 0, Hi = sizeof Builds / sizeof Builds[0] - 1, Mi;
while (Lo <= Hi)
{
Mi = (unsigned)(Lo + Hi) >> 1;
if (Builds[Mi].BuildNumber < VersionInfo.dwBuildNumber)
Lo = Mi + 1;
else if (Builds[Mi].BuildNumber > VersionInfo.dwBuildNumber)
Hi = Mi - 1;
else
{
Lo = Mi;
break;
}
}
Mi = Lo;
TempVersion |= (UINT8)Builds[Mi].Subver;
}
/* thread-safe because multiple threads will compute same value */
InterlockedExchange((PVOID)&Version, TempVersion);
}
return RequestedVersion <= Version;
}
NTSTATUS FspCreateGuid(GUID *Guid)
{
PAGED_CODE();

View File

@ -24,11 +24,13 @@
NTSTATUS FspVolumeCreate(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspVolumeCreateNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
FSP_SILO_GLOBALS *Globals);
VOID FspVolumeDelete(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static VOID FspVolumeDeleteNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
FSP_SILO_GLOBALS *Globals);
static WORKER_THREAD_ROUTINE FspVolumeDeleteDelayed;
NTSTATUS FspVolumeMount(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
@ -77,15 +79,25 @@ NTSTATUS FspVolumeCreate(
{
PAGED_CODE();
FSP_SILO_GLOBALS *Globals;
NTSTATUS Result;
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
FspDeviceGlobalLock();
Result = FspVolumeCreateNoLock(FsctlDeviceObject, Irp, IrpSp);
Result = FspVolumeCreateNoLock(FsctlDeviceObject, Irp, IrpSp,
Globals);
FspDeviceGlobalUnlock();
FspSiloDereferenceGlobals(Globals);
return Result;
}
static NTSTATUS FspVolumeCreateNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
FSP_SILO_GLOBALS *Globals)
{
PAGED_CODE();
@ -302,18 +314,18 @@ static NTSTATUS FspVolumeCreateNoLock(
/* do we need to register with fsmup? */
if (0 == FsvrtDeviceObject)
{
Result = FspMupRegister(FspFsmupDeviceObject, FsvolDeviceObject);
Result = FspMupRegister(Globals->FsmupDeviceObject, FsvolDeviceObject);
if (!NT_SUCCESS(Result))
{
FspDeviceDereference(FsvolDeviceObject);
return Result;
}
RtlInitUnicodeString(&FsmupDeviceName, L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME);
RtlInitUnicodeString(&FsmupDeviceName, Globals->FsmupDeviceNameBuf);
Result = IoCreateSymbolicLink(&FsvolDeviceExtension->VolumeName, &FsmupDeviceName);
if (!NT_SUCCESS(Result))
{
FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject);
FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject);
FspDeviceDereference(FsvolDeviceObject);
return Result;
}
@ -331,6 +343,7 @@ VOID FspVolumeDelete(
{
// !PAGED_CODE();
FSP_SILO_GLOBALS *Globals;
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
@ -350,10 +363,16 @@ VOID FspVolumeDelete(
FspDeviceReference(FsvolDeviceObject);
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
FspDeviceGlobalLock();
FspVolumeDeleteNoLock(FsctlDeviceObject, Irp, IrpSp);
FspVolumeDeleteNoLock(FsctlDeviceObject, Irp, IrpSp,
Globals);
FspDeviceGlobalUnlock();
FspSiloDereferenceGlobals(Globals);
/*
* Call MmForceSectionClosed on active files to ensure that Mm removes them from Standby List.
*/
@ -370,7 +389,8 @@ VOID FspVolumeDelete(
}
static VOID FspVolumeDeleteNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
FSP_SILO_GLOBALS *Globals)
{
// !PAGED_CODE();
@ -445,7 +465,7 @@ static VOID FspVolumeDeleteNoLock(
else
{
IoDeleteSymbolicLink(&FsvolDeviceExtension->VolumeName);
FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject);
FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject);
}
/* release the volume device object */
@ -945,6 +965,7 @@ NTSTATUS FspVolumeTransact(
if (0 != InternalBuffer)
{
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode);
*(PVOID *)OutputBuffer = 0;
FspFree(InternalBuffer);
}
FspIopCompleteCanceledIrp(PendingIrp);

2
tools/build-choco.bat Normal file → Executable file
View File

@ -19,7 +19,7 @@ if X%~nx0==Xbuild-choco.bat (
goto :choco
)
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
call "%~dp0vcvarsall.bat" x64
if not X%SignedPackage%==X (
if not exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi" (echo previous build not found >&2 & exit /b 1)

View File

@ -10,7 +10,7 @@ if not X%4==X set ProjDir=%~4
if X!ProjDir!==X (echo usage: build-sample Config Arch Sample ProjDir >&2 & goto fail)
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
call "%~dp0vcvarsall.bat" x64
if X!FSP_SAMPLE_DIR!==X (
set RegKey="HKLM\SOFTWARE\WinFsp"

View File

@ -19,7 +19,7 @@ if X%~nx0==Xbuild-choco.bat (
goto :choco
)
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
call "%~dp0vcvarsall.bat" x64
if not X%SignedPackage%==X (
if not exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi" (echo previous build not found >&2 & exit /b 1)

View File

@ -12,4 +12,4 @@ reg query %RegKey% /v %RegVal% >nul 2>&1 || (echo Cannot find Windows Kit >&2 &
for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%') do (
set KitRoot="%%j"
)
start "winfsp" %KitRoot%\Debuggers\x64\windbg -W %DebugWorkspace% -k net:port=%DebugPort%,key=%DebugKey%
start "%DebugWorkspace%" %KitRoot%\Debuggers\x64\windbg -W %DebugWorkspace% -k net:port=%DebugPort%,key=%DebugKey%

View File

@ -1,21 +1,36 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
set CONFIG=Debug
set SUFFIX=x64
set TARGET_MACHINE=WIN8DBG
if not X%1==X set TARGET_MACHINE=%1
set TARGET_ACCOUNT=\Users\%USERNAME%\Downloads\winfsp\
set TARGET=\\%TARGET_MACHINE%%TARGET_ACCOUNT%
set Config=Debug
set Suffix=x64
set Deploy=C:\Deploy\winfsp
set Target=Win10DBG
set Chkpnt=winfsp
if not X%1==X set Target=%1
if not X%2==X set Chkpnt=%2
cd %~dp0..
mkdir %TARGET% 2>nul
for %%f in (winfsp-%SUFFIX%.sys winfsp-%SUFFIX%.dll winfsp-tests-%SUFFIX%.exe fsbench-%SUFFIX%.exe fscrash-%SUFFIX%.exe memfs-%SUFFIX%.exe) do (
copy build\VStudio\build\%CONFIG%\%%f %TARGET% >nul
(
echo regsvr32 /s winfsp-x64.dll
) > %~dp0..\build\VStudio\build\%Config%\deploy-setup.bat
set Files=
for %%f in (
%~dp0..\build\VStudio\build\%Config%\
winfsp-%Suffix%.sys
winfsp-%Suffix%.dll
winfsp-tests-%Suffix%.exe
memfs-%Suffix%.exe
deploy-setup.bat
) do (
set File=%%~f
if [!File:~-1!] == [\] (
set Dir=!File!
) else (
if not [!Files!] == [] set Files=!Files!,
set Files=!Files!'!Dir!!File!'
)
)
copy tools\ifstest.bat %TARGET% >nul
echo sc create WinFsp type=filesys binPath=%%~dp0winfsp-%SUFFIX%.sys >%TARGET%sc-create.bat
echo sc start WinFsp >%TARGET%sc-start.bat
echo sc stop WinFsp >%TARGET%sc-stop.bat
echo sc delete WinFsp >%TARGET%sc-delete.bat
powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0deploy.ps1' -Name '%Target%' -CheckpointName '%Chkpnt%' -Files !Files! -Destination '%Deploy%'"

35
tools/deploy.ps1 Normal file
View File

@ -0,0 +1,35 @@
param (
[Parameter(Mandatory)][string]$Name,
[string]$CheckpointName,
[Parameter(Mandatory)][string[]]$Files,
[Parameter(Mandatory)][string]$Destination
)
function Restore-VM ($Name, $CheckpointName) {
$VM = Get-VM -Name $Name
if ($VM.State -eq "Running") {
Stop-VM -Name $Name -TurnOff
}
if (-not $CheckpointName) {
$Checkpoint = Get-VMCheckpoint -VMName $Name |
Sort-Object -Property CreationTime -Descending |
select -First 1
} else {
$Checkpoint = Get-VMCheckpoint -VMName $Name -Name $CheckpointName
}
Restore-VMCheckpoint -VMCheckpoint $Checkpoint -Confirm:$false
Start-VM -Name $Name
}
function Deploy-VMFiles ($Name, $Files, $Destination) {
foreach ($File in $Files) {
$Leaf = Split-Path -Path $File -Leaf
$Dest = Join-Path $Destination $Leaf
Copy-VMFile -Name $Name -SourcePath $File -DestinationPath $Dest -FileSource Host -CreateFullPath -Force
}
}
Restore-VM -Name $Name -CheckpointName $CheckpointName
Deploy-VMFiles -Name $Name -Files $Files -Destination $Destination

View File

@ -19,7 +19,7 @@ set cdef=/D_AMD64_
if /i X%outarch%==Xx86 set arch=x86
if /i X%outarch%==Xx86 set cdef=/D_X86_
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" !arch!
call "%~dp0vcvarsall.bat" !arch!
set INCLUDE=%~dp0..\opt\fsext\inc;%~dp0..\inc;!WindowsSdkDir!Include\!WindowsSDKVersion!km\crt;!WindowsSdkDir!Include\!WindowsSDKVersion!km;!WindowsSdkDir!Include\!WindowsSDKVersion!km\shared;!INCLUDE!
if exist !workdir! rmdir /s/q !workdir!

View File

@ -5,7 +5,7 @@ setlocal
set Configuration=Release
if not X%1==X set Configuration=%1
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
call "%~dp0vcvarsall.bat" x64
cd %~dp0..\ext\test
nmake /f Nmakefile

View File

@ -11,4 +11,9 @@ for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%'
set KitRoot=%%j
)
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\10.0.10586.0\shared\%~n0.h"
set KitVer=10.0.10586.0
for /f "tokens=*" %%i in ('dir /ad/b "%KitRoot%Include\10.*"') do (
set KitVer=%%i
)
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\%KitVer%\shared\%~n0.h"

345
tools/parselog.nim Normal file
View File

@ -0,0 +1,345 @@
# @file parselog.nim
#
# parse WinFsp debug logs
#
# @copyright 2015-2020 Bill Zissimopoulos
import algorithm
import macros
import parseopt
import parseutils
import strformat
import strscans
import strutils
import tables
type
Req = ref object
fsname: string
tid: uint32
irp: uint64
op: string
inform: string
context: string
args: seq[(string, string)]
Rsp = ref object
fsname: string
tid: uint32
irp: uint64
op: string
status: uint32
inform: uint
context: string
args: seq[(string, string)]
proc parseAndAddArg(prefix: string, rest: var string, args: var seq[(string, string)]) =
discard scanf(rest, ",$*", rest)
discard scanf(rest, "$s$*", rest)
var n, v: string
if scanf(rest, "\"$*\"$*", v, rest):
args.add((prefix & "", v))
elif scanf(rest, "$w=\"$*\"$*", n, v, rest):
args.add((prefix & n, v))
elif scanf(rest, "$w={$*}$*", n, v, rest):
while "" != v:
parseAndAddArg(n & ".", v, args)
elif scanf(rest, "$w=$*,$*", n, v, rest):
args.add((prefix & n, v))
elif scanf(rest, "$w=$*$.", n, v):
rest = ""
args.add((prefix & n, v))
elif scanf(rest, "$*,$*", v, rest):
args.add((prefix & "", v))
else:
v = rest
rest = ""
args.add((prefix & "", v))
proc parseArgs(rest: var string): seq[(string, string)] =
while "" != rest:
parseAndAddArg("", rest, result)
proc parseReq(op, rest: string): Req =
result = Req(op: op)
var rest = rest
var inform: string
if scanf(rest, "[$+]$s$*", inform, rest):
result.inform = inform
var c0, c1: uint64
if scanf(rest, "${parseHex[uint64]}:${parseHex[uint64]}$*", c0, c1, rest):
result.context = toHex(c0) & ":" & toHex(c1)
result.args = parseArgs(rest)
proc parseRsp(op, rest: string): Rsp =
result = Rsp(op: op)
var rest = rest
var status: uint32
var inform: uint
if scanf(rest, "IoStatus=${parseHex[uint32]}[${parseUint}]$s$*", status, inform, rest):
result.status = status
result.inform = inform
var c0, c1: uint64
if scanf(rest, "UserContext=${parseHex[uint64]}:${parseHex[uint64]}$*", c0, c1, rest):
result.context = toHex(c0) & ":" & toHex(c1)
result.args = parseArgs(rest)
proc parseLog(path: string, processReq: proc(req: Req), processRsp: proc(rsp: Rsp)) =
let file = open(path)
defer: file.close()
var lineno = 0
try:
for line in lines file:
inc lineno
var fsname, dir, op, rest: string
var tid: uint32
var irp: uint64
var req: Req
var rsp: Rsp
if scanf(line, "$+[TID=${parseHex[uint32]}]:$s${parseHex[uint64]}:$s$+ $*",
fsname, tid, irp, op, rest):
dir = op[0..1]
op = op[2..^1]
case dir
of ">>":
req = parseReq(op, rest)
req.fsname = fsname
req.tid = tid
req.irp = irp
processReq(req)
of "<<":
rsp = parseRsp(op, rest)
rsp.fsname = fsname
rsp.tid = tid
rsp.irp = irp
processRsp(rsp)
else:
continue
except:
echo &"An exception has occurred while parsing file {path} line {lineno}"
raise
type
Stat = ref object
ototal: int # open total
omulti: int # multiplicate open total
oerror: int # open error total
rtotal: int # read total
rnoaln: int # non-aligned read total
rbytes: uint64 # read bytes
rerror: int # read error total
wtotal: int # write total
wnoaln: int # non-aligned write total
wbytes: uint64 # write bytes
werror: int # write error total
dtotal: int # query directory total
dbytes: uint64 # query directory bytes
derror: int # query directory error total
ptotal: int # query directory w/ pattern total
pbytes: uint64 # query directory w/ pattern bytes
perror: int # query directory w/ pattern error total
ocount: int # current open count
var
reqtab = newTable[uint64, Req]()
filetab = newTable[string, string]()
stattab = newOrderedTable[string, Stat]()
aggr = Stat()
proc getArg(args: seq[(string, string)], name: string): string =
for n, v in items(args):
if name == n:
return v
proc processReq(req: Req) =
reqtab[req.irp] = req
case req.op
of "Close":
var filename: string
if filetab.pop(req.context, filename):
var stat = stattab.mgetOrPut(filename, Stat())
stat.ocount -= 1
proc processRsp(rsp: Rsp) =
var req: Req
if reqtab.pop(rsp.irp, req):
doAssert req.op == rsp.op
doAssert req.irp == rsp.irp
case req.op
of "Create":
var filename = getArg(req.args, "")
if "" != filename:
if 0 == rsp.status:
filetab[rsp.context] = filename
var stat = stattab.mgetOrPut(filename, Stat())
stat.ototal += 1
aggr.ototal += 1
stat.ocount += 1
if 2 == stat.ocount:
stat.omulti += 1
aggr.omulti += 1
else:
var stat = stattab.mgetOrPut(filename, Stat())
stat.oerror += 1
aggr.oerror += 1
of "Read":
var filename = filetab[req.context]
var stat = stattab.mgetOrPut(filename, Stat())
if 0 == rsp.status or 0xC0000011u32 == rsp.status:
var oarg = getArg(req.args, "Offset")
var larg = getArg(req.args, "Length")
var hi, lo: uint32
var offset: uint64
var length: uint
if scanf(oarg, "${parseHex[uint32]}:${parseHex[uint32]}", hi, lo):
offset = uint64(hi) * 0x100000000u64 + uint64(lo)
discard scanf(larg, "${parseUint}", length)
stat.rtotal += 1
stat.rbytes += rsp.inform
aggr.rtotal += 1
aggr.rbytes += rsp.inform
if 0 != offset mod 4096 or 0 != length mod 4096:
stat.rnoaln += 1
aggr.rnoaln += 1
else:
stat.rerror += 1
aggr.rerror += 1
of "Write":
var filename = filetab[req.context]
var stat = stattab.mgetOrPut(filename, Stat())
if 0 == rsp.status:
var oarg = getArg(req.args, "Offset")
var larg = getArg(req.args, "Length")
var hi, lo: uint32
var offset: uint64
var length: uint
if scanf(oarg, "${parseHex[uint32]}:${parseHex[uint32]}", hi, lo):
offset = uint64(hi) * 0x100000000u64 + uint64(lo)
discard scanf(larg, "${parseUint}", length)
stat.wtotal += 1
stat.wbytes += rsp.inform
aggr.wtotal += 1
aggr.wbytes += rsp.inform
if 0 != offset mod 4096 or 0 != length mod 4096:
stat.wnoaln += 1
aggr.wnoaln += 1
else:
stat.werror += 1
aggr.werror += 1
of "QueryDirectory":
var filename = filetab[req.context]
var stat = stattab.mgetOrPut(filename, Stat())
var pattern = getArg(req.args, "Pattern")
if "NULL" == pattern:
if 0 == rsp.status:
stat.dtotal += 1
stat.dbytes += rsp.inform
aggr.dtotal += 1
aggr.dbytes += rsp.inform
else:
stat.derror += 1
aggr.derror += 1
else:
if 0 == rsp.status:
stat.ptotal += 1
stat.pbytes += rsp.inform
aggr.ptotal += 1
aggr.pbytes += rsp.inform
else:
stat.perror += 1
aggr.perror += 1
macro identName(n: untyped): untyped =
result = n.strVal.newLit
template dumpstat(F: untyped) =
stattab.sort(proc (x, y: (string, Stat)): int =
cmp(x[1].F, y[1].F), SortOrder.Descending)
var width, rows = 0
for filename, stat in stattab.pairs:
if 0 == width:
var s = identName(F).toUpperAscii()
width = len($aggr.F)
if width < len(s):
width = len(s)
var f: string
formatValue(f, s, ">" & $width)
echo f, " PER% FILENAME"
var c0, c1: string
formatValue(c0, stat.F, $width)
if 0 != aggr.F:
formatValue(c1, 100.0 * float(stat.F) / float(aggr.F), "5.1f")
else:
c1 = " "
echo c0, " ", c1, " ", filename
inc rows
if opttop == rows:
break
var c0: string
formatValue(c0, aggr.F, $width)
echo c0, " 100.0 TOTAL"
proc main =
var filenames: seq[string]
var optstat: seq[string]
var opttop = 0
for kind, key, val in getopt(shortNoVal = {'Z'}, longNoVal = @["Zoo"]):
case kind
of cmdShortOption, cmdLongOption:
case key
of "stat":
optstat.add(val)
of "n":
opttop = parseInt(val)
of cmdArgument:
filenames.add(key)
else:
discard
if 0 == len(optstat):
optstat.add("ototal")
if 0 == len(filenames):
stderr.writeLine("usage: parselog [-nNN] [--stat ototal|rtotal|wtotal|dtotal|...] file...")
quit(2)
for filename in filenames:
parseLog filename, processReq, processRsp
for s in optstat:
case s
of "ototal":
dumpstat ototal
of "omulti":
dumpstat omulti
of "oerror":
dumpstat oerror
of "rtotal":
dumpstat rtotal
of "rnoaln":
dumpstat rnoaln
of "rbytes":
dumpstat rbytes
of "rerror":
dumpstat rerror
of "wtotal":
dumpstat wtotal
of "wnoaln":
dumpstat wnoaln
of "wbytes":
dumpstat wbytes
of "werror":
dumpstat werror
of "dtotal":
dumpstat dtotal
of "dbytes":
dumpstat dbytes
of "derror":
dumpstat derror
of "ptotal":
dumpstat ptotal
of "pbytes":
dumpstat pbytes
of "perror":
dumpstat perror
echo ""
when isMainModule:
main()

10
tools/vcvarsall.bat Executable file
View File

@ -0,0 +1,10 @@
@echo off
set vcvarsall="%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
if exist %vswhere% (
for /f "usebackq tokens=*" %%i in (`%vswhere% -find VC\**\vcvarsall.bat`) do (
set vcvarsall="%%i"
)
)
call %vcvarsall% %*

View File

@ -11,4 +11,9 @@ for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%'
set KitRoot=%%j
)
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\10.0.10586.0\shared\%~n0.h"
set KitVer=10.0.10586.0
for /f "tokens=*" %%i in ('dir /ad/b "%KitRoot%Include\10.*"') do (
set KitVer=%%i
)
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\%KitVer%\shared\%~n0.h"

View File

@ -10,9 +10,9 @@ cygfuse3: memfs-cygfuse3
winfsp-fuse3: memfs-winfsp-fuse3
memfs-cygfuse3: memfs-fuse3.cpp
g++ $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
g++ $^ -o $@ -g -Wall -std=gnu++17 `pkg-config fuse3 --cflags --libs`
memfs-winfsp-fuse3: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib
memfs-winfsp-fuse3: memfs-fuse3.cpp
ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install
g++ $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
g++ $^ -o $@ -g -Wall -std=gnu++17 `pkg-config fuse3 --cflags --libs`

View File

@ -1025,6 +1025,76 @@ void rename_test(void)
}
}
static void rename_backslash_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle;
BOOL Success;
WCHAR Dir1Path[MAX_PATH];
WCHAR Dir2Path[MAX_PATH];
WCHAR File0Path[MAX_PATH];
WCHAR File1Path[MAX_PATH];
StringCbPrintfW(Dir1Path, sizeof Dir1Path, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(Dir2Path, sizeof Dir2Path, L"%s%s\\dir2\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\dir1\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\dir1\\file1\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(Dir1Path, 0);
ASSERT(Success);
Handle = CreateFileW(File0Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
Success = MoveFileExW(File0Path, File1Path, 0);
ASSERT(Success);
Success = MoveFileExW(Dir1Path, Dir2Path, 0);
ASSERT(Success);
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\dir2\\file1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = DeleteFileW(File1Path);
ASSERT(Success);
Success = RemoveDirectoryW(Dir2Path);
ASSERT(Success);
memfs_stop(memfs);
}
void rename_backslash_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
rename_backslash_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
rename_backslash_dotest(MemfsDisk, 0, 0);
rename_backslash_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
rename_backslash_dotest(MemfsNet, L"\\\\memfs\\share", 0);
rename_backslash_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
static void rename_open_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -1930,6 +2000,44 @@ void setvolinfo_test(void)
}
}
void query_winfsp_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, BOOLEAN ExpectWinFsp)
{
void* memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH];
HANDLE Handle;
DWORD BytesTransferred;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(FilePath,
0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
if (ExpectWinFsp)
ASSERT(DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &BytesTransferred, 0));
else
ASSERT(!DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &BytesTransferred, 0) &&
ERROR_INVALID_FUNCTION == GetLastError());
CloseHandle(Handle);
memfs_stop(memfs);
}
void query_winfsp_test(void)
{
if (NtfsTests)
return;
if (WinFspDiskTests)
query_winfsp_dotest(MemfsDisk, 0, 0, TRUE);
if (WinFspNetTests)
query_winfsp_dotest(MemfsNet, L"\\\\memfs\\share", 0, TRUE);
}
void info_tests(void)
{
if (!OptShareName)
@ -1944,6 +2052,7 @@ void info_tests(void)
TEST(delete_mmap_test);
TEST(delete_standby_test);
TEST(rename_test);
TEST(rename_backslash_test);
TEST(rename_open_test);
TEST(rename_caseins_test);
if (!OptShareName)
@ -1955,4 +2064,6 @@ void info_tests(void)
TEST(rename_pid_test);
TEST(getvolinfo_test);
TEST(setvolinfo_test);
if (!NtfsTests)
TEST(query_winfsp_test);
}