mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
80 Commits
release/1.
...
v1.8B3
Author | SHA1 | Date | |
---|---|---|---|
c77690e59d | |||
32a5b2bc64 | |||
5045403d85 | |||
13a52c4ab4 | |||
c18d4f1508 | |||
fcfebb968f | |||
10053bc759 | |||
7985827c73 | |||
13146e4854 | |||
84e0744c28 | |||
20e19cb0fc | |||
2326521ef8 | |||
0296502f24 | |||
5d0b10d0b6 | |||
5fac25d200 | |||
b82aeeadbd | |||
dcaa24bc52 | |||
7e37fc57f9 | |||
8efe1f3a1f | |||
aa3beba928 | |||
899cd5595d | |||
6bcbfd5380 | |||
a197b99960 | |||
2ffb8a1c97 | |||
fc18b70a00 | |||
191c98bd41 | |||
5360f5ca6e | |||
89aaf33b62 | |||
675ecf2e51 | |||
b663cfdca5 | |||
dcf83b6d64 | |||
af52ac3df0 | |||
33cab186ca | |||
fd4c5326ed | |||
7c06ead34c | |||
768b596a76 | |||
26630ad7aa | |||
01744e8193 | |||
3eb115eb22 | |||
a0801674c4 | |||
98f809345d | |||
0268e51099 | |||
924d1f9a3e | |||
dc3f73bd2f | |||
e71aea8ad7 | |||
9066338220 | |||
ca12b5a19d | |||
94d8c0452f | |||
b4c39f656c | |||
42fd57904a | |||
9d69ae7503 | |||
f93cdbfa91 | |||
b7553925fb | |||
4b5b562307 | |||
ad68b36de7 | |||
0e8babf69c | |||
0e12212838 | |||
19b86972d8 | |||
403e234895 | |||
76ec0420d1 | |||
2a6beb2739 | |||
1933443e8d | |||
279b00e195 | |||
9b6542ab80 | |||
dfbab387ab | |||
10f4df519c | |||
24b5d48fed | |||
0650cabc47 | |||
71995a1fcd | |||
91c36b8f09 | |||
e3c19afb72 | |||
799025e8c2 | |||
896c00a08c | |||
8497855d80 | |||
52663ec676 | |||
0901fb6477 | |||
bf6d56ceac | |||
51350d5a42 | |||
9e32fed598 | |||
8301642e6b |
15
.github/workflows/avm.yml
vendored
Normal file
15
.github/workflows/avm.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: avm
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2,8,14,20 * * *'
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: [windows-latest]
|
||||
steps:
|
||||
- uses: billziss-gh/avm@v1
|
||||
with:
|
||||
files: |
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.6/winfsp-1.6.20027.msi
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.7B1/winfsp-1.7.20038.msi
|
@ -1,5 +1,97 @@
|
||||
= Changelog
|
||||
|
||||
|
||||
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:
|
||||
|
||||
* [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.7B1 (2020.1 B1)::
|
||||
|
||||
Changes since v1.6:
|
||||
|
||||
* [FIX] Workaround an incompatibility with Avast Antivirus. (GitHub issue #221.)
|
||||
* [FIX] Fix junction (mount point reparse point) handling. (GitHub issue #269.)
|
||||
|
||||
|
||||
v1.6 (2020)::
|
||||
|
||||
Changes since v1.5:
|
||||
|
@ -38,7 +38,7 @@
|
||||
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
|
||||
<br/>
|
||||
<br/>
|
||||
<img src="http://www.secfs.net/winfsp/files/cap.gif" height="450"/>
|
||||
<img src="doc/cap.gif" height="450"/>
|
||||
</p>
|
||||
|
||||
## Benefits
|
||||
@ -120,7 +120,7 @@ To fully build WinFsp (including the installer) you must use `tools\build.bat`.
|
||||
|
||||
tools\build.bat CONFIGURATION
|
||||
|
||||
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning on`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
|
||||
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning on`. For more information see this [document](doc/WinFsp-Debugging-Setup.asciidoc).
|
||||
|
||||
WinFsp is designed to run on Windows 7 and above. It has been tested on the following platforms:
|
||||
|
||||
|
10
appveyor.yml
10
appveyor.yml
@ -32,11 +32,17 @@ install:
|
||||
|
||||
build_script:
|
||||
- appveyor AddMessage "Reboot complete" -Category Information
|
||||
# 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"
|
||||
# build winfsp
|
||||
- tools\build.bat %CONFIGURATION%
|
||||
|
||||
test_script:
|
||||
- choco install winfsp -s build\VStudio\build\%CONFIGURATION% -y
|
||||
- if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/winfsp/resources/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip
|
||||
- choco install winfsp -s build\VStudio\build\%CONFIGURATION% -y --pre
|
||||
- if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip
|
||||
- if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn
|
||||
- if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION%
|
||||
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
|
||||
|
@ -101,7 +101,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>MEMFS_STANDALONE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -117,7 +117,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>MEMFS_STANDALONE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -135,7 +135,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>MEMFS_STANDALONE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -145,6 +145,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -155,7 +156,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>MEMFS_STANDALONE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -165,6 +166,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -149,6 +149,7 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -170,6 +171,7 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@ -183,6 +185,9 @@
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\..\src\fsptool\fsptool-version.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\um\minimal.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -5,9 +5,11 @@
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Include">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
<Filter Include="Source\shared">
|
||||
<UniqueIdentifier>{bd82112e-6494-4345-b35b-25eae56d5127}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\shared\um">
|
||||
<UniqueIdentifier>{dd21736e-dbea-4f24-8178-1903412e01f2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -20,4 +22,9 @@
|
||||
<Filter>Source</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\um\minimal.h">
|
||||
<Filter>Source\shared\um</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -155,6 +155,7 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -178,11 +179,9 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\minimal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\src\launcher\launchctl.c" />
|
||||
</ItemGroup>
|
||||
@ -199,6 +198,9 @@
|
||||
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\um\minimal.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -5,18 +5,13 @@
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Include">
|
||||
<UniqueIdentifier>{e650819b-355e-455c-81c9-10dc7debe109}</UniqueIdentifier>
|
||||
<Filter Include="Source\shared">
|
||||
<UniqueIdentifier>{9f7e57a6-7696-4de2-a9eb-cba60e24d02a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\shared">
|
||||
<UniqueIdentifier>{744edf89-567a-40b7-b6f2-ee2bc7b9f0d9}</UniqueIdentifier>
|
||||
<Filter Include="Source\shared\um">
|
||||
<UniqueIdentifier>{89fa307f-09d4-4373-a07f-49f23c698474}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\minimal.h">
|
||||
<Filter>Include\shared</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\src\launcher\launchctl.c">
|
||||
<Filter>Source</Filter>
|
||||
@ -27,4 +22,9 @@
|
||||
<Filter>Source</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\um\minimal.h">
|
||||
<Filter>Source\shared\um</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -158,6 +158,7 @@
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -182,6 +183,7 @@
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@ -193,9 +195,6 @@
|
||||
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\minimal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@ -204,6 +203,9 @@
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\um\minimal.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -5,11 +5,11 @@
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Include">
|
||||
<UniqueIdentifier>{11e7c0f2-7782-43ee-84fa-9e56efbe39de}</UniqueIdentifier>
|
||||
<Filter Include="Source\shared">
|
||||
<UniqueIdentifier>{ebc5d08c-dcc6-4889-a482-84cefda188cd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\shared">
|
||||
<UniqueIdentifier>{d83ea433-d9f7-494c-90b9-3a8997483cd9}</UniqueIdentifier>
|
||||
<Filter Include="Source\shared\um">
|
||||
<UniqueIdentifier>{574d211e-3e2c-4551-bc78-4786f33c4093}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -20,14 +20,14 @@
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\minimal.h">
|
||||
<Filter>Include\shared</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
|
||||
<Filter>Source</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\um\minimal.h">
|
||||
<Filter>Source\shared\um</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -16,10 +16,10 @@
|
||||
<MyCompanyName>Navimatics LLC</MyCompanyName>
|
||||
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
|
||||
|
||||
<MyCanonicalVersion>1.6</MyCanonicalVersion>
|
||||
<MyCanonicalVersion>1.8</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2020</MyProductVersion>
|
||||
<MyProductStage>Gold</MyProductStage>
|
||||
<MyProductVersion>2020.2 Beta3</MyProductVersion>
|
||||
<MyProductStage>Beta</MyProductStage>
|
||||
|
||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||
@ -37,6 +37,11 @@
|
||||
<PreprocessorDefinitions>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(IsKernelModeToolset)'=='true'">
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(DefaultPlatformToolset)'=='v140'">
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -35,8 +35,9 @@
|
||||
<ClInclude Include="..\..\src\dll\fuse3\library.h" />
|
||||
<ClInclude Include="..\..\src\dll\fuse\library.h" />
|
||||
<ClInclude Include="..\..\src\dll\library.h" />
|
||||
<ClInclude Include="..\..\src\ku\library.h" />
|
||||
<ClInclude Include="..\..\src\shared\minimal.h" />
|
||||
<ClInclude Include="..\..\src\shared\ku\config.h" />
|
||||
<ClInclude Include="..\..\src\shared\ku\library.h" />
|
||||
<ClInclude Include="..\..\src\shared\um\minimal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\dll\dirbuf.c" />
|
||||
@ -64,7 +65,7 @@
|
||||
<ClCompile Include="..\..\src\dll\service.c" />
|
||||
<ClCompile Include="..\..\src\dll\util.c" />
|
||||
<ClCompile Include="..\..\src\dll\wksid.c" />
|
||||
<ClCompile Include="..\..\src\ku\posix.c" />
|
||||
<ClCompile Include="..\..\src\shared\ku\posix.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
|
||||
@ -282,6 +283,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
|
||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -312,6 +314,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
|
||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -12,9 +12,6 @@
|
||||
<Filter Include="Include\winfsp">
|
||||
<UniqueIdentifier>{1d6501f4-cebd-4a00-a774-deb782b59fb5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\shared">
|
||||
<UniqueIdentifier>{c7b83307-0aa0-4593-b2d4-26ff2f1edfc6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\fuse">
|
||||
<UniqueIdentifier>{0e7ab1b1-bfca-4439-accb-45a909be9cad}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@ -27,8 +24,14 @@
|
||||
<Filter Include="Source\fuse3">
|
||||
<UniqueIdentifier>{96091a7b-3923-4a74-9491-3ee230c688f9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\ku">
|
||||
<UniqueIdentifier>{613cce77-2428-4f9a-9187-f37e009253c1}</UniqueIdentifier>
|
||||
<Filter Include="Source\shared">
|
||||
<UniqueIdentifier>{a099cca5-e40c-4f99-baff-b5399dac5406}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\shared\um">
|
||||
<UniqueIdentifier>{c2e11b62-74a0-41af-9f5b-0846fe81563c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\shared\ku">
|
||||
<UniqueIdentifier>{7963f853-656a-4fd7-b8df-e586c3fe3dab}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -41,9 +44,6 @@
|
||||
<ClInclude Include="..\..\src\dll\library.h">
|
||||
<Filter>Source</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\shared\minimal.h">
|
||||
<Filter>Include\shared</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\fuse\fuse.h">
|
||||
<Filter>Include\fuse</Filter>
|
||||
</ClInclude>
|
||||
@ -80,8 +80,14 @@
|
||||
<ClInclude Include="..\..\src\dll\fuse3\library.h">
|
||||
<Filter>Source\fuse3</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ku\library.h">
|
||||
<Filter>Source\ku</Filter>
|
||||
<ClInclude Include="..\..\src\shared\um\minimal.h">
|
||||
<Filter>Source\shared\um</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\shared\ku\library.h">
|
||||
<Filter>Source\shared\ku</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\shared\ku\config.h">
|
||||
<Filter>Source\shared\ku</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -157,12 +163,12 @@
|
||||
<ClCompile Include="..\..\src\dll\fuse3\fuse3_compat.c">
|
||||
<Filter>Source\fuse3</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ku\posix.c">
|
||||
<Filter>Source\ku</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\mount.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\shared\ku\posix.c">
|
||||
<Filter>Source\shared\ku</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\dll\library.def">
|
||||
|
@ -123,6 +123,7 @@
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -149,14 +150,15 @@
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<FilesToPackage Include="$(TargetPath)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\ku\posix.c" />
|
||||
<ClCompile Include="..\..\src\ku\uuid5.c" />
|
||||
<ClCompile Include="..\..\src\shared\ku\posix.c" />
|
||||
<ClCompile Include="..\..\src\shared\ku\uuid5.c" />
|
||||
<ClCompile Include="..\..\src\sys\cleanup.c" />
|
||||
<ClCompile Include="..\..\src\sys\close.c" />
|
||||
<ClCompile Include="..\..\src\sys\create.c" />
|
||||
@ -183,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" />
|
||||
@ -193,7 +196,8 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\inc\winfsp\fsctl.h" />
|
||||
<ClInclude Include="..\..\opt\fsext\inc\winfsp\fsext.h" />
|
||||
<ClInclude Include="..\..\src\ku\library.h" />
|
||||
<ClInclude Include="..\..\src\shared\ku\config.h" />
|
||||
<ClInclude Include="..\..\src\shared\ku\library.h" />
|
||||
<ClInclude Include="..\..\src\sys\driver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -12,8 +12,11 @@
|
||||
<Filter Include="Include\winfsp">
|
||||
<UniqueIdentifier>{904f0df1-2fb8-4f84-aa46-fa929488c39a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\ku">
|
||||
<UniqueIdentifier>{235076b8-290c-4dec-b005-71d9b8e8cba7}</UniqueIdentifier>
|
||||
<Filter Include="Source\shared">
|
||||
<UniqueIdentifier>{c4db9aa7-9474-4f0b-b38b-343a8a1e5686}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source\shared\ku">
|
||||
<UniqueIdentifier>{df147bf8-bbdf-4de7-95ce-1e281925725a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -110,15 +113,18 @@
|
||||
<ClCompile Include="..\..\src\sys\fsext.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ku\posix.c">
|
||||
<Filter>Source\ku</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ku\uuid5.c">
|
||||
<Filter>Source\ku</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\sys\mountdev.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\shared\ku\posix.c">
|
||||
<Filter>Source\shared\ku</Filter>
|
||||
</ClCompile>
|
||||
<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">
|
||||
@ -130,8 +136,11 @@
|
||||
<ClInclude Include="..\..\opt\fsext\inc\winfsp\fsext.h">
|
||||
<Filter>Include\winfsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ku\library.h">
|
||||
<Filter>Source\ku</Filter>
|
||||
<ClInclude Include="..\..\src\shared\ku\library.h">
|
||||
<Filter>Source\shared\ku</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\shared\ku\config.h">
|
||||
<Filter>Source\shared\ku</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -52,6 +52,6 @@ To verify installation:
|
||||
<file src="chocolateyInstall.ps1" target="tools" />
|
||||
<file src="chocolateyUninstall.ps1" target="tools" />
|
||||
<file src="chocolateyHelper.ps1" target="tools" />
|
||||
<file src="winfsp-$version$.msi" target="tools" />
|
||||
<file src="winfsp-$MsiVersion$.msi" target="tools" />
|
||||
</files>
|
||||
</package>
|
||||
|
@ -9,7 +9,7 @@ The documentation available here discusses various aspects of WinFsp.
|
||||
## Programming
|
||||
|
||||
- The [[Tutorial|WinFsp-Tutorial]] describes how to create a simple, but complete file system in C/C++.
|
||||
- The [[API Reference|WinFsp-API-winfsp.h]] describes the native WinFsp API. This external [[link|http://www.secfs.net/winfsp/apiref/]] may be easier to browse for some people.
|
||||
- The [[API Reference|WinFsp-API-winfsp.h]] describes the native WinFsp API.
|
||||
- There is also a FUSE compatibility layer for native Windows and Cygwin. See fuse.h in the source repository.
|
||||
- This [[document|Native-API-vs-FUSE]] discusses the need for both a native API and FUSE and gives some pointers on which one to choose.
|
||||
- Since release 2019.3 WinFsp supports development of file systems in kernel mode. This [[document|WinFsp-Kernel-Mode-File-Systems]] discusses how to write such file systems.
|
||||
@ -30,5 +30,3 @@ The documentation available here discusses various aspects of WinFsp.
|
||||
## Compatibility
|
||||
|
||||
- The [[Compatibility|NTFS-Compatibility]] document discusses current WinFsp compatibility with NTFS.
|
||||
|
||||
WinFsp is available under the GPLv3 license with a special exception for Free/Libre and Open Source Software.
|
||||
|
@ -4,9 +4,11 @@ This document contains a list of known file systems and file system libraries th
|
||||
|
||||
== File Systems
|
||||
|
||||
- https://github.com/wesley1975/blobfs-win[blobfs-win] - The native porting of the blobfs on the windows platform, blobfs can help you mount the Azure Blob storage as the local disk driver, no matter it is a Linux system or a Windows system.
|
||||
- https://github.com/vgough/encfs[EncFS] - an Encrypted Filesystem for FUSE
|
||||
- https://github.com/lowleveldesign/fsmemfs[fsmemfs] - Memory File System written in F#
|
||||
- https://github.com/ihaveamac/fuse-3ds[fuse-3ds] - FUSE Filesystem Python scripts for Nintendo 3DS files
|
||||
- https://github.com/sganis/golddrive[golddrive] - Windows ssh network drive
|
||||
- https://github.com/FrKaram/KS2.Drive[KS2.Drive] - Mount a webDAV/AOS server as a local drive
|
||||
- https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows
|
||||
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage
|
||||
@ -14,6 +16,7 @@ This document contains a list of known file systems and file system libraries th
|
||||
- https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming
|
||||
- https://github.com/netheril96/securefs[securefs] - Filesystem in userspace (FUSE) with transparent authenticated encryption
|
||||
- https://github.com/billziss-gh/sshfs-win[sshfs-win] - SSHFS for Windows
|
||||
- https://github.com/emoose/xbox-winfsp[xbox-winfsp] - Adds native support to Windows for the FATX, STFS & GDFX (aka XGD/XDVDFS) Xbox filesystems.
|
||||
- https://github.com/UtrechtUniversity/YodaDrive[YodaDrive] - Mount a Yoda drive as a local drive
|
||||
|
||||
== File System Libraries
|
||||
@ -22,4 +25,5 @@ This document contains a list of known file systems and file system libraries th
|
||||
- https://github.com/DuroSoft/fuse-bindings[Nodejs: fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
|
||||
- https://github.com/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR)
|
||||
- https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
|
||||
- https://github.com/pleiszenburg/refuse[Python: refuse] - Simple cross-plattform ctypes bindings for libfuse / FUSE for macOS / WinFsp
|
||||
- https://github.com/Scille/winfspy[Python: winfspy] - WinFSP binding for Python
|
||||
|
@ -1,263 +0,0 @@
|
||||
= winfsp/launch.h
|
||||
:author: (C) 2015-2018 Bill Zissimopoulos
|
||||
:toc: preamble
|
||||
:toc-title:
|
||||
|
||||
WinFsp Launch API.
|
||||
|
||||
In order to use the WinFsp Launch API a program must include <winfsp/launch.h>
|
||||
and link with the winfsp$$_$$x64.dll (or winfsp$$_$$x86.dll) library.
|
||||
|
||||
== Launch Control
|
||||
|
||||
=== Functions
|
||||
|
||||
*FspLaunchCallLauncherPipe* - Call launcher pipe.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
|
||||
WCHAR Command,
|
||||
ULONG Argc,
|
||||
PWSTR *Argv,
|
||||
ULONG *Argl,
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _Command_ - Launcher command to send. For example, the 'L' launcher command instructs
|
||||
the launcher to list all running service instances.
|
||||
- _Argc_ - Command argument count. May be 0.
|
||||
- _Argv_ - Command argument array. May be NULL.
|
||||
- _Argl_ - Command argument length array. May be NULL. If this is NULL all command arguments
|
||||
are assumed to be NULL-terminated strings. It is also possible for specific arguments
|
||||
to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
|
||||
- _Buffer_ - Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ - Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
*Discussion*
|
||||
|
||||
This function is used to send a command to the launcher and receive a response.
|
||||
|
||||
|
||||
*FspLaunchGetInfo* - Get information about a service instance.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchGetInfo(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _ClassName_ - Class name of the service instance to stop.
|
||||
- _InstanceName_ - Instance name of the service instance to stop.
|
||||
- _Buffer_ - Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ - Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
*Discussion*
|
||||
|
||||
The information is a list of NULL-terminated strings: the class name of the service instance,
|
||||
the instance name of the service instance and the full command line used to start the service
|
||||
instance.
|
||||
|
||||
|
||||
*FspLaunchGetNameList* - List service instances.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchGetNameList(
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _Buffer_ - Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ - Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
*Discussion*
|
||||
|
||||
The information is a list of pairs of NULL-terminated strings. Each pair contains the class
|
||||
name and instance name of a service instance. All currently running service instances are
|
||||
listed.
|
||||
|
||||
|
||||
*FspLaunchStart* - Start a service instance.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchStart(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
ULONG Argc,
|
||||
PWSTR *Argv,
|
||||
BOOLEAN HasSecret,
|
||||
PULONG PLauncherError);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _ClassName_ - Class name of the service instance to start.
|
||||
- _InstanceName_ - Instance name of the service instance to start.
|
||||
- _Argc_ - Service instance argument count. May be 0.
|
||||
- _Argv_ - Service instance argument array. May be NULL.
|
||||
- _HasSecret_ - Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
|
||||
Secrets are passed to service instances through standard input rather than the command
|
||||
line.
|
||||
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
|
||||
*FspLaunchStop* - Stop a service instance.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchStop(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
PULONG PLauncherError);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _ClassName_ - Class name of the service instance to stop.
|
||||
- _InstanceName_ - Instance name of the service instance to stop.
|
||||
- _PLauncherError_ - Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
|
||||
== Service Registry
|
||||
|
||||
=== Functions
|
||||
|
||||
*FspLaunchRegFreeRecord* - Free a service registry record.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API VOID FspLaunchRegFreeRecord(
|
||||
FSP_LAUNCH_REG_RECORD *Record);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _Record_ - The service record to free.
|
||||
|
||||
*See Also*
|
||||
|
||||
- FspLaunchRegGetRecord
|
||||
|
||||
|
||||
*FspLaunchRegGetRecord* - Get a service registry record.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchRegGetRecord(
|
||||
PWSTR ClassName,
|
||||
PWSTR Agent,
|
||||
FSP_LAUNCH_REG_RECORD **PRecord);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _ClassName_ - The service class name.
|
||||
- _Agent_ - The name of the agent that is retrieving the service record. This API matches
|
||||
the supplied Agent against the Agent in the service record and it only returns
|
||||
the record if they match. Pass NULL to match any Agent.
|
||||
- _PRecord_ - Pointer to a record pointer. Memory for the service record will be allocated
|
||||
and a pointer to it will be stored at this address. This memory must be later
|
||||
freed using FspLaunchRegFreeRecord.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS or error code.
|
||||
|
||||
*See Also*
|
||||
|
||||
- FspLaunchRegFreeRecord
|
||||
|
||||
|
||||
*FspLaunchRegSetRecord* - Add/change/delete a service registry record.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
FSP_API NTSTATUS FspLaunchRegSetRecord(
|
||||
PWSTR ClassName,
|
||||
const FSP_LAUNCH_REG_RECORD *Record);
|
||||
----
|
||||
|
||||
*Parameters*
|
||||
|
||||
- _ClassName_ - The service class name.
|
||||
- _Record_ - The record to set in the registry. If NULL, the registry record is deleted.
|
||||
|
||||
*Return Value*
|
||||
|
||||
STATUS$$_$$SUCCESS or error code.
|
||||
|
||||
|
||||
=== Typedefs
|
||||
|
||||
*FSP$$_$$LAUNCH$$_$$REG$$_$$RECORD* - Service registry record.
|
||||
|
||||
[source,c]
|
||||
----
|
||||
typedef struct _FSP_LAUNCH_REG_RECORD {
|
||||
PWSTR Agent;
|
||||
PWSTR Executable;
|
||||
PWSTR CommandLine;
|
||||
PWSTR WorkDirectory;
|
||||
PWSTR RunAs;
|
||||
PWSTR Security;
|
||||
PVOID Reserved0[6];
|
||||
ULONG JobControl;
|
||||
ULONG Credentials;
|
||||
ULONG Reserved1[6];
|
||||
UINT8 Buffer[];
|
||||
} FSP_LAUNCH_REG_RECORD;
|
||||
----
|
||||
|
||||
|
||||
|
421
doc/WinFsp-API-launch.h.md
Normal file
421
doc/WinFsp-API-launch.h.md
Normal file
@ -0,0 +1,421 @@
|
||||
# winfsp/launch.h
|
||||
|
||||
WinFsp Launch API.
|
||||
|
||||
In order to use the WinFsp Launch API a program must include <winfsp/launch.h>
|
||||
and link with the winfsp\_x64.dll (or winfsp\_x86.dll) library.
|
||||
|
||||
## LAUNCH CONTROL
|
||||
|
||||
### Functions
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchCallLauncherPipe</b> - Call launcher pipe.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
|
||||
WCHAR Command,
|
||||
ULONG Argc,
|
||||
PWSTR *Argv,
|
||||
ULONG *Argl,
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _Command_ \- Launcher command to send. For example, the 'L' launcher command instructs
|
||||
the launcher to list all running service instances.
|
||||
- _Argc_ \- Command argument count. May be 0.
|
||||
- _Argv_ \- Command argument array. May be NULL.
|
||||
- _Argl_ \- Command argument length array. May be NULL. If this is NULL all command arguments
|
||||
are assumed to be NULL-terminated strings. It is also possible for specific arguments
|
||||
to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
|
||||
- _Buffer_ \- Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ \- Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
**Discussion**
|
||||
|
||||
This function is used to send a command to the launcher and receive a response.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchCallLauncherPipeEx</b> - Call launcher pipe.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchCallLauncherPipeEx(
|
||||
WCHAR Command,
|
||||
ULONG Argc,
|
||||
PWSTR *Argv,
|
||||
ULONG *Argl,
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
BOOLEAN AllowImpersonation,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _Command_ \- Launcher command to send. For example, the 'L' launcher command instructs
|
||||
the launcher to list all running service instances.
|
||||
- _Argc_ \- Command argument count. May be 0.
|
||||
- _Argv_ \- Command argument array. May be NULL.
|
||||
- _Argl_ \- Command argument length array. May be NULL. If this is NULL all command arguments
|
||||
are assumed to be NULL-terminated strings. It is also possible for specific arguments
|
||||
to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
|
||||
- _Buffer_ \- Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ \- Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _AllowImpersonation_ \- Allow caller to be impersonated by launcher.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
**Discussion**
|
||||
|
||||
This function is used to send a command to the launcher and receive a response.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchGetInfo</b> - Get information about a service instance.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchGetInfo(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _ClassName_ \- Class name of the service instance to stop.
|
||||
- _InstanceName_ \- Instance name of the service instance to stop.
|
||||
- _Buffer_ \- Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ \- Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
**Discussion**
|
||||
|
||||
The information is a list of NULL-terminated strings: the class name of the service instance,
|
||||
the instance name of the service instance and the full command line used to start the service
|
||||
instance.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchGetNameList</b> - List service instances.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchGetNameList(
|
||||
PWSTR Buffer,
|
||||
PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _Buffer_ \- Buffer that receives the command response. May be NULL.
|
||||
- _PSize_ \- Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
contains the number of bytes transferred. May be NULL.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
**Discussion**
|
||||
|
||||
The information is a list of pairs of NULL-terminated strings. Each pair contains the class
|
||||
name and instance name of a service instance. All currently running service instances are
|
||||
listed.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchStart</b> - Start a service instance.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchStart(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
ULONG Argc,
|
||||
PWSTR *Argv,
|
||||
BOOLEAN HasSecret,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _ClassName_ \- Class name of the service instance to start.
|
||||
- _InstanceName_ \- Instance name of the service instance to start.
|
||||
- _Argc_ \- Service instance argument count. May be 0.
|
||||
- _Argv_ \- Service instance argument array. May be NULL.
|
||||
- _HasSecret_ \- Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
|
||||
Secrets are passed to service instances through standard input rather than the command
|
||||
line.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchStartEx</b> - Start a service instance.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchStartEx(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
ULONG Argc,
|
||||
PWSTR *Argv,
|
||||
BOOLEAN HasSecret,
|
||||
BOOLEAN AllowImpersonation,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _ClassName_ \- Class name of the service instance to start.
|
||||
- _InstanceName_ \- Instance name of the service instance to start.
|
||||
- _Argc_ \- Service instance argument count. May be 0.
|
||||
- _Argv_ \- Service instance argument array. May be NULL.
|
||||
- _HasSecret_ \- Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
|
||||
Secrets are passed to service instances through standard input rather than the command
|
||||
line.
|
||||
- _AllowImpersonation_ \- Allow caller to be impersonated by launcher.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchStop</b> - Stop a service instance.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchStop(
|
||||
PWSTR ClassName,
|
||||
PWSTR InstanceName,
|
||||
PULONG PLauncherError);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _ClassName_ \- Class name of the service instance to stop.
|
||||
- _InstanceName_ \- Instance name of the service instance to stop.
|
||||
- _PLauncherError_ \- Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
reported through PLauncherError.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
## SERVICE REGISTRY
|
||||
|
||||
### Functions
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchRegFreeRecord</b> - Free a service registry record.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API VOID FspLaunchRegFreeRecord(
|
||||
FSP_LAUNCH_REG_RECORD *Record);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _Record_ \- The service record to free.
|
||||
|
||||
**See Also**
|
||||
|
||||
- FspLaunchRegGetRecord
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchRegGetRecord</b> - Get a service registry record.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchRegGetRecord(
|
||||
PWSTR ClassName,
|
||||
PWSTR Agent,
|
||||
FSP_LAUNCH_REG_RECORD **PRecord);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _ClassName_ \- The service class name.
|
||||
- _Agent_ \- The name of the agent that is retrieving the service record. This API matches
|
||||
the supplied Agent against the Agent in the service record and it only returns
|
||||
the record if they match. Pass NULL to match any Agent.
|
||||
- _PRecord_ \- Pointer to a record pointer. Memory for the service record will be allocated
|
||||
and a pointer to it will be stored at this address. This memory must be later
|
||||
freed using FspLaunchRegFreeRecord.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS or error code.
|
||||
|
||||
**See Also**
|
||||
|
||||
- FspLaunchRegFreeRecord
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FspLaunchRegSetRecord</b> - Add/change/delete a service registry record.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
FSP_API NTSTATUS FspLaunchRegSetRecord(
|
||||
PWSTR ClassName,
|
||||
const FSP_LAUNCH_REG_RECORD *Record);
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- _ClassName_ \- The service class name.
|
||||
- _Record_ \- The record to set in the registry. If NULL, the registry record is deleted.
|
||||
|
||||
**Return Value**
|
||||
|
||||
STATUS\_SUCCESS or error code.
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
### Typedefs
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<b>FSP_LAUNCH_REG_RECORD</b> - Service registry record.
|
||||
</summary>
|
||||
<blockquote>
|
||||
<br/>
|
||||
|
||||
```c
|
||||
typedef struct _FSP_LAUNCH_REG_RECORD {
|
||||
PWSTR Agent;
|
||||
PWSTR Executable;
|
||||
PWSTR CommandLine;
|
||||
PWSTR WorkDirectory;
|
||||
PWSTR RunAs;
|
||||
PWSTR Security;
|
||||
PWSTR AuthPackage;
|
||||
PVOID Reserved0[5];
|
||||
ULONG JobControl;
|
||||
ULONG Credentials;
|
||||
ULONG AuthPackageId;
|
||||
ULONG Reserved1[5];
|
||||
UINT8 Buffer[];
|
||||
} FSP_LAUNCH_REG_RECORD;
|
||||
```
|
||||
|
||||
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
<sub>
|
||||
Copyright © 2015-2020 Bill Zissimopoulos
|
||||
<br/>
|
||||
Generated with <a href="https://github.com/billziss-gh/prettydoc">prettydoc</a>
|
||||
</sub>
|
||||
</p>
|
File diff suppressed because it is too large
Load Diff
2620
doc/WinFsp-API-winfsp.h.md
Normal file
2620
doc/WinFsp-API-winfsp.h.md
Normal file
File diff suppressed because it is too large
Load Diff
73
doc/WinFsp-Container-Support.asciidoc
Normal file
73
doc/WinFsp-Container-Support.asciidoc
Normal 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.
|
81
doc/WinFsp-Debugging-Setup.asciidoc
Normal file
81
doc/WinFsp-Debugging-Setup.asciidoc
Normal file
@ -0,0 +1,81 @@
|
||||
= WinFsp Debugging Setup
|
||||
|
||||
In this article I will describe the debugging setup used for WinFsp. Note that my debugging setup is somewhat peculiar, because all development and debugging is done on a Mac computer using two Windows virtual machines: one for development and one for debugging! However my description below should work for a one or two virtual machine setup.
|
||||
|
||||
WinFsp is being developed on Windows 10 and debugged and tested on Windows 8 (although it should run correctly on Windows Vista and higher). You will need some virtualization software (I use VirtualBox 5), you will also need a fresh installation of Windows and to configure it properly for kernel debugging and running test signed drivers:
|
||||
|
||||
* Create a Windows VM with a descriptive name (e.g. Win8DBG). Mine has a single CPU and just 2GB of memory.
|
||||
* Configure your VM for Host Only Networking. This will be used for WinDbg debugging and for deploying WinFsp.
|
||||
* Install Windows 8 on Win8DBG. Windows 8 is the minimum version of Windows that supports kernel network debugging.
|
||||
* I would recommend not to install your virtualization software guest additions to minimize issues with your debugging VM.
|
||||
* Configure Win8DBG for running test signed drivers:
|
||||
+
|
||||
----
|
||||
bcdedit.exe -set testsigning on
|
||||
----
|
||||
* Configure Win8DBG for debugging over the network:
|
||||
+
|
||||
----
|
||||
bcdedit /debug on
|
||||
bcdedit /dbgsettings net hostip:W.X.Y.Z port:NNNN key:KKKK
|
||||
----
|
||||
** Note that if you configure your VM with multiple network adapters you must also specify the correct `busparams` argument. You can find the correct `busparams` from the Windows Device Manager. For example, here are the settings on one of my VM's:
|
||||
+
|
||||
----
|
||||
>bcdedit /dbgsettings
|
||||
busparams 0.8.0
|
||||
key 1.1.1.1
|
||||
debugtype NET
|
||||
hostip 192.168.56.11
|
||||
port 50000
|
||||
dhcp Yes
|
||||
The operation completed successfully.
|
||||
----
|
||||
* Enable DbgPrint on Win8DBG. Create the following key/value in the registry:
|
||||
+
|
||||
----
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter]
|
||||
"DEFAULT"=dword:0000000f
|
||||
----
|
||||
* Create a directory on Win8DBG where you will be deploying WinFsp. I use a subdirectory of the Downloads directory:
|
||||
+
|
||||
----
|
||||
C:\Users\USERNAME\Downloads\winfsp
|
||||
----
|
||||
* Make the directory available outside the VM using Windows networking. You can use this new Windows share as an easy means to deploy WinFsp.
|
||||
+
|
||||
----
|
||||
copy build\VStudio\build\Debug\winfsp-x64.sys \\Win8DBG\Users\USERNAME\Downloads\winfsp
|
||||
----
|
||||
* Enable Driver Verifier for WinFsp on Win8DBG. The easiest way to do so is to run `verifier` from the command line.
|
||||
* For faster edit-compile-test cycles I strongly recommend to use your virtualization software snapshot feature. For example, in my Win8DBG VM after I set it up exactly how I wanted it, I took a snapshot while the VM was running. Now whenever I want to test WinFsp, I restart that same snapshot and within 3-4 seconds I have a new VM ready for use. Even more importantly whenever there is a hard crash on the VM (happens a lot when developing Windows drivers) I can simply close the crashed VM and restart a new one.
|
||||
* On your development machine configure WinDbg to use the Microsoft public symbol servers. From the main menu select File > Symbol File Path and enter:
|
||||
+
|
||||
----
|
||||
SRV*C:\Users\USERNAME\AppData\Local\Temp\SymbolCache*http://msdl.microsoft.com/download/symbols
|
||||
----
|
||||
* You can now run WinDbg and from the main menu select File > Kernel Debug, then enter the appropriate port number and key. Alternatively you can use the following windbg command line:
|
||||
+
|
||||
----
|
||||
windbg -k net:port=NNNN,key=KKKK
|
||||
----
|
||||
* Checkout the `tools/deploy.bat` and `tools/debug.bat` batch files in the source distribution to see how I deploy and debug WinFsp.
|
||||
|
||||
== Debugging a user mode process from kernel mode WinDbg
|
||||
|
||||
In order to debug a user mode process from a kernel mode WinDbg session, break into the debugger and issue the following commands:
|
||||
|
||||
----
|
||||
kd> !gflag +ksl
|
||||
kd> sxe ld MODULE-NAME.exe
|
||||
----
|
||||
|
||||
Restart the debugger and it will break within process creation. You can now set a breakpoint at your process wmain (or main, etc.):
|
||||
|
||||
----
|
||||
kd> bp MODULE_NAME!wmain
|
||||
----
|
||||
|
||||
Restart the debugger and it will stop at your program's entry point.
|
BIN
doc/cap.gif
Normal file
BIN
doc/cap.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
@ -360,7 +360,10 @@ static inline int fsp_fuse_set_signal_handlers(void *se)
|
||||
|
||||
static sigset_t sigmask;
|
||||
static pthread_t sigthr;
|
||||
struct sigaction oldsa, newsa = { 0 };
|
||||
struct sigaction oldsa, newsa;
|
||||
|
||||
// memset instead of initializer to avoid GCC -Wmissing-field-initializers warning
|
||||
memset(&newsa, 0, sizeof newsa);
|
||||
|
||||
if (0 != se)
|
||||
{
|
||||
|
@ -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))
|
||||
@ -176,7 +180,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\
|
||||
|
@ -287,11 +287,13 @@ typedef struct _FSP_LAUNCH_REG_RECORD
|
||||
PWSTR RunAs;
|
||||
PWSTR Security;
|
||||
PWSTR AuthPackage;
|
||||
PVOID Reserved0[5];
|
||||
PWSTR Stderr;
|
||||
PVOID Reserved0[4];
|
||||
ULONG JobControl;
|
||||
ULONG Credentials;
|
||||
ULONG AuthPackageId;
|
||||
ULONG Reserved1[5];
|
||||
ULONG Recovery;
|
||||
ULONG Reserved1[4];
|
||||
UINT8 Buffer[];
|
||||
} FSP_LAUNCH_REG_RECORD;
|
||||
#pragma warning(pop)
|
||||
|
@ -335,6 +335,18 @@ FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)
|
||||
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
|
||||
/* eliminate invalidated entries from the index */
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
ULONG I, J;
|
||||
for (I = Count - 1, J = Count; I < Count; I--)
|
||||
{
|
||||
if (FspFileSystemDirectoryBufferEntryInvalid == Index[I])
|
||||
continue;
|
||||
Index[--J] = Index[I];
|
||||
}
|
||||
DirBuffer->HiMark = (ULONG)((PUINT8)&Index[J] - DirBuffer->Buffer);
|
||||
|
||||
FspFileSystemSortDirectoryBuffer(DirBuffer);
|
||||
|
||||
ReleaseSRWLockExclusive(&DirBuffer->Lock);
|
||||
|
@ -273,6 +273,13 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
||||
OperationContext.Response = Response;
|
||||
TlsSetValue(FspFileSystemTlsKey, &OperationContext);
|
||||
|
||||
#if defined(FSP_CFG_REJECT_EARLY_IRP)
|
||||
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;
|
||||
#endif
|
||||
|
||||
memset(Response, 0, sizeof *Response);
|
||||
for (;;)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -1748,9 +1748,15 @@ reparse_data_exit:
|
||||
return IO_REPARSE_TAG_SYMLINK != ReparseData->ReparseTag ?
|
||||
STATUS_IO_REPARSE_DATA_INVALID : STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||
|
||||
if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData->ReparseTag)
|
||||
RemainderPathSize = lstrlenW(RemainderPath) * sizeof(WCHAR);
|
||||
|
||||
*PSize = ReparseDataSize;
|
||||
memcpy(Buffer, ReparseData, ReparseDataSize);
|
||||
|
||||
if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData->ReparseTag)
|
||||
OutputReparseData->Reserved = (USHORT)RemainderPathSize;
|
||||
|
||||
PIoStatus->Status = STATUS_REPARSE;
|
||||
PIoStatus->Information = ReparseData->ReparseTag;
|
||||
return STATUS_REPARSE;
|
||||
|
@ -510,6 +510,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
|
||||
opt_data.VolumeParams.PassQueryDirectoryFileName = TRUE;
|
||||
opt_data.VolumeParams.DeviceControl = TRUE;
|
||||
#if defined(FSP_CFG_REJECT_EARLY_IRP)
|
||||
opt_data.VolumeParams.RejectIrpPriorToTransact0 = TRUE;
|
||||
#endif
|
||||
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||
|
@ -1734,6 +1734,21 @@ exit:
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID fsp_fuse_intf_LogBadDirInfo(
|
||||
const char *PosixPath, const char *PosixName, const char *Message)
|
||||
{
|
||||
static LONG Count = 0;
|
||||
ULONG NewCount;
|
||||
|
||||
NewCount = (ULONG)InterlockedIncrement(&Count);
|
||||
|
||||
/* log only the first 5 such warnings to avoid warning overload */
|
||||
if (5 >= NewCount)
|
||||
FspDebugLog("%S[TID=%04lx]: WARN: readdir(\"%s\"): name=\"%s\": %s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(),
|
||||
PosixPath, PosixName, Message);
|
||||
}
|
||||
|
||||
/* !static: used by fuse2to3 */
|
||||
int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
|
||||
const struct fuse_stat *stbuf, fuse_off_t off)
|
||||
@ -1759,13 +1774,19 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
|
||||
|
||||
SizeA = lstrlenA(name);
|
||||
if (SizeA > 255)
|
||||
/* ignore bad filenames; should we return error code? */
|
||||
{
|
||||
fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
|
||||
"too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255);
|
||||
if (0 == SizeW)
|
||||
/* ignore bad filenames; should we return error code? */
|
||||
{
|
||||
fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
|
||||
"MultiByteToWideChar failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(DirInfo, 0, sizeof *DirInfo);
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
|
||||
@ -1866,7 +1887,12 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
|
||||
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
{
|
||||
/* mark the directory buffer entry as invalid */
|
||||
*Index = FspFileSystemDirectoryBufferEntryInvalid;
|
||||
fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, PosixName,
|
||||
"getattr failed");
|
||||
}
|
||||
|
||||
if (0 != PosixPathEnd)
|
||||
*PosixPathEnd = SavedPathChar;
|
||||
|
@ -271,9 +271,11 @@ FSP_API NTSTATUS FspLaunchRegSetRecord(
|
||||
SETFIELD(RunAs);
|
||||
SETFIELD(Security);
|
||||
SETFIELD(AuthPackage);
|
||||
SETFIELD(Stderr);
|
||||
SETFIELDI(JobControl, ~0); /* JobControl default is 1; but we treat as without default */
|
||||
SETFIELDI(Credentials, 0);
|
||||
SETFIELDI(AuthPackageId, 0);
|
||||
SETFIELDI(Recovery, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -423,9 +425,11 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
|
||||
GETFIELD(RunAs);
|
||||
GETFIELD(Security);
|
||||
GETFIELD(AuthPackage);
|
||||
GETFIELD(Stderr);
|
||||
GETFIELDI(JobControl);
|
||||
GETFIELDI(Credentials);
|
||||
GETFIELDI(AuthPackageId);
|
||||
GETFIELDI(Recovery);
|
||||
|
||||
if (0 == Record->Executable)
|
||||
{
|
||||
@ -456,9 +460,12 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
|
||||
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Security - RegBuf)) : 0;
|
||||
Record->AuthPackage = 0 != RecordBuf.AuthPackage ?
|
||||
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.AuthPackage - RegBuf)) : 0;
|
||||
Record->Stderr = 0 != RecordBuf.Stderr ?
|
||||
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Stderr - RegBuf)) : 0;
|
||||
Record->JobControl = RecordBuf.JobControl;
|
||||
Record->Credentials = RecordBuf.Credentials;
|
||||
Record->AuthPackageId = RecordBuf.AuthPackageId;
|
||||
Record->Recovery = RecordBuf.Recovery;
|
||||
|
||||
*PRecord = Record;
|
||||
Result = STATUS_SUCCESS;
|
||||
|
@ -25,9 +25,11 @@
|
||||
#define WINFSP_DLL_INTERNAL
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <winfsp/launch.h>
|
||||
#include <shared/minimal.h>
|
||||
#include <shared/um/minimal.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include <shared/ku/config.h>
|
||||
|
||||
#define LIBRARY_NAME "WinFsp"
|
||||
|
||||
/* DEBUGLOG */
|
||||
@ -64,6 +66,7 @@ PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);
|
||||
|
||||
PWSTR FspDiagIdent(VOID);
|
||||
|
||||
#define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1)
|
||||
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
|
||||
|
||||
|
@ -307,6 +307,11 @@ namespace Fsp
|
||||
get { return 0 != (_VolumeParams.Flags & VolumeParams.WslFeatures); }
|
||||
set { _VolumeParams.Flags |= (value ? VolumeParams.WslFeatures : 0); }
|
||||
}
|
||||
public Boolean RejectIrpPriorToTransact0
|
||||
{
|
||||
get { return 0 != (_VolumeParams.Flags & VolumeParams.RejectIrpPriorToTransact0); }
|
||||
set { _VolumeParams.Flags |= (value ? VolumeParams.RejectIrpPriorToTransact0 : 0); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the prefix for a network file system.
|
||||
/// </summary>
|
||||
|
@ -54,6 +54,7 @@ namespace Fsp.Interop
|
||||
internal const UInt32 AllowOpenInKernelMode = 0x01000000;
|
||||
internal const UInt32 CasePreservedExtendedAttributes = 0x02000000;
|
||||
internal const UInt32 WslFeatures = 0x04000000;
|
||||
internal const UInt32 RejectIrpPriorToTransact0 = 0x10000000;
|
||||
internal const int PrefixSize = 192;
|
||||
internal const int FileSystemNameSize = 16;
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <shared/minimal.h>
|
||||
#include <shared/um/minimal.h>
|
||||
#include <aclapi.h>
|
||||
#include <sddl.h>
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <winfsp/launch.h>
|
||||
#include <shared/minimal.h>
|
||||
#include <shared/um/minimal.h>
|
||||
|
||||
#define PROGNAME "launchctl"
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <winfsp/launch.h>
|
||||
#include <shared/minimal.h>
|
||||
#include <shared/um/minimal.h>
|
||||
#include <aclapi.h>
|
||||
#include <sddl.h>
|
||||
#include <userenv.h>
|
||||
@ -455,6 +455,8 @@ static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout)
|
||||
typedef struct
|
||||
{
|
||||
LONG RefCount;
|
||||
LIST_ENTRY ListEntry;
|
||||
HANDLE ClientToken;
|
||||
PWSTR ClassName;
|
||||
PWSTR InstanceName;
|
||||
PWSTR CommandLine;
|
||||
@ -462,27 +464,24 @@ typedef struct
|
||||
DWORD ProcessId;
|
||||
HANDLE Process;
|
||||
HANDLE ProcessWait;
|
||||
HANDLE StdioHandles[2];
|
||||
LIST_ENTRY ListEntry;
|
||||
HANDLE StdioHandles[3];
|
||||
DWORD Recovery;
|
||||
ULONG Argc;
|
||||
PWSTR *Argv;
|
||||
BOOLEAN HasSecret;
|
||||
BOOLEAN Started, Stopped;
|
||||
WCHAR Buffer[];
|
||||
} SVC_INSTANCE;
|
||||
|
||||
static HANDLE SvcJob;
|
||||
static CRITICAL_SECTION SvcInstanceLock;
|
||||
static HANDLE SvcInstanceEvent;
|
||||
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
|
||||
static DWORD SvcInstanceTlsKey = TLS_OUT_OF_INDEXES;
|
||||
|
||||
static inline PWSTR SvcInstanceUserName(VOID)
|
||||
{
|
||||
return TlsGetValue(SvcInstanceTlsKey);
|
||||
}
|
||||
|
||||
static inline VOID SvcInstanceSetUserName(PWSTR UserName)
|
||||
{
|
||||
TlsSetValue(SvcInstanceTlsKey, UserName);
|
||||
}
|
||||
|
||||
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout);
|
||||
NTSTATUS SvcInstanceStart(HANDLE ClientToken,
|
||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job,
|
||||
BOOLEAN HasSecret);
|
||||
|
||||
static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
|
||||
{
|
||||
@ -503,25 +502,28 @@ static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline ULONG SvcInstanceArgumentLength(PWSTR Arg, PWSTR Pattern)
|
||||
static inline ULONG SvcInstanceArgumentLength(PWSTR Arg, PWSTR Pattern, BOOLEAN Quote)
|
||||
{
|
||||
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
|
||||
|
||||
return 2 + (ULONG)(UINT_PTR)PathTransform(0, Arg, Pattern);
|
||||
return (Quote ? 2 : 0) + (ULONG)((UINT_PTR)PathTransform(0, Arg, Pattern) / sizeof(WCHAR));
|
||||
}
|
||||
|
||||
static inline PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg, PWSTR Pattern)
|
||||
static inline PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg, PWSTR Pattern, BOOLEAN Quote)
|
||||
{
|
||||
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
|
||||
|
||||
if (Quote)
|
||||
*Dest++ = L'"';
|
||||
Dest = PathTransform(Dest, Arg, Pattern);
|
||||
if (Quote)
|
||||
*Dest++ = L'"';
|
||||
|
||||
return Dest;
|
||||
}
|
||||
|
||||
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Argv,
|
||||
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String,
|
||||
ULONG Argc, PWSTR *Argv, PWSTR *Varv, BOOLEAN Quote,
|
||||
PWSTR *PNewString)
|
||||
{
|
||||
PWSTR NewString = 0, P, Q;
|
||||
@ -543,24 +545,24 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
||||
{
|
||||
Pattern = ++P;
|
||||
while (!(L'\0' == *P ||
|
||||
(L'0' <= *P && *P <= '9') ||
|
||||
(L'A' <= *P && *P <= 'Z')))
|
||||
(L'0' <= *P && *P <= L'9') ||
|
||||
(L'A' <= *P && *P <= L'Z')))
|
||||
P++;
|
||||
}
|
||||
if (L'0' <= *P && *P <= '9')
|
||||
if (L'0' <= *P && *P <= L'9')
|
||||
{
|
||||
if (Argc > (ULONG)(*P - L'0'))
|
||||
Length += SvcInstanceArgumentLength(Argv[*P - L'0'], Pattern);
|
||||
Length += SvcInstanceArgumentLength(Argv[*P - L'0'], Pattern, Quote);
|
||||
else
|
||||
Length += SvcInstanceArgumentLength(EmptyArg, 0);
|
||||
Length += SvcInstanceArgumentLength(EmptyArg, 0, Quote);
|
||||
}
|
||||
else
|
||||
if (L'U' == *P)
|
||||
if (L'A' <= *P && *P <= L'Z')
|
||||
{
|
||||
if (0 != SvcInstanceUserName())
|
||||
Length += SvcInstanceArgumentLength(SvcInstanceUserName(), Pattern);
|
||||
if (0 != Varv[*P - L'A'])
|
||||
Length += SvcInstanceArgumentLength(Varv[*P - L'A'], Pattern, Quote);
|
||||
else
|
||||
Length += SvcInstanceArgumentLength(EmptyArg, 0);
|
||||
Length += SvcInstanceArgumentLength(EmptyArg, 0, Quote);
|
||||
}
|
||||
else
|
||||
if (*P)
|
||||
@ -589,24 +591,24 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
||||
{
|
||||
Pattern = ++P;
|
||||
while (!(L'\0' == *P ||
|
||||
(L'0' <= *P && *P <= '9') ||
|
||||
(L'A' <= *P && *P <= 'Z')))
|
||||
(L'0' <= *P && *P <= L'9') ||
|
||||
(L'A' <= *P && *P <= L'Z')))
|
||||
P++;
|
||||
}
|
||||
if (L'0' <= *P && *P <= '9')
|
||||
if (L'0' <= *P && *P <= L'9')
|
||||
{
|
||||
if (Argc > (ULONG)(*P - L'0'))
|
||||
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0'], Pattern);
|
||||
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0'], Pattern, Quote);
|
||||
else
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0);
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0, Quote);
|
||||
}
|
||||
else
|
||||
if (L'U' == *P)
|
||||
if (L'A' <= *P && *P <= L'Z')
|
||||
{
|
||||
if (0 != SvcInstanceUserName())
|
||||
Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName(), Pattern);
|
||||
if (0 != Varv[*P - L'A'])
|
||||
Q = SvcInstanceArgumentCopy(Q, Varv[*P - L'A'], Pattern, Quote);
|
||||
else
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0);
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0, Quote);
|
||||
}
|
||||
else
|
||||
if (*P)
|
||||
@ -717,14 +719,15 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
|
||||
|
||||
static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||
PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory,
|
||||
HANDLE StdioHandles[2],
|
||||
HANDLE StdioHandles[2], HANDLE StderrHandle,
|
||||
PPROCESS_INFORMATION ProcessInfo)
|
||||
{
|
||||
WCHAR WorkDirectoryBuf[MAX_PATH];
|
||||
STARTUPINFOEXW StartupInfoEx;
|
||||
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
|
||||
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE/* NO CLOSE!*/ };
|
||||
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
|
||||
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
|
||||
BOOLEAN InitDoneAttrList = FALSE;
|
||||
SIZE_T Size;
|
||||
NTSTATUS Result;
|
||||
|
||||
@ -747,7 +750,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||
memset(&StartupInfoEx, 0, sizeof StartupInfoEx);
|
||||
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
|
||||
|
||||
if (0 != StdioHandles)
|
||||
if (0 != StdioHandles || INVALID_HANDLE_VALUE != StderrHandle)
|
||||
{
|
||||
/*
|
||||
* Create child process and redirect stdin/stdout. Do *not* inherit other handles.
|
||||
@ -756,6 +759,8 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||
* https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873/
|
||||
*/
|
||||
|
||||
if (0 != StdioHandles)
|
||||
{
|
||||
/* create stdin read/write ends; make them inheritable */
|
||||
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
|
||||
0, TRUE, FALSE, 0, 0))
|
||||
@ -763,7 +768,10 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != StdioHandles)
|
||||
{
|
||||
/* create stdout read/write ends; make them inheritable */
|
||||
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
|
||||
0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
|
||||
@ -771,8 +779,10 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ChildHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (INVALID_HANDLE_VALUE != StderrHandle)
|
||||
ChildHandles[2] = StderrHandle;
|
||||
|
||||
Size = 0;
|
||||
if (!InitializeProcThreadAttributeList(0, 1, 0, &Size) &&
|
||||
@ -794,10 +804,14 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
InitDoneAttrList = TRUE;
|
||||
|
||||
/* only the child ends of stdin/stdout are actually inherited */
|
||||
/* only the child ends of stdin/stdout/stderr are actually inherited */
|
||||
if (!UpdateProcThreadAttribute(AttrList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
||||
ChildHandles, sizeof ChildHandles, 0, 0))
|
||||
0 != StdioHandles ? ChildHandles : ChildHandles + 2,
|
||||
((0 != StdioHandles ? 2 : 0) + (INVALID_HANDLE_VALUE != StderrHandle ? 1 : 0)) *
|
||||
sizeof ChildHandles[0],
|
||||
0, 0))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
@ -862,7 +876,7 @@ exit:
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE != ParentHandles[0])
|
||||
CloseHandle(ParentHandles[0]);
|
||||
if (INVALID_HANDLE_VALUE != ParentHandles[0])
|
||||
if (INVALID_HANDLE_VALUE != ParentHandles[1])
|
||||
CloseHandle(ParentHandles[1]);
|
||||
}
|
||||
else if (0 != StdioHandles)
|
||||
@ -876,6 +890,8 @@ exit:
|
||||
if (INVALID_HANDLE_VALUE != ChildHandles[1])
|
||||
CloseHandle(ChildHandles[1]);
|
||||
|
||||
if (InitDoneAttrList)
|
||||
DeleteProcThreadAttributeList(AttrList);
|
||||
MemFree(AttrList);
|
||||
|
||||
return Result;
|
||||
@ -887,29 +903,29 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
SVC_INSTANCE **PSvcInstance)
|
||||
{
|
||||
SVC_INSTANCE *SvcInstance = 0;
|
||||
HKEY RegKey = 0;
|
||||
DWORD RegResult, RegSize;
|
||||
DWORD ClassNameSize, InstanceNameSize;
|
||||
WCHAR Executable[MAX_PATH], CommandLineBuf[512], WorkDirectory[MAX_PATH],
|
||||
SecurityBuf[512], RunAsBuf[64];
|
||||
PWSTR CommandLine, Security;
|
||||
DWORD JobControl, Credentials;
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor = 0, NewSecurityDescriptor;
|
||||
PWSTR Argv[10];
|
||||
PWSTR Varv[26];
|
||||
SYSTEMTIME SystemTime;
|
||||
PWSTR ClientUserName = 0, StderrFileName = 0;
|
||||
DWORD ClientTokenInformation = -1;
|
||||
SECURITY_ATTRIBUTES StderrSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
|
||||
FSP_LAUNCH_REG_RECORD *Record = 0;
|
||||
WCHAR CurrentTime[32], UserProfileDir[MAX_PATH], CommandLine[512], Security[512];
|
||||
DWORD Length, ClassNameSize, InstanceNameSize;
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor = 0, NewSecurityDescriptor;
|
||||
PROCESS_INFORMATION ProcessInfo;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PSvcInstance = 0;
|
||||
|
||||
lstrcpyW(CommandLineBuf, L"%0 ");
|
||||
lstrcpyW(SecurityBuf, L"O:SYG:SY");
|
||||
|
||||
if (Argc > sizeof Argv / sizeof Argv[0] - 1)
|
||||
Argc = sizeof Argv / sizeof Argv[0] - 1;
|
||||
memcpy(Argv + 1, Argv0, Argc * sizeof(PWSTR));
|
||||
Argv[0] = 0;
|
||||
Argc++;
|
||||
|
||||
memset(Varv, 0, sizeof Varv);
|
||||
|
||||
memset(&ProcessInfo, 0, sizeof ProcessInfo);
|
||||
|
||||
EnterCriticalSection(&SvcInstanceLock);
|
||||
@ -920,102 +936,63 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" FSP_LAUNCH_REGKEY,
|
||||
0, FSP_LAUNCH_REGKEY_WOW64 | KEY_READ, &RegKey);
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
GetSystemTime(&SystemTime);
|
||||
wsprintfW(CurrentTime, L"%04hu%02hu%02huT%02hu%02hu%02hu.%03huZ",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds);
|
||||
Varv[L'T' - L'A'] = CurrentTime;
|
||||
|
||||
RegSize = sizeof Credentials;
|
||||
Credentials = 0;
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"Credentials", RRF_RT_REG_DWORD, 0,
|
||||
&Credentials, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
Result = GetTokenUserName(ClientToken, &ClientUserName);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
}
|
||||
if ((!RedirectStdio && 0 != Credentials) ||
|
||||
( RedirectStdio && 0 == Credentials))
|
||||
Varv[L'U' - L'A'] = ClientUserName;
|
||||
|
||||
Length = MAX_PATH;
|
||||
if (!GetUserProfileDirectoryW(ClientToken, UserProfileDir, &Length))
|
||||
/* store an invalid filename; any attempt to use it will fail */
|
||||
lstrcpyW(UserProfileDir, L":INVALID:");
|
||||
Varv[L'P' - L'A'] = UserProfileDir;
|
||||
|
||||
Result = FspLaunchRegGetRecord(ClassName, 0, &Record);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
if ((!RedirectStdio && 0 != Record->Credentials) ||
|
||||
( RedirectStdio && 0 == Record->Credentials))
|
||||
{
|
||||
Result = STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegSize = sizeof Executable;
|
||||
Executable[0] = L'\0';
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
|
||||
Executable, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
Argv[0] = Executable;
|
||||
Argv[0] = Record->Executable;
|
||||
|
||||
CommandLine = CommandLineBuf + lstrlenW(CommandLineBuf);
|
||||
RegSize = (DWORD)(sizeof CommandLineBuf - (CommandLine - CommandLineBuf) * sizeof(WCHAR));
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"CommandLine", RRF_RT_REG_SZ, 0,
|
||||
CommandLine, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
lstrcpyW(CommandLine, L"%0 ");
|
||||
if (0 != Record->CommandLine)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
if (ERROR_FILE_NOT_FOUND == RegResult)
|
||||
CommandLine[-1] = L'\0';
|
||||
CommandLine = CommandLineBuf;
|
||||
|
||||
RegSize = sizeof WorkDirectory;
|
||||
WorkDirectory[0] = L'\0';
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"WorkDirectory", RRF_RT_REG_SZ, 0,
|
||||
WorkDirectory, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
Length = lstrlenW(CommandLine);
|
||||
lstrcpynW(CommandLine + Length, Record->CommandLine,
|
||||
sizeof CommandLine / sizeof(WCHAR) - Length);
|
||||
CommandLine[sizeof CommandLine / sizeof(WCHAR) - 1] = L'\0';
|
||||
}
|
||||
|
||||
Security = SecurityBuf + lstrlenW(SecurityBuf);
|
||||
RegSize = (DWORD)(sizeof SecurityBuf - (Security - SecurityBuf) * sizeof(WCHAR));
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"Security", RRF_RT_REG_SZ, 0,
|
||||
Security, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
lstrcpyW(Security, L"O:SYG:SY");
|
||||
if (0 != Record->Security)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
if (L'D' == Record->Security[0] && L':' == Record->Security[1])
|
||||
Length = lstrlenW(Security);
|
||||
else
|
||||
Length = 0;
|
||||
lstrcpynW(Security + Length, Record->Security,
|
||||
sizeof Security / sizeof(WCHAR) - Length);
|
||||
Security[sizeof Security / sizeof(WCHAR) - 1] = L'\0';
|
||||
}
|
||||
|
||||
RegSize = sizeof RunAsBuf;
|
||||
RunAsBuf[0] = L'\0';
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"RunAs", RRF_RT_REG_SZ, 0,
|
||||
RunAsBuf, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
else
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
Length = lstrlenW(Security);
|
||||
lstrcpyW(Security + Length, L"" FSP_LAUNCH_SERVICE_DEFAULT_SDDL);
|
||||
}
|
||||
|
||||
RegSize = sizeof JobControl;
|
||||
JobControl = 1; /* default is YES! */
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"JobControl", RRF_RT_REG_DWORD, 0,
|
||||
&JobControl, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegCloseKey(RegKey);
|
||||
RegKey = 0;
|
||||
|
||||
if (L'\0' == Security[0])
|
||||
lstrcpyW(Security, L"" FSP_LAUNCH_SERVICE_DEFAULT_SDDL);
|
||||
if (L'D' == Security[0] && L':' == Security[1])
|
||||
Security = SecurityBuf;
|
||||
|
||||
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(Security, SDDL_REVISION_1,
|
||||
&SecurityDescriptor, 0))
|
||||
{
|
||||
@ -1023,8 +1000,6 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
|
||||
|
||||
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
@ -1035,8 +1010,6 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
LocalFree(SecurityDescriptor);
|
||||
SecurityDescriptor = NewSecurityDescriptor;
|
||||
|
||||
//FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
|
||||
|
||||
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
|
||||
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
|
||||
|
||||
@ -1047,8 +1020,20 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* ClientToken: protect from CloseHandle; do not inherit */
|
||||
if (!GetHandleInformation(ClientToken, &ClientTokenInformation) ||
|
||||
!SetHandleInformation(ClientToken,
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE | HANDLE_FLAG_INHERIT,
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE | 0))
|
||||
{
|
||||
ClientTokenInformation = -1;
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(SvcInstance, 0, sizeof *SvcInstance);
|
||||
SvcInstance->RefCount = 2;
|
||||
SvcInstance->ClientToken = ClientToken;
|
||||
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
|
||||
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
||||
SvcInstance->ClassName = SvcInstance->Buffer;
|
||||
@ -1056,14 +1041,43 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
SvcInstance->SecurityDescriptor = SecurityDescriptor;
|
||||
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
|
||||
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
||||
SvcInstance->StdioHandles[2] = INVALID_HANDLE_VALUE;
|
||||
SvcInstance->Recovery = Record->Recovery;
|
||||
|
||||
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
|
||||
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, Varv, TRUE,
|
||||
&SvcInstance->CommandLine);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = SvcInstanceCreateProcess(L'\0' != RunAsBuf[0] ? RunAsBuf : 0, ClientToken,
|
||||
Executable, SvcInstance->CommandLine, L'\0' != WorkDirectory[0] ? WorkDirectory : 0,
|
||||
RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo);
|
||||
if (0 != Record->Stderr)
|
||||
{
|
||||
Result = SvcInstanceReplaceArguments(Record->Stderr, Argc, Argv, Varv, FALSE,
|
||||
&StderrFileName);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
SvcInstance->StdioHandles[2] = CreateFileW(
|
||||
StderrFileName,
|
||||
FILE_APPEND_DATA,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&StderrSecurityAttributes,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
if (INVALID_HANDLE_VALUE == SvcInstance->StdioHandles[2])
|
||||
FspServiceLog(EVENTLOG_WARNING_TYPE,
|
||||
L"Ignorning error: cannot create stderr file = %ld", GetLastError());
|
||||
}
|
||||
|
||||
Result = SvcInstanceCreateProcess(
|
||||
Record->RunAs,
|
||||
ClientToken,
|
||||
Record->Executable,
|
||||
SvcInstance->CommandLine,
|
||||
Record->WorkDirectory,
|
||||
RedirectStdio ? SvcInstance->StdioHandles : 0,
|
||||
SvcInstance->StdioHandles[2],
|
||||
&ProcessInfo);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
@ -1077,7 +1091,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (0 != Job && JobControl)
|
||||
if (0 != Job && Record->JobControl)
|
||||
{
|
||||
if (!AssignProcessToJobObject(Job, SvcInstance->Process))
|
||||
FspServiceLog(EVENTLOG_WARNING_TYPE,
|
||||
@ -1107,12 +1121,19 @@ exit:
|
||||
if (0 != ProcessInfo.hThread)
|
||||
CloseHandle(ProcessInfo.hThread);
|
||||
|
||||
if (-1 != ClientTokenInformation)
|
||||
SetHandleInformation(ClientToken,
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE | HANDLE_FLAG_INHERIT,
|
||||
ClientTokenInformation);
|
||||
|
||||
if (0 != SvcInstance)
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
|
||||
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
||||
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[2])
|
||||
CloseHandle(SvcInstance->StdioHandles[2]);
|
||||
|
||||
if (0 != SvcInstance->ProcessWait)
|
||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||
@ -1128,8 +1149,11 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != RegKey)
|
||||
RegCloseKey(RegKey);
|
||||
if (0 != Record)
|
||||
FspLaunchRegFreeRecord(Record);
|
||||
|
||||
MemFree(StderrFileName);
|
||||
MemFree(ClientUserName);
|
||||
|
||||
LeaveCriticalSection(&SvcInstanceLock);
|
||||
|
||||
@ -1149,10 +1173,25 @@ static VOID SvcInstanceRelease(SVC_INSTANCE *SvcInstance)
|
||||
SetEvent(SvcInstanceEvent);
|
||||
LeaveCriticalSection(&SvcInstanceLock);
|
||||
|
||||
SetHandleInformation(SvcInstance->ClientToken,
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE,
|
||||
0);
|
||||
|
||||
if (1 == SvcInstance->Recovery && SvcInstance->Started && !SvcInstance->Stopped)
|
||||
SvcInstanceStart(SvcInstance->ClientToken,
|
||||
SvcInstance->ClassName, SvcInstance->InstanceName,
|
||||
SvcInstance->Argc, SvcInstance->Argv,
|
||||
SvcJob,
|
||||
SvcInstance->HasSecret);
|
||||
|
||||
MemFree(SvcInstance->Argv);
|
||||
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
|
||||
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
||||
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[2])
|
||||
CloseHandle(SvcInstance->StdioHandles[2]);
|
||||
|
||||
if (0 != SvcInstance->ProcessWait)
|
||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||
@ -1162,6 +1201,18 @@ static VOID SvcInstanceRelease(SVC_INSTANCE *SvcInstance)
|
||||
LocalFree(SvcInstance->SecurityDescriptor);
|
||||
|
||||
MemFree(SvcInstance->CommandLine);
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* New instances store the ClientToken and protect it from CloseHandle.
|
||||
* This results in an unhandled exception when running under a debugger.
|
||||
* Such exceptions can be ignored.
|
||||
*
|
||||
* See MSDN CloseHandle for details:
|
||||
* https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
|
||||
*/
|
||||
CloseHandle(SvcInstance->ClientToken);
|
||||
|
||||
MemFree(SvcInstance);
|
||||
}
|
||||
|
||||
@ -1175,7 +1226,7 @@ static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout)
|
||||
SvcInstanceRelease(SvcInstance);
|
||||
}
|
||||
|
||||
NTSTATUS SvcInstanceStart(HANDLE ClientToken,
|
||||
static NTSTATUS SvcInstanceStartWithArgvCopy(HANDLE ClientToken,
|
||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job,
|
||||
BOOLEAN HasSecret)
|
||||
{
|
||||
@ -1264,6 +1315,19 @@ exit:
|
||||
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[2])
|
||||
{
|
||||
CloseHandle(SvcInstance->StdioHandles[2]);
|
||||
SvcInstance->StdioHandles[2] = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
SvcInstance->Argc = Argc;
|
||||
SvcInstance->Argv = Argv;
|
||||
SvcInstance->HasSecret = HasSecret;
|
||||
SvcInstance->Started = TRUE;
|
||||
}
|
||||
|
||||
SvcInstanceRelease(SvcInstance);
|
||||
|
||||
@ -1274,6 +1338,41 @@ exit:
|
||||
return Result;
|
||||
}
|
||||
|
||||
NTSTATUS SvcInstanceStart(HANDLE ClientToken,
|
||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job,
|
||||
BOOLEAN HasSecret)
|
||||
{
|
||||
DWORD ArgvSize;
|
||||
PWSTR *ArgvCopy;
|
||||
NTSTATUS Result;
|
||||
|
||||
ArgvSize = 0;
|
||||
for (ULONG I = 0; Argc > I; I++)
|
||||
ArgvSize += (lstrlenW(Argv[I]) + 1) * sizeof(WCHAR);
|
||||
|
||||
ArgvCopy = MemAlloc(Argc * sizeof(PWSTR) + ArgvSize);
|
||||
if (0 == ArgvCopy)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
ArgvSize = 0;
|
||||
for (ULONG I = 0; Argc > I; I++)
|
||||
{
|
||||
ULONG L = (lstrlenW(Argv[I]) + 1) * sizeof(WCHAR);
|
||||
ArgvCopy[I] = (PWSTR)((PUINT8)ArgvCopy + Argc * sizeof(PWSTR) + ArgvSize);
|
||||
memcpy(ArgvCopy[I], Argv[I], L);
|
||||
ArgvSize += L;
|
||||
}
|
||||
|
||||
Result = SvcInstanceStartWithArgvCopy(ClientToken,
|
||||
ClassName, InstanceName, Argc, ArgvCopy, Job,
|
||||
HasSecret);
|
||||
|
||||
if (!NT_SUCCESS(Result))
|
||||
MemFree(ArgvCopy);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
NTSTATUS SvcInstanceStop(HANDLE ClientToken,
|
||||
PWSTR ClassName, PWSTR InstanceName)
|
||||
{
|
||||
@ -1293,6 +1392,7 @@ NTSTATUS SvcInstanceStop(HANDLE ClientToken,
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
SvcInstance->Stopped = TRUE;
|
||||
KillProcess(SvcInstance->ProcessId, SvcInstance->Process, LAUNCHER_KILL_TIMEOUT);
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
@ -1394,6 +1494,7 @@ NTSTATUS SvcInstanceStopAndWaitAll(VOID)
|
||||
{
|
||||
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
|
||||
|
||||
SvcInstance->Stopped = TRUE;
|
||||
KillProcess(SvcInstance->ProcessId, SvcInstance->Process, LAUNCHER_KILL_TIMEOUT);
|
||||
}
|
||||
|
||||
@ -1451,7 +1552,7 @@ NTSTATUS SvcDefineDosDevice(HANDLE ClientToken,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static HANDLE SvcJob, SvcThread, SvcEvent;
|
||||
static HANDLE SvcThread, SvcEvent;
|
||||
static DWORD SvcThreadId;
|
||||
static HANDLE SvcPipe = INVALID_HANDLE_VALUE;
|
||||
static OVERLAPPED SvcOverlapped;
|
||||
@ -1484,10 +1585,6 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
if (0 == SvcInstanceEvent)
|
||||
goto fail;
|
||||
|
||||
SvcInstanceTlsKey = TlsAlloc();
|
||||
if (TLS_OUT_OF_INDEXES == SvcInstanceTlsKey)
|
||||
goto fail;
|
||||
|
||||
SvcJob = CreateJobObjectW(0, 0);
|
||||
if (0 != SvcJob)
|
||||
{
|
||||
@ -1550,9 +1647,6 @@ fail:
|
||||
if (0 != SvcJob)
|
||||
CloseHandle(SvcJob);
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
|
||||
TlsFree(SvcInstanceTlsKey);
|
||||
|
||||
if (0 != SvcInstanceEvent)
|
||||
CloseHandle(SvcInstanceEvent);
|
||||
|
||||
@ -1596,9 +1690,6 @@ static NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||
if (0 != SvcJob)
|
||||
CloseHandle(SvcJob);
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
|
||||
TlsFree(SvcInstanceTlsKey);
|
||||
|
||||
if (0 != SvcInstanceEvent)
|
||||
CloseHandle(SvcInstanceEvent);
|
||||
|
||||
@ -1708,6 +1799,15 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
|
||||
|
||||
SvcPipeTransact(ClientToken, PipeBuf, &BytesTransferred);
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* New instances store the ClientToken and protect it from CloseHandle.
|
||||
* This results in an unhandled exception when running under a debugger.
|
||||
* Such exceptions can be ignored.
|
||||
*
|
||||
* See MSDN CloseHandle for details:
|
||||
* https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
|
||||
*/
|
||||
CloseHandle(ClientToken);
|
||||
|
||||
LastError = SvcPipeWaitResult(
|
||||
@ -1773,7 +1873,7 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
return;
|
||||
|
||||
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
|
||||
PWSTR ClassName, InstanceName, UserName;
|
||||
PWSTR ClassName, InstanceName;
|
||||
PWSTR DeviceName, TargetPath;
|
||||
ULONG Argc; PWSTR Argv[9];
|
||||
BOOLEAN HasSecret = FALSE;
|
||||
@ -1781,9 +1881,6 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
|
||||
*PSize = 0;
|
||||
|
||||
GetTokenUserName(ClientToken, &UserName);
|
||||
SvcInstanceSetUserName(UserName);
|
||||
|
||||
switch (*P++)
|
||||
{
|
||||
case FspLaunchCmdStartWithSecret:
|
||||
@ -1858,9 +1955,6 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
|
||||
break;
|
||||
}
|
||||
|
||||
SvcInstanceSetUserName(0);
|
||||
MemFree(UserName);
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
|
@ -62,7 +62,7 @@
|
||||
*/
|
||||
|
||||
#include <winfsp/launch.h>
|
||||
#include <shared/minimal.h>
|
||||
#include <shared/um/minimal.h>
|
||||
|
||||
static PWSTR PathCopy(PWSTR Dest, PWSTR Arg, PWSTR ArgEnd, BOOLEAN WriteDest, WCHAR Replacement)
|
||||
{
|
||||
|
33
src/shared/ku/config.h
Normal file
33
src/shared/ku/config.h
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file shared/ku/config.h
|
||||
*
|
||||
* Shared kernel/user configuration. This file is to be included by the
|
||||
* FSD and DLL components ONLY!
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
|
||||
#ifndef WINFSP_SHARED_KU_CONFIG_H_INCLUDED
|
||||
#define WINFSP_SHARED_KU_CONFIG_H_INCLUDED
|
||||
|
||||
/*
|
||||
* Define the FSP_CFG_REJECT_EARLY_IRP macro to support the RejectIrpPriorToTransact0 flag.
|
||||
*/
|
||||
#define FSP_CFG_REJECT_EARLY_IRP
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file ku/library.h
|
||||
* @file shared/ku/library.h
|
||||
*
|
||||
* @copyright 2015-2020 Bill Zissimopoulos
|
||||
*/
|
||||
@ -19,8 +19,8 @@
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#ifndef WINFSP_KU_LIBRARY_H_INCLUDED
|
||||
#define WINFSP_KU_LIBRARY_H_INCLUDED
|
||||
#ifndef WINFSP_SHARED_KU_LIBRARY_H_INCLUDED
|
||||
#define WINFSP_SHARED_KU_LIBRARY_H_INCLUDED
|
||||
|
||||
#if !defined(_KERNEL_MODE)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file ku/posix.c
|
||||
* @file shared/ku/posix.c
|
||||
* POSIX Interop.
|
||||
*
|
||||
* This file provides routines for Windows/POSIX interoperability. It is based
|
||||
@ -32,7 +32,7 @@
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#include <ku/library.h>
|
||||
#include <shared/ku/library.h>
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid);
|
||||
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid);
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file dll/uuid5.c
|
||||
* @file shared/ku/uuid5.c
|
||||
*
|
||||
* @copyright 2015-2020 Bill Zissimopoulos
|
||||
*/
|
||||
@ -19,7 +19,7 @@
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#include <ku/library.h>
|
||||
#include <shared/ku/library.h>
|
||||
#include <bcrypt.h>
|
||||
|
||||
/*
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file shared/minimal.h
|
||||
* @file shared/um/minimal.h
|
||||
*
|
||||
* @copyright 2015-2020 Bill Zissimopoulos
|
||||
*/
|
||||
@ -19,8 +19,8 @@
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#ifndef WINFSP_SHARED_MINIMAL_H_INCLUDED
|
||||
#define WINFSP_SHARED_MINIMAL_H_INCLUDED
|
||||
#ifndef WINFSP_SHARED_UM_MINIMAL_H_INCLUDED
|
||||
#define WINFSP_SHARED_UM_MINIMAL_H_INCLUDED
|
||||
|
||||
/*
|
||||
* Eliminate dependency on the MSVCRT libraries.
|
@ -78,6 +78,7 @@ VOID FspAcquireFileForNtCreateSection(
|
||||
{
|
||||
/* Callers:
|
||||
* CcWriteBehind
|
||||
* MmCreateSection and friends
|
||||
*/
|
||||
|
||||
FSP_ENTER_VOID(PAGED_CODE());
|
||||
@ -85,6 +86,8 @@ VOID FspAcquireFileForNtCreateSection(
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
|
||||
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||
ASSERT(FALSE == FileNode->Tls.CreateSection);
|
||||
FileNode->Tls.CreateSection = TRUE;
|
||||
|
||||
FSP_LEAVE_VOID("FileObject=%p", FileObject);
|
||||
}
|
||||
@ -94,12 +97,14 @@ VOID FspReleaseFileForNtCreateSection(
|
||||
{
|
||||
/* Callers:
|
||||
* CcWriteBehind
|
||||
* MmCreateSection and friends
|
||||
*/
|
||||
|
||||
FSP_ENTER_VOID(PAGED_CODE());
|
||||
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
|
||||
FileNode->Tls.CreateSection = FALSE;
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
|
||||
FSP_LEAVE_VOID("FileObject=%p", FileObject);
|
||||
|
@ -284,6 +284,11 @@ static NTSTATUS FspFsvolCreateNoLock(
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(FSP_CFG_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;
|
||||
|
272
src/sys/driver.c
272
src/sys/driver.c
@ -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;
|
||||
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include <winfsp/fsctl.h>
|
||||
#include <winfsp/fsext.h>
|
||||
|
||||
#include <shared/ku/config.h>
|
||||
|
||||
/* disable warnings */
|
||||
#pragma warning(disable:4100) /* unreferenced formal parameter */
|
||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
||||
@ -501,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);
|
||||
@ -649,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);
|
||||
@ -1066,6 +1086,7 @@ typedef struct
|
||||
KSPIN_LOCK SpinLock;
|
||||
LONG RefCount;
|
||||
UINT32 Kind;
|
||||
GUID SiloContainerId;
|
||||
} FSP_DEVICE_EXTENSION;
|
||||
typedef struct
|
||||
{
|
||||
@ -1082,6 +1103,9 @@ typedef struct
|
||||
FSP_FSEXT_PROVIDER *Provider;
|
||||
UNICODE_STRING VolumePrefix;
|
||||
UNICODE_PREFIX_TABLE_ENTRY VolumePrefixEntry;
|
||||
#if defined(FSP_CFG_REJECT_EARLY_IRP)
|
||||
LONG ReadyToAcceptIrp;
|
||||
#endif
|
||||
FSP_IOQ *Ioq;
|
||||
FSP_META_CACHE *SecurityCache;
|
||||
FSP_META_CACHE *DirInfoCache;
|
||||
@ -1181,6 +1205,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_CFG_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)
|
||||
{
|
||||
@ -1369,6 +1411,7 @@ typedef struct FSP_FILE_NODE
|
||||
PIRP TopLevelIrp;
|
||||
UINT32 TopFlags;
|
||||
} CcFlush;
|
||||
BOOLEAN CreateSection;
|
||||
} Tls;
|
||||
/* read-only after creation (and insertion in the ContextTable) */
|
||||
PDEVICE_OBJECT FsvolDeviceObject;
|
||||
@ -1670,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[];
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -234,6 +234,7 @@ static NTSTATUS FspFsvolReadNonCached(
|
||||
ULONG ReadLength = IrpSp->Parameters.Read.Length;
|
||||
ULONG ReadKey = IrpSp->Parameters.Read.Key;
|
||||
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
BOOLEAN Success;
|
||||
|
||||
@ -248,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);
|
||||
|
||||
@ -278,26 +279,36 @@ static NTSTATUS FspFsvolReadNonCached(
|
||||
|
||||
/* if this is a non-cached transfer on a cached file then flush the file */
|
||||
if (!PagingIo && 0 != FileObject->SectionObjectPointer->DataSectionObject)
|
||||
{
|
||||
if (!CanWait)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
if (!CanWait)
|
||||
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);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
|
||||
FspFileNodeAcquireShared(FileNode, Full);
|
||||
}
|
||||
|
||||
/* convert FileNode to shared */
|
||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||
/* trim ReadLength during CreateProcess; resolve bugcheck for filesystem that reports incorrect size */
|
||||
if (FileNode->Tls.CreateSection)
|
||||
{
|
||||
FspFileNodeGetFileInfo(FileNode, &FileInfo);
|
||||
if ((UINT64)ReadOffset.QuadPart >= FileInfo.FileSize)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return STATUS_END_OF_FILE;
|
||||
}
|
||||
if ((UINT64)ReadLength > FileInfo.FileSize - ReadOffset.QuadPart)
|
||||
ReadLength = (ULONG)(FileInfo.FileSize - ReadOffset.QuadPart);
|
||||
}
|
||||
|
||||
Request = FspIrpRequest(Irp);
|
||||
if (0 == Request)
|
||||
|
325
src/sys/silo.c
Normal file
325
src/sys/silo.c
Normal 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);
|
||||
}
|
@ -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();
|
||||
|
@ -286,6 +286,11 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
#if defined(FSP_CFG_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_CFG_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;
|
||||
|
@ -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();
|
||||
|
||||
@ -277,6 +289,10 @@ static NTSTATUS FspVolumeCreateNoLock(
|
||||
RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName,
|
||||
FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf);
|
||||
RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName);
|
||||
#if defined(FSP_CFG_REJECT_EARLY_IRP)
|
||||
if (!FsvolDeviceExtension->VolumeParams.RejectIrpPriorToTransact0)
|
||||
FsvolDeviceExtension->ReadyToAcceptIrp = 1;
|
||||
#endif
|
||||
Result = FspDeviceInitialize(FsvolDeviceObject);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
@ -298,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;
|
||||
}
|
||||
@ -327,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;
|
||||
@ -346,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.
|
||||
*/
|
||||
@ -366,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();
|
||||
|
||||
@ -441,7 +465,7 @@ static VOID FspVolumeDeleteNoLock(
|
||||
else
|
||||
{
|
||||
IoDeleteSymbolicLink(&FsvolDeviceExtension->VolumeName);
|
||||
FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject);
|
||||
FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject);
|
||||
}
|
||||
|
||||
/* release the volume device object */
|
||||
@ -767,6 +791,11 @@ NTSTATUS FspVolumeTransact(
|
||||
if (!FspDeviceReference(FsvolDeviceObject))
|
||||
return STATUS_CANCELLED;
|
||||
|
||||
#if defined(FSP_CFG_REJECT_EARLY_IRP)
|
||||
if (0 == InputBufferLength && 0 == OutputBufferLength)
|
||||
FspFsvolDeviceSetReadyToAcceptIrp(FsvolDeviceObject);
|
||||
#endif
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PUINT8 BufferEnd;
|
||||
@ -936,6 +965,7 @@ NTSTATUS FspVolumeTransact(
|
||||
if (0 != InternalBuffer)
|
||||
{
|
||||
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode);
|
||||
*(PVOID *)OutputBuffer = 0;
|
||||
FspFree(InternalBuffer);
|
||||
}
|
||||
FspIopCompleteCanceledIrp(PendingIrp);
|
||||
|
126
tools/build-choco.bat
Executable file
126
tools/build-choco.bat
Executable file
@ -0,0 +1,126 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
set MsiName="WinFsp - Windows File System Proxy"
|
||||
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
|
||||
set Issuer="DigiCert"
|
||||
set Subject="Navimatics LLC"
|
||||
|
||||
set Configuration=Release
|
||||
set SignedPackage=
|
||||
|
||||
if not X%1==X set Configuration=%1
|
||||
if not X%2==X set SignedPackage=%2
|
||||
|
||||
if X%~nx0==Xbuild-choco.bat (
|
||||
cd %~dp0..\build\VStudio
|
||||
goto :choco
|
||||
)
|
||||
|
||||
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)
|
||||
if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
|
||||
del "%~dp0..\build\VStudio\build\%Configuration%\winfsp-*.msi"
|
||||
if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg"
|
||||
for /R "%SignedPackage%" %%f in (*.sys) do (
|
||||
copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
|
||||
)
|
||||
)
|
||||
|
||||
cd %~dp0..\build\VStudio
|
||||
set signfail=0
|
||||
|
||||
if X%SignedPackage%==X (
|
||||
if exist build\ for /R build\ %%d in (%Configuration%) do (
|
||||
if exist "%%d" rmdir /s/q "%%d"
|
||||
)
|
||||
|
||||
devenv winfsp.sln /build "%Configuration%|x64"
|
||||
if errorlevel 1 goto fail
|
||||
devenv winfsp.sln /build "%Configuration%|x86"
|
||||
if errorlevel 1 goto fail
|
||||
|
||||
for %%f in (build\%Configuration%\winfsp-x64.sys build\%Configuration%\winfsp-x86.sys) do (
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
|
||||
pushd build\%Configuration%
|
||||
echo .OPTION EXPLICIT >driver.ddf
|
||||
echo .Set CabinetFileCountThreshold=0 >>driver.ddf
|
||||
echo .Set FolderFileCountThreshold=0 >>driver.ddf
|
||||
echo .Set FolderSizeThreshold=0 >>driver.ddf
|
||||
echo .Set MaxCabinetSize=0 >>driver.ddf
|
||||
echo .Set MaxDiskFileCount=0 >>driver.ddf
|
||||
echo .Set MaxDiskSize=0 >>driver.ddf
|
||||
echo .Set CompressionType=MSZIP >>driver.ddf
|
||||
echo .Set Cabinet=on >>driver.ddf
|
||||
echo .Set Compress=on >>driver.ddf
|
||||
echo .Set CabinetNameTemplate=driver.cab >>driver.ddf
|
||||
echo .Set DiskDirectory1=. >>driver.ddf
|
||||
echo .Set DestinationDir=x64 >>driver.ddf
|
||||
echo driver-x64.inf >>driver.ddf
|
||||
echo winfsp-x64.sys >>driver.ddf
|
||||
echo .Set DestinationDir=x86 >>driver.ddf
|
||||
echo driver-x86.inf >>driver.ddf
|
||||
echo winfsp-x86.sys >>driver.ddf
|
||||
makecab /F driver.ddf
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /t http://timestamp.digicert.com driver.cab
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
popd
|
||||
)
|
||||
|
||||
devenv winfsp.sln /build "Installer.%Configuration%|x86"
|
||||
if errorlevel 1 goto fail
|
||||
|
||||
for %%f in (build\%Configuration%\winfsp-*.msi) do (
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com /d %MsiName% %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
REM signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
|
||||
REM if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
|
||||
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
|
||||
|
||||
set Version=
|
||||
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
|
||||
set Version=!Version:winfsp-=!
|
||||
if X%SignedPackage%==X (
|
||||
pushd build\%Configuration%
|
||||
powershell -command "Compress-Archive -Path winfsp-tests-*.exe,..\..\..\..\License.txt,..\..\..\..\tst\winfsp-tests\README.md -DestinationPath winfsp-tests-!Version!.zip"
|
||||
if errorlevel 1 goto fail
|
||||
popd
|
||||
)
|
||||
|
||||
:choco
|
||||
if not exist "build\%Configuration%\winfsp-*.msi" (echo installer msi not found >&2 & exit /b 1)
|
||||
set Version=
|
||||
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
|
||||
set Version=!Version:winfsp-=!
|
||||
set ProductStage=
|
||||
for /f "delims=<> tokens=3" %%i in ('findstr "<MyProductStage>" version.properties') do (
|
||||
set MyProductStage=%%i
|
||||
)
|
||||
set PackageVersion=!Version!
|
||||
if not X!MyProductStage!==XGold (
|
||||
set PackageVersion=!Version!-pre
|
||||
)
|
||||
where /q choco.exe
|
||||
if %ERRORLEVEL% equ 0 (
|
||||
copy ..\choco\* build\%Configuration%
|
||||
copy ..\choco\LICENSE.TXT /B + ..\..\License.txt /B build\%Configuration%\LICENSE.txt /B
|
||||
certutil -hashfile build\%Configuration%\winfsp-!Version!.msi SHA256 >>build\%Configuration%\VERIFICATION.txt
|
||||
choco pack build\%Configuration%\winfsp.nuspec --version=!PackageVersion! --outputdirectory=build\%Configuration% MsiVersion=!Version!
|
||||
if errorlevel 1 goto fail
|
||||
)
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
@ -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"
|
||||
|
@ -14,7 +14,12 @@ set SignedPackage=
|
||||
if not X%1==X set Configuration=%1
|
||||
if not X%2==X set SignedPackage=%2
|
||||
|
||||
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
|
||||
if X%~nx0==Xbuild-choco.bat (
|
||||
cd %~dp0..\build\VStudio
|
||||
goto :choco
|
||||
)
|
||||
|
||||
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)
|
||||
@ -83,9 +88,9 @@ for %%f in (build\%Configuration%\winfsp-*.msi) do (
|
||||
|
||||
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
|
||||
|
||||
set Version=
|
||||
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
|
||||
set Version=!Version:winfsp-=!
|
||||
|
||||
if X%SignedPackage%==X (
|
||||
pushd build\%Configuration%
|
||||
powershell -command "Compress-Archive -Path winfsp-tests-*.exe,..\..\..\..\License.txt,..\..\..\..\tst\winfsp-tests\README.md -DestinationPath winfsp-tests-!Version!.zip"
|
||||
@ -93,12 +98,25 @@ if X%SignedPackage%==X (
|
||||
popd
|
||||
)
|
||||
|
||||
:choco
|
||||
if not exist "build\%Configuration%\winfsp-*.msi" (echo installer msi not found >&2 & exit /b 1)
|
||||
set Version=
|
||||
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
|
||||
set Version=!Version:winfsp-=!
|
||||
set ProductStage=
|
||||
for /f "delims=<> tokens=3" %%i in ('findstr "<MyProductStage>" version.properties') do (
|
||||
set MyProductStage=%%i
|
||||
)
|
||||
set PackageVersion=!Version!
|
||||
if not X!MyProductStage!==XGold (
|
||||
set PackageVersion=!Version!-pre
|
||||
)
|
||||
where /q choco.exe
|
||||
if %ERRORLEVEL% equ 0 (
|
||||
copy ..\choco\* build\%Configuration%
|
||||
copy ..\choco\LICENSE.TXT /B + ..\..\License.txt /B build\%Configuration%\LICENSE.txt /B
|
||||
certutil -hashfile build\%Configuration%\winfsp-!Version!.msi SHA256 >>build\%Configuration%\VERIFICATION.txt
|
||||
choco pack build\%Configuration%\winfsp.nuspec --version=!Version! --outputdirectory=build\%Configuration%
|
||||
choco pack build\%Configuration%\winfsp.nuspec --version=!PackageVersion! --outputdirectory=build\%Configuration% MsiVersion=!Version!
|
||||
if errorlevel 1 goto fail
|
||||
)
|
||||
|
||||
|
@ -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%
|
||||
|
@ -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
35
tools/deploy.ps1
Normal 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
|
@ -5,13 +5,18 @@ cd $(dirname "$0")/../..
|
||||
PRETTYDOC="$PWD/../prettydoc/prettydoc"
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "usage: $(basename $0) {asciidoc|html}" 1>&2
|
||||
echo "usage: $(basename $0) {asciidoc|html|markdown}" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$PRETTYDOC" -f $1 -t -H=--outer-names-only -o doc inc/winfsp/winfsp.h inc/winfsp/launch.h
|
||||
"$PRETTYDOC" -f $1 -t --no-timestamp -H=--outer-names-only -o doc inc/winfsp/winfsp.h inc/winfsp/launch.h
|
||||
|
||||
if [[ "$1" == "asciidoc" ]]; then
|
||||
mv doc/winfsp.h.asciidoc doc/WinFsp-API-winfsp.h.asciidoc
|
||||
mv doc/launch.h.asciidoc doc/WinFsp-API-launch.h.asciidoc
|
||||
fi
|
||||
|
||||
if [[ "$1" == "markdown" ]]; then
|
||||
mv doc/winfsp.h.markdown doc/WinFsp-API-winfsp.h.md
|
||||
mv doc/launch.h.markdown doc/WinFsp-API-launch.h.md
|
||||
fi
|
||||
|
@ -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!
|
||||
|
@ -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
|
||||
|
@ -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
345
tools/parselog.nim
Normal 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
10
tools/vcvarsall.bat
Executable 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% %*
|
@ -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"
|
||||
|
@ -285,6 +285,7 @@ namespace memfs
|
||||
Host.PassQueryDirectoryFileName = true;
|
||||
Host.ExtendedAttributes = true;
|
||||
Host.WslFeatures = true;
|
||||
Host.RejectIrpPriorToTransact0 = true;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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,6 +80,14 @@ 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),
|
||||
|
@ -145,7 +145,7 @@ static void dirbuf_dots_test(void)
|
||||
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
|
||||
}
|
||||
|
||||
static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
|
||||
static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
|
||||
{
|
||||
PVOID DirBuffer = 0;
|
||||
NTSTATUS Result;
|
||||
@ -202,6 +202,51 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
}
|
||||
|
||||
#if 1
|
||||
{
|
||||
ASSERT(Count > InvalidCount);
|
||||
|
||||
#if !defined(FspFileSystemDirectoryBufferEntryInvalid)
|
||||
const ULONG FspFileSystemDirectoryBufferEntryInvalid = ((ULONG)-1);
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
SRWLOCK Lock;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *PeekDirBuffer = DirBuffer;
|
||||
PUINT8 PeekBuffer = PeekDirBuffer->Buffer;
|
||||
PULONG PeekIndex = (PULONG)(PeekDirBuffer->Buffer + PeekDirBuffer->HiMark);
|
||||
ULONG PeekCount = (PeekDirBuffer->Capacity - PeekDirBuffer->HiMark) / sizeof(ULONG);
|
||||
|
||||
ASSERT(Count == PeekCount);
|
||||
|
||||
for (ULONG I = 0; InvalidCount > I; I++)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
N = rand() % PeekCount;
|
||||
if (FspFileSystemDirectoryBufferEntryInvalid == PeekIndex[N])
|
||||
continue;
|
||||
|
||||
DirInfo = (PVOID)(PeekBuffer + PeekIndex[N]);
|
||||
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
|
||||
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
/* do not invalidate dot entries as they are used in testing below */
|
||||
if (0 == wcscmp(CurrFileName, L".") || 0 == wcscmp(CurrFileName, L".."))
|
||||
continue;
|
||||
|
||||
PeekIndex[N] = FspFileSystemDirectoryBufferEntryInvalid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Count -= InvalidCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
|
||||
|
||||
MarkerIndex = rand() % Count;
|
||||
@ -303,19 +348,32 @@ static void dirbuf_fill_test(void)
|
||||
{
|
||||
unsigned seed = (unsigned)time(0);
|
||||
|
||||
dirbuf_fill_dotest(1485473509, 10);
|
||||
dirbuf_fill_dotest(1485473509, 10, 0);
|
||||
dirbuf_fill_dotest(1485473509, 10, 3);
|
||||
|
||||
for (ULONG I = 0; 10000 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 10);
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 10, 0);
|
||||
dirbuf_fill_dotest(seed + I, 10, 3);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 1000 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 100);
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 100, 0);
|
||||
dirbuf_fill_dotest(seed + I, 100, 30);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 100 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 1000);
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 1000, 0);
|
||||
dirbuf_fill_dotest(seed + I, 1000, 300);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 10 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 10000);
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 10000, 0);
|
||||
dirbuf_fill_dotest(seed + I, 10000, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
void dirbuf_tests(void)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "winfsp-tests.h"
|
||||
|
||||
#pragma comment(lib, "bcrypt.lib")
|
||||
#include <ku/uuid5.c>
|
||||
#include <shared/ku/uuid5.c>
|
||||
|
||||
static void uuid5_test(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user