Compare commits

..

39 Commits

Author SHA1 Message Date
af52ac3df0 build: version.properties: update for version 2020.1 Gold 2020-05-21 15:05:22 -07:00
33cab186ca build: silence deprecation warnings for FSD 2020-05-19 00:22:45 -07:00
fd4c5326ed update changelog 2020-04-25 12:43:29 -07:00
7c06ead34c launcher: ignore bad Stderr setting 2020-04-25 12:32:20 -07:00
768b596a76 launcher: add %P variable (user profile directory) 2020-04-25 11:36:30 -07:00
26630ad7aa build: use PDBALTPATH 2020-04-25 01:16:22 -07:00
01744e8193 launcher: Stderr registry setting
This commit adds a new Stderr registry setting that can be used to redirect
the standard error output of a launched service instance.
2020-04-25 00:48:40 -07:00
3eb115eb22 launcher: SvcInstanceCreate: refactor to use FspLaunchRegGetRecord 2020-04-24 17:49:29 -07:00
a0801674c4 launcher: SvcInstanceCreateProcess: fix checking wrong handle 2020-04-24 16:04:07 -07:00
98f809345d doc: update known file system document 2020-04-21 13:38:53 -07:00
0268e51099 dll: launch: registry: support Recovery setting 2020-04-16 16:08:55 -07:00
924d1f9a3e update changelog 2020-04-15 23:28:42 +01:00
dc3f73bd2f Merge branch 'pvt-launcher' 2020-04-15 15:10:09 -07:00
e71aea8ad7 dll: fuse: ReadDirectory: log invalid directory entries 2020-04-15 15:07:01 -07:00
9066338220 dll: fuse: ReadDirectory: log invalid directory entries 2020-04-14 22:54:46 -07:00
ca12b5a19d launcher: error recovery
Service instances can now be restarted when the registry setting `Recovery=1` is set.
2020-04-14 17:12:05 -07:00
94d8c0452f launcher: eliminate TLS for ClientUserName 2020-04-13 22:31:45 -07:00
b4c39f656c dll,fuse: allow dir buffer entry invalidation
The FUSE implementation of ReadDirectory issues readdir followed
by a slew of getattr. In the current implementation if a getattr fails
the whole readdir operation fails.

This commit adds the ability to invalidate individual entries in the
directory buffer. Entries for which getattr fails are now marked invalid
rather than fail the overall ReadDirectory operation.

See #292
2020-04-13 15:52:03 -07:00
42fd57904a sys: FspFsvolReadNonCached: trim ReadLength
During CreateProcess/CreateSection Windows locks the image file (using AcquireFileForNtCreateSection),
gets the image file size and then reads the image file. Unfortunately if the file system (erroneously) reads
past the file size, Windows can bugcheck. This allows a faulty or malicious file system to crash Windows.

This commit adds a check in WinFsp to mitigate this problem.
2020-04-10 19:24:43 -07:00
9d69ae7503 doc: use markdown for API reference 2020-03-23 15:03:22 -07:00
f93cdbfa91 doc: update api reference 2020-03-21 17:35:04 -07:00
b7553925fb appveyor: build cygfuse 2020-03-21 16:20:51 -07:00
4b5b562307 inc: winfsp_fuse.h: fix memset comment 2020-03-21 15:44:02 -07:00
ad68b36de7 README: internal link to cap.gif 2020-03-10 20:19:05 +02:00
0e8babf69c appveyor: update location of IfsTest zip file 2020-03-10 20:00:14 +02:00
0e12212838 doc: Home 2020-03-10 19:34:32 +02:00
19b86972d8 doc: WinFsp-Debugging-Setup.asciidoc 2020-03-07 18:44:52 +02:00
403e234895 Merge pull request #288 from benrubson/cygwarn
Mute a GCC warning
2020-03-01 20:43:41 +02:00
76ec0420d1 Mute a GCC warning
solves #287
2020-02-29 23:58:51 +01:00
2a6beb2739 workflows: add AntiVirus monitor 2020-02-22 15:08:53 +02:00
1933443e8d appveyor: allow chocolatey prerelease installs 2020-02-17 08:53:38 +02:00
279b00e195 tools: build.bat: add choco prerelease support 2020-02-16 22:36:10 +02:00
9b6542ab80 update Changelog 2020-02-08 01:14:38 +00:00
dfbab387ab build: version.properties: bump version to 2020.1 B2 2020-02-07 17:09:25 -08:00
10f4df519c dotnet: RejectIrpPriorToTransact0 2020-02-07 17:07:50 -08:00
24b5d48fed add shared/ku/config.h and related changes 2020-02-07 15:40:08 -08:00
0650cabc47 refactor: shared->shared/um, ku->shared/ku 2020-02-07 15:28:25 -08:00
71995a1fcd dll,sys: FSP_CFG_REJECT_EARLY_IRP
Includes Avast fix for FUSE.
2020-02-07 15:11:24 -08:00
91c36b8f09 dll: FspFileSystemResolveReparsePointsInternal: fix warning 2020-02-07 14:54:09 -08:00
57 changed files with 3774 additions and 2384 deletions

15
.github/workflows/avm.yml vendored Normal file
View 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

View File

@ -1,5 +1,19 @@
= Changelog
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:

View File

@ -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:

View File

@ -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%

View File

@ -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'">
@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -18,8 +18,8 @@
<MyCanonicalVersion>1.7</MyCanonicalVersion>
<MyProductVersion>2020.1 B1</MyProductVersion>
<MyProductStage>Beta</MyProductStage>
<MyProductVersion>2020.1</MyProductVersion>
<MyProductStage>Gold</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>

View File

@ -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" />

View File

@ -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">

View File

@ -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" />
@ -193,7 +195,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>

View File

@ -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,15 @@
<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>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h">
@ -130,8 +133,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>

View File

@ -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>

View File

@ -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.

View File

@ -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

View File

@ -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
View 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

File diff suppressed because it is too large Load Diff

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -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)
{

View File

@ -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)

View File

@ -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);

View File

@ -273,10 +273,12 @@ 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 (;;)

View File

@ -1755,7 +1755,7 @@ reparse_data_exit:
memcpy(Buffer, ReparseData, ReparseDataSize);
if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData->ReparseTag)
OutputReparseData->Reserved = RemainderPathSize;
OutputReparseData->Reserved = (USHORT)RemainderPathSize;
PIoStatus->Status = STATUS_REPARSE;
PIoStatus->Information = ReparseData->ReparseTag;

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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>

View File

@ -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;

View File

@ -20,7 +20,7 @@
*/
#include <winfsp/winfsp.h>
#include <shared/minimal.h>
#include <shared/um/minimal.h>
#include <aclapi.h>
#include <sddl.h>

View File

@ -20,7 +20,7 @@
*/
#include <winfsp/launch.h>
#include <shared/minimal.h>
#include <shared/um/minimal.h>
#define PROGNAME "launchctl"

View File

@ -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);
*Dest++ = L'"';
if (Quote)
*Dest++ = L'"';
Dest = PathTransform(Dest, Arg, Pattern);
*Dest++ = L'"';
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,23 +759,30 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
* https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873/
*/
/* create stdin read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
0, TRUE, FALSE, 0, 0))
if (0 != StdioHandles)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
/* create stdin read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
0, TRUE, FALSE, 0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
/* create stdout read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
if (0 != StdioHandles)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
/* create stdout read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
{
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)

View File

@ -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
View 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

View File

@ -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)

View File

@ -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);

View File

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

View File

@ -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.

View File

@ -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);

View File

@ -284,7 +284,7 @@ static NTSTATUS FspFsvolCreateNoLock(
return STATUS_SUCCESS;
}
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
if (!FspFsvolDeviceReadyToAcceptIrp(FsvolDeviceObject))
return STATUS_CANCELLED;
#endif

View File

@ -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 */
@ -1028,7 +1030,6 @@ NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLen
#define FspStatisticsAdd(S,F,V) ((S)->F += (V))
/* device management */
#define FSP_DEVICE_REJECT_EARLY_IRP
enum
{
FspFsvolDeviceSecurityCacheCapacity = 100,
@ -1083,7 +1084,7 @@ typedef struct
FSP_FSEXT_PROVIDER *Provider;
UNICODE_STRING VolumePrefix;
UNICODE_PREFIX_TABLE_ENTRY VolumePrefixEntry;
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
LONG ReadyToAcceptIrp;
#endif
FSP_IOQ *Ioq;
@ -1185,7 +1186,7 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
static inline
BOOLEAN FspFsvolDeviceReadyToAcceptIrp(PDEVICE_OBJECT DeviceObject)
{
@ -1391,6 +1392,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;

View File

@ -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;
@ -296,6 +297,19 @@ static NTSTATUS FspFsvolReadNonCached(
}
}
/* 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);
}
/* convert FileNode to shared */
FspFileNodeConvertExclusiveToShared(FileNode, Full);

View File

@ -286,7 +286,7 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
{
PAGED_CODE();
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
if (!FspFsvolDeviceReadyToAcceptIrp(FsvolDeviceObject))
return STATUS_CANCELLED;
#endif
@ -419,7 +419,7 @@ static NTSTATUS FspFsvolSetVolumeInformation(
{
PAGED_CODE();
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
if (!FspFsvolDeviceReadyToAcceptIrp(FsvolDeviceObject))
return STATUS_CANCELLED;
#endif

View File

@ -277,7 +277,7 @@ static NTSTATUS FspVolumeCreateNoLock(
RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName,
FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf);
RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName);
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
if (!FsvolDeviceExtension->VolumeParams.RejectIrpPriorToTransact0)
FsvolDeviceExtension->ReadyToAcceptIrp = 1;
#endif
@ -771,7 +771,7 @@ NTSTATUS FspVolumeTransact(
if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED;
#if defined(FSP_DEVICE_REJECT_EARLY_IRP)
#if defined(FSP_CFG_REJECT_EARLY_IRP)
if (0 == InputBufferLength && 0 == OutputBufferLength)
FspFsvolDeviceSetReadyToAcceptIrp(FsvolDeviceObject);
#endif

View File

@ -103,12 +103,20 @@ if not exist "build\%Configuration%\winfsp-*.msi" (echo installer msi not found
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
)

View File

@ -103,12 +103,20 @@ if not exist "build\%Configuration%\winfsp-*.msi" (echo installer msi not found
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
)

View File

@ -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

View File

@ -285,6 +285,7 @@ namespace memfs
Host.PassQueryDirectoryFileName = true;
Host.ExtendedAttributes = true;
Host.WslFeatures = true;
Host.RejectIrpPriorToTransact0 = true;
return STATUS_SUCCESS;
}

View File

@ -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)

View File

@ -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)
{