mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
220 Commits
Author | SHA1 | Date | |
---|---|---|---|
12e40f908d | |||
42745e2239 | |||
249c1a5cb8 | |||
233904fd51 | |||
3e0f2316a7 | |||
bd952253fb | |||
c7780cf7fa | |||
31b54ecc47 | |||
4084448bd5 | |||
4dc1828e1f | |||
79b7b66b62 | |||
612c820630 | |||
e13233ef32 | |||
dd815f3c39 | |||
5faafc4d11 | |||
78e5d031c0 | |||
9ef562df15 | |||
a7cdc815d0 | |||
bd5e15fe24 | |||
214a8406eb | |||
6bd6f0ee35 | |||
f8cebd1f92 | |||
f8f6d0f1bc | |||
b06132cb6b | |||
748c9b6409 | |||
bfc7fc5dec | |||
03f906f966 | |||
4b1111fcc5 | |||
86ddeed129 | |||
e2d4b36057 | |||
ab2908a9ee | |||
fd7b12bb61 | |||
eb2000a194 | |||
e4cabc50c5 | |||
92dc2feecd | |||
43f333e8a6 | |||
59eb40fd9b | |||
d85d36c94f | |||
27b841faf8 | |||
c6967c737a | |||
4ccbd1bdf6 | |||
0a8b8e8444 | |||
352450d538 | |||
7e1861a9f5 | |||
860e9db8a7 | |||
1d435269bd | |||
e58ac1fbde | |||
1f0f2fe094 | |||
d7ec331c74 | |||
938c036387 | |||
16f5bd089d | |||
6afea44e31 | |||
2859355fd8 | |||
75012d1301 | |||
8e1512c067 | |||
fa6b621042 | |||
8ffb359f20 | |||
203873ef04 | |||
e73bda3926 | |||
0186b82fea | |||
db38d2f7f8 | |||
016d015fe6 | |||
87b2d4ca4c | |||
dfd6cbbde1 | |||
6a126da51d | |||
03df0a9c26 | |||
5c3a82a074 | |||
b591015b28 | |||
fb9b798d3d | |||
cc408b71e1 | |||
19a73ca01d | |||
3992b9ebb1 | |||
a46c0610c4 | |||
495fc7a5dc | |||
2ba46fdb71 | |||
7cb56bb132 | |||
687b02c1e6 | |||
218b162d75 | |||
5e13c8750e | |||
2e71d2fe14 | |||
866e4abe10 | |||
7894cc8b7b | |||
0c810c52fa | |||
b06e947e0e | |||
aed134080c | |||
3ce490d405 | |||
76aabecbfb | |||
8eebfe811d | |||
5798527237 | |||
817beebb63 | |||
b7a2b5e17a | |||
20e547c6d0 | |||
d0d0f60033 | |||
fbc3d3efce | |||
2c3f177314 | |||
91e8bb1229 | |||
4b48502232 | |||
74af44e2e7 | |||
915279d41d | |||
316a2940dc | |||
453c1753ab | |||
b11b622fc2 | |||
f1ba60e172 | |||
7c1b592b84 | |||
1e88fedb19 | |||
5ecc92f2ba | |||
5771eedc45 | |||
46a29f663a | |||
49cd11b34b | |||
aeff3dc21e | |||
b7368336d2 | |||
5afe7a5315 | |||
7815b9e2eb | |||
cbcea380ef | |||
10635db99b | |||
cb00f913cc | |||
c406c89158 | |||
f600d51ace | |||
7401481d42 | |||
2d3d92fb2d | |||
eca93bbdb3 | |||
5fa0c36c8f | |||
ea2cc54677 | |||
ccec269dd6 | |||
5888e9ab05 | |||
c12b88286d | |||
e412d735ed | |||
582997b5a4 | |||
1647702a65 | |||
ccf58122a2 | |||
be8c29114a | |||
30f2807e2b | |||
25a2873556 | |||
bd0acf2289 | |||
997476f015 | |||
f89c91cd10 | |||
af2cc10c15 | |||
0d25e73364 | |||
86d74371aa | |||
f32e335855 | |||
165f3ec45d | |||
811696d939 | |||
0c07be9628 | |||
5dcbbaa4e7 | |||
12b70f661f | |||
9b4b5abe48 | |||
5cd0dfb1b9 | |||
46ce4b1a6c | |||
28a20d5199 | |||
10ea9a833f | |||
d9713668aa | |||
00c0574f1f | |||
44c86ff9a4 | |||
28931f4687 | |||
80e07cead6 | |||
b88b2ec51d | |||
82e4dcb4a1 | |||
34e653a275 | |||
981e60643f | |||
fee75590a8 | |||
1298dd842d | |||
8334daa048 | |||
2f73bfa069 | |||
d2d2dd5099 | |||
146570dd74 | |||
f509281be4 | |||
613a564ca2 | |||
7ffc60f512 | |||
499a0cb866 | |||
edff3054db | |||
f7e0362350 | |||
7337f3c6cd | |||
ab278d7b60 | |||
858df29ba2 | |||
4366866653 | |||
e4b808806c | |||
13cee6e019 | |||
35b9cb15a3 | |||
0d8f0f9ac8 | |||
a4e2ad9dd6 | |||
9b4318c655 | |||
5827b1fa9c | |||
913f7ac9cd | |||
0e2f46dc90 | |||
a8d76d3e46 | |||
380ec074ca | |||
e7cba96c74 | |||
03db443406 | |||
0b65bc7e01 | |||
12e1caaa98 | |||
7a690a789b | |||
8ca419830c | |||
c310d8ea1b | |||
c3ddf73661 | |||
6b00b8e28a | |||
35c722e91b | |||
ae8802514b | |||
e90aa46a27 | |||
760cd5e46f | |||
b36b6c60e2 | |||
e4984bf675 | |||
0c8bcd5d7d | |||
b5d8cd3ea6 | |||
af5f409233 | |||
cffb066d46 | |||
804434d836 | |||
f7595e40b6 | |||
669dd07ce2 | |||
b6fa54d301 | |||
342e7e39e2 | |||
9dfdd19616 | |||
2c651b1bd8 | |||
41764f7b41 | |||
08e697c52c | |||
66cc043149 | |||
518cd0e8c0 | |||
c0344f53b0 | |||
76445a5403 | |||
0577b8febb | |||
610a7ac2a6 |
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "ext/test"]
|
[submodule "ext/test"]
|
||||||
path = ext/test
|
path = ext/test
|
||||||
url = https://bitbucket.org/billziss/secfs.test.git
|
url = https://github.com/billziss-gh/secfs.test.git
|
||||||
|
39
README.md
39
README.md
@ -1,5 +1,7 @@
|
|||||||
# WinFsp - Windows File System Proxy
|
# WinFsp - Windows File System Proxy
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Some of the benefits and features of using WinFsp are listed below:
|
Some of the benefits and features of using WinFsp are listed below:
|
||||||
@ -34,10 +36,41 @@ The project source code is organized as follows:
|
|||||||
* tst/memfs: Source code to an example file system written in C++ (memfs).
|
* tst/memfs: Source code to an example file system written in C++ (memfs).
|
||||||
* tst/winfsp-tests: WinFsp test suite.
|
* tst/winfsp-tests: WinFsp test suite.
|
||||||
|
|
||||||
## Building
|
## Building and Running
|
||||||
|
|
||||||
In order to build WinFsp you will need Windows 10 and Visual Studio 2015. You will also need the Windows Driver Kit (WDK) 10.
|
In order to build WinFsp you will need the following:
|
||||||
|
|
||||||
|
* Windows 10
|
||||||
|
* Visual Studio 2015
|
||||||
|
* Windows Driver Kit (WDK) 10
|
||||||
|
* [Wix toolset](http://wixtoolset.org)
|
||||||
|
|
||||||
|
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`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
|
||||||
|
|
||||||
|
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
|
||||||
|
|
||||||
|
* Windows 7 Enterprise
|
||||||
|
* Windows 8 Pro
|
||||||
|
* Windows 10 Pro
|
||||||
|
* Windows Server 2012
|
||||||
|
|
||||||
|
## How to Help
|
||||||
|
|
||||||
|
I am looking for help in the following areas:
|
||||||
|
|
||||||
|
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
|
||||||
|
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
|
||||||
|
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues) ~~[BitBucket repository](https://bitbucket.org/billziss/winfsp/issues?status=new&status=open)~~. Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. If you decide to tackle any of those please coordinate with me as I am actively working on that issue list.
|
||||||
|
|
||||||
|
In all cases I can provide ideas and/or support.
|
||||||
|
|
||||||
|
## Where to Discuss
|
||||||
|
|
||||||
|
If you wish to discuss WinFsp there are now two options:
|
||||||
|
|
||||||
|
- [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp)
|
||||||
|
- [Author's Twitter](https://twitter.com/BZissimopoulos)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
WinFsp is available under the [AGPLv3](http://www.gnu.org/licenses/agpl-3.0.html) license. If you find the constraints of the AGPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
|
WinFsp is available under the [GPLv3](http://www.gnu.org/licenses/gpl-3.0.html) license. If you find the constraints of the GPLv3 too onerous, a commercial license is also available. Please contact Bill Zissimopoulos <billziss at navimatics.com> for more details.
|
||||||
|
@ -6,6 +6,7 @@ environment:
|
|||||||
install:
|
install:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
|
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
|
||||||
|
- verifier /standard /driver winfsp-x64.sys
|
||||||
- bcdedit /set testsigning on
|
- bcdedit /set testsigning on
|
||||||
- ps: Restart-Computer -Force
|
- ps: Restart-Computer -Force
|
||||||
- ps: Start-Sleep -s 10
|
- ps: Start-Sleep -s 10
|
||||||
@ -19,3 +20,4 @@ test_script:
|
|||||||
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
|
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
|
||||||
- tools\nmake-ext-test.bat %CONFIGURATION%
|
- tools\nmake-ext-test.bat %CONFIGURATION%
|
||||||
- tools\run-tests.bat %CONFIGURATION%
|
- tools\run-tests.bat %CONFIGURATION%
|
||||||
|
- verifier /query
|
||||||
|
BIN
art/winfsp-outln.afdesign
Normal file
BIN
art/winfsp-outln.afdesign
Normal file
Binary file not shown.
BIN
art/winfsp-solid.afdesign
Normal file
BIN
art/winfsp-solid.afdesign
Normal file
Binary file not shown.
BIN
art/winfsp-solid.png
Normal file
BIN
art/winfsp-solid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
art/wixbanner.pxm
Normal file
BIN
art/wixbanner.pxm
Normal file
Binary file not shown.
BIN
art/wixdialog.pxm
Normal file
BIN
art/wixdialog.pxm
Normal file
Binary file not shown.
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -40,18 +40,20 @@
|
|||||||
<Directory Id="INCDIR" Name="inc" />
|
<Directory Id="INCDIR" Name="inc" />
|
||||||
<Directory Id="LIBDIR" Name="lib" />
|
<Directory Id="LIBDIR" Name="lib" />
|
||||||
<Directory Id="SMPDIR" Name="samples" />
|
<Directory Id="SMPDIR" Name="samples" />
|
||||||
|
<Directory Id="SYMDIR" Name="sym" />
|
||||||
</Directory>
|
</Directory>
|
||||||
</Directory>
|
</Directory>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<DirectoryRef Id="INSTALLDIR">
|
<DirectoryRef Id="INSTALLDIR">
|
||||||
<Component Id="C.INSTALLDIR">
|
<Component Id="C.INSTALLDIR" Guid="{F876F26E-5016-4AC6-93B3-653C0312A6CE}">
|
||||||
<RegistryValue
|
<RegistryValue
|
||||||
Root="HKLM"
|
Root="HKLM"
|
||||||
Key="[P.RegistryKey]"
|
Key="[P.RegistryKey]"
|
||||||
Name="InstallDir"
|
Name="InstallDir"
|
||||||
Type="string"
|
Type="string"
|
||||||
Value="[INSTALLDIR]" />
|
Value="[INSTALLDIR]"
|
||||||
|
KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
|
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
|
||||||
@ -135,6 +137,10 @@
|
|||||||
<File Name="launchctl-x86.exe" KeyPath="yes" />
|
<File Name="launchctl-x86.exe" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
|
|
||||||
|
<Component Id="C.diag.bat">
|
||||||
|
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
|
||||||
<Component Id="C.memfs_x64.exe">
|
<Component Id="C.memfs_x64.exe">
|
||||||
<File Name="memfs-x64.exe" KeyPath="yes" />
|
<File Name="memfs-x64.exe" KeyPath="yes" />
|
||||||
<RegistryKey
|
<RegistryKey
|
||||||
@ -253,6 +259,38 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</Directory>
|
</Directory>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
|
<DirectoryRef Id="SYMDIR">
|
||||||
|
<Component Id="C.winfsp_x64.sys.pdb">
|
||||||
|
<File Name="winfsp-x64.sys.pdb" Source="..\build\$(var.Configuration)\winfsp-x64.sys.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.winfsp_x86.sys.pdb">
|
||||||
|
<File Name="winfsp-x86.sys.pdb" Source="..\build\$(var.Configuration)\winfsp-x86.sys.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.winfsp_x64.dll.pdb">
|
||||||
|
<File Name="winfsp-x64.dll.pdb" Source="..\build\$(var.Configuration)\winfsp-x64.dll.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.winfsp_x86.dll.pdb">
|
||||||
|
<File Name="winfsp-x86.dll.pdb" Source="..\build\$(var.Configuration)\winfsp-x86.dll.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.launcher_x64.pdb">
|
||||||
|
<File Name="launcher-x64.pdb" Source="..\build\$(var.Configuration)\launcher-x64.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.launcher_x86.pdb">
|
||||||
|
<File Name="launcher-x86.pdb" Source="..\build\$(var.Configuration)\launcher-x86.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.launchctl_x64.pdb">
|
||||||
|
<File Name="launchctl-x64.pdb" Source="..\build\$(var.Configuration)\launchctl-x64.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.launchctl_x86.pdb">
|
||||||
|
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.memfs_x64.pdb">
|
||||||
|
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.memfs_x86.pdb">
|
||||||
|
<File Name="memfs-x86.pdb" Source="..\build\$(var.Configuration)\memfs-x86.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
</DirectoryRef>
|
||||||
|
|
||||||
<ComponentGroup Id="C.WinFsp.bin">
|
<ComponentGroup Id="C.WinFsp.bin">
|
||||||
<ComponentRef Id="C.winfsp_x64.sys" />
|
<ComponentRef Id="C.winfsp_x64.sys" />
|
||||||
@ -267,6 +305,7 @@
|
|||||||
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
|
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
|
||||||
<ComponentRef Id="C.launchctl_x64.exe" />
|
<ComponentRef Id="C.launchctl_x64.exe" />
|
||||||
<ComponentRef Id="C.launchctl_x86.exe" />
|
<ComponentRef Id="C.launchctl_x86.exe" />
|
||||||
|
<ComponentRef Id="C.diag.bat" />
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
<ComponentGroup Id="C.WinFsp.inc">
|
<ComponentGroup Id="C.WinFsp.inc">
|
||||||
<ComponentRef Id="C.fsctl.h" />
|
<ComponentRef Id="C.fsctl.h" />
|
||||||
@ -289,6 +328,18 @@
|
|||||||
<ComponentRef Id="C.memfs.cpp" />
|
<ComponentRef Id="C.memfs.cpp" />
|
||||||
<ComponentRef Id="C.memfs_main.c" />
|
<ComponentRef Id="C.memfs_main.c" />
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
|
<ComponentGroup Id="C.WinFsp.sym">
|
||||||
|
<ComponentRef Id="C.winfsp_x64.sys.pdb" />
|
||||||
|
<ComponentRef Id="C.winfsp_x86.sys.pdb" />
|
||||||
|
<ComponentRef Id="C.winfsp_x86.dll.pdb" />
|
||||||
|
<ComponentRef Id="C.winfsp_x64.dll.pdb" />
|
||||||
|
<ComponentRef Id="C.launcher_x86.pdb" />
|
||||||
|
<ComponentRef Id="C.launcher_x64.pdb" />
|
||||||
|
<ComponentRef Id="C.launchctl_x64.pdb" />
|
||||||
|
<ComponentRef Id="C.launchctl_x86.pdb" />
|
||||||
|
<ComponentRef Id="C.memfs_x64.pdb" />
|
||||||
|
<ComponentRef Id="C.memfs_x86.pdb" />
|
||||||
|
</ComponentGroup>
|
||||||
|
|
||||||
<Feature
|
<Feature
|
||||||
Id="F.Main"
|
Id="F.Main"
|
||||||
@ -322,9 +373,12 @@
|
|||||||
<ComponentGroupRef Id="C.WinFsp.inc" />
|
<ComponentGroupRef Id="C.WinFsp.inc" />
|
||||||
<ComponentGroupRef Id="C.WinFsp.lib" />
|
<ComponentGroupRef Id="C.WinFsp.lib" />
|
||||||
<ComponentGroupRef Id="C.WinFsp.smp" />
|
<ComponentGroupRef Id="C.WinFsp.smp" />
|
||||||
|
<ComponentGroupRef Id="C.WinFsp.sym" />
|
||||||
</Feature>
|
</Feature>
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
|
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
|
||||||
|
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyDevStage).bmp" />
|
||||||
<UI Id="FeatureTree">
|
<UI Id="FeatureTree">
|
||||||
<UIRef Id="WixUI_FeatureTree" />
|
<UIRef Id="WixUI_FeatureTree" />
|
||||||
<!-- skip the license agreement dialog; higher Order takes priority (weird) -->
|
<!-- skip the license agreement dialog; higher Order takes priority (weird) -->
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||||
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
|
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
|
||||||
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion)</DefineConstants>
|
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
|
||||||
<SuppressAllWarnings>False</SuppressAllWarnings>
|
<SuppressAllWarnings>False</SuppressAllWarnings>
|
||||||
<Pedantic>True</Pedantic>
|
<Pedantic>True</Pedantic>
|
||||||
<SuppressPdbOutput>True</SuppressPdbOutput>
|
<SuppressPdbOutput>True</SuppressPdbOutput>
|
||||||
@ -25,7 +25,7 @@
|
|||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||||
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
|
<IntermediateOutputPath>$(SolutionDir)build\$(Name).build\$(Configuration)\$(Platform)\</IntermediateOutputPath>
|
||||||
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion)</DefineConstants>
|
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
|
||||||
<SuppressAllWarnings>False</SuppressAllWarnings>
|
<SuppressAllWarnings>False</SuppressAllWarnings>
|
||||||
<Pedantic>True</Pedantic>
|
<Pedantic>True</Pedantic>
|
||||||
<SuppressPdbOutput>True</SuppressPdbOutput>
|
<SuppressPdbOutput>True</SuppressPdbOutput>
|
||||||
|
BIN
build/VStudio/installer/wixbanner.bmp
Normal file
BIN
build/VStudio/installer/wixbanner.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
build/VStudio/installer/wixdialog-Beta.bmp
Normal file
BIN
build/VStudio/installer/wixdialog-Beta.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 601 KiB |
BIN
build/VStudio/installer/wixdialog-Gold.bmp
Normal file
BIN
build/VStudio/installer/wixdialog-Gold.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 601 KiB |
BIN
build/VStudio/installer/wixdialog-RC.bmp
Normal file
BIN
build/VStudio/installer/wixdialog-RC.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 601 KiB |
@ -105,11 +105,14 @@
|
|||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -123,11 +126,14 @@
|
|||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -142,6 +148,8 @@
|
|||||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -149,6 +157,7 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -163,6 +172,8 @@
|
|||||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -170,6 +181,7 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -105,11 +105,15 @@
|
|||||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -123,11 +127,15 @@
|
|||||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -142,6 +150,8 @@
|
|||||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -149,6 +159,8 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -163,6 +175,8 @@
|
|||||||
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -170,6 +184,8 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -108,6 +108,7 @@
|
|||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -124,6 +125,7 @@
|
|||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -144,6 +146,7 @@
|
|||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -164,6 +167,7 @@
|
|||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -186,6 +186,7 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
|
||||||
@ -193,13 +194,16 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\path-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\path-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\rdwr-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\rdwr-test.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h" />
|
<ClInclude Include="..\..\..\ext\tlib\testsuite.h" />
|
||||||
<ClInclude Include="..\..\..\tst\memfs\memfs.h" />
|
<ClInclude Include="..\..\..\tst\memfs\memfs.h" />
|
||||||
|
<ClInclude Include="..\..\..\tst\winfsp-tests\winfsp-tests.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\winfsp_dll.vcxproj">
|
<ProjectReference Include="..\winfsp_dll.vcxproj">
|
||||||
|
@ -61,6 +61,15 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c">
|
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||||
@ -69,5 +78,8 @@
|
|||||||
<ClInclude Include="..\..\..\tst\memfs\memfs.h">
|
<ClInclude Include="..\..\..\tst\memfs\memfs.h">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\tst\winfsp-tests\winfsp-tests.h">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -5,9 +5,15 @@
|
|||||||
<MyDescription>Windows File System Proxy</MyDescription>
|
<MyDescription>Windows File System Proxy</MyDescription>
|
||||||
<MyCompanyName>Navimatics Corporation</MyCompanyName>
|
<MyCompanyName>Navimatics Corporation</MyCompanyName>
|
||||||
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
|
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
|
||||||
|
<MyDevStage>Beta</MyDevStage>
|
||||||
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
|
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
|
||||||
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
|
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
|
||||||
<MyVersion>0.13.$(MyBuildNumber)</MyVersion>
|
<MyVersion>0.17.$(MyBuildNumber)</MyVersion>
|
||||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>NTDDI_VERSION=0x06000000;_WIN32_WINNT=0x0600</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
</Project>
|
</Project>
|
@ -173,6 +173,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@ -182,7 +184,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -198,6 +201,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@ -207,7 +212,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -224,6 +230,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@ -235,7 +243,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -252,6 +261,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\src;..\..\inc</AdditionalIncludeDirectories>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@ -263,7 +274,8 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -118,6 +118,8 @@
|
|||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc" />
|
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
|
||||||
|
<Filter>Source\fuse</Filter>
|
||||||
|
</CustomBuild>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -34,6 +34,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
<TargetVersion>Windows10</TargetVersion>
|
<TargetVersion>Windows10</TargetVersion>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||||
<ConfigurationType>Driver</ConfigurationType>
|
<ConfigurationType>Driver</ConfigurationType>
|
||||||
<DriverType>WDM</DriverType>
|
<DriverType>WDM</DriverType>
|
||||||
@ -41,6 +42,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<TargetVersion>Windows10</TargetVersion>
|
<TargetVersion>Windows10</TargetVersion>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||||
<ConfigurationType>Driver</ConfigurationType>
|
<ConfigurationType>Driver</ConfigurationType>
|
||||||
<DriverType>WDM</DriverType>
|
<DriverType>WDM</DriverType>
|
||||||
@ -48,6 +50,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<TargetVersion>Windows10</TargetVersion>
|
<TargetVersion>Windows10</TargetVersion>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||||
<ConfigurationType>Driver</ConfigurationType>
|
<ConfigurationType>Driver</ConfigurationType>
|
||||||
<DriverType>WDM</DriverType>
|
<DriverType>WDM</DriverType>
|
||||||
@ -55,6 +58,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<TargetVersion>Windows10</TargetVersion>
|
<TargetVersion>Windows10</TargetVersion>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
|
||||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||||
<ConfigurationType>Driver</ConfigurationType>
|
<ConfigurationType>Driver</ConfigurationType>
|
||||||
<DriverType>WDM</DriverType>
|
<DriverType>WDM</DriverType>
|
||||||
@ -105,6 +109,7 @@
|
|||||||
<GenerateMapFile>true</GenerateMapFile>
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -117,6 +122,7 @@
|
|||||||
<GenerateMapFile>true</GenerateMapFile>
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -129,6 +135,7 @@
|
|||||||
<GenerateMapFile>true</GenerateMapFile>
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -141,6 +148,7 @@
|
|||||||
<GenerateMapFile>true</GenerateMapFile>
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,6 +1,41 @@
|
|||||||
= Changelog
|
= Changelog
|
||||||
|
|
||||||
|
|
||||||
|
v0.17::
|
||||||
|
|
||||||
|
This release brings support for named streams.
|
||||||
|
|
||||||
|
- Named streams (or alternate data streams) are additional streams of data within a file. When a file gets opened the main (default, unnamed) data stream of a file gets accessed. However NTFS (and now WinFsp) supports multiple data streams per file accessible using the `filename:streamname` syntax.
|
||||||
|
- WinFsp handles a lot of the hairy details regarding named streams, including sharing checks, pending delete checks, conflicts between the main and named streams, etc.
|
||||||
|
- User mode file systems that wish to support named streams must set the `FSP_FSCTL_VOLUME_PARAMS::NamedStreams` flag and must also be prepared to handle named streams on `Create`, `Cleanup`, etc. They must also implement the new `FSP_FILE_SYSTEM_INTERFACE::GetStreamInfo` operation. For more information on how to correctly handle named streams refer to the MEMFS sample.
|
||||||
|
|
||||||
|
|
||||||
|
v0.16::
|
||||||
|
|
||||||
|
This release brings support for reparse points and symbolic links as well as other minor changes.
|
||||||
|
|
||||||
|
- Reparse points are a general mechanism for attaching special behavior to files. Symbolic links in Windows are implemented as reparse points. WinFsp supports any kind of reparse point including symbolic links.
|
||||||
|
- The WinFsp FUSE implementation supports symbolic links. It also supports POSIX special files (FIFO, SOCK, CHR, BLK) as NFS reparse points (see https://msdn.microsoft.com/en-us/library/dn617178.aspx).
|
||||||
|
- User mode file systems that wish to support reparse points will have to set the `FSP_FSCTL_VOLUME_PARAMS::ReparsePoints` flag and implement the `FSP_FILE_SYSTEM_INTERFACE` methods `ResolveReparsePoints`, `GetReparsePoint`, `SetReparsePoint`, `DeleteReparsePoint`. More information in this blog article: http://www.secfs.net/winfsp/blog/files/reparse-points-symlinks-api-changes.html
|
||||||
|
- The installation now includes public symbol files for all WinFsp components shipped.
|
||||||
|
|
||||||
|
|
||||||
|
v0.15::
|
||||||
|
|
||||||
|
This is a minor release that brings support for Windows 7 and 32-bit OS'es.
|
||||||
|
|
||||||
|
- Fixes a number of issues for Windows 7. Windows 7 is now officially supported.
|
||||||
|
- Fixes a number of issues with the 32-bit FSD and user mode components. 32-bit versions of Windows are now officially supported.
|
||||||
|
|
||||||
|
|
||||||
|
v0.14::
|
||||||
|
|
||||||
|
This release includes support for file systems protected by credentials.
|
||||||
|
|
||||||
|
- WinFsp now supports file systems that require username/password to be unlocked (e.g. sshfs/secfs). Such file systems must add a DWORD registry value with name "Credentials" and value 1 under their WinFsp.Launcher service entry. The WinFsp network provider will then prompt for credentials using the `CredUIPromptForWindowsCredentials` API. Credentials can optionally be saved with the Windows Credential Manager.
|
||||||
|
- WinFsp-FUSE now uses the S-1-0-65534 <--> 65534 mapping for unmapped SID/UID's. The Anonymous SID mapping from the previous release had security issues.
|
||||||
|
|
||||||
|
|
||||||
v0.13::
|
v0.13::
|
||||||
|
|
||||||
This release includes a Cygwin package, an API change and some other minor changes:
|
This release includes a Cygwin package, an API change and some other minor changes:
|
||||||
|
143
doc/License.txt
143
doc/License.txt
@ -1,12 +1,12 @@
|
|||||||
The WinFsp project is Copyright (C) Bill Zissimopoulos. It is licensed
|
The WinFsp project is Copyright (C) Bill Zissimopoulos. It is licensed
|
||||||
under the terms of the AGPLv3. The full text of this license follows
|
under the terms of the GPLv3. The full text of this license follows
|
||||||
below. Commercial licensing options are also available: Please contact
|
below. Commercial licensing options are also available: Please contact
|
||||||
Bill Zissimopoulos <billziss at navimatics.com>.
|
Bill Zissimopoulos <billziss at navimatics.com>.
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 19 November 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
@ -14,15 +14,17 @@ Bill Zissimopoulos <billziss at navimatics.com>.
|
|||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU Affero General Public License is a free, copyleft license for
|
The GNU General Public License is a free, copyleft license for
|
||||||
software and other kinds of works, specifically designed to ensure
|
software and other kinds of works.
|
||||||
cooperation with the community in the case of network server software.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
our General Public Licenses are intended to guarantee your freedom to
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
share and change all versions of a program--to make sure it remains free
|
share and change all versions of a program--to make sure it remains free
|
||||||
software for all its users.
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
@ -31,34 +33,44 @@ them if you wish), that you receive source code or can get it if you
|
|||||||
want it, that you can change the software or use pieces of it in new
|
want it, that you can change the software or use pieces of it in new
|
||||||
free programs, and that you know you can do these things.
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
Developers that use our General Public Licenses protect your rights
|
To protect your rights, we need to prevent others from denying you
|
||||||
with two steps: (1) assert copyright on the software, and (2) offer
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
you this License which gives you legal permission to copy, distribute
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
and/or modify the software.
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
A secondary benefit of defending all users' freedom is that
|
For example, if you distribute copies of such a program, whether
|
||||||
improvements made in alternate versions of the program, if they
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
receive widespread use, become available for other developers to
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
incorporate. Many developers of free software are heartened and
|
or can get the source code. And you must show them these terms so they
|
||||||
encouraged by the resulting cooperation. However, in the case of
|
know their rights.
|
||||||
software used on network servers, this result may fail to come about.
|
|
||||||
The GNU General Public License permits making a modified version and
|
|
||||||
letting the public access it on a server without ever releasing its
|
|
||||||
source code to the public.
|
|
||||||
|
|
||||||
The GNU Affero General Public License is designed specifically to
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
ensure that, in such cases, the modified source code becomes available
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
to the community. It requires the operator of a network server to
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
provide the source code of the modified version running there to the
|
|
||||||
users of that server. Therefore, public use of a modified version, on
|
|
||||||
a publicly accessible server, gives the public access to the source
|
|
||||||
code of the modified version.
|
|
||||||
|
|
||||||
An older license, called the Affero General Public License and
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
published by Affero, was designed to accomplish similar goals. This is
|
that there is no warranty for this free software. For both users' and
|
||||||
a different license, not a version of the Affero GPL, but Affero has
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
released a new version of the Affero GPL which permits relicensing under
|
changed, so that their problems will not be attributed erroneously to
|
||||||
this license.
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
@ -67,7 +79,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
0. Definitions.
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
works, such as semiconductor masks.
|
||||||
@ -544,45 +556,35 @@ to collect a royalty for further conveying from those to whom you convey
|
|||||||
the Program, the only way you could satisfy both those terms and this
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, if you modify the
|
|
||||||
Program, your modified version must prominently offer all users
|
|
||||||
interacting with it remotely through a computer network (if your version
|
|
||||||
supports such interaction) an opportunity to receive the Corresponding
|
|
||||||
Source of your version by providing access to the Corresponding Source
|
|
||||||
from a network server at no charge, through some standard or customary
|
|
||||||
means of facilitating copying of software. This Corresponding Source
|
|
||||||
shall include the Corresponding Source for any work covered by version 3
|
|
||||||
of the GNU General Public License that is incorporated pursuant to the
|
|
||||||
following paragraph.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU General Public License into a single
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
combined work, and to convey the resulting work. The terms of this
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the work with which it is combined will remain governed by version
|
but the special requirements of the GNU Affero General Public License,
|
||||||
3 of the GNU General Public License.
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU Affero General Public License from time to time. Such new versions
|
the GNU General Public License from time to time. Such new versions will
|
||||||
will be similar in spirit to the present version, but may differ in detail to
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU Affero General
|
Program specifies that a certain numbered version of the GNU General
|
||||||
Public License "or any later version" applies to it, you have the
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU Affero General Public License, you may choose any version ever published
|
GNU General Public License, you may choose any version ever published
|
||||||
by the Free Software Foundation.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU Affero General Public License can be used, that proxy's
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
public statement of acceptance of a version permanently authorizes you
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
to choose that version for the Program.
|
||||||
|
|
||||||
@ -640,29 +642,40 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Affero General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If your software can interact with users remotely through a computer
|
If the program does terminal interaction, make it output a short
|
||||||
network, you should also make sure that it provides a way for users to
|
notice like this when it starts in an interactive mode:
|
||||||
get its source. For example, if your program is a web application, its
|
|
||||||
interface could display a "Source" link that leads users to an archive
|
<program> Copyright (C) <year> <name of author>
|
||||||
of the code. There are many ways you could offer source, and different
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
solutions will be better for different programs; see section 13 for the
|
This is free software, and you are welcome to redistribute it
|
||||||
specific requirements.
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
<http://www.gnu.org/licenses/>.
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
|
50
doc/native-api-vs-fuse.adoc
Normal file
50
doc/native-api-vs-fuse.adoc
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
= Native API vs FUSE
|
||||||
|
|
||||||
|
This document compares the "native" WinFsp API to the FUSE API and provides a rationale for the existence of both within WinFsp.
|
||||||
|
|
||||||
|
== Overview
|
||||||
|
|
||||||
|
WinFsp provides two different but conceptually similar API's for the same purpose of implementing a user mode file system:
|
||||||
|
|
||||||
|
- The WinFsp API, which is documented in the include file `inc/winfsp/winfsp.h` (and online at http://www.secfs.net/winfsp/apiref/). This API consists of the `FSP_FILE_SYSTEM_INTERFACE` "class" and the `FspFileSystem*` functions.
|
||||||
|
- The FUSE (high-level) API, which is the well understood API from the FUSE project originally by Miklos Szeredi.
|
||||||
|
|
||||||
|
Given the similarities between the two API's some questions naturally arise:
|
||||||
|
|
||||||
|
- What are the differences between the two API's?
|
||||||
|
- Why are both needed?
|
||||||
|
- What is the target audience for each API?
|
||||||
|
|
||||||
|
== Comparison
|
||||||
|
|
||||||
|
The primary difference between the two API's is that the WinFsp API is being designed to use all features available to a Windows file system, whereas the FUSE API is being designed (by the FUSE project) to better fit a POSIX file system. For example, a Windows file system can do the following, that cannot be (easily) made available to FUSE:
|
||||||
|
|
||||||
|
- Create and manage alternate data streams.
|
||||||
|
- Manage arbitrary security descriptors (SID's and ACL's vs POSIX permissions).
|
||||||
|
- Create and manage special files beyond what is supported through FUSE `mknod` (using reparse points).
|
||||||
|
- Support volume labels.
|
||||||
|
- Allow the file system to fulfill Read/Write requests using asynchronous I/O.
|
||||||
|
|
||||||
|
Furthermore there are other smaller, but still important differences:
|
||||||
|
|
||||||
|
- The file deletion model on Windows is different from the FUSE/POSIX model.
|
||||||
|
- The reparse mechanism (which supports symbolic links) on Windows is quite more powerful (and more complicated) than FUSE/POSIX symbolic links.
|
||||||
|
- Windows uses UTF-16 for file names, whereas FUSE uses UTF-8, requiring constant conversions between the two.
|
||||||
|
|
||||||
|
These and other differences make the creation of the WinFsp FUSE compatibility layer non-trivial and suggest that a native API that more closely resembles the Windows file system model is desirable. At the same time there are hundreds of FUSE (high-level) file systems and having a FUSE compatible API is also very desirable.
|
||||||
|
|
||||||
|
== Target Audiences
|
||||||
|
|
||||||
|
As mentioned WinFsp provides two different API's; to further complicate matters the FUSE API can be used from both a native Windows application and a Cygwin (POSIX) application. There are then 3 different audiences that the API's cater for:
|
||||||
|
|
||||||
|
- The WinFsp API audience. This consists of Windows-only file systems or cross-platform file systems that wish to provide maximum features and/or performance on Windows.
|
||||||
|
- The FUSE API for native Windows audience. This consists of FUSE file-systems that have had their core file system code ported to Windows, but have not yet been integrated into the operating system. It also includes cross-platform file systems that do not wish to include advanced (non-POSIX) Windows file system features.
|
||||||
|
- The FUSE API for Cygwin audience. This consists of FUSE file-systems that are ported to Windows/Cygwin with minimal work. For example, the author of this document has ported SSHFS to Cygwin using this API and a minimal SSHFS patch.
|
||||||
|
|
||||||
|
For the developer of a new or Windows exclusive file system the recommendation is to use the WinFsp API as it provides support for all features of the Windows file system.
|
||||||
|
|
||||||
|
For the developer of a FUSE file system that wishes to port their file system to Windows a natural process may be the following:
|
||||||
|
|
||||||
|
- Use the FUSE API for Cygwin to port the file system to Cygwin. In many cases little or no changes to the file system code are required.
|
||||||
|
- Use the FUSE API for native Windows to port the file system to native Windows. This would require porting the core file system code (i.e. those parts of the file system code that actually manage and organize files). Little to no changes should be required for the file system FUSE layer glue.
|
||||||
|
- Use the WinFsp API only if the file system requires maximum features and/or performance under Windows.
|
@ -1,6 +1,6 @@
|
|||||||
= SSHFS Port Case Study
|
= SSHFS Port Case Study
|
||||||
|
|
||||||
This document is a case study in porting SSHFS to Windows and WinFsp. At the time of this writing WinFsp has a native API, but no FUSE compatible API. The main purpose of this case study is to develop a FUSE compatible API for WinFsp.
|
This document is a case study in porting SSHFS to Windows and WinFsp. At the time that the document was started WinFsp had a native API, but no FUSE compatible API. The main purpose of the case study was to develop a FUSE compatible API for WinFsp.
|
||||||
|
|
||||||
== Step 1: Gather Information about SSHFS
|
== Step 1: Gather Information about SSHFS
|
||||||
|
|
||||||
@ -215,3 +215,52 @@ fuse_destroy
|
|||||||
----
|
----
|
||||||
|
|
||||||
With this change `fuse_daemonize` works and allows me to declare the Cygwin portion of the SSHFS port complete!
|
With this change `fuse_daemonize` works and allows me to declare the Cygwin portion of the SSHFS port complete!
|
||||||
|
|
||||||
|
== Step 5: POSIX special files
|
||||||
|
|
||||||
|
Although WinFsp now has a working FUSE implementation there remains an important problem: how to handle POSIX special files such as named pipes (FIFO), devices (CHR, BLK), sockets (SOCK) or symbolic links (LNK).
|
||||||
|
|
||||||
|
While Windows has support for symbolic links (LNK) there is no direct support for other POSIX special files. The question then is how to represent such files when they are accessed by Windows. This is especially important to systems like Cygwin that understand POSIX special files and can even create them.
|
||||||
|
|
||||||
|
Cygwin normally emulates symbolic links and special files using special shortcut (.lnk) files. However many FUSE file systems support POSIX special files; it is desirable then that applications, like Cygwin, that understand them should be able to create and access them without resorting to hacks like using .lnk files.
|
||||||
|
|
||||||
|
The problem was originally mentioned by Herbert Stocker on the Cygwin mailing list:
|
||||||
|
|
||||||
|
[quote]
|
||||||
|
____
|
||||||
|
The mkfifo system call will have Cygwin create a .lnk file and
|
||||||
|
WinFsp will forward it as such to the file system process. The
|
||||||
|
system calls readdir or open will then have the file system
|
||||||
|
process tell WinFsp that there is a .lnk file and Cygwin will
|
||||||
|
translate this back to a fifo, so in this sense it does work.
|
||||||
|
|
||||||
|
But the file system will see a file (with name *.lnk) where it
|
||||||
|
should see a pipe (mknod call with \'mode' set to S_IFIFO).
|
||||||
|
IMHO one could say this is a break of the FUSE API.
|
||||||
|
|
||||||
|
Practically it will break:
|
||||||
|
|
||||||
|
- File systems that special-treat pipe files (or .lnk files).
|
||||||
|
|
||||||
|
- If one uses sshfs to connect to a Linux based server and
|
||||||
|
issues the command mkfifo foo from Cygwin, the server will
|
||||||
|
end up with a .lnk file instead of a pipe special file.
|
||||||
|
|
||||||
|
- Imagine something like mysqlfs, which stores the stuff in a
|
||||||
|
database. When you run SQL statements to analyze the data
|
||||||
|
in the file system, you won't see the pipes as such. Or if
|
||||||
|
you open the file system from Linux you'll see the .lnk
|
||||||
|
files.
|
||||||
|
____
|
||||||
|
|
||||||
|
Herbert is of course right. A .lnk file is not a FIFO to any application other than Cygwin. We need a better mechanism for representing special files. One such mechanism is reparse points.
|
||||||
|
|
||||||
|
Reparse points can be viewed as a form of special metadata that can be attached to a file or directory. The interesting thing about reparse points is that they can have special meaning to a file system driver (NTFS/WinFsp), a filter driver (e.g. a hierarchical storage system) or even an application (Cygwin).
|
||||||
|
|
||||||
|
Symbolic links are already implemented as reparse points on Windows. We could perhaps define a new reparse point type for representing POSIX special files. Turns out that this is unnecessary, because Microsoft has already defined a reparse point type for special files on NFS: https://msdn.microsoft.com/en-us/library/dn617178.aspx
|
||||||
|
|
||||||
|
It is a relatively straightforward task then to map reparse point operations into their FUSE equivalents:
|
||||||
|
|
||||||
|
GetReparsePoint:: Mapped to `getattr`/`fgetattr` and possibly `readlink` (in the case of a symbolic link). The returned `stat.st_mode` information is transformed to the appropriate reparse point information.
|
||||||
|
|
||||||
|
SetReparsePoint:: Mapped to `symlink` or `mknod` depending on whether a symbolic link or other special file is created.
|
||||||
|
2
ext/test
2
ext/test
Submodule ext/test updated: da7b88d6cf...feb554380e
@ -11,9 +11,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -244,6 +244,7 @@ struct fsp_fuse_env
|
|||||||
void (*memfree)(void *);
|
void (*memfree)(void *);
|
||||||
int (*daemonize)(int);
|
int (*daemonize)(int);
|
||||||
int (*set_signal_handlers)(void *);
|
int (*set_signal_handlers)(void *);
|
||||||
|
void (*reserved[4])();
|
||||||
};
|
};
|
||||||
|
|
||||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -24,12 +24,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* static_assert is a C++11 feature, but seems to work with C on MSVC 2015 */
|
||||||
|
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
|
||||||
|
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(e,m)
|
||||||
|
#else
|
||||||
|
#define FSP_FSCTL_STATIC_ASSERT(e,m)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
|
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
|
||||||
#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
|
#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
|
||||||
#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
|
#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
|
||||||
|
|
||||||
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
|
|
||||||
|
|
||||||
// {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54}
|
// {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54}
|
||||||
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
|
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
|
||||||
{ 0x6f9d25fa, 0x6dee, 0x4a9d, { 0x80, 0xf5, 0xe9, 0x8e, 0x14, 0xf3, 0x5e, 0x54 } };
|
{ 0x6f9d25fa, 0x6dee, 0x4a9d, { 0x80, 0xf5, 0xe9, 0x8e, 0x14, 0xf3, 0x5e, 0x54 } };
|
||||||
@ -55,15 +60,26 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
|
|||||||
#define FSP_FSCTL_STOP \
|
#define FSP_FSCTL_STOP \
|
||||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
|
|
||||||
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
|
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
|
||||||
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (64 * sizeof(WCHAR))
|
|
||||||
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
|
|
||||||
|
|
||||||
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */
|
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
|
||||||
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */
|
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (192 * sizeof(WCHAR))
|
||||||
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN 16384
|
#define FSP_FSCTL_VOLUME_FSNAME_SIZE (16 * sizeof(WCHAR))
|
||||||
|
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
|
||||||
|
"Max volume name size is greater than MAX_PATH.");
|
||||||
|
|
||||||
|
#define FSP_FSCTL_TRANSACT_PATH_SIZEMAX (1024 * sizeof(WCHAR))
|
||||||
|
|
||||||
|
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (16 * 1024 - 64) /* 64: size for internal request header */
|
||||||
|
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (16 * 1024)
|
||||||
|
#define FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX (FSP_FSCTL_TRANSACT_REQ_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_REQ))
|
||||||
|
#define FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX (FSP_FSCTL_TRANSACT_RSP_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_RSP))
|
||||||
|
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
|
||||||
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
|
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
|
||||||
|
|
||||||
|
#define FSP_FSCTL_TRANSACT_USERCONTEXT(s,i) (((PUINT64)&(s).UserContext)[i])
|
||||||
|
|
||||||
/* marshalling */
|
/* marshalling */
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
||||||
@ -90,6 +106,7 @@ enum
|
|||||||
FspFsctlTransactLockControlKind,
|
FspFsctlTransactLockControlKind,
|
||||||
FspFsctlTransactQuerySecurityKind,
|
FspFsctlTransactQuerySecurityKind,
|
||||||
FspFsctlTransactSetSecurityKind,
|
FspFsctlTransactSetSecurityKind,
|
||||||
|
FspFsctlTransactQueryStreamInformationKind,
|
||||||
FspFsctlTransactKindCount,
|
FspFsctlTransactKindCount,
|
||||||
};
|
};
|
||||||
enum
|
enum
|
||||||
@ -124,12 +141,20 @@ typedef struct
|
|||||||
UINT32 CasePreservedNames:1; /* file system preserves the case of file names */
|
UINT32 CasePreservedNames:1; /* file system preserves the case of file names */
|
||||||
UINT32 UnicodeOnDisk:1; /* file system supports Unicode in file names */
|
UINT32 UnicodeOnDisk:1; /* file system supports Unicode in file names */
|
||||||
UINT32 PersistentAcls:1; /* file system preserves and enforces access control lists */
|
UINT32 PersistentAcls:1; /* file system preserves and enforces access control lists */
|
||||||
UINT32 ReparsePoints:1; /* file system supports reparse points (!!!: unimplemented) */
|
UINT32 ReparsePoints:1; /* file system supports reparse points */
|
||||||
UINT32 NamedStreams:1; /* file system supports named streams (!!!: unimplemented) */
|
UINT32 ReparsePointsAccessCheck:1; /* file system performs reparse point access checks */
|
||||||
|
UINT32 NamedStreams:1; /* file system supports named streams */
|
||||||
UINT32 HardLinks:1; /* unimplemented; set to 0 */
|
UINT32 HardLinks:1; /* unimplemented; set to 0 */
|
||||||
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
|
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
|
||||||
UINT32 ReadOnlyVolume:1;
|
UINT32 ReadOnlyVolume:1;
|
||||||
|
/* kernel-mode flags */
|
||||||
|
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
|
||||||
|
UINT32 KmReservedFlags:5;
|
||||||
|
/* user-mode flags */
|
||||||
|
UINT32 UmFileNodeIsUserContext2:1; /* user mode: FileNode parameter is UserContext2 */
|
||||||
|
UINT32 UmReservedFlags:15;
|
||||||
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */
|
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */
|
||||||
|
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||||
} FSP_FSCTL_VOLUME_PARAMS;
|
} FSP_FSCTL_VOLUME_PARAMS;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -160,6 +185,13 @@ typedef struct
|
|||||||
WCHAR FileNameBuf[];
|
WCHAR FileNameBuf[];
|
||||||
} FSP_FSCTL_DIR_INFO;
|
} FSP_FSCTL_DIR_INFO;
|
||||||
typedef struct
|
typedef struct
|
||||||
|
{
|
||||||
|
UINT16 Size;
|
||||||
|
UINT64 StreamSize;
|
||||||
|
UINT64 StreamAllocationSize;
|
||||||
|
WCHAR StreamNameBuf[];
|
||||||
|
} FSP_FSCTL_STREAM_INFO;
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT16 Offset;
|
UINT16 Offset;
|
||||||
UINT16 Size;
|
UINT16 Size;
|
||||||
@ -186,6 +218,8 @@ typedef struct
|
|||||||
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
|
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
|
||||||
UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */
|
UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */
|
||||||
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
|
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
|
||||||
|
UINT32 ReservedFlags:28;
|
||||||
|
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
|
||||||
} Create;
|
} Create;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -288,6 +322,14 @@ typedef struct
|
|||||||
FSP_FSCTL_TRANSACT_BUF Pattern;
|
FSP_FSCTL_TRANSACT_BUF Pattern;
|
||||||
} QueryDirectory;
|
} QueryDirectory;
|
||||||
struct
|
struct
|
||||||
|
{
|
||||||
|
UINT64 UserContext;
|
||||||
|
UINT64 UserContext2;
|
||||||
|
UINT32 FsControlCode;
|
||||||
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
|
UINT16 TargetOnFileSystem; /* the target of the symbolic link is on this file system */
|
||||||
|
} FileSystemControl;
|
||||||
|
struct
|
||||||
{
|
{
|
||||||
UINT64 UserContext;
|
UINT64 UserContext;
|
||||||
UINT64 UserContext2;
|
UINT64 UserContext2;
|
||||||
@ -300,6 +342,11 @@ typedef struct
|
|||||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
UINT64 AccessToken; /* request access token (HANDLE) */
|
||||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||||
} SetSecurity;
|
} SetSecurity;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
UINT64 UserContext;
|
||||||
|
UINT64 UserContext2;
|
||||||
|
} QueryStreamInformation;
|
||||||
} Req;
|
} Req;
|
||||||
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */
|
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */
|
||||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
||||||
@ -330,7 +377,7 @@ typedef struct
|
|||||||
/* IoStatus.Status == STATUS_REPARSE */
|
/* IoStatus.Status == STATUS_REPARSE */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_BUF FileName; /* file name to use for STATUS_REPARSE */
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
} Reparse;
|
} Reparse;
|
||||||
} Create;
|
} Create;
|
||||||
struct
|
struct
|
||||||
@ -358,6 +405,10 @@ typedef struct
|
|||||||
FSP_FSCTL_VOLUME_INFO VolumeInfo;
|
FSP_FSCTL_VOLUME_INFO VolumeInfo;
|
||||||
} SetVolumeInformation;
|
} SetVolumeInformation;
|
||||||
struct
|
struct
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
|
} FileSystemControl;
|
||||||
|
struct
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||||
} QuerySecurity;
|
} QuerySecurity;
|
||||||
@ -365,6 +416,10 @@ typedef struct
|
|||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* Size==0 means no security descriptor returned */
|
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* Size==0 means no security descriptor returned */
|
||||||
} SetSecurity;
|
} SetSecurity;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
|
} QueryStreamInformation;
|
||||||
} Rsp;
|
} Rsp;
|
||||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
||||||
} FSP_FSCTL_TRANSACT_RSP;
|
} FSP_FSCTL_TRANSACT_RSP;
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -40,13 +40,51 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The REPARSE_DATA_BUFFER definitions appear to be missing from the user mode headers.
|
||||||
|
*/
|
||||||
|
#if !defined(SYMLINK_FLAG_RELATIVE)
|
||||||
|
#define SYMLINK_FLAG_RELATIVE 1
|
||||||
|
#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
|
||||||
|
typedef struct _REPARSE_DATA_BUFFER
|
||||||
|
{
|
||||||
|
ULONG ReparseTag;
|
||||||
|
USHORT ReparseDataLength;
|
||||||
|
USHORT Reserved;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
ULONG Flags;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} SymbolicLinkReparseBuffer;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} MountPointReparseBuffer;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
UCHAR DataBuffer[1];
|
||||||
|
} GenericReparseBuffer;
|
||||||
|
} DUMMYUNIONNAME;
|
||||||
|
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group File System
|
* @group File System
|
||||||
*
|
*
|
||||||
* A user mode file system is a program that uses the WinFsp API to expose a file system to
|
* A user mode file system is a program that uses the WinFsp API to expose a file system to
|
||||||
* Windows. The user mode file system must implement the operations in FSP_FILE_SYSTEM_INTERFACE,
|
* Windows. The user mode file system must implement the operations in FSP_FILE_SYSTEM_INTERFACE,
|
||||||
* create a file system object using FspFileSystemCreate and start its dispatcher using
|
* create a file system object using FspFileSystemCreate and start its dispatcher using
|
||||||
* FspFileSystemStartDispatcher. At that point it will start receing file system requests on the
|
* FspFileSystemStartDispatcher. At that point it will start receiving file system requests on the
|
||||||
* FSP_FILE_SYSTEM_INTERFACE operations.
|
* FSP_FILE_SYSTEM_INTERFACE operations.
|
||||||
*/
|
*/
|
||||||
typedef struct _FSP_FILE_SYSTEM FSP_FILE_SYSTEM;
|
typedef struct _FSP_FILE_SYSTEM FSP_FILE_SYSTEM;
|
||||||
@ -54,6 +92,36 @@ typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION_GUARD(FSP_FILE_SYSTEM *,
|
|||||||
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
||||||
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *,
|
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *,
|
||||||
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
||||||
|
/**
|
||||||
|
* User mode file system locking strategy.
|
||||||
|
*
|
||||||
|
* Two concurrency models are provided:
|
||||||
|
*
|
||||||
|
* 1. A fine-grained concurrency model where file system NAMESPACE accesses
|
||||||
|
* are guarded using an exclusive-shared (read-write) lock. File I/O is not
|
||||||
|
* guarded and concurrent reads/writes/etc. are possible. [Note that the FSD
|
||||||
|
* will still apply an exclusive-shared lock PER INDIVIDUAL FILE, but it will
|
||||||
|
* not limit I/O operations for different files.]
|
||||||
|
*
|
||||||
|
* The fine-grained concurrency model applies the exclusive-shared lock as
|
||||||
|
* follows:
|
||||||
|
* <ul>
|
||||||
|
* <li>EXCL: SetVolumeLabel, Flush(Volume),
|
||||||
|
* Create, Cleanup(Delete), SetInformation(Rename)</li>
|
||||||
|
* <li>SHRD: GetVolumeInfo, Open, SetInformation(Disposition), ReadDirectory</li>
|
||||||
|
* <li>NONE: all other operations</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* 2. A coarse-grained concurrency model where all file system accesses are
|
||||||
|
* guarded by a mutually exclusive lock.
|
||||||
|
*
|
||||||
|
* @see FspFileSystemSetOperationGuardStrategy
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
||||||
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
|
||||||
|
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
|
||||||
/**
|
/**
|
||||||
* @class FSP_FILE_SYSTEM
|
* @class FSP_FILE_SYSTEM
|
||||||
* File system interface.
|
* File system interface.
|
||||||
@ -74,7 +142,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the volume information on successful return
|
* Pointer to a structure that will receive the volume information on successful return
|
||||||
* from this call.
|
* from this call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -92,7 +160,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the volume information on successful return
|
* Pointer to a structure that will receive the volume information on successful return
|
||||||
* from this call.
|
* from this call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -108,6 +176,10 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param PFileAttributes
|
* @param PFileAttributes
|
||||||
* Pointer to a memory location that will receive the file attributes on successful return
|
* Pointer to a memory location that will receive the file attributes on successful return
|
||||||
* from this call. May be NULL.
|
* from this call. May be NULL.
|
||||||
|
*
|
||||||
|
* If this call returns STATUS_REPARSE, the file system MAY place here the index of the
|
||||||
|
* first reparse point within FileName. The file system MAY also leave this at its default
|
||||||
|
* value of 0.
|
||||||
* @param SecurityDescriptor
|
* @param SecurityDescriptor
|
||||||
* Pointer to a buffer that will receive the file security descriptor on successful return
|
* Pointer to a buffer that will receive the file security descriptor on successful return
|
||||||
* from this call. May be NULL.
|
* from this call. May be NULL.
|
||||||
@ -116,10 +188,14 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* security descriptor buffer. On output it will contain the actual size of the security
|
* security descriptor buffer. On output it will contain the actual size of the security
|
||||||
* descriptor copied into the security descriptor buffer. May be NULL.
|
* descriptor copied into the security descriptor buffer. May be NULL.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS, STATUS_REPARSE or error code.
|
||||||
|
*
|
||||||
|
* STATUS_REPARSE should be returned by file systems that support reparse points when
|
||||||
|
* they encounter a FileName that contains reparse points anywhere but the final path
|
||||||
|
* component.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetSecurityByName)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetSecurityByName)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
PWSTR FileName, PUINT32 PFileAttributes,
|
PWSTR FileName, PUINT32 PFileAttributes/* or ReparsePointIndex */,
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize);
|
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize);
|
||||||
/**
|
/**
|
||||||
* Create new file or directory.
|
* Create new file or directory.
|
||||||
@ -158,7 +234,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -193,7 +269,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -217,7 +293,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -242,6 +318,10 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* tested to see if the delete can proceed and if the answer is positive the file is then
|
* tested to see if the delete can proceed and if the answer is positive the file is then
|
||||||
* deleted during Cleanup.
|
* deleted during Cleanup.
|
||||||
*
|
*
|
||||||
|
* As an optimization a file system may specify the FSP_FSCTL_VOLUME_PARAMS ::
|
||||||
|
* PostCleanupOnDeleteOnly flag. In this case the FSD will only post Cleanup requests when a
|
||||||
|
* file is being deleted.
|
||||||
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
* @param Request
|
||||||
@ -292,7 +372,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param PBytesTransferred [out]
|
* @param PBytesTransferred [out]
|
||||||
* Pointer to a memory location that will receive the actual number of bytes read.
|
* Pointer to a memory location that will receive the actual number of bytes read.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code. STATUS_PENDING is supported allowing for asynchronous
|
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -325,7 +405,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code. STATUS_PENDING is supported allowing for asynchronous
|
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -345,7 +425,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param FileNode
|
* @param FileNode
|
||||||
* The file node of the file to be flushed. When NULL the whole volume is being flushed.
|
* The file node of the file to be flushed. When NULL the whole volume is being flushed.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -363,7 +443,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -394,7 +474,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -435,7 +515,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -463,7 +543,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param FileName
|
* @param FileName
|
||||||
* The name of the file or directory to test for deletion.
|
* The name of the file or directory to test for deletion.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
* @see
|
* @see
|
||||||
* Cleanup
|
* Cleanup
|
||||||
*/
|
*/
|
||||||
@ -495,7 +575,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param ReplaceIfExists
|
* @param ReplaceIfExists
|
||||||
* Whether to replace a file that already exists at NewFileName.
|
* Whether to replace a file that already exists at NewFileName.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -516,7 +596,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* security descriptor buffer. On output it will contain the actual size of the security
|
* security descriptor buffer. On output it will contain the actual size of the security
|
||||||
* descriptor copied into the security descriptor buffer. Cannot be NULL.
|
* descriptor copied into the security descriptor buffer. Cannot be NULL.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -535,7 +615,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Security descriptor to apply to the file or directory. This security descriptor will
|
* Security descriptor to apply to the file or directory. This security descriptor will
|
||||||
* always be in self-relative format.
|
* always be in self-relative format.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -566,7 +646,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param PBytesTransferred [out]
|
* @param PBytesTransferred [out]
|
||||||
* Pointer to a memory location that will receive the actual number of bytes read.
|
* Pointer to a memory location that will receive the actual number of bytes read.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code. STATUS_PENDING is supported allowing for asynchronous
|
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
|
||||||
* operation.
|
* operation.
|
||||||
* @see
|
* @see
|
||||||
* FspFileSystemAddDirInfo
|
* FspFileSystemAddDirInfo
|
||||||
@ -576,26 +656,156 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PWSTR Pattern,
|
PWSTR Pattern,
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
|
/**
|
||||||
|
* Resolve reparse points.
|
||||||
|
*
|
||||||
|
* Reparse points are a general mechanism for attaching special behavior to files.
|
||||||
|
* A file or directory can contain a reparse point. A reparse point is data that has
|
||||||
|
* special meaning to the file system, Windows or user applications. For example, NTFS
|
||||||
|
* and Windows use reparse points to implement symbolic links. As another example,
|
||||||
|
* a particular file system may use reparse points to emulate UNIX FIFO's.
|
||||||
|
*
|
||||||
|
* This function is expected to resolve as many reparse points as possible. If a reparse
|
||||||
|
* point is encountered that is not understood by the file system further reparse point
|
||||||
|
* resolution should stop; the reparse point data should be returned to the FSD with status
|
||||||
|
* STATUS_REPARSE/reparse-tag. If a reparse point (symbolic link) is encountered that is
|
||||||
|
* understood by the file system but points outside it, the reparse point should be
|
||||||
|
* resolved, but further reparse point resolution should stop; the resolved file name
|
||||||
|
* should be returned to the FSD with status STATUS_REPARSE/IO_REPARSE.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param FileName
|
||||||
|
* The name of the file or directory to have its reparse points resolved.
|
||||||
|
* @param ReparsePointIndex
|
||||||
|
* The index of the first reparse point within FileName.
|
||||||
|
* @param ResolveLastPathComponent
|
||||||
|
* If FALSE, the last path component of FileName should not be resolved, even
|
||||||
|
* if it is a reparse point that can be resolved. If TRUE, all path components
|
||||||
|
* should be resolved if possible.
|
||||||
|
* @param PIoStatus
|
||||||
|
* Pointer to storage that will receive the status to return to the FSD. When
|
||||||
|
* this function succeeds it must set PIoStatus->Status to STATUS_REPARSE and
|
||||||
|
* PIoStatus->Information to either IO_REPARSE or the reparse tag.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the resolved file name (IO_REPARSE) or
|
||||||
|
* reparse data (reparse tag). If the function returns a file name, it should
|
||||||
|
* not be NULL terminated.
|
||||||
|
* @param PSize [in,out]
|
||||||
|
* Pointer to the buffer size. On input it contains the size of the buffer.
|
||||||
|
* On output it will contain the actual size of data copied.
|
||||||
|
* @return
|
||||||
|
* STATUS_REPARSE or error code.
|
||||||
|
*/
|
||||||
|
NTSTATUS (*ResolveReparsePoints)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
||||||
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
/**
|
||||||
|
* Get reparse point.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the reparse point.
|
||||||
|
* @param FileName
|
||||||
|
* The file name of the reparse point.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the results of this operation. If
|
||||||
|
* the function returns a symbolic link path, it should not be NULL terminated.
|
||||||
|
* @param PSize [in,out]
|
||||||
|
* Pointer to the buffer size. On input it contains the size of the buffer.
|
||||||
|
* On output it will contain the actual size of data copied.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* SetReparsePoint
|
||||||
|
*/
|
||||||
|
NTSTATUS (*GetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
/**
|
||||||
|
* Set reparse point.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the reparse point.
|
||||||
|
* @param FileName
|
||||||
|
* The file name of the reparse point.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that contains the data for this operation. If this buffer
|
||||||
|
* contains a symbolic link path, it should not be assumed to be NULL terminated.
|
||||||
|
* @param Size
|
||||||
|
* Size of data to write.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* GetReparsePoint
|
||||||
|
*/
|
||||||
|
NTSTATUS (*SetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
|
/**
|
||||||
|
* Delete reparse point.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the reparse point.
|
||||||
|
* @param FileName
|
||||||
|
* The file name of the reparse point.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that contains the data for this operation.
|
||||||
|
* @param Size
|
||||||
|
* Size of data to write.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
*/
|
||||||
|
NTSTATUS (*DeleteReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
|
/**
|
||||||
|
* Get named streams information.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the file or directory to get stream information for.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the stream information.
|
||||||
|
* @param Length
|
||||||
|
* Length of buffer.
|
||||||
|
* @param PBytesTransferred [out]
|
||||||
|
* Pointer to a memory location that will receive the actual number of bytes stored.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* FspFileSystemAddStreamInfo
|
||||||
|
*/
|
||||||
|
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode, PVOID Buffer, ULONG Length,
|
||||||
|
PULONG PBytesTransferred);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This ensures that this interface will always contain 64 function pointers.
|
* This ensures that this interface will always contain 64 function pointers.
|
||||||
* Please update when changing the interface as it is important for future compatibility.
|
* Please update when changing the interface as it is important for future compatibility.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Reserved[45])();
|
NTSTATUS (*Reserved[40])();
|
||||||
} FSP_FILE_SYSTEM_INTERFACE;
|
} FSP_FILE_SYSTEM_INTERFACE;
|
||||||
#if defined(WINFSP_DLL_INTERNAL)
|
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||||
/*
|
|
||||||
* Static_assert is a C++11 feature, but seems to work with C on MSVC 2015.
|
|
||||||
* Use it to verify that FSP_FILE_SYSTEM_INTERFACE has the right size.
|
|
||||||
*/
|
|
||||||
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
|
||||||
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||||
#endif
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
|
|
||||||
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
|
|
||||||
typedef struct _FSP_FILE_SYSTEM
|
typedef struct _FSP_FILE_SYSTEM
|
||||||
{
|
{
|
||||||
UINT16 Version;
|
UINT16 Version;
|
||||||
@ -613,6 +823,7 @@ typedef struct _FSP_FILE_SYSTEM
|
|||||||
UINT32 DebugLog;
|
UINT32 DebugLog;
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||||
SRWLOCK OpGuardLock;
|
SRWLOCK OpGuardLock;
|
||||||
|
BOOLEAN UmFileNodeIsUserContext2;
|
||||||
} FSP_FILE_SYSTEM;
|
} FSP_FILE_SYSTEM;
|
||||||
/**
|
/**
|
||||||
* Create a file system object.
|
* Create a file system object.
|
||||||
@ -628,7 +839,7 @@ typedef struct _FSP_FILE_SYSTEM
|
|||||||
* Pointer that will receive the file system object created on successful return from this
|
* Pointer that will receive the file system object created on successful return from this
|
||||||
* call.
|
* call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||||
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
||||||
@ -654,7 +865,7 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
* The mount point for the new file system. A value of NULL means that the file system should
|
* The mount point for the new file system. A value of NULL means that the file system should
|
||||||
* use the next available drive letter counting downwards from Z: as its mount point.
|
* use the next available drive letter counting downwards from Z: as its mount point.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
|
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
|
||||||
/**
|
/**
|
||||||
@ -677,7 +888,7 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
* The number of threads for the file system dispatcher. A value of 0 will create a default
|
* The number of threads for the file system dispatcher. A value of 0 will create a default
|
||||||
* number of threads and should be chosen in most cases.
|
* number of threads and should be chosen in most cases.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG ThreadCount);
|
FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG ThreadCount);
|
||||||
/**
|
/**
|
||||||
@ -740,6 +951,16 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FileSystem->EnterOperation = EnterOperation;
|
FileSystem->EnterOperation = EnterOperation;
|
||||||
FileSystem->LeaveOperation = LeaveOperation;
|
FileSystem->LeaveOperation = LeaveOperation;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Set file system locking strategy.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system object.
|
||||||
|
* @param GuardStrategy
|
||||||
|
* The locking (guard) strategy.
|
||||||
|
* @see
|
||||||
|
* FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY
|
||||||
|
*/
|
||||||
static inline
|
static inline
|
||||||
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
|
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
|
||||||
@ -807,10 +1028,14 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
|
FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
|
FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers
|
* Helpers
|
||||||
@ -841,6 +1066,140 @@ FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
*/
|
*/
|
||||||
FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo,
|
FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo,
|
||||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||||
|
/**
|
||||||
|
* Find reparse point in file name.
|
||||||
|
*
|
||||||
|
* Given a file name this function returns an index to the first path component that is a reparse
|
||||||
|
* point. The function will call the supplied GetReparsePointByName function for every path
|
||||||
|
* component until it finds a reparse point or the whole path is processed.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the GetSecurityByName operation in file systems
|
||||||
|
* that support reparse points.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system object.
|
||||||
|
* @param GetReparsePointByName
|
||||||
|
* Pointer to function that can retrieve reparse point information by name. The
|
||||||
|
* FspFileSystemFindReparsePoint will call this function with the Buffer and PSize
|
||||||
|
* arguments set to NULL. The function should return STATUS_SUCCESS if the passed
|
||||||
|
* FileName is a reparse point or STATUS_NOT_A_REPARSE_POINT (or other error code)
|
||||||
|
* otherwise.
|
||||||
|
* @param Context
|
||||||
|
* User context to supply to GetReparsePointByName.
|
||||||
|
* @param FileName
|
||||||
|
* The name of the file or directory.
|
||||||
|
* @param PReparsePointIndex
|
||||||
|
* Pointer to a memory location that will receive the index of the first reparse point
|
||||||
|
* within FileName. A value is only placed in this memory location if the function returns
|
||||||
|
* TRUE. May be NULL.
|
||||||
|
* @return
|
||||||
|
* TRUE if a reparse point was found, FALSE otherwise.
|
||||||
|
* @see
|
||||||
|
* GetSecurityByName
|
||||||
|
*/
|
||||||
|
FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
NTSTATUS (*GetReparsePointByName)(
|
||||||
|
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||||
|
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),
|
||||||
|
PVOID Context,
|
||||||
|
PWSTR FileName, PUINT32 PReparsePointIndex);
|
||||||
|
/**
|
||||||
|
* Resolve reparse points.
|
||||||
|
*
|
||||||
|
* Given a file name (and an index where to start resolving) this function will attempt to
|
||||||
|
* resolve as many reparse points as possible. The function will call the supplied
|
||||||
|
* GetReparsePointByName function for every path component until it resolves the reparse points
|
||||||
|
* or the whole path is processed.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the ResolveReparsePoints operation in file systems
|
||||||
|
* that support reparse points.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system object.
|
||||||
|
* @param GetReparsePointByName
|
||||||
|
* Pointer to function that can retrieve reparse point information by name. The function
|
||||||
|
* should return STATUS_SUCCESS if the passed FileName is a reparse point or
|
||||||
|
* STATUS_NOT_A_REPARSE_POINT (or other error code) otherwise.
|
||||||
|
* @param Context
|
||||||
|
* User context to supply to GetReparsePointByName.
|
||||||
|
* @param FileName
|
||||||
|
* The name of the file or directory to have its reparse points resolved.
|
||||||
|
* @param ReparsePointIndex
|
||||||
|
* The index of the first reparse point within FileName.
|
||||||
|
* @param ResolveLastPathComponent
|
||||||
|
* If FALSE, the last path component of FileName should not be resolved, even
|
||||||
|
* if it is a reparse point that can be resolved. If TRUE, all path components
|
||||||
|
* should be resolved if possible.
|
||||||
|
* @param PIoStatus
|
||||||
|
* Pointer to storage that will receive the status to return to the FSD. When
|
||||||
|
* this function succeeds it must set PIoStatus->Status to STATUS_REPARSE and
|
||||||
|
* PIoStatus->Information to either IO_REPARSE or the reparse tag.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the resolved file name (IO_REPARSE) or
|
||||||
|
* reparse data (reparse tag). If the function returns a file name, it should
|
||||||
|
* not be NULL terminated.
|
||||||
|
* @param PSize [in,out]
|
||||||
|
* Pointer to the buffer size. On input it contains the size of the buffer.
|
||||||
|
* On output it will contain the actual size of data copied.
|
||||||
|
* @return
|
||||||
|
* STATUS_REPARSE or error code.
|
||||||
|
* @see
|
||||||
|
* ResolveReparsePoints
|
||||||
|
*/
|
||||||
|
FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
NTSTATUS (*GetReparsePointByName)(
|
||||||
|
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||||
|
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),
|
||||||
|
PVOID Context,
|
||||||
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
||||||
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
/**
|
||||||
|
* Test whether reparse data can be replaced.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the SetReparsePoint/DeleteReparsePoint operation
|
||||||
|
* in file systems that support reparse points.
|
||||||
|
*
|
||||||
|
* @param CurrentReparseData
|
||||||
|
* Pointer to the current reparse data.
|
||||||
|
* @param CurrentReparseDataSize
|
||||||
|
* Pointer to the current reparse data size.
|
||||||
|
* @param ReplaceReparseData
|
||||||
|
* Pointer to the replacement reparse data.
|
||||||
|
* @param ReplaceReparseDataSize
|
||||||
|
* Pointer to the replacement reparse data size.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* SetReparsePoint
|
||||||
|
* DeleteReparsePoint
|
||||||
|
*/
|
||||||
|
FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
|
||||||
|
PVOID CurrentReparseData, SIZE_T CurrentReparseDataSize,
|
||||||
|
PVOID ReplaceReparseData, SIZE_T ReplaceReparseDataSize);
|
||||||
|
/**
|
||||||
|
* Add named stream information to a buffer.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the GetStreamInfo operation.
|
||||||
|
*
|
||||||
|
* @param StreamInfo
|
||||||
|
* The stream information to add. A value of NULL acts as an EOF marker for a GetStreamInfo
|
||||||
|
* operation.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the stream information. This should contain
|
||||||
|
* the same value passed to the GetStreamInfo Buffer parameter.
|
||||||
|
* @param Length
|
||||||
|
* Length of buffer. This should contain the same value passed to the GetStreamInfo
|
||||||
|
* Length parameter.
|
||||||
|
* @param PBytesTransferred [out]
|
||||||
|
* Pointer to a memory location that will receive the actual number of bytes stored. This should
|
||||||
|
* contain the same value passed to the GetStreamInfo PBytesTransferred parameter.
|
||||||
|
* @return
|
||||||
|
* TRUE if the stream information was added, FALSE if there was not enough space to add it.
|
||||||
|
* @see
|
||||||
|
* GetStreamInfo
|
||||||
|
*/
|
||||||
|
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
|
||||||
|
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Security
|
* Security
|
||||||
@ -848,8 +1207,8 @@ FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo,
|
|||||||
FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID);
|
FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID);
|
||||||
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
|
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
|
||||||
UINT32 DesiredAccess, PUINT32 PGrantedAccess,
|
UINT32 DesiredAccess, PUINT32 PGrantedAccess/* or ReparsePointIndex */,
|
||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
||||||
FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -864,11 +1223,11 @@ FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
|
|||||||
static inline
|
static inline
|
||||||
NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
|
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
|
||||||
UINT32 DesiredAccess, PUINT32 PGrantedAccess)
|
UINT32 DesiredAccess, PUINT32 PGrantedAccess)
|
||||||
{
|
{
|
||||||
return FspAccessCheckEx(FileSystem, Request,
|
return FspAccessCheckEx(FileSystem, Request,
|
||||||
CheckParentDirectory, AllowTraverseCheck,
|
CheckParentOrMain, AllowTraverseCheck,
|
||||||
DesiredAccess, PGrantedAccess,
|
DesiredAccess, PGrantedAccess,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
@ -885,8 +1244,20 @@ FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
|
|||||||
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
|
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||||
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode);
|
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode);
|
||||||
FSP_API NTSTATUS FspPosixMapWindowsToPosixPath(PWSTR WindowsPath, char **PPosixPath);
|
FSP_API NTSTATUS FspPosixMapWindowsToPosixPathEx(PWSTR WindowsPath, char **PPosixPath,
|
||||||
FSP_API NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPath);
|
BOOLEAN Translate);
|
||||||
|
FSP_API NTSTATUS FspPosixMapPosixToWindowsPathEx(const char *PosixPath, PWSTR *PWindowsPath,
|
||||||
|
BOOLEAN Translate);
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspPosixMapWindowsToPosixPath(PWSTR WindowsPath, char **PPosixPath)
|
||||||
|
{
|
||||||
|
return FspPosixMapWindowsToPosixPathEx(WindowsPath, PPosixPath, TRUE);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPath)
|
||||||
|
{
|
||||||
|
return FspPosixMapPosixToWindowsPathEx(PosixPath, PWindowsPath, TRUE);
|
||||||
|
}
|
||||||
FSP_API VOID FspPosixDeletePath(void *Path);
|
FSP_API VOID FspPosixDeletePath(void *Path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -973,7 +1344,7 @@ ULONG FspServiceRun(PWSTR ServiceName,
|
|||||||
* Pointer that will receive the service object created on successful return from this
|
* Pointer that will receive the service object created on successful return from this
|
||||||
* call.
|
* call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
|
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
|
||||||
FSP_SERVICE_START *OnStart,
|
FSP_SERVICE_START *OnStart,
|
||||||
@ -1053,7 +1424,7 @@ FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service);
|
|||||||
* @param Service
|
* @param Service
|
||||||
* The service object.
|
* The service object.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
|
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
|
||||||
/**
|
/**
|
||||||
@ -1066,7 +1437,7 @@ FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
|
|||||||
* @param Service
|
* @param Service
|
||||||
* The service object.
|
* The service object.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
|
FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
|
||||||
/**
|
/**
|
||||||
@ -1098,9 +1469,10 @@ FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error);
|
|||||||
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status);
|
FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status);
|
||||||
FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...);
|
FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...);
|
||||||
FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
|
FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
|
||||||
FSP_API VOID FspDebugLog(const char *format, ...);
|
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle);
|
||||||
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor);
|
FSP_API VOID FspDebugLog(const char *Format, ...);
|
||||||
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime);
|
FSP_API VOID FspDebugLogSD(const char *Format, PSECURITY_DESCRIPTOR SecurityDescriptor);
|
||||||
|
FSP_API VOID FspDebugLogFT(const char *Format, PFILETIME FileTime);
|
||||||
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
|
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
NAME="fuse"
|
NAME="fuse"
|
||||||
VERSION=2.8
|
VERSION=2.8
|
||||||
RELEASE=2
|
RELEASE=3
|
||||||
CATEGORY="Utils"
|
CATEGORY="Utils"
|
||||||
SUMMARY="WinFsp-FUSE compatibility layer"
|
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||||
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||||
|
192
src/dll/debug.c
192
src/dll/debug.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -19,6 +19,13 @@
|
|||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
static HANDLE FspDebugLogHandle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle)
|
||||||
|
{
|
||||||
|
FspDebugLogHandle = Handle;
|
||||||
|
}
|
||||||
|
|
||||||
FSP_API VOID FspDebugLog(const char *format, ...)
|
FSP_API VOID FspDebugLog(const char *format, ...)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@ -28,7 +35,13 @@ FSP_API VOID FspDebugLog(const char *format, ...)
|
|||||||
wvsprintfA(buf, format, ap);
|
wvsprintfA(buf, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
buf[sizeof buf - 1] = '\0';
|
buf[sizeof buf - 1] = '\0';
|
||||||
OutputDebugStringA(buf);
|
if (INVALID_HANDLE_VALUE != FspDebugLogHandle)
|
||||||
|
{
|
||||||
|
DWORD bytes;
|
||||||
|
WriteFile(FspDebugLogHandle, buf, lstrlenA(buf), &bytes, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OutputDebugStringA(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor)
|
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||||
@ -161,6 +174,98 @@ static const char *FspDebugLogVolumeInfoString(FSP_FSCTL_VOLUME_INFO *VolumeInfo
|
|||||||
return Buf;
|
return Buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *FspDebugLogWideCharBufferString(PVOID WideCharBuf, ULONG Length, char *Buf)
|
||||||
|
{
|
||||||
|
WCHAR TempWideCharBuf[64 + 1];
|
||||||
|
|
||||||
|
if (Length > sizeof TempWideCharBuf - sizeof(WCHAR))
|
||||||
|
Length = sizeof TempWideCharBuf - sizeof(WCHAR);
|
||||||
|
|
||||||
|
memcpy(TempWideCharBuf, WideCharBuf, Length);
|
||||||
|
TempWideCharBuf[Length / sizeof(WCHAR)] = L'\0';
|
||||||
|
|
||||||
|
wsprintfA(Buf, "%.64S", TempWideCharBuf);
|
||||||
|
|
||||||
|
return Buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PREPARSE_DATA_BUFFER D;
|
||||||
|
PREPARSE_GUID_DATA_BUFFER G;
|
||||||
|
} ReparseData;
|
||||||
|
char SubstituteName[64 + 1], PrintName[64 + 1];
|
||||||
|
|
||||||
|
ReparseData.D = ReparseData0;
|
||||||
|
if (0 == ReparseData.D->ReparseDataLength)
|
||||||
|
wsprintfA(Buf,
|
||||||
|
"{"
|
||||||
|
"ReparseTag=%#lx, "
|
||||||
|
"ReparseDataLength=%hu"
|
||||||
|
"}",
|
||||||
|
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
|
||||||
|
else if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData.D->ReparseTag)
|
||||||
|
wsprintfA(Buf,
|
||||||
|
"{"
|
||||||
|
"ReparseTag=IO_REPARSE_TAG_MOUNT_POINT, "
|
||||||
|
"SubstituteName=\"%s\", "
|
||||||
|
"PrintName=\"%s\""
|
||||||
|
"}",
|
||||||
|
FspDebugLogWideCharBufferString(
|
||||||
|
ReparseData.D->MountPointReparseBuffer.PathBuffer +
|
||||||
|
ReparseData.D->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||||
|
ReparseData.D->MountPointReparseBuffer.SubstituteNameLength,
|
||||||
|
SubstituteName),
|
||||||
|
FspDebugLogWideCharBufferString(
|
||||||
|
ReparseData.D->MountPointReparseBuffer.PathBuffer +
|
||||||
|
ReparseData.D->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR),
|
||||||
|
ReparseData.D->MountPointReparseBuffer.PrintNameLength,
|
||||||
|
PrintName));
|
||||||
|
else if (IO_REPARSE_TAG_SYMLINK == ReparseData.D->ReparseTag)
|
||||||
|
wsprintfA(Buf,
|
||||||
|
"{"
|
||||||
|
"ReparseTag=IO_REPARSE_TAG_SYMLINK, "
|
||||||
|
"SubstituteName=\"%s\", "
|
||||||
|
"PrintName=\"%s\", "
|
||||||
|
"Flags=%u"
|
||||||
|
"}",
|
||||||
|
FspDebugLogWideCharBufferString(
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameLength,
|
||||||
|
SubstituteName),
|
||||||
|
FspDebugLogWideCharBufferString(
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR),
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameLength,
|
||||||
|
PrintName),
|
||||||
|
ReparseData.D->SymbolicLinkReparseBuffer.Flags);
|
||||||
|
else if (IsReparseTagMicrosoft(ReparseData.D->ReparseTag))
|
||||||
|
wsprintfA(Buf,
|
||||||
|
"{"
|
||||||
|
"ReparseTag=%#lx, "
|
||||||
|
"ReparseDataLength=%hu"
|
||||||
|
"}",
|
||||||
|
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
|
||||||
|
else
|
||||||
|
#define Guid ReparseData.G->ReparseGuid
|
||||||
|
wsprintfA(Buf,
|
||||||
|
"{"
|
||||||
|
"ReparseTag=%#lx, "
|
||||||
|
"ReparseDataLength=%hu, "
|
||||||
|
"ReparseGuid={%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
|
||||||
|
"}",
|
||||||
|
ReparseData.G->ReparseTag, ReparseData.G->ReparseDataLength,
|
||||||
|
Guid.Data1, Guid.Data2, Guid.Data3,
|
||||||
|
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
|
||||||
|
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
|
||||||
|
#undef Guid
|
||||||
|
|
||||||
|
return Buf;
|
||||||
|
}
|
||||||
|
|
||||||
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
|
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
|
||||||
{
|
{
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
|
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
|
||||||
@ -178,6 +283,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
{
|
{
|
||||||
char UserContextBuf[40];
|
char UserContextBuf[40];
|
||||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32];
|
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32];
|
||||||
|
char InfoBuf[256];
|
||||||
char *Sddl = 0;
|
char *Sddl = 0;
|
||||||
|
|
||||||
switch (Request->Kind)
|
switch (Request->Kind)
|
||||||
@ -368,6 +474,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
FspDebugLogUserContextString(
|
FspDebugLogUserContextString(
|
||||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||||
UserContextBuf));
|
UserContextBuf));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FspFsctlTransactQueryEaKind:
|
case FspFsctlTransactQueryEaKind:
|
||||||
@ -423,7 +530,45 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
|
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
|
||||||
break;
|
break;
|
||||||
case FspFsctlTransactFileSystemControlKind:
|
case FspFsctlTransactFileSystemControlKind:
|
||||||
FspDebugLogRequestVoid(Request, "FILESYSTEMCONTROL");
|
switch (Request->Req.FileSystemControl.FsControlCode)
|
||||||
|
{
|
||||||
|
case FSCTL_GET_REPARSE_POINT:
|
||||||
|
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
|
||||||
|
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||||
|
Request->FileName.Size ? "\"" : "",
|
||||||
|
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||||
|
Request->FileName.Size ? "\", " : "",
|
||||||
|
FspDebugLogUserContextString(
|
||||||
|
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||||
|
UserContextBuf));
|
||||||
|
break;
|
||||||
|
case FSCTL_SET_REPARSE_POINT:
|
||||||
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
|
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
|
||||||
|
"ReparseData=%s\n",
|
||||||
|
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||||
|
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
|
||||||
|
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
|
||||||
|
Request->FileName.Size ? "\"" : "",
|
||||||
|
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||||
|
Request->FileName.Size ? "\", " : "",
|
||||||
|
FspDebugLogUserContextString(
|
||||||
|
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||||
|
UserContextBuf),
|
||||||
|
FspDebugLogReparseDataString(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||||
|
InfoBuf));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %s%S%s%s\n",
|
||||||
|
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||||
|
Request->FileName.Size ? "\"" : "",
|
||||||
|
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||||
|
Request->FileName.Size ? "\", " : "",
|
||||||
|
FspDebugLogUserContextString(
|
||||||
|
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||||
|
UserContextBuf));
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case FspFsctlTransactDeviceControlKind:
|
case FspFsctlTransactDeviceControlKind:
|
||||||
FspDebugLogRequestVoid(Request, "DEVICECONTROL");
|
FspDebugLogRequestVoid(Request, "DEVICECONTROL");
|
||||||
@ -492,11 +637,27 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
|||||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||||
FspDebugLogResponseStatus(Response, "Create");
|
FspDebugLogResponseStatus(Response, "Create");
|
||||||
else if (STATUS_REPARSE == Response->IoStatus.Status)
|
else if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
{
|
||||||
"Reparse.FileName=\"%S\"\n",
|
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
|
||||||
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
"Reparse.FileName=\"%s\"\n",
|
||||||
(PWSTR)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset));
|
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||||
|
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||||
|
FspDebugLogWideCharBufferString(
|
||||||
|
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||||
|
Response->Rsp.Create.Reparse.Buffer.Size,
|
||||||
|
InfoBuf));
|
||||||
|
else if (1/*IO_REMOUNT*/ == Response->IoStatus.Information)
|
||||||
|
FspDebugLogResponseStatus(Response, "Create");
|
||||||
|
else
|
||||||
|
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||||
|
"Reparse.Data=\"%s\"\n",
|
||||||
|
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||||
|
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||||
|
FspDebugLogReparseDataString(
|
||||||
|
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||||
|
InfoBuf));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||||
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
|
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
|
||||||
@ -590,7 +751,16 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
|||||||
FspDebugLogResponseStatus(Response, "QueryDirectory");
|
FspDebugLogResponseStatus(Response, "QueryDirectory");
|
||||||
break;
|
break;
|
||||||
case FspFsctlTransactFileSystemControlKind:
|
case FspFsctlTransactFileSystemControlKind:
|
||||||
FspDebugLogResponseStatus(Response, "FILESYSTEMCONTROL");
|
if (!NT_SUCCESS(Response->IoStatus.Status) ||
|
||||||
|
0 == Response->Rsp.FileSystemControl.Buffer.Size)
|
||||||
|
FspDebugLogResponseStatus(Response, "FileSystemControl");
|
||||||
|
else
|
||||||
|
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
|
||||||
|
"ReparseData=%s\n",
|
||||||
|
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
|
||||||
|
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||||
|
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||||
|
InfoBuf));
|
||||||
break;
|
break;
|
||||||
case FspFsctlTransactDeviceControlKind:
|
case FspFsctlTransactDeviceControlKind:
|
||||||
FspDebugLogResponseStatus(Response, "DEVICECONTROL");
|
FspDebugLogResponseStatus(Response, "DEVICECONTROL");
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -1,63 +1,63 @@
|
|||||||
//
|
//
|
||||||
// Values are 32 bit values laid out as follows:
|
// Values are 32 bit values laid out as follows:
|
||||||
//
|
//
|
||||||
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||||
// +---+-+-+-----------------------+-------------------------------+
|
// +---+-+-+-----------------------+-------------------------------+
|
||||||
// |Sev|C|R| Facility | Code |
|
// |Sev|C|R| Facility | Code |
|
||||||
// +---+-+-+-----------------------+-------------------------------+
|
// +---+-+-+-----------------------+-------------------------------+
|
||||||
//
|
//
|
||||||
// where
|
// where
|
||||||
//
|
//
|
||||||
// Sev - is the severity code
|
// Sev - is the severity code
|
||||||
//
|
//
|
||||||
// 00 - Success
|
// 00 - Success
|
||||||
// 01 - Informational
|
// 01 - Informational
|
||||||
// 10 - Warning
|
// 10 - Warning
|
||||||
// 11 - Error
|
// 11 - Error
|
||||||
//
|
//
|
||||||
// C - is the Customer code flag
|
// C - is the Customer code flag
|
||||||
//
|
//
|
||||||
// R - is a reserved bit
|
// R - is a reserved bit
|
||||||
//
|
//
|
||||||
// Facility - is the facility code
|
// Facility - is the facility code
|
||||||
//
|
//
|
||||||
// Code - is the facility's status code
|
// Code - is the facility's status code
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Define the facility codes
|
// Define the facility codes
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Define the severity codes
|
// Define the severity codes
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// MessageId: FSP_EVENTLOG_INFORMATION
|
// MessageId: FSP_EVENTLOG_INFORMATION
|
||||||
//
|
//
|
||||||
// MessageText:
|
// MessageText:
|
||||||
//
|
//
|
||||||
// %1: %2
|
// %1: %2
|
||||||
//
|
//
|
||||||
#define FSP_EVENTLOG_INFORMATION 0x60000001L
|
#define FSP_EVENTLOG_INFORMATION 0x60000001L
|
||||||
|
|
||||||
//
|
//
|
||||||
// MessageId: FSP_EVENTLOG_WARNING
|
// MessageId: FSP_EVENTLOG_WARNING
|
||||||
//
|
//
|
||||||
// MessageText:
|
// MessageText:
|
||||||
//
|
//
|
||||||
// %1: %2
|
// %1: %2
|
||||||
//
|
//
|
||||||
#define FSP_EVENTLOG_WARNING 0xA0000001L
|
#define FSP_EVENTLOG_WARNING 0xA0000001L
|
||||||
|
|
||||||
//
|
//
|
||||||
// MessageId: FSP_EVENTLOG_ERROR
|
// MessageId: FSP_EVENTLOG_ERROR
|
||||||
//
|
//
|
||||||
// MessageText:
|
// MessageText:
|
||||||
//
|
//
|
||||||
// %1: %2
|
// %1: %2
|
||||||
//
|
//
|
||||||
#define FSP_EVENTLOG_ERROR 0xE0000001L
|
#define FSP_EVENTLOG_ERROR 0xE0000001L
|
||||||
|
|
||||||
|
10
src/dll/fs.c
10
src/dll/fs.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -96,8 +96,10 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
|||||||
FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation;
|
FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation;
|
||||||
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
|
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
|
||||||
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
|
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
|
||||||
|
FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl;
|
||||||
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
|
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
|
||||||
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
|
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
|
||||||
|
FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation;
|
||||||
FileSystem->Interface = Interface;
|
FileSystem->Interface = Interface;
|
||||||
|
|
||||||
FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
|
FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
|
||||||
@ -105,6 +107,8 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
|||||||
FileSystem->EnterOperation = FspFileSystemOpEnter;
|
FileSystem->EnterOperation = FspFileSystemOpEnter;
|
||||||
FileSystem->LeaveOperation = FspFileSystemOpLeave;
|
FileSystem->LeaveOperation = FspFileSystemOpLeave;
|
||||||
|
|
||||||
|
FileSystem->UmFileNodeIsUserContext2 = !!VolumeParams->UmFileNodeIsUserContext2;
|
||||||
|
|
||||||
*PFileSystem = FileSystem;
|
*PFileSystem = FileSystem;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -32,7 +32,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
PWSTR DeviceRoot;
|
PWSTR DeviceRoot;
|
||||||
SIZE_T DeviceRootSize, DevicePathSize;
|
SIZE_T DeviceRootSize, DevicePathSize;
|
||||||
WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr, *DevicePathEnd;
|
WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd;
|
||||||
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
|
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
|
||||||
DWORD Bytes;
|
DWORD Bytes;
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
|
|||||||
VolumeNameBuf[0] = L'\0';
|
VolumeNameBuf[0] = L'\0';
|
||||||
*PVolumeHandle = INVALID_HANDLE_VALUE;
|
*PVolumeHandle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
/* check lengths; everything (including encoded volume params) must fit within MAX_PATH */
|
/* check lengths; everything (including encoded volume params) must fit within DevicePathBuf */
|
||||||
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
|
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
|
||||||
DeviceRootSize = lstrlenW(DeviceRoot) * sizeof(WCHAR);
|
DeviceRootSize = lstrlenW(DeviceRoot) * sizeof(WCHAR);
|
||||||
DevicePathSize = lstrlenW(DevicePath) * sizeof(WCHAR);
|
DevicePathSize = lstrlenW(DevicePath) * sizeof(WCHAR);
|
||||||
@ -132,7 +132,9 @@ exit:
|
|||||||
|
|
||||||
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle)
|
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle)
|
||||||
{
|
{
|
||||||
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, 0, 0))
|
DWORD Bytes;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, &Bytes, 0))
|
||||||
return FspNtStatusFromWin32(GetLastError());
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
773
src/dll/fsop.c
773
src/dll/fsop.c
File diff suppressed because it is too large
Load Diff
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -37,10 +37,11 @@ struct fsp_fuse_core_opt_data
|
|||||||
set_umask, umask,
|
set_umask, umask,
|
||||||
set_uid, uid,
|
set_uid, uid,
|
||||||
set_gid, gid,
|
set_gid, gid,
|
||||||
set_attr_timeout, attr_timeout;
|
set_attr_timeout, attr_timeout,
|
||||||
|
rellinks;
|
||||||
int set_FileInfoTimeout;
|
int set_FileInfoTimeout;
|
||||||
int CaseInsensitiveSearch, ReparsePoints,
|
int CaseInsensitiveSearch,
|
||||||
NamedStreams, ReadOnlyVolume;
|
ReadOnlyVolume;
|
||||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,6 +79,11 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
|||||||
FUSE_OPT_KEY("intr_signal=", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("intr_signal=", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("modules=", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("modules=", FUSE_OPT_KEY_DISCARD),
|
||||||
|
|
||||||
|
FSP_FUSE_CORE_OPT("rellinks", rellinks, 1),
|
||||||
|
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
|
||||||
|
|
||||||
|
FUSE_OPT_KEY("fstypename=", 'F'),
|
||||||
|
|
||||||
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
||||||
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
||||||
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
||||||
@ -89,13 +95,14 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
|||||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
|
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
|
||||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
||||||
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
|
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
|
||||||
FSP_FUSE_CORE_OPT("ReparsePoints", ReparsePoints, 1),
|
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
|
||||||
FSP_FUSE_CORE_OPT("NamedStreams", NamedStreams, 1),
|
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
|
||||||
|
FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
|
||||||
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
|
|
||||||
FUSE_OPT_KEY("--UNC=", 'U'),
|
FUSE_OPT_KEY("--UNC=", 'U'),
|
||||||
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
||||||
|
FUSE_OPT_KEY("--FileSystemName=", 'F'),
|
||||||
|
|
||||||
FUSE_OPT_END,
|
FUSE_OPT_END,
|
||||||
};
|
};
|
||||||
@ -449,10 +456,9 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
|||||||
" -o VolumeSerialNumber=N 32-bit wide\n"
|
" -o VolumeSerialNumber=N 32-bit wide\n"
|
||||||
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
|
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
|
||||||
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
|
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
|
||||||
//" -o ReparsePoints file system supports reparse points\n"
|
|
||||||
//" -o NamedStreams file system supports named streams\n"
|
|
||||||
//" -o ReadOnlyVolume file system is read only\n"
|
//" -o ReadOnlyVolume file system is read only\n"
|
||||||
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n");
|
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
|
||||||
|
" --FileSystemName=FSN Name of user mode file system\n");
|
||||||
opt_data->help = 1;
|
opt_data->help = 1;
|
||||||
return 1;
|
return 1;
|
||||||
case 'V':
|
case 'V':
|
||||||
@ -463,12 +469,27 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
|||||||
return 1;
|
return 1;
|
||||||
case 'U':
|
case 'U':
|
||||||
if ('U' == arg[2])
|
if ('U' == arg[2])
|
||||||
arg += sizeof "--UNC" - 1;
|
arg += sizeof "--UNC=" - 1;
|
||||||
else if ('V' == arg[2])
|
else if ('V' == arg[2])
|
||||||
arg += sizeof "--VolumePrefix" - 1;
|
arg += sizeof "--VolumePrefix=" - 1;
|
||||||
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
|
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
|
||||||
opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR)))
|
opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR)))
|
||||||
return -1;
|
return -1;
|
||||||
|
opt_data->VolumeParams.Prefix
|
||||||
|
[sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0';
|
||||||
|
return 0;
|
||||||
|
case 'F':
|
||||||
|
if ('f' == arg[0])
|
||||||
|
arg += sizeof "fstypename=" - 1;
|
||||||
|
else if ('F' == arg[2])
|
||||||
|
arg += sizeof "--FileSystemName=" - 1;
|
||||||
|
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
|
||||||
|
opt_data->VolumeParams.FileSystemName + 5,
|
||||||
|
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR)) - 5)
|
||||||
|
return -1;
|
||||||
|
opt_data->VolumeParams.FileSystemName
|
||||||
|
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
|
||||||
|
memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,15 +519,24 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
|||||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
||||||
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
|
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
|
||||||
opt_data.VolumeParams.PersistentAcls = TRUE;
|
opt_data.VolumeParams.PersistentAcls = TRUE;
|
||||||
opt_data.VolumeParams.ReparsePoints = !!opt_data.ReparsePoints;
|
opt_data.VolumeParams.ReparsePoints = TRUE;
|
||||||
opt_data.VolumeParams.NamedStreams = !!opt_data.NamedStreams;
|
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
|
||||||
|
opt_data.VolumeParams.NamedStreams = FALSE;
|
||||||
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
|
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
|
||||||
|
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
|
||||||
|
opt_data.VolumeParams.UmFileNodeIsUserContext2 = TRUE;
|
||||||
|
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||||
|
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||||
|
|
||||||
f = fsp_fuse_obj_alloc(env, sizeof *f);
|
f = fsp_fuse_obj_alloc(env, sizeof *f);
|
||||||
if (0 == f)
|
if (0 == f)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
f->env = env;
|
f->env = env;
|
||||||
|
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
|
||||||
|
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
|
||||||
|
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
|
||||||
|
f->rellinks = opt_data.rellinks;
|
||||||
memcpy(&f->ops, ops, opsize);
|
memcpy(&f->ops, ops, opsize);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
f->DebugLog = opt_data.debug ? -1 : 0;
|
f->DebugLog = opt_data.debug ? -1 : 0;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -29,9 +29,15 @@
|
|||||||
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \
|
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \
|
||||||
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
|
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
|
||||||
|
|
||||||
|
#define FSP_FUSE_HAS_SYMLINKS(f) (0 != (f)->ops.readlink)
|
||||||
|
|
||||||
struct fuse
|
struct fuse
|
||||||
{
|
{
|
||||||
struct fsp_fuse_env *env;
|
struct fsp_fuse_env *env;
|
||||||
|
int set_umask, umask;
|
||||||
|
int set_uid, uid;
|
||||||
|
int set_gid, gid;
|
||||||
|
int rellinks;
|
||||||
struct fuse_operations ops;
|
struct fuse_operations ops;
|
||||||
void *data;
|
void *data;
|
||||||
UINT32 DebugLog;
|
UINT32 DebugLog;
|
||||||
@ -45,8 +51,6 @@ struct fuse
|
|||||||
|
|
||||||
struct fsp_fuse_context_header
|
struct fsp_fuse_context_header
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
|
||||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
|
||||||
char *PosixPath;
|
char *PosixPath;
|
||||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
|
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
|
||||||
};
|
};
|
||||||
@ -54,7 +58,7 @@ struct fsp_fuse_context_header
|
|||||||
struct fsp_fuse_file_desc
|
struct fsp_fuse_file_desc
|
||||||
{
|
{
|
||||||
char *PosixPath;
|
char *PosixPath;
|
||||||
BOOLEAN IsDirectory;
|
BOOLEAN IsDirectory, IsReparsePoint;
|
||||||
int OpenFlags;
|
int OpenFlags;
|
||||||
UINT64 FileHandle;
|
UINT64 FileHandle;
|
||||||
PVOID DirBuffer;
|
PVOID DirBuffer;
|
||||||
@ -86,4 +90,12 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
|
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
|
||||||
|
|
||||||
|
/* NFS reparse points */
|
||||||
|
|
||||||
|
#define NFS_SPECFILE_FIFO 0x000000004F464946
|
||||||
|
#define NFS_SPECFILE_CHR 0x0000000000524843
|
||||||
|
#define NFS_SPECFILE_BLK 0x00000000004b4c42
|
||||||
|
#define NFS_SPECFILE_LNK 0x00000000014b4e4c
|
||||||
|
#define NFS_SPECFILE_SOCK 0x000000004B434F53
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -53,4 +53,17 @@ PWSTR FspDiagIdent(VOID);
|
|||||||
|
|
||||||
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
|
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
|
||||||
|
|
||||||
|
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
|
||||||
|
{
|
||||||
|
WCHAR Root[2] = L"\\";
|
||||||
|
PWSTR Remain, Suffix;
|
||||||
|
ULONG Result;
|
||||||
|
|
||||||
|
FspPathSuffix(FileName, &Remain, &Suffix, Root);
|
||||||
|
Result = Remain == Root ? 0 : (ULONG)(Suffix - Remain);
|
||||||
|
FspPathCombine(FileName, Suffix);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
338
src/dll/np.c
338
src/dll/np.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -18,10 +18,29 @@
|
|||||||
#include <dll/library.h>
|
#include <dll/library.h>
|
||||||
#include <launcher/launcher.h>
|
#include <launcher/launcher.h>
|
||||||
#include <npapi.h>
|
#include <npapi.h>
|
||||||
|
#include <wincred.h>
|
||||||
|
|
||||||
#define FSP_NP_NAME LIBRARY_NAME ".Np"
|
#define FSP_NP_NAME LIBRARY_NAME ".Np"
|
||||||
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
|
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define the following macro to use CredUIPromptForWindowsCredentials.
|
||||||
|
* Otherwise CredUIPromptForCredentials will be used.
|
||||||
|
*/
|
||||||
|
#define FSP_NP_CREDUI_PROMPT_NEW
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define the following macro to include support for the credential manager.
|
||||||
|
*/
|
||||||
|
#define FSP_NP_CREDENTIAL_MANAGER
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FSP_NP_CREDENTIALS_NONE = 0,
|
||||||
|
FSP_NP_CREDENTIALS_PASSWORD = 1,
|
||||||
|
FSP_NP_CREDENTIALS_USERPASS = 3,
|
||||||
|
};
|
||||||
|
|
||||||
DWORD APIENTRY NPGetCaps(DWORD Index)
|
DWORD APIENTRY NPGetCaps(DWORD Index)
|
||||||
{
|
{
|
||||||
switch (Index)
|
switch (Index)
|
||||||
@ -102,6 +121,9 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
|
|||||||
PWSTR ClassName, InstanceName, P;
|
PWSTR ClassName, InstanceName, P;
|
||||||
ULONG ClassNameLen, InstanceNameLen;
|
ULONG ClassNameLen, InstanceNameLen;
|
||||||
|
|
||||||
|
if (!FspNpCheckRemoteName(RemoteName))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
ClassName = RemoteName + 2; /* skip \\ */
|
ClassName = RemoteName + 2; /* skip \\ */
|
||||||
for (P = ClassName; *P; P++)
|
for (P = ClassName; *P; P++)
|
||||||
if (L'\\' == *P)
|
if (L'\\' == *P)
|
||||||
@ -129,6 +151,27 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
|
||||||
|
PWSTR UserName, ULONG UserNameSize/* in chars */)
|
||||||
|
{
|
||||||
|
PWSTR ClassName, InstanceName, P;
|
||||||
|
ULONG ClassNameLen, InstanceNameLen;
|
||||||
|
|
||||||
|
if (FspNpParseRemoteName(RemoteName,
|
||||||
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
||||||
|
{
|
||||||
|
for (P = InstanceName; *P; P++)
|
||||||
|
if ('@' == *P && (ULONG)(P - InstanceName) < UserNameSize)
|
||||||
|
{
|
||||||
|
memcpy(UserName, InstanceName, (P - InstanceName) * sizeof(WCHAR));
|
||||||
|
UserName[P - InstanceName] = L'\0';
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
|
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
|
||||||
{
|
{
|
||||||
DWORD NpResult;
|
DWORD NpResult;
|
||||||
@ -225,6 +268,144 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
|
||||||
|
{
|
||||||
|
HKEY RegKey = 0;
|
||||||
|
DWORD NpResult, RegSize;
|
||||||
|
DWORD Credentials;
|
||||||
|
PWSTR ClassName, InstanceName;
|
||||||
|
ULONG ClassNameLen, InstanceNameLen;
|
||||||
|
WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
||||||
|
|
||||||
|
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
|
||||||
|
|
||||||
|
if (!FspNpParseRemoteName(RemoteName,
|
||||||
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
||||||
|
return WN_BAD_NETNAME;
|
||||||
|
|
||||||
|
if (ClassNameLen > sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1)
|
||||||
|
ClassNameLen = sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1;
|
||||||
|
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
|
||||||
|
ClassNameBuf[ClassNameLen] = '\0';
|
||||||
|
|
||||||
|
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
|
||||||
|
if (ERROR_SUCCESS != NpResult)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
RegSize = sizeof Credentials;
|
||||||
|
Credentials = 0; /* default is NO credentials */
|
||||||
|
NpResult = RegGetValueW(RegKey, ClassNameBuf, L"Credentials", RRF_RT_REG_DWORD, 0,
|
||||||
|
&Credentials, &RegSize);
|
||||||
|
if (ERROR_SUCCESS != NpResult && ERROR_FILE_NOT_FOUND != NpResult)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
switch (Credentials)
|
||||||
|
{
|
||||||
|
case FSP_NP_CREDENTIALS_NONE:
|
||||||
|
case FSP_NP_CREDENTIALS_PASSWORD:
|
||||||
|
case FSP_NP_CREDENTIALS_USERPASS:
|
||||||
|
*PCredentialsKind = Credentials;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NpResult = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != RegKey)
|
||||||
|
RegCloseKey(RegKey);
|
||||||
|
|
||||||
|
return NpResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD FspNpGetCredentials(
|
||||||
|
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
|
||||||
|
DWORD CredentialsKind,
|
||||||
|
PBOOL PSave,
|
||||||
|
PWSTR UserName, ULONG UserNameSize/* in chars */,
|
||||||
|
PWSTR Password, ULONG PasswordSize/* in chars */)
|
||||||
|
{
|
||||||
|
DWORD NpResult;
|
||||||
|
CREDUI_INFOW UiInfo;
|
||||||
|
|
||||||
|
memset(&UiInfo, 0, sizeof UiInfo);
|
||||||
|
UiInfo.cbSize = sizeof UiInfo;
|
||||||
|
UiInfo.hwndParent = hwndOwner;
|
||||||
|
UiInfo.pszCaptionText = Caption;
|
||||||
|
UiInfo.pszMessageText = L"Enter credentials to unlock this file system.";
|
||||||
|
|
||||||
|
#if !defined(FSP_NP_CREDUI_PROMPT_NEW)
|
||||||
|
NpResult = CredUIPromptForCredentialsW(&UiInfo, L"NONE", 0, 0,
|
||||||
|
UserName, UserNameSize,
|
||||||
|
Password, PasswordSize,
|
||||||
|
PSave,
|
||||||
|
CREDUI_FLAGS_GENERIC_CREDENTIALS |
|
||||||
|
CREDUI_FLAGS_DO_NOT_PERSIST |
|
||||||
|
CREDUI_FLAGS_ALWAYS_SHOW_UI |
|
||||||
|
(0 != PrevNpResult ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0) |
|
||||||
|
(0 != PSave ? CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX : 0) |
|
||||||
|
(FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0));
|
||||||
|
#else
|
||||||
|
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
|
||||||
|
ULONG AuthPackage = 0;
|
||||||
|
PVOID InAuthBuf = 0, OutAuthBuf = 0;
|
||||||
|
ULONG InAuthSize, OutAuthSize, DomainSize;
|
||||||
|
|
||||||
|
InAuthSize = 0;
|
||||||
|
if (!CredPackAuthenticationBufferW(
|
||||||
|
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, 0, &InAuthSize) &&
|
||||||
|
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||||
|
{
|
||||||
|
NpResult = GetLastError();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
InAuthBuf = MemAlloc(InAuthSize);
|
||||||
|
if (0 == InAuthBuf)
|
||||||
|
{
|
||||||
|
NpResult = ERROR_NO_SYSTEM_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CredPackAuthenticationBufferW(
|
||||||
|
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, InAuthBuf, &InAuthSize))
|
||||||
|
{
|
||||||
|
NpResult = GetLastError();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
|
||||||
|
&AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave,
|
||||||
|
CREDUIWIN_GENERIC | (0 != PSave ? CREDUIWIN_CHECKBOX : 0));
|
||||||
|
if (ERROR_SUCCESS != NpResult)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
DomainSize = sizeof Domain / sizeof Domain[0];
|
||||||
|
if (!CredUnPackAuthenticationBufferW(0, OutAuthBuf, OutAuthSize,
|
||||||
|
UserName, &UserNameSize, Domain, &DomainSize, Password, &PasswordSize))
|
||||||
|
{
|
||||||
|
NpResult = GetLastError();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
NpResult = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != OutAuthBuf)
|
||||||
|
{
|
||||||
|
SecureZeroMemory(OutAuthBuf, OutAuthSize);
|
||||||
|
CoTaskMemFree(OutAuthBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != InAuthBuf)
|
||||||
|
{
|
||||||
|
SecureZeroMemory(InAuthBuf, InAuthSize);
|
||||||
|
MemFree(InAuthBuf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NpResult;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD APIENTRY NPGetConnection(
|
DWORD APIENTRY NPGetConnection(
|
||||||
LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
|
LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
|
||||||
{
|
{
|
||||||
@ -303,12 +484,6 @@ DWORD APIENTRY NPGetConnection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
|
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
|
||||||
{
|
|
||||||
return NPAddConnection3(0, lpNetResource, lpPassword, lpUserName, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
|
||||||
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
|
|
||||||
{
|
{
|
||||||
DWORD NpResult;
|
DWORD NpResult;
|
||||||
DWORD dwType = lpNetResource->dwType;
|
DWORD dwType = lpNetResource->dwType;
|
||||||
@ -317,14 +492,15 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
|||||||
WCHAR LocalNameBuf[3];
|
WCHAR LocalNameBuf[3];
|
||||||
PWSTR ClassName, InstanceName, RemoteName, P;
|
PWSTR ClassName, InstanceName, RemoteName, P;
|
||||||
ULONG ClassNameLen, InstanceNameLen;
|
ULONG ClassNameLen, InstanceNameLen;
|
||||||
|
DWORD CredentialsKind;
|
||||||
PWSTR PipeBuf = 0;
|
PWSTR PipeBuf = 0;
|
||||||
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||||
|
PCREDENTIALW Credential = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (dwType & RESOURCETYPE_PRINT)
|
if (dwType & RESOURCETYPE_PRINT)
|
||||||
return WN_BAD_VALUE;
|
return WN_BAD_VALUE;
|
||||||
|
|
||||||
if (!FspNpCheckRemoteName(lpRemoteName))
|
|
||||||
return WN_BAD_NETNAME;
|
|
||||||
|
|
||||||
if (!FspNpParseRemoteName(lpRemoteName,
|
if (!FspNpParseRemoteName(lpRemoteName,
|
||||||
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
||||||
return WN_BAD_NETNAME;
|
return WN_BAD_NETNAME;
|
||||||
@ -344,22 +520,75 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
|||||||
return WN_ALREADY_CONNECTED;
|
return WN_ALREADY_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
|
||||||
|
|
||||||
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||||
|
/* if we need credentials and none were passed check with the credential manager */
|
||||||
|
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind && 0 == lpPassword &&
|
||||||
|
CredReadW(lpRemoteName, CRED_TYPE_GENERIC, 0, &Credential))
|
||||||
|
{
|
||||||
|
if (sizeof(WCHAR) <= Credential->CredentialBlobSize &&
|
||||||
|
L'\0' == ((PWSTR)(Credential->CredentialBlob))
|
||||||
|
[(Credential->CredentialBlobSize / sizeof(WCHAR)) - 1])
|
||||||
|
{
|
||||||
|
lpUserName = Credential->UserName;
|
||||||
|
lpPassword = (PVOID)Credential->CredentialBlob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* if we need credentials and we don't have any return ACCESS DENIED */
|
||||||
|
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
|
||||||
|
{
|
||||||
|
int Length;
|
||||||
|
if (0 == lpPassword ||
|
||||||
|
(0 == (Length = lstrlenW(lpPassword))) || CREDUI_MAX_PASSWORD_LENGTH < Length)
|
||||||
|
{
|
||||||
|
NpResult = WN_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
|
||||||
|
{
|
||||||
|
int Length;
|
||||||
|
if (0 == lpUserName ||
|
||||||
|
(0 == (Length = lstrlenW(lpUserName))) || CREDUI_MAX_USERNAME_LENGTH < Length)
|
||||||
|
{
|
||||||
|
NpResult = WN_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
|
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
|
||||||
if (0 == PipeBuf)
|
if (0 == PipeBuf)
|
||||||
return WN_OUT_OF_MEMORY;
|
{
|
||||||
|
NpResult = WN_OUT_OF_MEMORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we do not explicitly check, but assumption is it all fits in LAUNCHER_PIPE_BUFFER_SIZE */
|
||||||
P = PipeBuf;
|
P = PipeBuf;
|
||||||
*P++ = LauncherSvcInstanceStart;
|
*P++ = FSP_NP_CREDENTIALS_NONE != CredentialsKind ?
|
||||||
|
LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
|
||||||
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
|
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
|
||||||
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
||||||
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
|
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
|
||||||
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
|
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
|
||||||
|
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
|
||||||
|
{
|
||||||
|
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;
|
||||||
|
}
|
||||||
|
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
|
||||||
|
{
|
||||||
|
lstrcpyW(P, lpPassword); P += lstrlenW(lpPassword) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
NpResult = FspNpCallLauncherPipe(
|
NpResult = FspNpCallLauncherPipe(
|
||||||
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
|
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
|
||||||
switch (NpResult)
|
switch (NpResult)
|
||||||
{
|
{
|
||||||
case WN_SUCCESS:
|
case WN_SUCCESS:
|
||||||
|
case WN_ACCESS_DENIED:
|
||||||
break;
|
break;
|
||||||
case ERROR_ALREADY_EXISTS:
|
case ERROR_ALREADY_EXISTS:
|
||||||
/*
|
/*
|
||||||
@ -393,8 +622,89 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
MemFree(PipeBuf);
|
MemFree(PipeBuf);
|
||||||
|
|
||||||
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||||
|
if (0 != Credential)
|
||||||
|
CredFree(Credential);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NpResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
||||||
|
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
DWORD NpResult;
|
||||||
|
PWSTR RemoteName = lpNetResource->lpRemoteName;
|
||||||
|
DWORD CredentialsKind;
|
||||||
|
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
||||||
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||||
|
BOOL Save = TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//dwFlags |= CONNECT_INTERACTIVE | CONNECT_PROMPT; /* TESTING ONLY! */
|
||||||
|
|
||||||
|
/* CONNECT_PROMPT is only valid if CONNECT_INTERACTIVE is also set */
|
||||||
|
if (CONNECT_PROMPT == (dwFlags & (CONNECT_INTERACTIVE | CONNECT_PROMPT)))
|
||||||
|
return WN_BAD_VALUE;
|
||||||
|
|
||||||
|
/* if not CONNECT_PROMPT go ahead and attempt to NPAddConnection once */
|
||||||
|
if (0 == (dwFlags & CONNECT_PROMPT))
|
||||||
|
{
|
||||||
|
NpResult = NPAddConnection(lpNetResource, lpPassword, lpUserName);
|
||||||
|
if (WN_ACCESS_DENIED != NpResult || 0 == (dwFlags & CONNECT_INTERACTIVE))
|
||||||
|
return NpResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspNpGetCredentialsKind(RemoteName, &CredentialsKind);
|
||||||
|
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
|
||||||
|
return WN_CANCEL;
|
||||||
|
|
||||||
|
/* if CONNECT_INTERACTIVE keep asking the user for valid credentials or cancel */
|
||||||
|
NpResult = WN_SUCCESS;
|
||||||
|
lstrcpyW(UserName, L"UNSPECIFIED");
|
||||||
|
Password[0] = L'\0';
|
||||||
|
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
|
||||||
|
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
NpResult = FspNpGetCredentials(
|
||||||
|
hwndOwner, RemoteName, NpResult,
|
||||||
|
CredentialsKind,
|
||||||
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||||
|
&Save,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
UserName, sizeof UserName / sizeof UserName[0],
|
||||||
|
Password, sizeof Password / sizeof Password[0]);
|
||||||
|
if (WN_SUCCESS != NpResult)
|
||||||
|
break;
|
||||||
|
|
||||||
|
NpResult = NPAddConnection(lpNetResource, Password, UserName);
|
||||||
|
} while (WN_ACCESS_DENIED == NpResult);
|
||||||
|
|
||||||
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
||||||
|
if (WN_SUCCESS == NpResult && Save)
|
||||||
|
{
|
||||||
|
CREDENTIALW Credential;
|
||||||
|
|
||||||
|
memset(&Credential, 0, sizeof Credential);
|
||||||
|
Credential.Type = CRED_TYPE_GENERIC;
|
||||||
|
Credential.Persist = CRED_PERSIST_LOCAL_MACHINE;
|
||||||
|
Credential.TargetName = RemoteName;
|
||||||
|
Credential.UserName = UserName;
|
||||||
|
Credential.CredentialBlobSize = (lstrlenW(Password) + 1) * sizeof(WCHAR);
|
||||||
|
Credential.CredentialBlob = (PVOID)Password;
|
||||||
|
|
||||||
|
CredWriteW(&Credential, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SecureZeroMemory(Password, sizeof Password);
|
||||||
|
|
||||||
return NpResult;
|
return NpResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -42,16 +42,16 @@ union
|
|||||||
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
|
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
|
||||||
} FspUnmappedSidBuf =
|
} FspUnmappedSidBuf =
|
||||||
{
|
{
|
||||||
/* S-1-5-7 (Anonymous) */
|
/* S-1-0-65534 */
|
||||||
.V.Revision = SID_REVISION,
|
.V.Revision = SID_REVISION,
|
||||||
.V.SubAuthorityCount = 1,
|
.V.SubAuthorityCount = 1,
|
||||||
.V.IdentifierAuthority.Value[5] = 5,
|
.V.IdentifierAuthority.Value[5] = 0,
|
||||||
.V.SubAuthority[0] = 7,
|
.V.SubAuthority[0] = 65534,
|
||||||
};
|
};
|
||||||
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
|
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
|
||||||
|
|
||||||
#define FspUnmappedSid (&FspUnmappedSidBuf.V)
|
#define FspUnmappedSid (&FspUnmappedSidBuf.V)
|
||||||
#define FspUnmappedUid (7)
|
#define FspUnmappedUid (65534)
|
||||||
|
|
||||||
static BOOL WINAPI FspPosixInitialize(
|
static BOOL WINAPI FspPosixInitialize(
|
||||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||||
@ -223,7 +223,7 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
|||||||
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
|
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
|
||||||
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
|
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
|
||||||
*/
|
*/
|
||||||
else if (0x1000 <= Uid && Uid < 0x100000)
|
else if (FspUnmappedUid != Uid && 0x1000 <= Uid && Uid < 0x100000)
|
||||||
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
|
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
|
||||||
|
|
||||||
if (0 == *PSid)
|
if (0 == *PSid)
|
||||||
@ -325,7 +325,9 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
|||||||
*/
|
*/
|
||||||
*PUid = 0x60000 + Rid;
|
*PUid = 0x60000 + Rid;
|
||||||
}
|
}
|
||||||
else
|
else if (
|
||||||
|
FspUnmappedSid->IdentifierAuthority.Value[5] != Authority ||
|
||||||
|
FspUnmappedSid->SubAuthority[0] != Rid)
|
||||||
{
|
{
|
||||||
/* [IDMAP]
|
/* [IDMAP]
|
||||||
* Other well-known SIDs:
|
* Other well-known SIDs:
|
||||||
@ -803,7 +805,8 @@ static UINT32 FspPosixInvalidPathChars[4] =
|
|||||||
0x00000008,
|
0x00000008,
|
||||||
};
|
};
|
||||||
|
|
||||||
FSP_API NTSTATUS FspPosixMapWindowsToPosixPath(PWSTR WindowsPath, char **PPosixPath)
|
FSP_API NTSTATUS FspPosixMapWindowsToPosixPathEx(PWSTR WindowsPath, char **PPosixPath,
|
||||||
|
BOOLEAN Translate)
|
||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
ULONG Size;
|
ULONG Size;
|
||||||
@ -826,25 +829,28 @@ FSP_API NTSTATUS FspPosixMapWindowsToPosixPath(PWSTR WindowsPath, char **PPosixP
|
|||||||
if (0 == Size)
|
if (0 == Size)
|
||||||
goto lasterror;
|
goto lasterror;
|
||||||
|
|
||||||
for (p = PosixPath, q = p; *p; p++)
|
if (Translate)
|
||||||
{
|
{
|
||||||
unsigned char c = *p;
|
for (p = PosixPath, q = p; *p; p++)
|
||||||
|
|
||||||
if ('\\' == c)
|
|
||||||
*q++ = '/';
|
|
||||||
/* encode characters in the Unicode private use area: U+F0XX -> XX */
|
|
||||||
else if (0xef == c && 0x80 == (0xfc & p[1]) && 0x80 == (0xc0 & p[2]))
|
|
||||||
{
|
{
|
||||||
c = ((p[1] & 0x3) << 6) | (p[2] & 0x3f);
|
unsigned char c = *p;
|
||||||
if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
|
||||||
*q++ = c, p += 2;
|
if ('\\' == c)
|
||||||
|
*q++ = '/';
|
||||||
|
/* encode characters in the Unicode private use area: U+F0XX -> XX */
|
||||||
|
else if (0xef == c && 0x80 == (0xfc & p[1]) && 0x80 == (0xc0 & p[2]))
|
||||||
|
{
|
||||||
|
c = ((p[1] & 0x3) << 6) | (p[2] & 0x3f);
|
||||||
|
if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
||||||
|
*q++ = c, p += 2;
|
||||||
|
else
|
||||||
|
*q++ = *p++, *q++ = *p++, *q++ = *p;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
*q++ = *p++, *q++ = *p++, *q++ = *p;
|
*q++ = c;
|
||||||
}
|
}
|
||||||
else
|
*q = '\0';
|
||||||
*q++ = c;
|
|
||||||
}
|
}
|
||||||
*q = '\0';
|
|
||||||
|
|
||||||
*PPosixPath = PosixPath;
|
*PPosixPath = PosixPath;
|
||||||
|
|
||||||
@ -861,7 +867,8 @@ lasterror:
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPath)
|
FSP_API NTSTATUS FspPosixMapPosixToWindowsPathEx(const char *PosixPath, PWSTR *PWindowsPath,
|
||||||
|
BOOLEAN Translate)
|
||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
ULONG Size;
|
ULONG Size;
|
||||||
@ -884,14 +891,17 @@ FSP_API NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWi
|
|||||||
if (0 == Size)
|
if (0 == Size)
|
||||||
goto lasterror;
|
goto lasterror;
|
||||||
|
|
||||||
for (p = WindowsPath; *p; p++)
|
if (Translate)
|
||||||
{
|
{
|
||||||
WCHAR c = *p;
|
for (p = WindowsPath; *p; p++)
|
||||||
|
{
|
||||||
|
WCHAR c = *p;
|
||||||
|
|
||||||
if (L'/' == c)
|
if (L'/' == c)
|
||||||
*p = L'\\';
|
*p = L'\\';
|
||||||
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
|
||||||
*p |= 0xf000;
|
*p |= 0xf000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*PWindowsPath = WindowsPath;
|
*PWindowsPath = WindowsPath;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -50,10 +50,21 @@ static NTSTATUS FspGetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
BOOLEAN CheckParentDirectory, BOOLEAN AllowTraverseCheck,
|
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,
|
||||||
UINT32 DesiredAccess, PUINT32 PGrantedAccess,
|
UINT32 DesiredAccess, PUINT32 PGrantedAccess,
|
||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
||||||
{
|
{
|
||||||
|
BOOLEAN CheckParentDirectory, CheckMainFile;
|
||||||
|
|
||||||
|
CheckParentDirectory = CheckMainFile = FALSE;
|
||||||
|
if (CheckParentOrMain)
|
||||||
|
{
|
||||||
|
if (!Request->Req.Create.NamedStream)
|
||||||
|
CheckParentDirectory = TRUE;
|
||||||
|
else
|
||||||
|
CheckMainFile = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
*PGrantedAccess = 0;
|
*PGrantedAccess = 0;
|
||||||
if (0 != PSecurityDescriptor)
|
if (0 != PSecurityDescriptor)
|
||||||
*PSecurityDescriptor = 0;
|
*PSecurityDescriptor = 0;
|
||||||
@ -76,17 +87,23 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
WCHAR Root[2] = L"\\", TraverseCheckRoot[2] = L"\\";
|
WCHAR Root[2] = L"\\", TraverseCheckRoot[2] = L"\\";
|
||||||
PWSTR FileName, Suffix, Prefix, Remain;
|
PWSTR FileName, Suffix, Prefix, Remain;
|
||||||
UINT32 FileAttributes;
|
UINT32 FileAttributes = 0;
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
||||||
SIZE_T SecurityDescriptorSize;
|
SIZE_T SecurityDescriptorSize;
|
||||||
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
|
UINT8 PrivilegeSetBuf[sizeof(PRIVILEGE_SET) + 15 * sizeof(LUID_AND_ATTRIBUTES)];
|
||||||
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
|
PPRIVILEGE_SET PrivilegeSet = (PVOID)PrivilegeSetBuf;
|
||||||
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
|
DWORD PrivilegeSetLength = sizeof PrivilegeSetBuf;
|
||||||
UINT32 TraverseAccess, ParentAccess, DesiredAccess2;
|
UINT32 TraverseAccess, ParentAccess, DesiredAccess2;
|
||||||
|
UINT16 NamedStreamSave;
|
||||||
BOOL AccessStatus;
|
BOOL AccessStatus;
|
||||||
|
|
||||||
if (CheckParentDirectory)
|
if (CheckParentDirectory)
|
||||||
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
|
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
|
||||||
|
else if (CheckMainFile)
|
||||||
|
{
|
||||||
|
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L'\0';
|
||||||
|
FileName = (PWSTR)Request->Buffer;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
FileName = (PWSTR)Request->Buffer;
|
FileName = (PWSTR)Request->Buffer;
|
||||||
|
|
||||||
@ -111,18 +128,54 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = FspGetSecurityByName(FileSystem, Prefix, 0,
|
FileAttributes = 0;
|
||||||
|
Result = FspGetSecurityByName(FileSystem, Prefix, &FileAttributes,
|
||||||
&SecurityDescriptor, &SecurityDescriptorSize);
|
&SecurityDescriptor, &SecurityDescriptorSize);
|
||||||
|
|
||||||
|
/* compute the ReparsePointIndex and place it in FileAttributes now */
|
||||||
|
if (NT_SUCCESS(Result) && STATUS_REPARSE != Result &&
|
||||||
|
(FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||||
|
FileAttributes = FspPathSuffixIndex(Prefix);
|
||||||
|
|
||||||
FspPathCombine(FileName, Remain);
|
FspPathCombine(FileName, Remain);
|
||||||
|
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
{
|
{
|
||||||
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
||||||
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and then immediately return
|
||||||
|
* STATUS_REPARSE. We do this check BEFORE the directory check, because
|
||||||
|
* contrary to NTFS we want to allow non-directory symlinks to directories.
|
||||||
|
*
|
||||||
|
* Note that this effectively turns off traverse checking a path comprised of
|
||||||
|
* reparse points even when the originating process does not have the Traverse
|
||||||
|
* privilege. [I am not sure what NTFS does in this case, but POSIX symlinks
|
||||||
|
* behave similarly.] We will still traverse check the reparsed path when
|
||||||
|
* the FSD sends it back to us though!
|
||||||
|
*
|
||||||
|
* Now if the reparse points are not symlinks (or symlink-like) things
|
||||||
|
* get even more complicated. Argh! Windows!
|
||||||
|
*/
|
||||||
|
if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
/* ReparsePointIndex already computed after FspGetSecurityByName call above */
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this is a directory, otherwise the path is invalid.
|
||||||
|
*/
|
||||||
|
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_PATH_NOT_FOUND; /* use STATUS_OBJECT_PATH_INVALID? */
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (0 < SecurityDescriptorSize)
|
if (0 < SecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
|
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
|
||||||
@ -136,95 +189,137 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileAttributes = 0;
|
||||||
Result = FspGetSecurityByName(FileSystem, FileName, &FileAttributes,
|
Result = FspGetSecurityByName(FileSystem, FileName, &FileAttributes,
|
||||||
&SecurityDescriptor, &SecurityDescriptorSize);
|
&SecurityDescriptor, &SecurityDescriptorSize);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
|
||||||
|
{
|
||||||
|
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
||||||
|
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||||
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
|
else
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the desired access includes the DELETE or FILE_READ_ATTRIBUTES
|
||||||
|
* (or MAXIMUM_ALLOWED) rights we must still check with our parent to
|
||||||
|
* see if it gives us access (through the FILE_DELETE_CHILD and
|
||||||
|
* FILE_LIST_DIRECTORY rights).
|
||||||
|
*
|
||||||
|
* Does the Windows security model suck? Ermmmm...
|
||||||
|
*/
|
||||||
|
if (STATUS_ACCESS_DENIED != Result ||
|
||||||
|
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
NamedStreamSave = Request->Req.Create.NamedStream;
|
||||||
|
Request->Req.Create.NamedStream = 0;
|
||||||
|
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
|
||||||
|
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
|
||||||
|
(
|
||||||
|
((DELETE & DesiredAccess) ? FILE_DELETE_CHILD : 0) |
|
||||||
|
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
|
||||||
|
),
|
||||||
|
&ParentAccess);
|
||||||
|
Request->Req.Create.NamedStream = NamedStreamSave;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
/* any failure just becomes ACCESS DENIED at this point */
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* redo the access check but remove the DELETE and/or FILE_READ_ATTRIBUTES rights */
|
||||||
|
DesiredAccess2 = DesiredAccess & ~(
|
||||||
|
((FILE_DELETE_CHILD & ParentAccess) ? DELETE : 0) |
|
||||||
|
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
||||||
|
if (0 != DesiredAccess2)
|
||||||
|
{
|
||||||
|
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
||||||
|
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||||
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
|
else
|
||||||
|
/* any failure just becomes ACCESS DENIED at this point */
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FILE_DELETE_CHILD & ParentAccess)
|
||||||
|
*PGrantedAccess |= DELETE;
|
||||||
|
if (FILE_LIST_DIRECTORY & ParentAccess)
|
||||||
|
*PGrantedAccess |= FILE_READ_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckParentDirectory)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and then immediately return
|
||||||
|
* STATUS_REPARSE. We do this check BEFORE the directory check, because
|
||||||
|
* contrary to NTFS we want to allow non-directory symlinks to directories.
|
||||||
|
*/
|
||||||
|
if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
FileAttributes = FspPathSuffixIndex(FileName);
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_NOT_A_DIRECTORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CheckMainFile)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and FILE_OPEN_REPARSE_POINT
|
||||||
|
* was not specified, in which case we return STATUS_REPARSE.
|
||||||
|
*/
|
||||||
|
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||||
|
0 == (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
|
||||||
|
{
|
||||||
|
FileAttributes = FspPathSuffixIndex(FileName);
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and FILE_OPEN_REPARSE_POINT
|
||||||
|
* was not specified, in which case we return STATUS_REPARSE.
|
||||||
|
*/
|
||||||
|
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||||
|
0 == (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
|
||||||
|
{
|
||||||
|
FileAttributes = FspPathSuffixIndex(FileName);
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) &&
|
||||||
|
0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_NOT_A_DIRECTORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if ((Request->Req.Create.CreateOptions & FILE_NON_DIRECTORY_FILE) &&
|
||||||
|
0 != (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_FILE_IS_A_DIRECTORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Request->Req.Create.UserMode)
|
if (Request->Req.Create.UserMode)
|
||||||
{
|
{
|
||||||
if (0 < SecurityDescriptorSize)
|
|
||||||
{
|
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
|
||||||
else
|
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the desired access includes the DELETE or FILE_READ_ATTRIBUTES
|
|
||||||
* (or MAXIMUM_ALLOWED) rights we must still check with our parent to
|
|
||||||
* see if it gives us access (through the FILE_DELETE_CHILD and
|
|
||||||
* FILE_LIST_DIRECTORY rights).
|
|
||||||
*
|
|
||||||
* Does the Windows security model suck? Ermmmm...
|
|
||||||
*/
|
|
||||||
if (STATUS_ACCESS_DENIED != Result ||
|
|
||||||
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
|
|
||||||
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
|
|
||||||
(
|
|
||||||
((DELETE & DesiredAccess) ? FILE_DELETE_CHILD : 0) |
|
|
||||||
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
|
|
||||||
),
|
|
||||||
&ParentAccess);
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
{
|
|
||||||
/* any failure just becomes ACCESS DENIED at this point */
|
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* redo the access check but remove the DELETE and/or FILE_READ_ATTRIBUTES rights */
|
|
||||||
DesiredAccess2 = DesiredAccess & ~(
|
|
||||||
((FILE_DELETE_CHILD & ParentAccess) ? DELETE : 0) |
|
|
||||||
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
|
||||||
if (0 != DesiredAccess2)
|
|
||||||
{
|
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
|
||||||
else
|
|
||||||
/* any failure just becomes ACCESS DENIED at this point */
|
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FILE_DELETE_CHILD & ParentAccess)
|
|
||||||
*PGrantedAccess |= DELETE;
|
|
||||||
if (FILE_LIST_DIRECTORY & ParentAccess)
|
|
||||||
*PGrantedAccess |= FILE_READ_ATTRIBUTES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckParentDirectory)
|
|
||||||
{
|
|
||||||
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
Result = STATUS_NOT_A_DIRECTORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) &&
|
|
||||||
0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
Result = STATUS_NOT_A_DIRECTORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if ((Request->Req.Create.CreateOptions & FILE_NON_DIRECTORY_FILE) &&
|
|
||||||
0 != (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
Result = STATUS_FILE_IS_A_DIRECTORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY))
|
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||||
{
|
{
|
||||||
if (DesiredAccess &
|
if (DesiredAccess &
|
||||||
@ -256,7 +351,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (0 != PSecurityDescriptor && 0 < SecurityDescriptorSize && NT_SUCCESS(Result))
|
if (STATUS_REPARSE == Result)
|
||||||
|
*PGrantedAccess = FileAttributes; /* FileAttributes contains ReparsePointIndex */
|
||||||
|
else if (0 != PSecurityDescriptor && 0 < SecurityDescriptorSize && NT_SUCCESS(Result))
|
||||||
*PSecurityDescriptor = SecurityDescriptor;
|
*PSecurityDescriptor = SecurityDescriptor;
|
||||||
else
|
else
|
||||||
MemFree(SecurityDescriptor);
|
MemFree(SecurityDescriptor);
|
||||||
@ -268,6 +365,8 @@ exit:
|
|||||||
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
||||||
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
else if (CheckMainFile)
|
||||||
|
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L':';
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -282,6 +381,10 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (FspFsctlTransactCreateKind != Request->Kind)
|
if (FspFsctlTransactCreateKind != Request->Kind)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
/* stream support: return NULL security descriptor when creating named stream */
|
||||||
|
if (Request->Req.Create.NamedStream)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
if (!CreatePrivateObjectSecurity(
|
if (!CreatePrivateObjectSecurity(
|
||||||
ParentDescriptor,
|
ParentDescriptor,
|
||||||
0 != Request->Req.Create.SecurityDescriptor.Offset ?
|
0 != Request->Req.Create.SecurityDescriptor.Offset ?
|
||||||
@ -362,6 +465,10 @@ FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
|
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||||
NTSTATUS (*CreateFunc)())
|
NTSTATUS (*CreateFunc)())
|
||||||
{
|
{
|
||||||
|
/* stream support: allow NULL security descriptors */
|
||||||
|
if (0 == SecurityDescriptor)
|
||||||
|
return;
|
||||||
|
|
||||||
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc ||
|
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc ||
|
||||||
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc)
|
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc)
|
||||||
MemFree(SecurityDescriptor);
|
MemFree(SecurityDescriptor);
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -54,9 +54,10 @@ static void usage(void)
|
|||||||
"usage: %s COMMAND ARGS\n"
|
"usage: %s COMMAND ARGS\n"
|
||||||
"\n"
|
"\n"
|
||||||
"commands:\n"
|
"commands:\n"
|
||||||
" start ClassName InstanceName Args...\n"
|
" start ClassName InstanceName Args...\n"
|
||||||
" stop ClassName InstanceName\n"
|
" startWithSecret ClassName InstanceName Args... Secret\n"
|
||||||
" info ClassName InstanceName\n"
|
" stop ClassName InstanceName\n"
|
||||||
|
" info ClassName InstanceName\n"
|
||||||
" list\n",
|
" list\n",
|
||||||
PROGNAME);
|
PROGNAME);
|
||||||
}
|
}
|
||||||
@ -115,7 +116,8 @@ static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int start(PWSTR PipeBuf, ULONG PipeBufSize,
|
int start(PWSTR PipeBuf, ULONG PipeBufSize,
|
||||||
PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv)
|
PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv,
|
||||||
|
BOOLEAN HasSecret)
|
||||||
{
|
{
|
||||||
PWSTR P;
|
PWSTR P;
|
||||||
DWORD ClassNameSize, InstanceNameSize, ArgvSize;
|
DWORD ClassNameSize, InstanceNameSize, ArgvSize;
|
||||||
@ -130,7 +132,7 @@ int start(PWSTR PipeBuf, ULONG PipeBufSize,
|
|||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
P = PipeBuf;
|
P = PipeBuf;
|
||||||
*P++ = LauncherSvcInstanceStart;
|
*P++ = HasSecret ? LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
|
||||||
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
|
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
|
||||||
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
|
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
|
||||||
for (DWORD Argi = 0; Argc > Argi; Argi++)
|
for (DWORD Argi = 0; Argc > Argi; Argi++)
|
||||||
@ -230,7 +232,17 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
if (3 > argc || argc > 12)
|
if (3 > argc || argc > 12)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3);
|
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (0 == lstrcmpW(L"startWithSecret", argv[0]))
|
||||||
|
{
|
||||||
|
if (4 > argc || argc > 13)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
|
||||||
|
TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (0 == lstrcmpW(L"stop", argv[0]))
|
if (0 == lstrcmpW(L"stop", argv[0]))
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -19,7 +19,54 @@
|
|||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
|
|
||||||
#define PROGNAME "WinFsp.Launcher"
|
#define PROGNAME "WinFsp.Launcher"
|
||||||
#define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services"
|
#define REGKEY LAUNCHER_REGKEY
|
||||||
|
|
||||||
|
BOOL CreateOverlappedPipe(
|
||||||
|
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size,
|
||||||
|
DWORD ReadMode, DWORD WriteMode)
|
||||||
|
{
|
||||||
|
RPC_STATUS RpcStatus;
|
||||||
|
UUID Uuid;
|
||||||
|
WCHAR PipeNameBuf[MAX_PATH];
|
||||||
|
HANDLE ReadPipe, WritePipe;
|
||||||
|
DWORD LastError;
|
||||||
|
|
||||||
|
RpcStatus = UuidCreate(&Uuid);
|
||||||
|
if (S_OK != RpcStatus && RPC_S_UUID_LOCAL_ONLY != RpcStatus)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INTERNAL_ERROR);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
wsprintfW(PipeNameBuf, L"\\\\.\\pipe\\"
|
||||||
|
"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||||
|
Uuid.Data1, Uuid.Data2, Uuid.Data3,
|
||||||
|
Uuid.Data4[0], Uuid.Data4[1], Uuid.Data4[2], Uuid.Data4[3],
|
||||||
|
Uuid.Data4[4], Uuid.Data4[5], Uuid.Data4[6], Uuid.Data4[7]);
|
||||||
|
|
||||||
|
ReadPipe = CreateNamedPipeW(PipeNameBuf,
|
||||||
|
PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode,
|
||||||
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
|
||||||
|
1, Size, Size, 120 * 1000, SecurityAttributes);
|
||||||
|
if (INVALID_HANDLE_VALUE == ReadPipe)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
WritePipe = CreateFileW(PipeNameBuf,
|
||||||
|
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
SecurityAttributes, OPEN_EXISTING, WriteMode, 0);
|
||||||
|
if (INVALID_HANDLE_VALUE == WritePipe)
|
||||||
|
{
|
||||||
|
LastError = GetLastError();
|
||||||
|
CloseHandle(ReadPipe);
|
||||||
|
SetLastError(LastError);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PReadPipe = ReadPipe;
|
||||||
|
*PWritePipe = WritePipe;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -80,6 +127,7 @@ static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout)
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
LONG RefCount;
|
||||||
PWSTR ClassName;
|
PWSTR ClassName;
|
||||||
PWSTR InstanceName;
|
PWSTR InstanceName;
|
||||||
PWSTR CommandLine;
|
PWSTR CommandLine;
|
||||||
@ -87,6 +135,7 @@ typedef struct
|
|||||||
DWORD ProcessId;
|
DWORD ProcessId;
|
||||||
HANDLE Process;
|
HANDLE Process;
|
||||||
HANDLE ProcessWait;
|
HANDLE ProcessWait;
|
||||||
|
HANDLE StdioHandles[2];
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
WCHAR Buffer[];
|
WCHAR Buffer[];
|
||||||
} SVC_INSTANCE;
|
} SVC_INSTANCE;
|
||||||
@ -108,8 +157,8 @@ static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
|
|||||||
{
|
{
|
||||||
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
|
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
|
||||||
|
|
||||||
if (0 == lstrcmpW(ClassName, SvcInstance->ClassName) &&
|
if (0 == lstrcmpiW(ClassName, SvcInstance->ClassName) &&
|
||||||
0 == lstrcmpW(InstanceName, SvcInstance->InstanceName))
|
0 == lstrcmpiW(InstanceName, SvcInstance->InstanceName))
|
||||||
return SvcInstance;
|
return SvcInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,8 +280,132 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
|
||||||
|
HANDLE StdioHandles[2],
|
||||||
|
PPROCESS_INFORMATION ProcessInfo)
|
||||||
|
{
|
||||||
|
STARTUPINFOEXW StartupInfoEx;
|
||||||
|
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
|
||||||
|
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
|
||||||
|
SECURITY_ATTRIBUTES PipeAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
|
||||||
|
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
|
||||||
|
SIZE_T Size;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
memset(&StartupInfoEx, 0, sizeof StartupInfoEx);
|
||||||
|
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
|
||||||
|
|
||||||
|
if (0 != StdioHandles)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Create child process and redirect stdin/stdout. Do *not* inherit other handles.
|
||||||
|
*
|
||||||
|
* For explanation see:
|
||||||
|
* https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* create stdin read/write ends; make them inheritable */
|
||||||
|
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0], &PipeAttributes, 0,
|
||||||
|
0, 0))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create stdout read/write ends; make them inheritable */
|
||||||
|
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1], &PipeAttributes, 0,
|
||||||
|
FILE_FLAG_OVERLAPPED, 0))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChildHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
|
Size = 0;
|
||||||
|
if (!InitializeProcThreadAttributeList(0, 1, 0, &Size) &&
|
||||||
|
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttrList = MemAlloc(Size);
|
||||||
|
if (0 == AttrList)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!InitializeProcThreadAttributeList(AttrList, 1, 0, &Size))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only the child ends of stdin/stdout are actually inherited */
|
||||||
|
if (!UpdateProcThreadAttribute(AttrList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
||||||
|
ChildHandles, sizeof ChildHandles, 0, 0))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx;
|
||||||
|
StartupInfoEx.lpAttributeList = AttrList;
|
||||||
|
StartupInfoEx.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
StartupInfoEx.StartupInfo.hStdInput = ChildHandles[0];
|
||||||
|
StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1];
|
||||||
|
StartupInfoEx.StartupInfo.hStdError = ChildHandles[2];
|
||||||
|
|
||||||
|
if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE,
|
||||||
|
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, 0, 0,
|
||||||
|
&StartupInfoEx.StartupInfo, ProcessInfo))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!CreateProcessW(Executable, CommandLine, 0, 0, FALSE,
|
||||||
|
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0,
|
||||||
|
&StartupInfoEx.StartupInfo, ProcessInfo))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
if (INVALID_HANDLE_VALUE != ParentHandles[0])
|
||||||
|
CloseHandle(ParentHandles[0]);
|
||||||
|
if (INVALID_HANDLE_VALUE != ParentHandles[0])
|
||||||
|
CloseHandle(ParentHandles[1]);
|
||||||
|
}
|
||||||
|
else if (0 != StdioHandles)
|
||||||
|
{
|
||||||
|
StdioHandles[0] = ParentHandles[0];
|
||||||
|
StdioHandles[1] = ParentHandles[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INVALID_HANDLE_VALUE != ChildHandles[0])
|
||||||
|
CloseHandle(ChildHandles[0]);
|
||||||
|
if (INVALID_HANDLE_VALUE != ChildHandles[1])
|
||||||
|
CloseHandle(ChildHandles[1]);
|
||||||
|
|
||||||
|
MemFree(AttrList);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
||||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0, HANDLE Job,
|
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0, HANDLE Job,
|
||||||
|
BOOLEAN RedirectStdio,
|
||||||
SVC_INSTANCE **PSvcInstance)
|
SVC_INSTANCE **PSvcInstance)
|
||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance = 0;
|
SVC_INSTANCE *SvcInstance = 0;
|
||||||
@ -241,10 +414,9 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
DWORD ClassNameSize, InstanceNameSize;
|
DWORD ClassNameSize, InstanceNameSize;
|
||||||
WCHAR Executable[MAX_PATH], CommandLineBuf[512], SecurityBuf[512];
|
WCHAR Executable[MAX_PATH], CommandLineBuf[512], SecurityBuf[512];
|
||||||
PWSTR CommandLine, Security;
|
PWSTR CommandLine, Security;
|
||||||
DWORD JobControl;
|
DWORD JobControl, Credentials;
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
||||||
PWSTR Argv[10];
|
PWSTR Argv[10];
|
||||||
STARTUPINFOW StartupInfo;
|
|
||||||
PROCESS_INFORMATION ProcessInfo;
|
PROCESS_INFORMATION ProcessInfo;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
@ -259,7 +431,6 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
Argv[0] = 0;
|
Argv[0] = 0;
|
||||||
Argc++;
|
Argc++;
|
||||||
|
|
||||||
memset(&StartupInfo, 0, sizeof StartupInfo);
|
|
||||||
memset(&ProcessInfo, 0, sizeof ProcessInfo);
|
memset(&ProcessInfo, 0, sizeof ProcessInfo);
|
||||||
|
|
||||||
EnterCriticalSection(&SvcInstanceLock);
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
@ -277,6 +448,22 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if ((!RedirectStdio && 0 != Credentials) ||
|
||||||
|
( RedirectStdio && 0 == Credentials))
|
||||||
|
{
|
||||||
|
Result = STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
RegSize = sizeof Executable;
|
RegSize = sizeof Executable;
|
||||||
Executable[0] = L'\0';
|
Executable[0] = L'\0';
|
||||||
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
|
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
|
||||||
@ -336,7 +523,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
|
//FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
|
||||||
|
|
||||||
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor);
|
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -353,23 +540,23 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(SvcInstance, 0, sizeof *SvcInstance);
|
memset(SvcInstance, 0, sizeof *SvcInstance);
|
||||||
|
SvcInstance->RefCount = 2;
|
||||||
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
|
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
|
||||||
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
||||||
SvcInstance->ClassName = SvcInstance->Buffer;
|
SvcInstance->ClassName = SvcInstance->Buffer;
|
||||||
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
|
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
|
||||||
SvcInstance->SecurityDescriptor = SecurityDescriptor;
|
SvcInstance->SecurityDescriptor = SecurityDescriptor;
|
||||||
|
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
|
||||||
|
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
|
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
StartupInfo.cb = sizeof StartupInfo;
|
Result = SvcInstanceCreateProcess(Executable, SvcInstance->CommandLine,
|
||||||
if (!CreateProcessW(Executable, SvcInstance->CommandLine, 0, 0, FALSE,
|
RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo);
|
||||||
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0, &StartupInfo, &ProcessInfo))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
|
||||||
|
|
||||||
SvcInstance->ProcessId = ProcessInfo.dwProcessId;
|
SvcInstance->ProcessId = ProcessInfo.dwProcessId;
|
||||||
SvcInstance->Process = ProcessInfo.hProcess;
|
SvcInstance->Process = ProcessInfo.hProcess;
|
||||||
@ -413,6 +600,11 @@ exit:
|
|||||||
|
|
||||||
if (0 != SvcInstance)
|
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 (0 != SvcInstance->ProcessWait)
|
if (0 != SvcInstance->ProcessWait)
|
||||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||||
|
|
||||||
@ -435,13 +627,21 @@ exit:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID SvcInstanceDelete(SVC_INSTANCE *SvcInstance)
|
static VOID SvcInstanceRelease(SVC_INSTANCE *SvcInstance)
|
||||||
{
|
{
|
||||||
|
if (0 != InterlockedDecrement(&SvcInstance->RefCount))
|
||||||
|
return;
|
||||||
|
|
||||||
EnterCriticalSection(&SvcInstanceLock);
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
if (RemoveEntryList(&SvcInstance->ListEntry))
|
if (RemoveEntryList(&SvcInstance->ListEntry))
|
||||||
SetEvent(SvcInstanceEvent);
|
SetEvent(SvcInstanceEvent);
|
||||||
LeaveCriticalSection(&SvcInstanceLock);
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||||
|
|
||||||
if (0 != SvcInstance->ProcessWait)
|
if (0 != SvcInstance->ProcessWait)
|
||||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||||
if (0 != SvcInstance->Process)
|
if (0 != SvcInstance->Process)
|
||||||
@ -457,15 +657,102 @@ static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout)
|
|||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance = Context;
|
SVC_INSTANCE *SvcInstance = Context;
|
||||||
|
|
||||||
SvcInstanceDelete(SvcInstance);
|
SvcInstanceRelease(SvcInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS SvcInstanceStart(HANDLE ClientToken,
|
NTSTATUS SvcInstanceStart(HANDLE ClientToken,
|
||||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job)
|
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job,
|
||||||
|
BOOLEAN HasSecret)
|
||||||
{
|
{
|
||||||
SVC_INSTANCE *SvcInstance;
|
SVC_INSTANCE *SvcInstance;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, Job, &SvcInstance);
|
if (HasSecret && (0 == Argc || L'\0' == Argv[Argc - 1][0]))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
HasSecret = !!HasSecret;
|
||||||
|
|
||||||
|
Result = SvcInstanceCreate(ClientToken, ClassName, InstanceName,
|
||||||
|
Argc - HasSecret, Argv, Job, HasSecret,
|
||||||
|
&SvcInstance);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
if (!HasSecret)
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PWSTR Secret = Argv[Argc - 1];
|
||||||
|
UINT8 ReqBuf[256];
|
||||||
|
UINT8 RspBuf[2];
|
||||||
|
DWORD BytesTransferred;
|
||||||
|
OVERLAPPED Overlapped;
|
||||||
|
DWORD WaitResult;
|
||||||
|
|
||||||
|
if (0 == (BytesTransferred =
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, Secret, lstrlenW(Secret), ReqBuf, sizeof ReqBuf, 0, 0)))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WriteFile(SvcInstance->StdioHandles[0], ReqBuf, BytesTransferred, &BytesTransferred, 0))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||||
|
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
memset(&Overlapped, 0, sizeof Overlapped);
|
||||||
|
if (!ReadFile(SvcInstance->StdioHandles[1], RspBuf, sizeof RspBuf, 0, &Overlapped) &&
|
||||||
|
ERROR_IO_PENDING != GetLastError())
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to perform a GetOverlappedResult with a timeout. GetOverlappedResultEx would
|
||||||
|
* be perfect except that it is a Windows 8 and above API. We will therefore replace with
|
||||||
|
* WaitForSingleObject followed by GetOverlappedResult on success.
|
||||||
|
*/
|
||||||
|
WaitResult = WaitForSingleObject(SvcInstance->StdioHandles[1],
|
||||||
|
LAUNCHER_START_WITH_SECRET_TIMEOUT);
|
||||||
|
if (WAIT_OBJECT_0 == WaitResult)
|
||||||
|
Result = GetOverlappedResult(SvcInstance->StdioHandles[1], &Overlapped, &BytesTransferred, TRUE) ?
|
||||||
|
STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
|
||||||
|
else if (WAIT_TIMEOUT == WaitResult)
|
||||||
|
Result = STATUS_TIMEOUT;
|
||||||
|
else
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
if (!NT_SUCCESS(Result) || STATUS_TIMEOUT == Result)
|
||||||
|
{
|
||||||
|
CancelIoEx(SvcInstance->StdioHandles[1], &Overlapped);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeof RspBuf <= BytesTransferred && 'O' == RspBuf[0] && 'K' == RspBuf[1])
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
else
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
|
||||||
|
{
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[0]);
|
||||||
|
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
|
||||||
|
{
|
||||||
|
CloseHandle(SvcInstance->StdioHandles[1]);
|
||||||
|
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SvcInstanceRelease(SvcInstance);
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS SvcInstanceStop(HANDLE ClientToken,
|
NTSTATUS SvcInstanceStop(HANDLE ClientToken,
|
||||||
@ -625,7 +912,7 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
&SecurityAttributes.lpSecurityDescriptor, 0))
|
&SecurityAttributes.lpSecurityDescriptor, 0))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityAttributes.lpSecurityDescriptor);
|
//FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityAttributes.lpSecurityDescriptor);
|
||||||
|
|
||||||
SvcInstanceEvent = CreateEventW(0, TRUE, TRUE, 0);
|
SvcInstanceEvent = CreateEventW(0, TRUE, TRUE, 0);
|
||||||
if (0 == SvcInstanceEvent)
|
if (0 == SvcInstanceEvent)
|
||||||
@ -909,12 +1196,16 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
|||||||
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
|
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
|
||||||
PWSTR ClassName, InstanceName;
|
PWSTR ClassName, InstanceName;
|
||||||
ULONG Argc; PWSTR Argv[9];
|
ULONG Argc; PWSTR Argv[9];
|
||||||
|
BOOLEAN HasSecret = FALSE;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
*PSize = 0;
|
*PSize = 0;
|
||||||
|
|
||||||
switch (*P++)
|
switch (*P++)
|
||||||
{
|
{
|
||||||
|
case LauncherSvcInstanceStartWithSecret:
|
||||||
|
HasSecret = TRUE;
|
||||||
|
/* fall through! */
|
||||||
case LauncherSvcInstanceStart:
|
case LauncherSvcInstanceStart:
|
||||||
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
|
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
|
||||||
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
|
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
|
||||||
@ -924,7 +1215,8 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
|||||||
|
|
||||||
Result = STATUS_INVALID_PARAMETER;
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
if (0 != ClassName && 0 != InstanceName)
|
if (0 != ClassName && 0 != InstanceName)
|
||||||
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv, SvcJob);
|
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv, SvcJob,
|
||||||
|
HasSecret);
|
||||||
|
|
||||||
SvcPipeTransactResult(Result, PipeBuf, PSize);
|
SvcPipeTransactResult(Result, PipeBuf, PSize);
|
||||||
break;
|
break;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -21,13 +21,17 @@
|
|||||||
#include <winfsp/winfsp.h>
|
#include <winfsp/winfsp.h>
|
||||||
#include <shared/minimal.h>
|
#include <shared/minimal.h>
|
||||||
|
|
||||||
|
#define LAUNCHER_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
|
||||||
|
|
||||||
#define LAUNCHER_STOP_TIMEOUT 5500
|
#define LAUNCHER_STOP_TIMEOUT 5500
|
||||||
#define LAUNCHER_KILL_TIMEOUT 5000
|
#define LAUNCHER_KILL_TIMEOUT 5000
|
||||||
|
|
||||||
#define LAUNCHER_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
|
#define LAUNCHER_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
|
||||||
#define LAUNCHER_PIPE_BUFFER_SIZE 2048
|
#define LAUNCHER_PIPE_BUFFER_SIZE 4096
|
||||||
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
|
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
|
||||||
|
|
||||||
|
#define LAUNCHER_START_WITH_SECRET_TIMEOUT 15000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
|
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
|
||||||
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
|
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
|
||||||
@ -53,6 +57,7 @@
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
LauncherSvcInstanceStart = 'S', /* requires: SERVICE_START */
|
LauncherSvcInstanceStart = 'S', /* requires: SERVICE_START */
|
||||||
|
LauncherSvcInstanceStartWithSecret = 'X', /* requires: SERVICE_START */
|
||||||
LauncherSvcInstanceStop = 'T', /* requires: SERVICE_STOP */
|
LauncherSvcInstanceStop = 'T', /* requires: SERVICE_STOP */
|
||||||
LauncherSvcInstanceInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
|
LauncherSvcInstanceInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
|
||||||
LauncherSvcInstanceList = 'L', /* requires: none*/
|
LauncherSvcInstanceList = 'L', /* requires: none*/
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -29,7 +29,7 @@
|
|||||||
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
|
* - "Linker > Input > Ignore All Default Libraries" must be "Yes".
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Update:
|
* Update 1:
|
||||||
*
|
*
|
||||||
* It is possible to have the "Linker > Input > Ignore All Default Libraries"
|
* It is possible to have the "Linker > Input > Ignore All Default Libraries"
|
||||||
* setting to "No" and still eliminate most dependencies on the MSVCRT libraries.
|
* setting to "No" and still eliminate most dependencies on the MSVCRT libraries.
|
||||||
@ -43,6 +43,22 @@
|
|||||||
* that are not required (or worse create a half-baked CRT). For example, the WinFsp
|
* that are not required (or worse create a half-baked CRT). For example, the WinFsp
|
||||||
* DLL ensures this by setting the "Linker > Input > Ignore All Default Libraries"
|
* DLL ensures this by setting the "Linker > Input > Ignore All Default Libraries"
|
||||||
* to "Yes" on 64-bit builds and "No" on 32-bit builds.
|
* to "Yes" on 64-bit builds and "No" on 32-bit builds.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Update 2:
|
||||||
|
*
|
||||||
|
* Using the /Gs[size] compiler option with a large size is a very bad idea.
|
||||||
|
* Turns out that the compiler uses the _chkstk call to ensure that enough
|
||||||
|
* stack space has been committed even when a function accesses locations in
|
||||||
|
* the stack below the guard page.
|
||||||
|
*
|
||||||
|
* The following links explain the problem very well:
|
||||||
|
* - http://stackoverflow.com/questions/8400118/what-is-the-purpose-of-the-chkstk-function#8400171
|
||||||
|
* - https://support.microsoft.com/en-us/kb/100775
|
||||||
|
*
|
||||||
|
* A library/program that does not wish to use the MSVCRT libraries (and hence
|
||||||
|
* does not have _chkstk available) must take care to not use more than a page
|
||||||
|
* (4096 bytes) of stack within a single function.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#undef RtlFillMemory
|
#undef RtlFillMemory
|
||||||
@ -50,8 +66,14 @@
|
|||||||
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
|
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
|
||||||
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
|
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
|
||||||
|
|
||||||
#pragma function(memcpy)
|
|
||||||
#pragma function(memset)
|
#pragma function(memset)
|
||||||
|
#pragma function(memcpy)
|
||||||
|
static inline
|
||||||
|
void *memset(void *dst, int val, size_t siz)
|
||||||
|
{
|
||||||
|
RtlFillMemory(dst, (DWORD)siz, val);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
static inline
|
static inline
|
||||||
void *memcpy(void *dst, const void *src, size_t siz)
|
void *memcpy(void *dst, const void *src, size_t siz)
|
||||||
{
|
{
|
||||||
@ -59,9 +81,9 @@ void *memcpy(void *dst, const void *src, size_t siz)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
void *memset(void *dst, int val, size_t siz)
|
void *memmove(void *dst, const void *src, size_t siz)
|
||||||
{
|
{
|
||||||
RtlFillMemory(dst, (DWORD)siz, val);
|
RtlMoveMemory(dst, src, (DWORD)siz);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -116,7 +116,9 @@ NTSTATUS FspAcquireForModWrite(
|
|||||||
Success = FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, FALSE);
|
Success = FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, FALSE);
|
||||||
if (Success)
|
if (Success)
|
||||||
{
|
{
|
||||||
*ResourceToRelease = FileNode->Header.PagingIoResource;
|
*ResourceToRelease = 0 == FileNode->MainFileNode ?
|
||||||
|
FileNode->Header.PagingIoResource :
|
||||||
|
FileNode->MainFileNode->Header.PagingIoResource;
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -72,6 +72,7 @@ static NTSTATUS FspFsvolCleanup(
|
|||||||
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
@ -87,9 +88,6 @@ static NTSTATUS FspFsvolCleanup(
|
|||||||
/* if this is a directory inform the FSRTL Notify mechanism */
|
/* if this is a directory inform the FSRTL Notify mechanism */
|
||||||
if (FileNode->IsDirectory)
|
if (FileNode->IsDirectory)
|
||||||
{
|
{
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
|
||||||
FspFsvolDeviceExtension(FsvolDeviceObject);
|
|
||||||
|
|
||||||
if (DeletePending)
|
if (DeletePending)
|
||||||
FspNotifyDeletePending(
|
FspNotifyDeletePending(
|
||||||
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList, FileNode);
|
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList, FileNode);
|
||||||
@ -114,14 +112,22 @@ static NTSTATUS FspFsvolCleanup(
|
|||||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
FspIopRequestContext(Request, RequestIrp) = Irp;
|
FspIopRequestContext(Request, RequestIrp) = Irp;
|
||||||
|
|
||||||
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
|
if (DeletePending || !FsvolDeviceExtension->VolumeParams.PostCleanupOnDeleteOnly)
|
||||||
|
/*
|
||||||
|
* Note that it is still possible for this request to not be delivered,
|
||||||
|
* if the volume device Ioq is stopped. But such failures are benign
|
||||||
|
* from our perspective, because they mean that the file system is going
|
||||||
|
* away and should correctly tear things down.
|
||||||
|
*/
|
||||||
|
return FSP_STATUS_IOQ_POST_BEST_EFFORT;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* if the file is being resized invalidate the volume info */
|
||||||
|
if (FileNode->TruncateOnClose)
|
||||||
|
FspFsvolDeviceInvalidateVolumeInfo(IrpSp->DeviceObject);
|
||||||
|
|
||||||
/*
|
return STATUS_SUCCESS; /* FspFsvolCleanupRequestFini will take care of the rest! */
|
||||||
* Note that it is still possible for this request to not be delivered,
|
}
|
||||||
* if the volume device Ioq is stopped. But such failures are benign
|
|
||||||
* from our perspective, because they mean that the file system is going
|
|
||||||
* away and should correctly tear things down.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FspFsvolCleanupComplete(
|
NTSTATUS FspFsvolCleanupComplete(
|
||||||
@ -161,12 +167,21 @@ static VOID FspFsvolCleanupRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Co
|
|||||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
|
HANDLE MainFileHandle;
|
||||||
|
|
||||||
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
FspFileNodeReleaseOwner(FileNode, Pgio, Request);
|
FspFileNodeReleaseOwner(FileNode, Pgio, Request);
|
||||||
|
|
||||||
FspFileNodeCleanupComplete(FileNode, FileObject);
|
FspFileNodeCleanupComplete(FileNode, FileObject);
|
||||||
|
|
||||||
|
MainFileHandle = FileDesc->MainFileHandle;
|
||||||
|
FileDesc->MainFileHandle = 0;
|
||||||
|
|
||||||
FspFileNodeReleaseOwner(FileNode, Main, Request);
|
FspFileNodeReleaseOwner(FileNode, Main, Request);
|
||||||
|
|
||||||
|
FspMainFileClose(MainFileHandle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FspCleanup(
|
NTSTATUS FspCleanup(
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -77,7 +77,7 @@ static NTSTATUS FspFsvolClose(
|
|||||||
FspFileNodeClose(FileNode, FileObject);
|
FspFileNodeClose(FileNode, FileObject);
|
||||||
|
|
||||||
/* delete the FileDesc and deref the FileNode; order is important (FileDesc has FileNode ref) */
|
/* delete the FileDesc and deref the FileNode; order is important (FileDesc has FileNode ref) */
|
||||||
FspFileDescDelete(FileDesc);
|
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
|
||||||
FspFileNodeDereference(FileNode);
|
FspFileNodeDereference(FileNode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
367
src/sys/create.c
367
src/sys/create.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -24,7 +24,8 @@ static NTSTATUS FspFsvrtCreate(
|
|||||||
static NTSTATUS FspFsvolCreate(
|
static NTSTATUS FspFsvolCreate(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
static NTSTATUS FspFsvolCreateNoLock(
|
static NTSTATUS FspFsvolCreateNoLock(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN MainFileOpen);
|
||||||
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
|
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
|
||||||
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
@ -109,23 +110,30 @@ static NTSTATUS FspFsvolCreate(
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result = STATUS_SUCCESS;
|
NTSTATUS Result = STATUS_SUCCESS;
|
||||||
|
BOOLEAN MainFileOpen = FspMainFileOpenCheck(Irp);
|
||||||
|
|
||||||
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
|
if (!MainFileOpen)
|
||||||
try
|
|
||||||
{
|
{
|
||||||
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp);
|
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
|
||||||
}
|
try
|
||||||
finally
|
{
|
||||||
{
|
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, FALSE);
|
||||||
if (FSP_STATUS_IOQ_POST != Result)
|
}
|
||||||
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
|
finally
|
||||||
|
{
|
||||||
|
if (FSP_STATUS_IOQ_POST != Result)
|
||||||
|
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolCreateNoLock(
|
static NTSTATUS FspFsvolCreateNoLock(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN MainFileOpen)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
@ -162,10 +170,16 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
ULONG Flags = IrpSp->Flags;
|
ULONG Flags = IrpSp->Flags;
|
||||||
KPROCESSOR_MODE RequestorMode =
|
KPROCESSOR_MODE RequestorMode =
|
||||||
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
|
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
|
||||||
|
BOOLEAN CaseSensitiveRequested =
|
||||||
|
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
|
||||||
|
BOOLEAN CaseSensitive =
|
||||||
|
CaseSensitiveRequested || FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
|
||||||
BOOLEAN HasTraversePrivilege =
|
BOOLEAN HasTraversePrivilege =
|
||||||
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
|
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
|
||||||
FSP_FILE_NODE *FileNode, *RelatedFileNode;
|
FSP_FILE_NODE *FileNode, *RelatedFileNode;
|
||||||
FSP_FILE_DESC *FileDesc;
|
FSP_FILE_DESC *FileDesc;
|
||||||
|
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
|
||||||
|
ULONG StreamType = FspUnicodePathStreamTypeNone;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
/* cannot open files by fileid */
|
/* cannot open files by fileid */
|
||||||
@ -210,10 +224,6 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
FileName.Buffer++;
|
FileName.Buffer++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check filename validity */
|
|
||||||
if (!FspUnicodePathIsValid(&FileName, 0 != FsvolDeviceExtension->VolumeParams.NamedStreams))
|
|
||||||
return STATUS_OBJECT_NAME_INVALID;
|
|
||||||
|
|
||||||
/* is this a relative or absolute open? */
|
/* is this a relative or absolute open? */
|
||||||
if (0 != RelatedFileObject)
|
if (0 != RelatedFileObject)
|
||||||
{
|
{
|
||||||
@ -265,21 +275,47 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
Result = RtlAppendUnicodeStringToString(&FileNode->FileName, &FileName);
|
Result = RtlAppendUnicodeStringToString(&FileNode->FileName, &FileName);
|
||||||
ASSERT(NT_SUCCESS(Result));
|
ASSERT(NT_SUCCESS(Result));
|
||||||
|
|
||||||
|
/* check filename validity */
|
||||||
|
if (!FspUnicodePathIsValid(&FileNode->FileName,
|
||||||
|
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
|
||||||
|
&StreamType))
|
||||||
|
{
|
||||||
|
FspFileNodeDereference(FileNode);
|
||||||
|
return STATUS_OBJECT_NAME_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we have a stream part (even non-empty), ensure that FileNode->FileName has single colon */
|
||||||
|
if (0 != StreamPart.Buffer)
|
||||||
|
{
|
||||||
|
ASSERT(
|
||||||
|
(PUINT8)FileNode->FileName.Buffer + sizeof(WCHAR) <= (PUINT8)StreamPart.Buffer &&
|
||||||
|
(PUINT8)StreamPart.Buffer + StreamPart.Length <=
|
||||||
|
(PUINT8)FileNode->FileName.Buffer + FileNode->FileName.Length);
|
||||||
|
|
||||||
|
FileNode->FileName.Length = (USHORT)
|
||||||
|
((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer + StreamPart.Length -
|
||||||
|
(0 == StreamPart.Length) * sizeof(WCHAR));
|
||||||
|
}
|
||||||
|
|
||||||
/* check and remove any volume prefix */
|
/* check and remove any volume prefix */
|
||||||
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
|
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
|
||||||
{
|
{
|
||||||
if (FileNode->FileName.Length <= FsvolDeviceExtension->VolumePrefix.Length ||
|
if (!FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &FileNode->FileName) ||
|
||||||
!RtlEqualMemory(FileNode->FileName.Buffer, FsvolDeviceExtension->VolumePrefix.Buffer,
|
(FileNode->FileName.Length > FsvolDeviceExtension->VolumePrefix.Length &&
|
||||||
FsvolDeviceExtension->VolumePrefix.Length) ||
|
'\\' != FileNode->FileName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)]))
|
||||||
'\\' != FileNode->FileName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)])
|
|
||||||
{
|
{
|
||||||
FspFileNodeDereference(FileNode);
|
FspFileNodeDereference(FileNode);
|
||||||
return STATUS_OBJECT_PATH_NOT_FOUND;
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode->FileName.Length -= FsvolDeviceExtension->VolumePrefix.Length;
|
if (FileNode->FileName.Length > FsvolDeviceExtension->VolumePrefix.Length)
|
||||||
FileNode->FileName.MaximumLength -= FsvolDeviceExtension->VolumePrefix.Length;
|
{
|
||||||
FileNode->FileName.Buffer += FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR);
|
FileNode->FileName.Length -= FsvolDeviceExtension->VolumePrefix.Length;
|
||||||
|
FileNode->FileName.MaximumLength -= FsvolDeviceExtension->VolumePrefix.Length;
|
||||||
|
FileNode->FileName.Buffer += FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FileNode->FileName.Length = sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(sizeof(WCHAR) <= FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0]);
|
ASSERT(sizeof(WCHAR) <= FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0]);
|
||||||
@ -297,25 +333,35 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
FileNode->FileName.Length -= sizeof(WCHAR);
|
FileNode->FileName.Length -= sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not all operations allowed on the root directory */
|
/* if a $DATA stream type, this cannot be a directory */
|
||||||
if (sizeof(WCHAR) == FileNode->FileName.Length &&
|
if (FspUnicodePathStreamTypeData == StreamType)
|
||||||
(FILE_CREATE == CreateDisposition ||
|
{
|
||||||
FILE_OVERWRITE == CreateDisposition ||
|
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
|
||||||
FILE_OVERWRITE_IF == CreateDisposition ||
|
{
|
||||||
FILE_SUPERSEDE == CreateDisposition ||
|
FspFileNodeDereference(FileNode);
|
||||||
BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY)))
|
return STATUS_NOT_A_DIRECTORY;
|
||||||
{
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not all operations allowed on the root directory */
|
||||||
|
if (sizeof(WCHAR) == FileNode->FileName.Length &&
|
||||||
|
(FILE_CREATE == CreateDisposition ||
|
||||||
|
FILE_OVERWRITE == CreateDisposition ||
|
||||||
|
FILE_OVERWRITE_IF == CreateDisposition ||
|
||||||
|
FILE_SUPERSEDE == CreateDisposition ||
|
||||||
|
BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY)))
|
||||||
|
{
|
||||||
FspFileNodeDereference(FileNode);
|
FspFileNodeDereference(FileNode);
|
||||||
return STATUS_ACCESS_DENIED;
|
return STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cannot FILE_DELETE_ON_CLOSE on the root directory */
|
/* cannot FILE_DELETE_ON_CLOSE on the root directory */
|
||||||
if (sizeof(WCHAR) == FileNode->FileName.Length &&
|
if (sizeof(WCHAR) == FileNode->FileName.Length &&
|
||||||
FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE))
|
FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE))
|
||||||
{
|
{
|
||||||
FspFileNodeDereference(FileNode);
|
FspFileNodeDereference(FileNode);
|
||||||
return STATUS_CANNOT_DELETE;
|
return STATUS_CANNOT_DELETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = FspFileDescCreate(&FileDesc);
|
Result = FspFileDescCreate(&FileDesc);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -324,6 +370,71 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* fix FileAttributes */
|
||||||
|
ClearFlag(FileAttributes,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
|
||||||
|
if (CreateOptions & FILE_DIRECTORY_FILE)
|
||||||
|
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
|
||||||
|
/* if we have a non-empty stream part, open the main file */
|
||||||
|
if (0 != StreamPart.Length)
|
||||||
|
{
|
||||||
|
/* named streams can never be directories (even when attached to directories) */
|
||||||
|
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
|
||||||
|
{
|
||||||
|
Result = STATUS_NOT_A_DIRECTORY;
|
||||||
|
goto main_stream_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cannot open target directory of a named stream */
|
||||||
|
if (FlagOn(Flags, SL_OPEN_TARGET_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
goto main_stream_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainFileName.Length = MainFileName.MaximumLength = (USHORT)
|
||||||
|
((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer - sizeof(WCHAR));
|
||||||
|
MainFileName.Buffer = FileNode->FileName.Buffer;
|
||||||
|
|
||||||
|
Result = FspMainFileOpen(
|
||||||
|
FsvolDeviceObject,
|
||||||
|
FileObject->DeviceObject, /* use as device hint when using MUP */
|
||||||
|
&MainFileName, CaseSensitive,
|
||||||
|
SecurityDescriptor,
|
||||||
|
FileAttributes,
|
||||||
|
CreateDisposition,
|
||||||
|
&FileDesc->MainFileHandle,
|
||||||
|
&FileDesc->MainFileObject);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto main_stream_exit;
|
||||||
|
|
||||||
|
/* check that the main file is one we recognize */
|
||||||
|
if (!FspFileNodeIsValid(FileDesc->MainFileObject->FsContext))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto main_stream_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cannot set security descriptor or file attributes on named stream */
|
||||||
|
SecurityDescriptor = 0;
|
||||||
|
SecurityDescriptorSize = 0;
|
||||||
|
FileAttributes = 0;
|
||||||
|
|
||||||
|
/* remember the main file node */
|
||||||
|
FileNode->MainFileNode = FileDesc->MainFileObject->FsContext;
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
main_stream_exit:
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileDescDelete(FileDesc);
|
||||||
|
FspFileNodeDereference(FileNode);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* create the user-mode file system request */
|
/* create the user-mode file system request */
|
||||||
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, SecurityDescriptorSize,
|
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, SecurityDescriptorSize,
|
||||||
FspFsvolCreateRequestFini, &Request);
|
FspFsvolCreateRequestFini, &Request);
|
||||||
@ -334,23 +445,19 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix FileAttributes */
|
|
||||||
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
|
|
||||||
if (CreateOptions & FILE_DIRECTORY_FILE)
|
|
||||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
||||||
* with the Request as well. After this is done completing our IRP will automatically
|
* with the Request as well. After this is done completing our IRP will automatically
|
||||||
* delete the Request and any associated resources.
|
* delete the Request and any associated resources.
|
||||||
*/
|
*/
|
||||||
FileDesc->FileNode = FileNode;
|
FileDesc->FileNode = FileNode;
|
||||||
FileDesc->CaseSensitive =
|
FileDesc->CaseSensitive = CaseSensitive;
|
||||||
0 != FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch ||
|
|
||||||
BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
|
|
||||||
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
|
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
|
||||||
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
if (!MainFileOpen)
|
||||||
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
|
{
|
||||||
|
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
||||||
|
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
|
||||||
|
}
|
||||||
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
||||||
|
|
||||||
/* populate the Create request */
|
/* populate the Create request */
|
||||||
@ -369,7 +476,12 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
Request->Req.Create.UserMode = UserMode == RequestorMode;
|
Request->Req.Create.UserMode = UserMode == RequestorMode;
|
||||||
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
|
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
|
||||||
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
|
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
|
||||||
Request->Req.Create.CaseSensitive = BooleanFlagOn(Flags, SL_CASE_SENSITIVE);
|
Request->Req.Create.CaseSensitive = CaseSensitiveRequested;
|
||||||
|
Request->Req.Create.NamedStream = MainFileName.Length;
|
||||||
|
|
||||||
|
ASSERT(
|
||||||
|
0 == StreamPart.Length && 0 == MainFileName.Length ||
|
||||||
|
0 != StreamPart.Length && 0 != MainFileName.Length);
|
||||||
|
|
||||||
/* copy the security descriptor (if any) into the request */
|
/* copy the security descriptor (if any) into the request */
|
||||||
if (0 != SecurityDescriptorSize)
|
if (0 != SecurityDescriptorSize)
|
||||||
@ -485,7 +597,8 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
|
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
|
||||||
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
||||||
FSP_FILE_NODE *OpenedFileNode;
|
FSP_FILE_NODE *OpenedFileNode;
|
||||||
UNICODE_STRING ReparseFileName;
|
PREPARSE_DATA_BUFFER ReparseData;
|
||||||
|
UNICODE_STRING ReparseTargetPrefix0, ReparseTargetPrefix1, ReparseTargetPath;
|
||||||
|
|
||||||
if (FspFsctlTransactCreateKind == Request->Kind)
|
if (FspFsctlTransactCreateKind == Request->Kind)
|
||||||
{
|
{
|
||||||
@ -498,32 +611,100 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* special case STATUS_REPARSE */
|
/* special case STATUS_REPARSE */
|
||||||
if (STATUS_REPARSE == Result)
|
if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||||
{
|
{
|
||||||
ReparseFileName.Buffer =
|
if (IO_REMOUNT == Response->IoStatus.Information)
|
||||||
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
|
|
||||||
ReparseFileName.Length = ReparseFileName.MaximumLength =
|
|
||||||
Response->Rsp.Create.Reparse.FileName.Size;
|
|
||||||
|
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
if (IO_REPARSE == Response->IoStatus.Information)
|
|
||||||
{
|
{
|
||||||
if (0 == ReparseFileName.Length ||
|
Irp->IoStatus.Information = IO_REMOUNT;
|
||||||
(PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
|
FSP_RETURN(Result = STATUS_REPARSE);
|
||||||
(PUINT8)Response + Response->Size)
|
}
|
||||||
FSP_RETURN();
|
else
|
||||||
|
if (IO_REPARSE == Response->IoStatus.Information ||
|
||||||
|
IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* IO_REPARSE means that the user-mode file system has returned an absolute (in
|
||||||
|
* the device namespace) path. Send it as is to the IO Manager.
|
||||||
|
*
|
||||||
|
* IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full
|
||||||
|
* symbolic link reparse buffer. If the symbolic link is absolute send it to the
|
||||||
|
* IO Manager as is. If the symbolic link is device-relative (absolute in the
|
||||||
|
* device namespace) prefix it with our volume name/prefix and then send it to the
|
||||||
|
* IO Manager.
|
||||||
|
*
|
||||||
|
* We do our own handling of IO_REPARSE_TAG_SYMLINK reparse points because
|
||||||
|
* experimentation with handing them directly to the IO Manager revealed problems
|
||||||
|
* with UNC paths (\??\UNC\{VolumePrefix}\{FilePath}).
|
||||||
|
*/
|
||||||
|
|
||||||
if (ReparseFileName.Length > FileObject->FileName.MaximumLength)
|
if (IO_REPARSE == Response->IoStatus.Information)
|
||||||
{
|
{
|
||||||
PVOID Buffer = FspAllocExternal(ReparseFileName.Length);
|
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
|
||||||
|
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
|
||||||
|
|
||||||
|
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
|
||||||
|
Response->Rsp.Create.Reparse.Buffer.Size;
|
||||||
|
ReparseTargetPath.Buffer =
|
||||||
|
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset);
|
||||||
|
|
||||||
|
if ((PUINT8)ReparseTargetPath.Buffer + ReparseTargetPath.Length >
|
||||||
|
(PUINT8)Response + Response->Size ||
|
||||||
|
ReparseTargetPath.Length < sizeof(WCHAR) || L'\\' != ReparseTargetPath.Buffer[0])
|
||||||
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information);
|
||||||
|
|
||||||
|
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset);
|
||||||
|
|
||||||
|
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Buffer.Size >
|
||||||
|
(PUINT8)Response + Response->Size)
|
||||||
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Buffer.Size,
|
||||||
|
ReparseData);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
|
|
||||||
|
if (!FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE))
|
||||||
|
{
|
||||||
|
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
|
||||||
|
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RtlCopyMemory(&ReparseTargetPrefix0, &FsvolDeviceExtension->VolumeName,
|
||||||
|
sizeof ReparseTargetPrefix0);
|
||||||
|
RtlCopyMemory(&ReparseTargetPrefix1, &FsvolDeviceExtension->VolumePrefix,
|
||||||
|
sizeof ReparseTargetPrefix1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
||||||
|
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
|
||||||
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||||
|
|
||||||
|
if (ReparseTargetPath.Length < sizeof(WCHAR) || L'\\' != ReparseTargetPath.Buffer[0])
|
||||||
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length >
|
||||||
|
FileObject->FileName.MaximumLength)
|
||||||
|
{
|
||||||
|
PVOID Buffer = FspAllocExternal(
|
||||||
|
ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length);
|
||||||
if (0 == Buffer)
|
if (0 == Buffer)
|
||||||
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
|
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
|
||||||
FspFreeExternal(FileObject->FileName.Buffer);
|
FspFreeExternal(FileObject->FileName.Buffer);
|
||||||
FileObject->FileName.MaximumLength = ReparseFileName.Length;
|
FileObject->FileName.MaximumLength =
|
||||||
|
ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length;
|
||||||
FileObject->FileName.Buffer = Buffer;
|
FileObject->FileName.Buffer = Buffer;
|
||||||
}
|
}
|
||||||
FileObject->FileName.Length = 0;
|
FileObject->FileName.Length = 0;
|
||||||
RtlCopyUnicodeString(&FileObject->FileName, &ReparseFileName);
|
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix0);
|
||||||
|
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix1);
|
||||||
|
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPath);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The RelatedFileObject does not need to be changed according to:
|
* The RelatedFileObject does not need to be changed according to:
|
||||||
@ -539,19 +720,35 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
* STATUS_REPARSE status returned by the filter. Therefore, it is not
|
* STATUS_REPARSE status returned by the filter. Therefore, it is not
|
||||||
* the responsibility of the filter to free that file object.
|
* the responsibility of the filter to free that file object.
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
else
|
|
||||||
if (IO_REMOUNT == Response->IoStatus.Information)
|
|
||||||
{
|
|
||||||
if (0 != ReparseFileName.Length)
|
|
||||||
FSP_RETURN();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
FSP_RETURN();
|
|
||||||
|
|
||||||
Irp->IoStatus.Information = (ULONG_PTR)Response->IoStatus.Information;
|
Irp->IoStatus.Information = IO_REPARSE;
|
||||||
Result = Response->IoStatus.Status;
|
FSP_RETURN(Result = STATUS_REPARSE);
|
||||||
FSP_RETURN();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset);
|
||||||
|
|
||||||
|
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Buffer.Size >
|
||||||
|
(PUINT8)Response + Response->Size)
|
||||||
|
FSP_RETURN(Result = STATUS_IO_REPARSE_DATA_INVALID);
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Buffer.Size,
|
||||||
|
ReparseData);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
FSP_RETURN();
|
||||||
|
|
||||||
|
ASSERT(0 == Irp->Tail.Overlay.AuxiliaryBuffer);
|
||||||
|
Irp->Tail.Overlay.AuxiliaryBuffer = FspAllocNonPagedExternal(
|
||||||
|
Response->Rsp.Create.Reparse.Buffer.Size);
|
||||||
|
if (0 == Irp->Tail.Overlay.AuxiliaryBuffer)
|
||||||
|
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
|
||||||
|
|
||||||
|
RtlCopyMemory(Irp->Tail.Overlay.AuxiliaryBuffer, ReparseData,
|
||||||
|
Response->Rsp.Create.Reparse.Buffer.Size);
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = ReparseData->ReparseTag;
|
||||||
|
FSP_RETURN(Result = STATUS_REPARSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
|
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
|
||||||
@ -634,6 +831,8 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
if (FileNode->IsDirectory)
|
if (FileNode->IsDirectory)
|
||||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
|
||||||
|
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
|
||||||
|
|
||||||
/* disassociate the FileDesc momentarily from the Request */
|
/* disassociate the FileDesc momentarily from the Request */
|
||||||
FspIopRequestContext(Request, RequestDeviceObject) = 0;
|
FspIopRequestContext(Request, RequestDeviceObject) = 0;
|
||||||
FspIopRequestContext(Request, RequestFileDesc) = 0;
|
FspIopRequestContext(Request, RequestFileDesc) = 0;
|
||||||
@ -642,7 +841,7 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
Request->Kind = FspFsctlTransactOverwriteKind;
|
Request->Kind = FspFsctlTransactOverwriteKind;
|
||||||
RtlZeroMemory(&Request->Req.Create, sizeof Request->Req.Create);
|
RtlZeroMemory(&Request->Req.Create, sizeof Request->Req.Create);
|
||||||
FspIopResetRequest(Request, FspFsvolCreateOverwriteRequestFini);
|
FspIopResetRequest(Request, FspFsvolCreateOverwriteRequestFini);
|
||||||
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
|
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
|
||||||
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
||||||
FspIopRequestContext(Request, RequestFileObject) = FileObject;
|
FspIopRequestContext(Request, RequestFileObject) = FileObject;
|
||||||
FspIopRequestContext(Request, RequestState) = (PVOID)RequestPending;
|
FspIopRequestContext(Request, RequestState) = (PVOID)RequestPending;
|
||||||
@ -725,7 +924,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
|
|
||||||
if (FspFsctlTransactCreateKind == Request->Kind)
|
if (FspFsctlTransactCreateKind == Request->Kind)
|
||||||
{
|
{
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = FspIopRequestContext(Request, RequestDeviceObject);
|
PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject);
|
||||||
|
|
||||||
/* disassociate the FileDesc momentarily from the Request */
|
/* disassociate the FileDesc momentarily from the Request */
|
||||||
Request = FspIrpRequest(Irp);
|
Request = FspIrpRequest(Irp);
|
||||||
@ -735,7 +934,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
/* reset the Request and reassociate the FileDesc and FileObject with it */
|
/* reset the Request and reassociate the FileDesc and FileObject with it */
|
||||||
Request->Kind = FspFsctlTransactReservedKind;
|
Request->Kind = FspFsctlTransactReservedKind;
|
||||||
FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini);
|
FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini);
|
||||||
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
|
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
|
||||||
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
||||||
FspIopRequestContext(Request, RequestFileObject) = FileObject;
|
FspIopRequestContext(Request, RequestFileObject) = FileObject;
|
||||||
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
|
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -47,7 +47,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
|
|||||||
PVOID **PContexts, PULONG PContextCount);
|
PVOID **PContexts, PULONG PContextCount);
|
||||||
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
|
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
|
||||||
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
|
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
|
||||||
BOOLEAN SubpathOnly, PVOID *PRestartKey);
|
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
|
||||||
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
|
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
|
||||||
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
|
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
|
||||||
@ -295,7 +295,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
||||||
LARGE_INTEGER IrpTimeout;
|
LARGE_INTEGER IrpTimeout;
|
||||||
LARGE_INTEGER SecurityTimeout, DirInfoTimeout;
|
LARGE_INTEGER SecurityTimeout, DirInfoTimeout, StreamInfoTimeout;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Volume device initialization is a mess, because of the different ways of
|
* Volume device initialization is a mess, because of the different ways of
|
||||||
@ -347,6 +347,16 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
|
|||||||
return Result;
|
return Result;
|
||||||
FsvolDeviceExtension->InitDoneDir = 1;
|
FsvolDeviceExtension->InitDoneDir = 1;
|
||||||
|
|
||||||
|
/* create our stream info meta cache */
|
||||||
|
StreamInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
|
||||||
|
/* convert millis to nanos */
|
||||||
|
Result = FspMetaCacheCreate(
|
||||||
|
FspFsvolDeviceStreamInfoCacheCapacity, FspFsvolDeviceStreamInfoCacheItemSizeMax, &StreamInfoTimeout,
|
||||||
|
&FsvolDeviceExtension->StreamInfoCache);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
FsvolDeviceExtension->InitDoneStrm = 1;
|
||||||
|
|
||||||
/* initialize the FSRTL Notify mechanism */
|
/* initialize the FSRTL Notify mechanism */
|
||||||
Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync);
|
Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -406,6 +416,10 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
|
|||||||
FspNotifyUninitializeSync(&FsvolDeviceExtension->NotifySync);
|
FspNotifyUninitializeSync(&FsvolDeviceExtension->NotifySync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* delete the stream info meta cache */
|
||||||
|
if (FsvolDeviceExtension->InitDoneStrm)
|
||||||
|
FspMetaCacheDelete(FsvolDeviceExtension->StreamInfoCache);
|
||||||
|
|
||||||
/* delete the directory meta cache */
|
/* delete the directory meta cache */
|
||||||
if (FsvolDeviceExtension->InitDoneDir)
|
if (FsvolDeviceExtension->InitDoneDir)
|
||||||
FspMetaCacheDelete(FsvolDeviceExtension->DirInfoCache);
|
FspMetaCacheDelete(FsvolDeviceExtension->DirInfoCache);
|
||||||
@ -484,6 +498,7 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
|
|||||||
InterruptTime = KeQueryInterruptTime();
|
InterruptTime = KeQueryInterruptTime();
|
||||||
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
|
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
|
||||||
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
|
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
|
||||||
|
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
|
||||||
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
|
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
|
||||||
|
|
||||||
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
|
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
|
||||||
@ -601,20 +616,19 @@ VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
|
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
|
||||||
BOOLEAN SubpathOnly, PVOID *PRestartKey)
|
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
||||||
BOOLEAN CaseInsensitive = 0 == FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
|
BOOLEAN CaseInsensitive = 0 == FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Result;
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Result;
|
||||||
ULONG DeleteCount = 0;
|
|
||||||
|
|
||||||
if (0 != *PRestartKey)
|
if (0 != RestartKey->RestartKey)
|
||||||
SubpathOnly = FALSE;
|
NextFlag = TRUE;
|
||||||
|
|
||||||
Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable,
|
Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable,
|
||||||
0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName);
|
0, 0, NextFlag, &RestartKey->RestartKey, &RestartKey->DeleteCount, &FileName);
|
||||||
|
|
||||||
if (0 != Result &&
|
if (0 != Result &&
|
||||||
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&
|
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -100,7 +100,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
__VA_ARGS__\
|
__VA_ARGS__\
|
||||||
Info = DestBuf;\
|
Info = DestBuf;\
|
||||||
RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(TYPE, FileName));\
|
RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(TYPE, FileName));\
|
||||||
RtlCopyMemory(Info->FileName, DirInfo->FileNameBuf, FileName.Length);\
|
RtlMoveMemory(Info->FileName, DirInfo->FileNameBuf, CopyLength);\
|
||||||
} while (0,0)
|
} while (0,0)
|
||||||
#define FILL_INFO(TYPE, ...)\
|
#define FILL_INFO(TYPE, ...)\
|
||||||
FILL_INFO_BASE(TYPE,\
|
FILL_INFO_BASE(TYPE,\
|
||||||
@ -117,6 +117,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
NTSTATUS Result = STATUS_SUCCESS;
|
||||||
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer;
|
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer;
|
||||||
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
|
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
|
||||||
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
|
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
|
||||||
@ -124,7 +125,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
PUINT8 DestBufBgn = (PUINT8)DestBuf;
|
PUINT8 DestBufBgn = (PUINT8)DestBuf;
|
||||||
PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen;
|
PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen;
|
||||||
PVOID PrevDestBuf = 0;
|
PVOID PrevDestBuf = 0;
|
||||||
ULONG BaseInfoLen;
|
ULONG BaseInfoLen, CopyLength;
|
||||||
UNICODE_STRING FileName;
|
UNICODE_STRING FileName;
|
||||||
|
|
||||||
*PDestLen = 0;
|
*PDestLen = 0;
|
||||||
@ -178,17 +179,27 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
|
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
|
||||||
FileName.Buffer = DirInfo->FileNameBuf;
|
FileName.Buffer = DirInfo->FileNameBuf;
|
||||||
|
|
||||||
|
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
||||||
|
CopyLength = FileName.Length;
|
||||||
|
|
||||||
if (MatchAll || FsRtlIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0))
|
if (MatchAll || FsRtlIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0))
|
||||||
{
|
{
|
||||||
if ((PUINT8)DestBuf +
|
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
|
||||||
FSP_FSCTL_ALIGN_UP(BaseInfoLen + FileName.Length, sizeof(LONGLONG)) > DestBufEnd)
|
|
||||||
{
|
{
|
||||||
if (0 == *PDestLen)
|
/* if we have already copied something exit the loop */
|
||||||
|
if (0 != *PDestLen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((PUINT8)DestBuf + BaseInfoLen > DestBufEnd)
|
||||||
|
/* buffer is too small, can't copy anything */
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
*PDestLen = BaseInfoLen + FileName.Length;
|
/* copy as much of the file name as we can and return STATUS_BUFFER_OVERFLOW */
|
||||||
return STATUS_BUFFER_OVERFLOW;
|
CopyLength = (USHORT)(DestBufEnd - ((PUINT8)DestBuf + BaseInfoLen));
|
||||||
|
Result = STATUS_BUFFER_OVERFLOW;
|
||||||
|
Loop = FALSE;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != PrevDestBuf)
|
if (0 != PrevDestBuf)
|
||||||
@ -196,7 +207,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
PrevDestBuf = DestBuf;
|
PrevDestBuf = DestBuf;
|
||||||
|
|
||||||
*PDirectoryOffset = DirInfo->NextOffset;
|
*PDirectoryOffset = DirInfo->NextOffset;
|
||||||
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + FileName.Length - DestBufBgn);
|
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
|
||||||
|
|
||||||
switch (FileInformationClass)
|
switch (FileInformationClass)
|
||||||
{
|
{
|
||||||
@ -238,7 +249,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DestBuf = (PVOID)((PUINT8)DestBuf +
|
DestBuf = (PVOID)((PUINT8)DestBuf +
|
||||||
FSP_FSCTL_ALIGN_UP(BaseInfoLen + FileName.Length, sizeof(LONGLONG)));
|
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
|
||||||
|
|
||||||
if (ReturnSingleEntry)
|
if (ReturnSingleEntry)
|
||||||
/* cannot just break, *PDirInfo must be advanced */
|
/* cannot just break, *PDirInfo must be advanced */
|
||||||
@ -250,15 +261,18 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
}
|
}
|
||||||
except (EXCEPTION_EXECUTE_HANDLER)
|
except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
NTSTATUS Result = GetExceptionCode();
|
Result = GetExceptionCode();
|
||||||
if (STATUS_INSUFFICIENT_RESOURCES == Result)
|
if (STATUS_INSUFFICIENT_RESOURCES == Result)
|
||||||
return Result;
|
return Result;
|
||||||
return FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
|
return FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* our code flow should allow only these two status codes here */
|
||||||
|
ASSERT(STATUS_SUCCESS == Result || STATUS_BUFFER_OVERFLOW == Result);
|
||||||
|
|
||||||
*PDirInfo = DirInfo;
|
*PDirInfo = DirInfo;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return Result;
|
||||||
|
|
||||||
#undef FILL_INFO
|
#undef FILL_INFO
|
||||||
#undef FILL_INFO_BASE
|
#undef FILL_INFO_BASE
|
||||||
@ -604,7 +618,7 @@ static NTSTATUS FspFsvolQueryDirectory(
|
|||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
/* check that FileName is valid (if supplied) */
|
/* check that FileName is valid (if supplied) */
|
||||||
if (0 != FileName && !FspUnicodePathIsValid(FileName, FALSE))
|
if (0 != FileName && !FspUnicodePathIsValidPattern(FileName))
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
/* is this an allowed file information class? */
|
/* is this an allowed file information class? */
|
||||||
@ -857,7 +871,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
|||||||
|
|
||||||
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
|
if (FspFsctlTransactQueryDirectoryKind == Request->Kind)
|
||||||
{
|
{
|
||||||
DirInfoChangeNumber = FileNode->DirInfoChangeNumber;
|
DirInfoChangeNumber = FspFileNodeDirInfoChangeNumber(FileNode);
|
||||||
Request->Kind = FspFsctlTransactReservedKind;
|
Request->Kind = FspFsctlTransactReservedKind;
|
||||||
FspIopResetRequest(Request, 0);
|
FspIopResetRequest(Request, 0);
|
||||||
FspIopRequestContext(Request, RequestDirInfoChangeNumber) = (PVOID)DirInfoChangeNumber;
|
FspIopRequestContext(Request, RequestDirInfoChangeNumber) = (PVOID)DirInfoChangeNumber;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
152
src/sys/driver.h
152
src/sys/driver.h
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -45,6 +45,7 @@
|
|||||||
#define FSP_ALLOC_INTERNAL_TAG 'IpsF'
|
#define FSP_ALLOC_INTERNAL_TAG 'IpsF'
|
||||||
#define FSP_ALLOC_EXTERNAL_TAG 'XpsF'
|
#define FSP_ALLOC_EXTERNAL_TAG 'XpsF'
|
||||||
#define FSP_IO_INCREMENT IO_NETWORK_INCREMENT
|
#define FSP_IO_INCREMENT IO_NETWORK_INCREMENT
|
||||||
|
#define FSP_VOLUME_PREFIX_CASE_INS TRUE
|
||||||
|
|
||||||
/* debug */
|
/* debug */
|
||||||
#if DBG
|
#if DBG
|
||||||
@ -416,17 +417,31 @@ BOOLEAN FspExpirationTimeValid(UINT64 ExpirationTime)
|
|||||||
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (KeQueryInterruptTime() < ExpirationTime);
|
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (KeQueryInterruptTime() < ExpirationTime);
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
|
BOOLEAN FspExpirationTimeValidEx(UINT64 ExpirationTime, UINT64 CurrentTime)
|
||||||
|
{
|
||||||
|
/* if ExpirationTime is 0 or -1 then ExpirationTime else CurrentTime < ExpirationTime */
|
||||||
|
return 1 >= ExpirationTime + 1 ? (0 != ExpirationTime) : (CurrentTime < ExpirationTime);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime)
|
BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime)
|
||||||
{
|
{
|
||||||
return CurrentTime < ExpirationTime;
|
return CurrentTime < ExpirationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* utility */
|
/* utility */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FspUnicodePathStreamTypeNone = 0,
|
||||||
|
FspUnicodePathStreamTypeData = 1,
|
||||||
|
};
|
||||||
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
|
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
|
||||||
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
|
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
|
||||||
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
|
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
|
||||||
|
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
|
||||||
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
|
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
|
||||||
NTSTATUS FspCreateGuid(GUID *Guid);
|
NTSTATUS FspCreateGuid(GUID *Guid);
|
||||||
|
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
|
||||||
|
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
|
||||||
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||||
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
|
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
|
||||||
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
||||||
@ -655,13 +670,14 @@ enum
|
|||||||
#define FspIopPostWorkRequestBestEffort(D, R)\
|
#define FspIopPostWorkRequestBestEffort(D, R)\
|
||||||
FspIopPostWorkRequestFunnel(D, R, TRUE)
|
FspIopPostWorkRequestFunnel(D, R, TRUE)
|
||||||
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
|
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
|
||||||
|
#define REQ_ALIGN_SIZE 16
|
||||||
typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]);
|
typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]);
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
FSP_IOP_REQUEST_FINI *RequestFini;
|
FSP_IOP_REQUEST_FINI *RequestFini;
|
||||||
PVOID Context[4];
|
PVOID Context[4];
|
||||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[];
|
__declspec(align(REQ_ALIGN_SIZE)) UINT8 RequestBuf[];
|
||||||
} FSP_FSCTL_TRANSACT_REQ_HEADER;
|
} FSP_FSCTL_TRANSACT_REQ_HEADER;
|
||||||
static inline
|
static inline
|
||||||
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
|
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
|
||||||
@ -718,6 +734,8 @@ enum
|
|||||||
FspFsvolDeviceSecurityCacheItemSizeMax = 4096,
|
FspFsvolDeviceSecurityCacheItemSizeMax = 4096,
|
||||||
FspFsvolDeviceDirInfoCacheCapacity = 100,
|
FspFsvolDeviceDirInfoCacheCapacity = 100,
|
||||||
FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
|
FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
|
||||||
|
FspFsvolDeviceStreamInfoCacheCapacity = 100,
|
||||||
|
FspFsvolDeviceStreamInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
|
||||||
};
|
};
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -729,6 +747,11 @@ typedef struct
|
|||||||
RTL_BALANCED_LINKS Header;
|
RTL_BALANCED_LINKS Header;
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA Data;
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA Data;
|
||||||
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT;
|
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PVOID RestartKey;
|
||||||
|
ULONG DeleteCount;
|
||||||
|
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FspFsctlDeviceExtensionKind = '\0ltC', /* file system control device (e.g. \Device\WinFsp.Disk) */
|
FspFsctlDeviceExtensionKind = '\0ltC', /* file system control device (e.g. \Device\WinFsp.Disk) */
|
||||||
@ -744,7 +767,7 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
FSP_DEVICE_EXTENSION Base;
|
FSP_DEVICE_EXTENSION Base;
|
||||||
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1,
|
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1,
|
||||||
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1;
|
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1;
|
||||||
PDEVICE_OBJECT FsctlDeviceObject;
|
PDEVICE_OBJECT FsctlDeviceObject;
|
||||||
PDEVICE_OBJECT FsvrtDeviceObject;
|
PDEVICE_OBJECT FsvrtDeviceObject;
|
||||||
@ -756,6 +779,7 @@ typedef struct
|
|||||||
FSP_IOQ *Ioq;
|
FSP_IOQ *Ioq;
|
||||||
FSP_META_CACHE *SecurityCache;
|
FSP_META_CACHE *SecurityCache;
|
||||||
FSP_META_CACHE *DirInfoCache;
|
FSP_META_CACHE *DirInfoCache;
|
||||||
|
FSP_META_CACHE *StreamInfoCache;
|
||||||
KSPIN_LOCK ExpirationLock;
|
KSPIN_LOCK ExpirationLock;
|
||||||
WORK_QUEUE_ITEM ExpirationWorkItem;
|
WORK_QUEUE_ITEM ExpirationWorkItem;
|
||||||
BOOLEAN ExpirationInProgress;
|
BOOLEAN ExpirationInProgress;
|
||||||
@ -804,7 +828,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
|
|||||||
PVOID **PContexts, PULONG PContextCount);
|
PVOID **PContexts, PULONG PContextCount);
|
||||||
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
|
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
|
||||||
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
|
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
|
||||||
BOOLEAN SubpathOnly, PVOID *PRestartKey);
|
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
|
||||||
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
|
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
|
||||||
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
|
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
|
||||||
@ -814,6 +838,12 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I
|
|||||||
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||||
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||||
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
|
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
|
||||||
|
static inline
|
||||||
|
BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING String)
|
||||||
|
{
|
||||||
|
return RtlPrefixUnicodeString(&FspFsvolDeviceExtension(DeviceObject)->VolumePrefix, String,
|
||||||
|
FSP_VOLUME_PREFIX_CASE_INS);
|
||||||
|
}
|
||||||
NTSTATUS FspDeviceCopyList(
|
NTSTATUS FspDeviceCopyList(
|
||||||
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
|
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
|
||||||
VOID FspDeviceDeleteList(
|
VOID FspDeviceDeleteList(
|
||||||
@ -878,10 +908,11 @@ typedef struct
|
|||||||
ERESOURCE PagingIoResource;
|
ERESOURCE PagingIoResource;
|
||||||
FAST_MUTEX HeaderFastMutex;
|
FAST_MUTEX HeaderFastMutex;
|
||||||
SECTION_OBJECT_POINTERS SectionObjectPointers;
|
SECTION_OBJECT_POINTERS SectionObjectPointers;
|
||||||
KSPIN_LOCK DirInfoSpinLock;
|
KSPIN_LOCK NpInfoSpinLock; /* allows to invalidate non-page Info w/o resources acquired */
|
||||||
UINT64 DirInfo; /* allows to invalidate DirInfo w/o resources acquired */
|
UINT64 DirInfo;
|
||||||
|
UINT64 StreamInfo;
|
||||||
} FSP_FILE_NODE_NONPAGED;
|
} FSP_FILE_NODE_NONPAGED;
|
||||||
typedef struct
|
typedef struct FSP_FILE_NODE
|
||||||
{
|
{
|
||||||
FSRTL_ADVANCED_FCB_HEADER Header;
|
FSRTL_ADVANCED_FCB_HEADER Header;
|
||||||
FSP_FILE_NODE_NONPAGED *NonPaged;
|
FSP_FILE_NODE_NONPAGED *NonPaged;
|
||||||
@ -892,22 +923,25 @@ typedef struct
|
|||||||
LONG OpenCount; /* ContextTable ref count */
|
LONG OpenCount; /* ContextTable ref count */
|
||||||
LONG HandleCount; /* HANDLE count (CREATE/CLEANUP) */
|
LONG HandleCount; /* HANDLE count (CREATE/CLEANUP) */
|
||||||
SHARE_ACCESS ShareAccess;
|
SHARE_ACCESS ShareAccess;
|
||||||
|
ULONG MainFileDenyDeleteCount; /* number of times main file is denying delete */
|
||||||
|
ULONG StreamDenyDeleteCount; /* number of times open streams are denying delete */
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage;
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage;
|
||||||
/* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */
|
/* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */
|
||||||
UNICODE_STRING FileName;
|
UNICODE_STRING FileName;
|
||||||
PWSTR ExternalFileName;
|
PWSTR ExternalFileName;
|
||||||
/* locked under Header.Resource */
|
/* locked under Header.Resource */
|
||||||
UINT64 InfoExpirationTime;
|
UINT64 FileInfoExpirationTime, BasicInfoExpirationTime;
|
||||||
UINT32 FileAttributes;
|
UINT32 FileAttributes;
|
||||||
UINT32 ReparseTag;
|
UINT32 ReparseTag;
|
||||||
UINT64 CreationTime;
|
UINT64 CreationTime;
|
||||||
UINT64 LastAccessTime;
|
UINT64 LastAccessTime;
|
||||||
UINT64 LastWriteTime;
|
UINT64 LastWriteTime;
|
||||||
UINT64 ChangeTime;
|
UINT64 ChangeTime;
|
||||||
ULONG InfoChangeNumber;
|
ULONG FileInfoChangeNumber;
|
||||||
UINT64 Security;
|
UINT64 Security;
|
||||||
ULONG SecurityChangeNumber;
|
ULONG SecurityChangeNumber;
|
||||||
ULONG DirInfoChangeNumber;
|
ULONG DirInfoChangeNumber;
|
||||||
|
ULONG StreamInfoChangeNumber;
|
||||||
BOOLEAN TruncateOnClose;
|
BOOLEAN TruncateOnClose;
|
||||||
FILE_LOCK FileLock;
|
FILE_LOCK FileLock;
|
||||||
struct
|
struct
|
||||||
@ -925,6 +959,7 @@ typedef struct
|
|||||||
UINT64 IndexNumber;
|
UINT64 IndexNumber;
|
||||||
BOOLEAN IsDirectory;
|
BOOLEAN IsDirectory;
|
||||||
BOOLEAN IsRootDirectory;
|
BOOLEAN IsRootDirectory;
|
||||||
|
struct FSP_FILE_NODE *MainFileNode; /* this becomes invalid after our last desc close */
|
||||||
WCHAR FileNameBuf[];
|
WCHAR FileNameBuf[];
|
||||||
} FSP_FILE_NODE;
|
} FSP_FILE_NODE;
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -939,6 +974,9 @@ typedef struct
|
|||||||
UINT64 DirectoryOffset;
|
UINT64 DirectoryOffset;
|
||||||
UINT64 DirInfo;
|
UINT64 DirInfo;
|
||||||
ULONG DirInfoCacheHint;
|
ULONG DirInfoCacheHint;
|
||||||
|
/* stream support */
|
||||||
|
HANDLE MainFileHandle;
|
||||||
|
PFILE_OBJECT MainFileObject;
|
||||||
} FSP_FILE_DESC;
|
} FSP_FILE_DESC;
|
||||||
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
|
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
|
||||||
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
|
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
|
||||||
@ -983,20 +1021,86 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
|||||||
const FSP_FSCTL_FILE_INFO *FileInfo);
|
const FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||||
|
static inline
|
||||||
|
ULONG FspFileNodeFileInfoChangeNumber(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
return (FileNode->MainFileNode->FileInfoChangeNumber & 0xfffff) |
|
||||||
|
((FileNode->FileInfoChangeNumber & 0xfff) << 20);
|
||||||
|
else
|
||||||
|
return FileNode->FileInfoChangeNumber & 0xfffff;
|
||||||
|
}
|
||||||
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
|
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
|
||||||
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
||||||
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
ULONG SecurityChangeNumber);
|
ULONG SecurityChangeNumber);
|
||||||
|
static inline
|
||||||
|
ULONG FspFileNodeSecurityChangeNumber(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
return FileNode->SecurityChangeNumber;
|
||||||
|
}
|
||||||
BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
|
BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
|
||||||
VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
||||||
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
ULONG DirInfoChangeNumber);
|
ULONG DirInfoChangeNumber);
|
||||||
|
static inline
|
||||||
|
ULONG FspFileNodeDirInfoChangeNumber(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
return FileNode->DirInfoChangeNumber;
|
||||||
|
}
|
||||||
|
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
|
||||||
|
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
||||||
|
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
|
ULONG StreamInfoChangeNumber);
|
||||||
|
static inline
|
||||||
|
ULONG FspFileNodeStreamInfoChangeNumber(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
return FileNode->StreamInfoChangeNumber;
|
||||||
|
}
|
||||||
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action);
|
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action);
|
||||||
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
|
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
|
||||||
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
|
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
|
||||||
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
|
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
|
||||||
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
||||||
PUNICODE_STRING FileName, BOOLEAN Reset);
|
PUNICODE_STRING FileName, BOOLEAN Reset);
|
||||||
|
NTSTATUS FspMainFileOpen(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
|
PDEVICE_OBJECT DeviceObjectHint,
|
||||||
|
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||||
|
ULONG FileAttributes,
|
||||||
|
ULONG Disposition,
|
||||||
|
PHANDLE PMainFileHandle,
|
||||||
|
PFILE_OBJECT *PMainFileObject);
|
||||||
|
NTSTATUS FspMainFileClose(
|
||||||
|
HANDLE MainFileHandle,
|
||||||
|
PFILE_OBJECT MainFileObject);
|
||||||
|
static __forceinline
|
||||||
|
BOOLEAN FspMainFileOpenCheck(PIRP Irp)
|
||||||
|
{
|
||||||
|
extern const GUID FspMainFileOpenEcpGuid;
|
||||||
|
NTSTATUS Result;
|
||||||
|
PECP_LIST ExtraCreateParameters = 0;
|
||||||
|
PVOID ExtraCreateParameter = 0;
|
||||||
|
|
||||||
|
Result = FsRtlGetEcpListFromIrp(Irp, &ExtraCreateParameters);
|
||||||
|
if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameters)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
Result = FsRtlFindExtraCreateParameter(ExtraCreateParameters,
|
||||||
|
&FspMainFileOpenEcpGuid, &ExtraCreateParameter, 0);
|
||||||
|
if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameter)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (FsRtlIsEcpFromUserMode(ExtraCreateParameter))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
#define FspFileNodeAcquireShared(N,F) FspFileNodeAcquireSharedF(N, FspFileNodeAcquire ## F)
|
#define FspFileNodeAcquireShared(N,F) FspFileNodeAcquireSharedF(N, FspFileNodeAcquire ## F)
|
||||||
#define FspFileNodeTryAcquireShared(N,F) FspFileNodeTryAcquireSharedF(N, FspFileNodeAcquire ## F, FALSE)
|
#define FspFileNodeTryAcquireShared(N,F) FspFileNodeTryAcquireSharedF(N, FspFileNodeAcquire ## F, FALSE)
|
||||||
#define FspFileNodeAcquireExclusive(N,F) FspFileNodeAcquireExclusiveF(N, FspFileNodeAcquire ## F)
|
#define FspFileNodeAcquireExclusive(N,F) FspFileNodeAcquireExclusiveF(N, FspFileNodeAcquire ## F)
|
||||||
@ -1007,6 +1111,7 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
|||||||
#define FspFileNodeReleaseOwner(N,F,P) FspFileNodeReleaseOwnerF(N, FspFileNodeAcquire ## F, P)
|
#define FspFileNodeReleaseOwner(N,F,P) FspFileNodeReleaseOwnerF(N, FspFileNodeAcquire ## F, P)
|
||||||
#define FspFileNodeDereferenceSecurity(P) FspMetaCacheDereferenceItemBuffer(P)
|
#define FspFileNodeDereferenceSecurity(P) FspMetaCacheDereferenceItemBuffer(P)
|
||||||
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
||||||
|
#define FspFileNodeDereferenceStreamInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
||||||
#define FspFileNodeUnlockAll(N,F,P) FsRtlFastUnlockAll(&(N)->FileLock, F, P, N)
|
#define FspFileNodeUnlockAll(N,F,P) FsRtlFastUnlockAll(&(N)->FileLock, F, P, N)
|
||||||
|
|
||||||
/* multiversion support */
|
/* multiversion support */
|
||||||
@ -1031,7 +1136,30 @@ extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[];
|
|||||||
extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
|
extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
|
||||||
extern ERESOURCE FspDeviceGlobalResource;
|
extern ERESOURCE FspDeviceGlobalResource;
|
||||||
extern WCHAR FspFileDescDirectoryPatternMatchAll[];
|
extern WCHAR FspFileDescDirectoryPatternMatchAll[];
|
||||||
|
extern const GUID FspMainFileOpenEcpGuid;
|
||||||
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
|
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
|
||||||
extern ULONG FspMvMdlMappingNoWrite;
|
extern ULONG FspMvMdlMappingNoWrite;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fixes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ObCloseHandle: add missing prototype */
|
||||||
|
#if (NTDDI_VERSION < NTDDI_WIN7)
|
||||||
|
NTKERNELAPI
|
||||||
|
NTSTATUS
|
||||||
|
ObCloseHandle(
|
||||||
|
_In_ HANDLE Handle,
|
||||||
|
_In_ KPROCESSOR_MODE PreviousMode
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* RtlEqualMemory: this is defined as memcmp, which does not exist on Win7 x86! */
|
||||||
|
#undef RtlEqualMemory
|
||||||
|
static inline
|
||||||
|
LOGICAL RtlEqualMemory(const VOID *Source1, const VOID *Source2, SIZE_T Length)
|
||||||
|
{
|
||||||
|
return Length == RtlCompareMemory(Source1, Source2, Length);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
633
src/sys/file.c
633
src/sys/file.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -57,6 +57,11 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
|||||||
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
ULONG DirInfoChangeNumber);
|
ULONG DirInfoChangeNumber);
|
||||||
static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode);
|
static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode);
|
||||||
|
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
|
||||||
|
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
|
||||||
|
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
|
ULONG StreamInfoChangeNumber);
|
||||||
|
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode);
|
||||||
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
|
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
|
||||||
ULONG Filter, ULONG Action);
|
ULONG Filter, ULONG Action);
|
||||||
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
|
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
|
||||||
@ -65,6 +70,18 @@ NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
|
|||||||
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
|
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
|
||||||
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
||||||
PUNICODE_STRING FileName, BOOLEAN Reset);
|
PUNICODE_STRING FileName, BOOLEAN Reset);
|
||||||
|
NTSTATUS FspMainFileOpen(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
|
PDEVICE_OBJECT DeviceObjectHint,
|
||||||
|
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||||
|
ULONG FileAttributes,
|
||||||
|
ULONG Disposition,
|
||||||
|
PHANDLE PMainFileHandle,
|
||||||
|
PFILE_OBJECT *PMainFileObject);
|
||||||
|
NTSTATUS FspMainFileClose(
|
||||||
|
HANDLE MainFileHandle,
|
||||||
|
PFILE_OBJECT MainFileObject);
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspFileNodeCopyList)
|
#pragma alloc_text(PAGE, FspFileNodeCopyList)
|
||||||
@ -97,12 +114,18 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
|||||||
// !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo)
|
// !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo)
|
||||||
// !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo)
|
// !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo)
|
||||||
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfo)
|
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfo)
|
||||||
|
// !#pragma alloc_text(PAGE, FspFileNodeReferenceStreamInfo)
|
||||||
|
// !#pragma alloc_text(PAGE, FspFileNodeSetStreamInfo)
|
||||||
|
// !#pragma alloc_text(PAGE, FspFileNodeTrySetStreamInfo)
|
||||||
|
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateStreamInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeNotifyChange)
|
#pragma alloc_text(PAGE, FspFileNodeNotifyChange)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeProcessLockIrp)
|
#pragma alloc_text(PAGE, FspFileNodeProcessLockIrp)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
|
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
|
||||||
#pragma alloc_text(PAGE, FspFileDescCreate)
|
#pragma alloc_text(PAGE, FspFileDescCreate)
|
||||||
#pragma alloc_text(PAGE, FspFileDescDelete)
|
#pragma alloc_text(PAGE, FspFileDescDelete)
|
||||||
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
|
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
|
||||||
|
#pragma alloc_text(PAGE, FspMainFileOpen)
|
||||||
|
#pragma alloc_text(PAGE, FspMainFileClose)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FSP_FILE_NODE_GET_FLAGS() \
|
#define FSP_FILE_NODE_GET_FLAGS() \
|
||||||
@ -176,7 +199,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
|
|||||||
ExInitializeResourceLite(&NonPaged->Resource);
|
ExInitializeResourceLite(&NonPaged->Resource);
|
||||||
ExInitializeResourceLite(&NonPaged->PagingIoResource);
|
ExInitializeResourceLite(&NonPaged->PagingIoResource);
|
||||||
ExInitializeFastMutex(&NonPaged->HeaderFastMutex);
|
ExInitializeFastMutex(&NonPaged->HeaderFastMutex);
|
||||||
KeInitializeSpinLock(&NonPaged->DirInfoSpinLock);
|
KeInitializeSpinLock(&NonPaged->NpInfoSpinLock);
|
||||||
|
|
||||||
RtlZeroMemory(FileNode, sizeof *FileNode + ExtraSize);
|
RtlZeroMemory(FileNode, sizeof *FileNode + ExtraSize);
|
||||||
FileNode->Header.NodeTypeCode = FspFileNodeFileKind;
|
FileNode->Header.NodeTypeCode = FspFileNodeFileKind;
|
||||||
@ -211,6 +234,7 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
|
|||||||
|
|
||||||
FsRtlTeardownPerStreamContexts(&FileNode->Header);
|
FsRtlTeardownPerStreamContexts(&FileNode->Header);
|
||||||
|
|
||||||
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, FileNode->NonPaged->StreamInfo);
|
||||||
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, FileNode->NonPaged->DirInfo);
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, FileNode->NonPaged->DirInfo);
|
||||||
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security);
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security);
|
||||||
|
|
||||||
@ -230,6 +254,9 @@ VOID FspFileNodeAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
||||||
|
|
||||||
@ -246,6 +273,9 @@ BOOLEAN FspFileNodeTryAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags, BOOLE
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
||||||
|
|
||||||
@ -279,6 +309,9 @@ VOID FspFileNodeAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
||||||
|
|
||||||
@ -295,6 +328,9 @@ BOOLEAN FspFileNodeTryAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags, BO
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
FSP_FILE_NODE_ASSERT_FLAGS_CLR();
|
||||||
|
|
||||||
@ -328,6 +364,9 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
|
|
||||||
if (Flags & FspFileNodeAcquirePgio)
|
if (Flags & FspFileNodeAcquirePgio)
|
||||||
@ -341,6 +380,9 @@ VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
|
|
||||||
Owner = (PVOID)((UINT_PTR)Owner | 3);
|
Owner = (PVOID)((UINT_PTR)Owner | 3);
|
||||||
@ -356,6 +398,9 @@ VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
FSP_FILE_NODE_ASSERT_FLAGS_SET();
|
FSP_FILE_NODE_ASSERT_FLAGS_SET();
|
||||||
|
|
||||||
@ -372,6 +417,9 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FILE_NODE_GET_FLAGS();
|
FSP_FILE_NODE_GET_FLAGS();
|
||||||
FSP_FILE_NODE_ASSERT_FLAGS_SET();
|
FSP_FILE_NODE_ASSERT_FLAGS_SET();
|
||||||
|
|
||||||
@ -410,12 +458,43 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
||||||
FSP_FILE_NODE *OpenedFileNode;
|
FSP_FILE_NODE *OpenedFileNode = 0;
|
||||||
BOOLEAN Inserted, DeletePending;
|
BOOLEAN Inserted, DeletePending;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is a named stream we must also check with our main file.
|
||||||
|
* Note that FileNode->MainFileNode and OpenedFileNode->MainFileNode
|
||||||
|
* will always be the same.
|
||||||
|
*/
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
{
|
||||||
|
DeletePending = 0 != FileNode->MainFileNode->DeletePending;
|
||||||
|
MemoryBarrier();
|
||||||
|
if (DeletePending)
|
||||||
|
{
|
||||||
|
Result = STATUS_DELETE_PENDING;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sharing violations between main file and streams were determined
|
||||||
|
* through experimentation with NTFS. They may be wrong!
|
||||||
|
*/
|
||||||
|
if (0 < FileNode->MainFileNode->MainFileDenyDeleteCount)
|
||||||
|
{
|
||||||
|
if (!FlagOn(ShareAccess, FILE_SHARE_DELETE) &&
|
||||||
|
FlagOn(GrantedAccess,
|
||||||
|
FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE))
|
||||||
|
{
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OpenedFileNode = FspFsvolDeviceInsertContextByName(FsvolDeviceObject,
|
OpenedFileNode = FspFsvolDeviceInsertContextByName(FsvolDeviceObject,
|
||||||
&FileNode->FileName, FileNode, &FileNode->ContextByNameElementStorage, &Inserted);
|
&FileNode->FileName, FileNode, &FileNode->ContextByNameElementStorage, &Inserted);
|
||||||
ASSERT(0 != OpenedFileNode);
|
ASSERT(0 != OpenedFileNode);
|
||||||
@ -439,6 +518,7 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
* opening a prior FileNode that we found in the table.
|
* opening a prior FileNode that we found in the table.
|
||||||
*/
|
*/
|
||||||
ASSERT(OpenedFileNode != FileNode);
|
ASSERT(OpenedFileNode != FileNode);
|
||||||
|
ASSERT(OpenedFileNode->MainFileNode == FileNode->MainFileNode);
|
||||||
|
|
||||||
DeletePending = 0 != OpenedFileNode->DeletePending;
|
DeletePending = 0 != OpenedFileNode->DeletePending;
|
||||||
MemoryBarrier();
|
MemoryBarrier();
|
||||||
@ -448,6 +528,22 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sharing violations between main file and streams were determined
|
||||||
|
* through experimentation with NTFS. They may be wrong!
|
||||||
|
*/
|
||||||
|
if (0 < OpenedFileNode->StreamDenyDeleteCount)
|
||||||
|
{
|
||||||
|
/* we must be the main file! */
|
||||||
|
ASSERT(0 == OpenedFileNode->MainFileNode);
|
||||||
|
|
||||||
|
if (FlagOn(GrantedAccess, DELETE))
|
||||||
|
{
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FastFat says to do the following on Vista and above.
|
* FastFat says to do the following on Vista and above.
|
||||||
*
|
*
|
||||||
@ -468,15 +564,41 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
/* share access check */
|
/* share access check */
|
||||||
Result = IoCheckShareAccess(GrantedAccess, ShareAccess, FileObject,
|
Result = IoCheckShareAccess(GrantedAccess, ShareAccess, FileObject,
|
||||||
&OpenedFileNode->ShareAccess, TRUE);
|
&OpenedFileNode->ShareAccess, TRUE);
|
||||||
|
|
||||||
exit:
|
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
goto exit;
|
||||||
if (0 != PResult)
|
}
|
||||||
*PResult = Result;
|
|
||||||
|
|
||||||
OpenedFileNode = 0;
|
/*
|
||||||
}
|
* No more failures allowed at this point!
|
||||||
|
* This is because we have potentially inserted a new FileNode into the Context table.
|
||||||
|
* We also updated OpenedFileNode->ShareAccess in IoSetShareAccess/IoCheckShareAccess.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sharing violations between main file and streams were determined
|
||||||
|
* through experimentation with NTFS. They may be wrong!
|
||||||
|
*/
|
||||||
|
if (0 == OpenedFileNode->MainFileNode)
|
||||||
|
{
|
||||||
|
if (FileObject->DeleteAccess)
|
||||||
|
OpenedFileNode->MainFileDenyDeleteCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((FileObject->ReadAccess || FileObject->WriteAccess || FileObject->DeleteAccess) &&
|
||||||
|
!FileObject->SharedDelete)
|
||||||
|
OpenedFileNode->MainFileNode->StreamDenyDeleteCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
if (0 != PResult)
|
||||||
|
*PResult = Result;
|
||||||
|
|
||||||
|
OpenedFileNode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != OpenedFileNode)
|
if (0 != OpenedFileNode)
|
||||||
@ -546,6 +668,22 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
|
|||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sharing violations between main file and streams were determined
|
||||||
|
* through experimentation with NTFS. They may be wrong!
|
||||||
|
*/
|
||||||
|
if (0 == FileNode->MainFileNode)
|
||||||
|
{
|
||||||
|
if (FileObject->DeleteAccess)
|
||||||
|
FileNode->MainFileDenyDeleteCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((FileObject->ReadAccess || FileObject->WriteAccess || FileObject->DeleteAccess) &&
|
||||||
|
!FileObject->SharedDelete)
|
||||||
|
FileNode->MainFileNode->StreamDenyDeleteCount--;
|
||||||
|
}
|
||||||
|
|
||||||
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
|
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
|
||||||
|
|
||||||
if (0 == --FileNode->HandleCount)
|
if (0 == --FileNode->HandleCount)
|
||||||
@ -668,23 +806,94 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
||||||
|
FSP_FILE_NODE *DescendantFileNode;
|
||||||
|
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
|
||||||
|
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
|
||||||
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
|
||||||
BOOLEAN Deleted, Inserted;
|
BOOLEAN Deleted, Inserted;
|
||||||
|
USHORT FileNameLength;
|
||||||
|
PWSTR ExternalFileName;
|
||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, &Deleted);
|
DescendantFileNodes = DescendantFileNodeArray;
|
||||||
ASSERT(Deleted);
|
DescendantFileNodes[0] = FileNode;
|
||||||
|
DescendantFileNodeCount = 1;
|
||||||
|
memset(&RestartKey, 0, sizeof RestartKey);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
||||||
|
&FileNode->FileName, TRUE, &RestartKey);
|
||||||
|
if (0 == DescendantFileNode)
|
||||||
|
break;
|
||||||
|
|
||||||
if (0 != FileNode->ExternalFileName)
|
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
|
||||||
FspFree(FileNode->ExternalFileName);
|
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
|
||||||
FileNode->FileName = *NewFileName;
|
DescendantFileNodeCount++;
|
||||||
FileNode->ExternalFileName = NewFileName->Buffer;
|
}
|
||||||
|
|
||||||
FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &FileNode->FileName, FileNode,
|
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
|
||||||
&FileNode->ContextByNameElementStorage, &Inserted);
|
{
|
||||||
ASSERT(Inserted);
|
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
|
||||||
|
DescendantFileNodes[0] = FileNode;
|
||||||
|
DescendantFileNodeIndex = 1;
|
||||||
|
memset(&RestartKey, 0, sizeof RestartKey);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
||||||
|
&FileNode->FileName, TRUE, &RestartKey);
|
||||||
|
if (0 == DescendantFileNode)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;
|
||||||
|
DescendantFileNodeIndex++;
|
||||||
|
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileNameLength = FileNode->FileName.Length;
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
ASSERT(DescendantFileNode->FileName.Length >= FileNameLength);
|
||||||
|
|
||||||
|
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, &Deleted);
|
||||||
|
ASSERT(Deleted);
|
||||||
|
|
||||||
|
ExternalFileName = DescendantFileNode->ExternalFileName;
|
||||||
|
|
||||||
|
DescendantFileNode->FileName.MaximumLength =
|
||||||
|
DescendantFileNode->FileName.Length - FileNameLength + NewFileName->Length;
|
||||||
|
DescendantFileNode->ExternalFileName = FspAllocMustSucceed(
|
||||||
|
DescendantFileNode->FileName.MaximumLength);
|
||||||
|
|
||||||
|
RtlCopyMemory((PUINT8)DescendantFileNode->ExternalFileName + NewFileName->Length,
|
||||||
|
(PUINT8)DescendantFileNode->FileName.Buffer + FileNameLength,
|
||||||
|
DescendantFileNode->FileName.Length - FileNameLength);
|
||||||
|
RtlCopyMemory(DescendantFileNode->ExternalFileName,
|
||||||
|
NewFileName->Buffer,
|
||||||
|
NewFileName->Length);
|
||||||
|
|
||||||
|
DescendantFileNode->FileName.Length = DescendantFileNode->FileName.MaximumLength;
|
||||||
|
DescendantFileNode->FileName.Buffer = DescendantFileNode->ExternalFileName;
|
||||||
|
|
||||||
|
if (0 != ExternalFileName)
|
||||||
|
FspFree(ExternalFileName);
|
||||||
|
|
||||||
|
FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
|
||||||
|
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
|
||||||
|
ASSERT(Inserted);
|
||||||
|
}
|
||||||
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
if (DescendantFileNodeArray != DescendantFileNodes)
|
||||||
|
FspFree(DescendantFileNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
|
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
@ -697,7 +906,7 @@ BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_FILE_NODE *FileNode;
|
FSP_FILE_NODE *FileNode;
|
||||||
PVOID RestartKey = 0;
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey = { 0 };
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -717,7 +926,14 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
|
|||||||
FileInfo->AllocationSize = FileNode->Header.AllocationSize.QuadPart;
|
FileInfo->AllocationSize = FileNode->Header.AllocationSize.QuadPart;
|
||||||
FileInfo->FileSize = FileNode->Header.FileSize.QuadPart;
|
FileInfo->FileSize = FileNode->Header.FileSize.QuadPart;
|
||||||
|
|
||||||
FileInfo->FileAttributes = FileNode->FileAttributes;
|
UINT32 FileAttributesMask = ~(UINT32)0;
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
{
|
||||||
|
FileAttributesMask = ~(UINT32)FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfo->FileAttributes = FileNode->FileAttributes & FileAttributesMask;
|
||||||
FileInfo->ReparseTag = FileNode->ReparseTag;
|
FileInfo->ReparseTag = FileNode->ReparseTag;
|
||||||
FileInfo->CreationTime = FileNode->CreationTime;
|
FileInfo->CreationTime = FileNode->CreationTime;
|
||||||
FileInfo->LastAccessTime = FileNode->LastAccessTime;
|
FileInfo->LastAccessTime = FileNode->LastAccessTime;
|
||||||
@ -729,25 +945,20 @@ BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
BOOLEAN Result;
|
UINT64 CurrentTime = KeQueryInterruptTime();
|
||||||
|
|
||||||
if (FspExpirationTimeValid(FileNode->InfoExpirationTime))
|
if (0 != FileNode->MainFileNode)
|
||||||
{
|
{
|
||||||
FileInfo->AllocationSize = FileNode->Header.AllocationSize.QuadPart;
|
/* if this is a stream the main file basic info must have not expired as well! */
|
||||||
FileInfo->FileSize = FileNode->Header.FileSize.QuadPart;
|
if (!FspExpirationTimeValidEx(FileNode->MainFileNode->BasicInfoExpirationTime, CurrentTime))
|
||||||
|
return FALSE;
|
||||||
FileInfo->FileAttributes = FileNode->FileAttributes;
|
|
||||||
FileInfo->ReparseTag = FileNode->ReparseTag;
|
|
||||||
FileInfo->CreationTime = FileNode->CreationTime;
|
|
||||||
FileInfo->LastAccessTime = FileNode->LastAccessTime;
|
|
||||||
FileInfo->LastWriteTime = FileNode->LastWriteTime;
|
|
||||||
FileInfo->ChangeTime = FileNode->ChangeTime;
|
|
||||||
Result = TRUE;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Result = FALSE;
|
|
||||||
|
|
||||||
return Result;
|
if (!FspExpirationTimeValidEx(FileNode->FileInfoExpirationTime, CurrentTime))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
FspFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
@ -768,15 +979,29 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
|||||||
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
|
FileNode->Header.AllocationSize.QuadPart = AllocationSize;
|
||||||
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
|
FileNode->Header.FileSize.QuadPart = FileInfo->FileSize;
|
||||||
|
|
||||||
FileNode->FileAttributes = FileInfo->FileAttributes;
|
FileNode->FileInfoExpirationTime = FileNode->BasicInfoExpirationTime =
|
||||||
FileNode->ReparseTag = FileInfo->ReparseTag;
|
FspExpirationTimeFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
|
||||||
FileNode->CreationTime = FileInfo->CreationTime;
|
FileNode->FileInfoChangeNumber++;
|
||||||
FileNode->LastAccessTime = FileInfo->LastAccessTime;
|
|
||||||
FileNode->LastWriteTime = FileInfo->LastWriteTime;
|
FSP_FILE_NODE *MainFileNode = FileNode;
|
||||||
FileNode->ChangeTime = FileInfo->ChangeTime;
|
UINT32 FileAttributesMask = ~(UINT32)0;
|
||||||
FileNode->InfoExpirationTime = FspExpirationTimeFromMillis(
|
if (0 != FileNode->MainFileNode)
|
||||||
FsvolDeviceExtension->VolumeParams.FileInfoTimeout);
|
{
|
||||||
FileNode->InfoChangeNumber++;
|
FileAttributesMask = ~(UINT32)FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
MainFileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
|
MainFileNode->BasicInfoExpirationTime = FileNode->BasicInfoExpirationTime;
|
||||||
|
MainFileNode->FileInfoChangeNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainFileNode->FileAttributes =
|
||||||
|
(MainFileNode->FileAttributes & ~FileAttributesMask) |
|
||||||
|
(FileInfo->FileAttributes & FileAttributesMask);
|
||||||
|
MainFileNode->ReparseTag = FileInfo->ReparseTag;
|
||||||
|
MainFileNode->CreationTime = FileInfo->CreationTime;
|
||||||
|
MainFileNode->LastAccessTime = FileInfo->LastAccessTime;
|
||||||
|
MainFileNode->LastWriteTime = FileInfo->LastWriteTime;
|
||||||
|
MainFileNode->ChangeTime = FileInfo->ChangeTime;
|
||||||
|
|
||||||
if (0 != CcFileObject)
|
if (0 != CcFileObject)
|
||||||
{
|
{
|
||||||
@ -796,7 +1021,7 @@ BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileOb
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
if (FileNode->InfoChangeNumber != InfoChangeNumber)
|
if (FspFileNodeFileInfoChangeNumber(FileNode) != InfoChangeNumber)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo);
|
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo);
|
||||||
@ -807,6 +1032,9 @@ BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, P
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
|
|
||||||
@ -818,6 +1046,9 @@ VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
|
|
||||||
@ -832,7 +1063,7 @@ BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
if (FileNode->SecurityChangeNumber != SecurityChangeNumber)
|
if (FspFileNodeSecurityChangeNumber(FileNode) != SecurityChangeNumber)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
FspFileNodeSetSecurity(FileNode, Buffer, Size);
|
FspFileNodeSetSecurity(FileNode, Buffer, Size);
|
||||||
@ -848,7 +1079,7 @@ BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PU
|
|||||||
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
|
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
|
||||||
UINT64 DirInfo;
|
UINT64 DirInfo;
|
||||||
|
|
||||||
/* no need to acquire the DirInfoSpinLock as the FileNode is acquired */
|
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
|
||||||
DirInfo = NonPaged->DirInfo;
|
DirInfo = NonPaged->DirInfo;
|
||||||
|
|
||||||
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->DirInfoCache,
|
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->DirInfoCache,
|
||||||
@ -865,7 +1096,7 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
|
|||||||
KIRQL Irql;
|
KIRQL Irql;
|
||||||
UINT64 DirInfo;
|
UINT64 DirInfo;
|
||||||
|
|
||||||
/* no need to acquire the DirInfoSpinLock as the FileNode is acquired */
|
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
|
||||||
DirInfo = NonPaged->DirInfo;
|
DirInfo = NonPaged->DirInfo;
|
||||||
|
|
||||||
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
|
||||||
@ -873,10 +1104,10 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
|
|||||||
FspMetaCacheAddItem(FsvolDeviceExtension->DirInfoCache, Buffer, Size) : 0;
|
FspMetaCacheAddItem(FsvolDeviceExtension->DirInfoCache, Buffer, Size) : 0;
|
||||||
FileNode->DirInfoChangeNumber++;
|
FileNode->DirInfoChangeNumber++;
|
||||||
|
|
||||||
/* acquire the DirInfoSpinLock to protect against concurrent FspFileNodeInvalidateDirInfo */
|
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateDirInfo */
|
||||||
KeAcquireSpinLock(&NonPaged->DirInfoSpinLock, &Irql);
|
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
|
||||||
NonPaged->DirInfo = DirInfo;
|
NonPaged->DirInfo = DirInfo;
|
||||||
KeReleaseSpinLock(&NonPaged->DirInfoSpinLock, Irql);
|
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
@ -884,7 +1115,7 @@ BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG S
|
|||||||
{
|
{
|
||||||
// !PAGED_CODE();
|
// !PAGED_CODE();
|
||||||
|
|
||||||
if (FileNode->DirInfoChangeNumber != DirInfoChangeNumber)
|
if (FspFileNodeDirInfoChangeNumber(FileNode) != DirInfoChangeNumber)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
FspFileNodeSetDirInfo(FileNode, Buffer, Size);
|
FspFileNodeSetDirInfo(FileNode, Buffer, Size);
|
||||||
@ -901,14 +1132,93 @@ static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode)
|
|||||||
KIRQL Irql;
|
KIRQL Irql;
|
||||||
UINT64 DirInfo;
|
UINT64 DirInfo;
|
||||||
|
|
||||||
/* acquire the DirInfoSpinLock to protect against concurrent FspFileNodeSetDirInfo */
|
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetDirInfo */
|
||||||
KeAcquireSpinLock(&NonPaged->DirInfoSpinLock, &Irql);
|
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
|
||||||
DirInfo = NonPaged->DirInfo;
|
DirInfo = NonPaged->DirInfo;
|
||||||
KeReleaseSpinLock(&NonPaged->DirInfoSpinLock, Irql);
|
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
|
||||||
|
|
||||||
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
|
||||||
|
{
|
||||||
|
// !PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
|
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
|
||||||
|
UINT64 StreamInfo;
|
||||||
|
|
||||||
|
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
|
||||||
|
StreamInfo = NonPaged->StreamInfo;
|
||||||
|
|
||||||
|
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->StreamInfoCache,
|
||||||
|
StreamInfo, PBuffer, PSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
// !PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
|
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
|
||||||
|
KIRQL Irql;
|
||||||
|
UINT64 StreamInfo;
|
||||||
|
|
||||||
|
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
|
||||||
|
StreamInfo = NonPaged->StreamInfo;
|
||||||
|
|
||||||
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo);
|
||||||
|
StreamInfo = 0 != Buffer ?
|
||||||
|
FspMetaCacheAddItem(FsvolDeviceExtension->StreamInfoCache, Buffer, Size) : 0;
|
||||||
|
FileNode->StreamInfoChangeNumber++;
|
||||||
|
|
||||||
|
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateStreamInfo */
|
||||||
|
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
|
||||||
|
NonPaged->StreamInfo = StreamInfo;
|
||||||
|
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
|
||||||
|
ULONG StreamInfoChangeNumber)
|
||||||
|
{
|
||||||
|
// !PAGED_CODE();
|
||||||
|
|
||||||
|
if (FspFileNodeStreamInfoChangeNumber(FileNode) != StreamInfoChangeNumber)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
FspFileNodeSetStreamInfo(FileNode, Buffer, Size);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
// !PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
|
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
|
||||||
|
KIRQL Irql;
|
||||||
|
UINT64 StreamInfo;
|
||||||
|
|
||||||
|
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetStreamInfo */
|
||||||
|
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
|
||||||
|
StreamInfo = NonPaged->StreamInfo;
|
||||||
|
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
|
||||||
|
|
||||||
|
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo);
|
||||||
|
}
|
||||||
|
|
||||||
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
|
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
|
||||||
ULONG Filter, ULONG Action)
|
ULONG Filter, ULONG Action)
|
||||||
{
|
{
|
||||||
@ -946,11 +1256,38 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FspNotifyReportChange(
|
if (0 != FileNode->MainFileNode)
|
||||||
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList,
|
{
|
||||||
&FileNode->FileName,
|
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME))
|
||||||
(USHORT)((PUINT8)Suffix.Buffer - (PUINT8)FileNode->FileName.Buffer),
|
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_NAME);
|
||||||
0, Filter, Action);
|
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_SIZE))
|
||||||
|
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_SIZE);
|
||||||
|
/* ???: what about FILE_NOTIFY_CHANGE_STREAM_WRITE */
|
||||||
|
ClearFlag(Filter, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE));
|
||||||
|
|
||||||
|
switch (Action)
|
||||||
|
{
|
||||||
|
case FILE_ACTION_ADDED:
|
||||||
|
Action = FILE_ACTION_ADDED_STREAM;
|
||||||
|
FspFileNodeInvalidateStreamInfo(FileNode);
|
||||||
|
break;
|
||||||
|
case FILE_ACTION_REMOVED:
|
||||||
|
Action = FILE_ACTION_REMOVED_STREAM;
|
||||||
|
FspFileNodeInvalidateStreamInfo(FileNode);
|
||||||
|
break;
|
||||||
|
case FILE_ACTION_MODIFIED:
|
||||||
|
Action = FILE_ACTION_MODIFIED_STREAM;
|
||||||
|
//FspFileNodeInvalidateStreamInfo(FileNode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != Filter)
|
||||||
|
FspNotifyReportChange(
|
||||||
|
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList,
|
||||||
|
&FileNode->FileName,
|
||||||
|
(USHORT)((PUINT8)Suffix.Buffer - (PUINT8)FileNode->FileName.Buffer),
|
||||||
|
0, Filter, Action);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp)
|
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp)
|
||||||
@ -1008,6 +1345,8 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc)
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FspMainFileClose(FileDesc->MainFileHandle, FileDesc->MainFileObject);
|
||||||
|
|
||||||
if (0 != FileDesc->DirectoryPattern.Buffer &&
|
if (0 != FileDesc->DirectoryPattern.Buffer &&
|
||||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
|
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
|
||||||
{
|
{
|
||||||
@ -1067,4 +1406,172 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspMainFileOpen(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
|
PDEVICE_OBJECT DeviceObjectHint,
|
||||||
|
PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive,
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||||
|
ULONG FileAttributes,
|
||||||
|
ULONG Disposition,
|
||||||
|
PHANDLE PMainFileHandle,
|
||||||
|
PFILE_OBJECT *PMainFileObject)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
|
UNICODE_STRING FullFileName = { 0 };
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
IO_DRIVER_CREATE_CONTEXT DriverCreateContext = { 0 };
|
||||||
|
PVOID ExtraCreateParameter;
|
||||||
|
HANDLE MainFileHandle;
|
||||||
|
PFILE_OBJECT MainFileObject;
|
||||||
|
|
||||||
|
/* assert that the supplied name is actually a main file name */
|
||||||
|
ASSERT(FspUnicodePathIsValid(MainFileName, 0, 0));
|
||||||
|
|
||||||
|
*PMainFileHandle = 0;
|
||||||
|
*PMainFileObject = 0;
|
||||||
|
|
||||||
|
switch (Disposition)
|
||||||
|
{
|
||||||
|
case FILE_CREATE:
|
||||||
|
case FILE_OPEN_IF:
|
||||||
|
case FILE_OVERWRITE_IF:
|
||||||
|
Disposition = FILE_OPEN_IF;
|
||||||
|
break;
|
||||||
|
case FILE_OPEN:
|
||||||
|
case FILE_OVERWRITE:
|
||||||
|
case FILE_SUPERSEDE:
|
||||||
|
Disposition = FILE_OPEN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullFileName.Length = 0;
|
||||||
|
FullFileName.MaximumLength =
|
||||||
|
FsvolDeviceExtension->VolumeName.Length +
|
||||||
|
FsvolDeviceExtension->VolumePrefix.Length +
|
||||||
|
MainFileName->Length;
|
||||||
|
FullFileName.Buffer = FspAlloc(FullFileName.MaximumLength);
|
||||||
|
if (0 == FullFileName.Buffer)
|
||||||
|
{
|
||||||
|
IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlAppendUnicodeStringToString(&FullFileName, &FsvolDeviceExtension->VolumeName);
|
||||||
|
RtlAppendUnicodeStringToString(&FullFileName, &FsvolDeviceExtension->VolumePrefix);
|
||||||
|
RtlAppendUnicodeStringToString(&FullFileName, MainFileName);
|
||||||
|
|
||||||
|
InitializeObjectAttributes(
|
||||||
|
&ObjectAttributes,
|
||||||
|
&FullFileName,
|
||||||
|
OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK | (CaseSensitive ? 0 : OBJ_CASE_INSENSITIVE),
|
||||||
|
0/*RootDirectory*/,
|
||||||
|
SecurityDescriptor);
|
||||||
|
|
||||||
|
/* do not use SiloContext field as it is only available on Win10 v1607 and higher */
|
||||||
|
DriverCreateContext.Size =
|
||||||
|
FIELD_OFFSET(IO_DRIVER_CREATE_CONTEXT, TxnParameters) +
|
||||||
|
sizeof(((PIO_DRIVER_CREATE_CONTEXT)0)->TxnParameters);
|
||||||
|
DriverCreateContext.DeviceObjectHint = 0 != FsvolDeviceExtension->FsvrtDeviceObject ?
|
||||||
|
FsvolDeviceObject : DeviceObjectHint;
|
||||||
|
|
||||||
|
IoStatus.Status = FsRtlAllocateExtraCreateParameterList(0,
|
||||||
|
&DriverCreateContext.ExtraCreateParameter);
|
||||||
|
if (!NT_SUCCESS(IoStatus.Status))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
IoStatus.Status = FsRtlAllocateExtraCreateParameter(&FspMainFileOpenEcpGuid,
|
||||||
|
sizeof(PVOID),
|
||||||
|
0/*Flags*/,
|
||||||
|
0/*CleanupCallback*/,
|
||||||
|
FSP_ALLOC_INTERNAL_TAG,
|
||||||
|
&ExtraCreateParameter);
|
||||||
|
if (!NT_SUCCESS(IoStatus.Status))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
IoStatus.Status = FsRtlInsertExtraCreateParameter(DriverCreateContext.ExtraCreateParameter,
|
||||||
|
ExtraCreateParameter);
|
||||||
|
if (!NT_SUCCESS(IoStatus.Status))
|
||||||
|
{
|
||||||
|
FsRtlFreeExtraCreateParameter(ExtraCreateParameter);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoStatus.Status = IoCreateFileEx(
|
||||||
|
&MainFileHandle,
|
||||||
|
FILE_READ_ATTRIBUTES,
|
||||||
|
&ObjectAttributes,
|
||||||
|
&IoStatus,
|
||||||
|
0/*AllocationSize*/,
|
||||||
|
FileAttributes,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
Disposition,
|
||||||
|
FILE_OPEN_REPARSE_POINT,
|
||||||
|
0/*EaBuffer*/,
|
||||||
|
0/*EaLength*/,
|
||||||
|
CreateFileTypeNone,
|
||||||
|
0/*InternalParameters*/,
|
||||||
|
IO_FORCE_ACCESS_CHECK,
|
||||||
|
&DriverCreateContext);
|
||||||
|
if (!NT_SUCCESS(IoStatus.Status))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
IoStatus.Status = ObReferenceObjectByHandle(
|
||||||
|
MainFileHandle,
|
||||||
|
0/*DesiredAccess*/,
|
||||||
|
*IoFileObjectType,
|
||||||
|
KernelMode,
|
||||||
|
&MainFileObject,
|
||||||
|
0/*HandleInformation*/);
|
||||||
|
if (!NT_SUCCESS(IoStatus.Status))
|
||||||
|
{
|
||||||
|
ObCloseHandle(MainFileHandle, KernelMode);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PMainFileHandle = MainFileHandle;
|
||||||
|
*PMainFileObject = MainFileObject;
|
||||||
|
|
||||||
|
IoStatus.Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != DriverCreateContext.ExtraCreateParameter)
|
||||||
|
FsRtlFreeExtraCreateParameterList(DriverCreateContext.ExtraCreateParameter);
|
||||||
|
|
||||||
|
if (0 != FullFileName.Buffer)
|
||||||
|
FspFree(FullFileName.Buffer);
|
||||||
|
|
||||||
|
return IoStatus.Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspMainFileClose(
|
||||||
|
HANDLE MainFileHandle,
|
||||||
|
PFILE_OBJECT MainFileObject)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
NTSTATUS Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (0 != MainFileObject)
|
||||||
|
ObDereferenceObject(MainFileObject);
|
||||||
|
|
||||||
|
if (0 != MainFileHandle)
|
||||||
|
{
|
||||||
|
Result = ObCloseHandle(MainFileHandle, KernelMode);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
|
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
|
||||||
|
|
||||||
|
// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B}
|
||||||
|
const GUID FspMainFileOpenEcpGuid =
|
||||||
|
{ 0x904862b4, 0xeb3f, 0x461e, { 0xac, 0xb2, 0x4d, 0xf2, 0xb3, 0xfc, 0x89, 0x8b } };
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -38,6 +38,13 @@ static NTSTATUS FspFsvolQueryPositionInformation(PFILE_OBJECT FileObject,
|
|||||||
static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
|
||||||
PVOID *PBuffer, PVOID BufferEnd,
|
PVOID *PBuffer, PVOID BufferEnd,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo);
|
const FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
|
static NTSTATUS FspFsvolQueryStreamInformationCopy(
|
||||||
|
FSP_FSCTL_STREAM_INFO *StreamInfoBuffer, ULONG StreamInfoBufferSize,
|
||||||
|
PVOID DestBuf, PULONG PDestLen);
|
||||||
|
static NTSTATUS FspFsvolQueryStreamInformation(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
|
static NTSTATUS FspFsvolQueryStreamInformationSuccess(
|
||||||
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
static NTSTATUS FspFsvolQueryInformation(
|
static NTSTATUS FspFsvolQueryInformation(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete;
|
||||||
@ -78,6 +85,9 @@ FSP_DRIVER_DISPATCH FspSetInformation;
|
|||||||
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryPositionInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryPositionInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryStandardInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryStandardInformation)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationCopy)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformation)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationSuccess)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryInformationComplete)
|
#pragma alloc_text(PAGE, FspFsvolQueryInformationComplete)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini)
|
#pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini)
|
||||||
@ -349,6 +359,235 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolQueryStreamInformationCopy(
|
||||||
|
FSP_FSCTL_STREAM_INFO *StreamInfo, ULONG StreamInfoSize,
|
||||||
|
PVOID DestBuf, PULONG PDestLen)
|
||||||
|
{
|
||||||
|
#define STREAM_TYPE ":$DATA"
|
||||||
|
#define STREAM_TYPE_LENGTH (sizeof L"" STREAM_TYPE - sizeof(WCHAR))
|
||||||
|
#define STREAM_EXTRA_LENGTH (sizeof L":" STREAM_TYPE - sizeof(WCHAR))
|
||||||
|
#define FILL_INFO()\
|
||||||
|
do\
|
||||||
|
{\
|
||||||
|
FILE_STREAM_INFORMATION InfoStruct = { 0 }, *Info = &InfoStruct;\
|
||||||
|
Info->NextEntryOffset = 0;\
|
||||||
|
Info->StreamNameLength = StreamNameLength;\
|
||||||
|
Info->StreamSize.QuadPart = StreamInfo->StreamSize;\
|
||||||
|
Info->StreamAllocationSize.QuadPart = StreamInfo->StreamAllocationSize;\
|
||||||
|
Info = DestBuf;\
|
||||||
|
RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName));\
|
||||||
|
{\
|
||||||
|
PWSTR StreamName = Info->StreamName;\
|
||||||
|
ULONG Length[3];\
|
||||||
|
Length[0] = 0 < CopyLength ? sizeof(WCHAR) : 0;\
|
||||||
|
Length[1] = Info->StreamNameLength - STREAM_EXTRA_LENGTH < CopyLength - Length[0] ?\
|
||||||
|
Info->StreamNameLength - STREAM_EXTRA_LENGTH : CopyLength - Length[0];\
|
||||||
|
Length[2] = CopyLength - Length[0] - Length[1];\
|
||||||
|
ASSERT(\
|
||||||
|
sizeof(WCHAR) >= Length[0] &&\
|
||||||
|
Info->StreamNameLength - STREAM_EXTRA_LENGTH >= Length[1] &&\
|
||||||
|
STREAM_TYPE_LENGTH >= Length[2]);\
|
||||||
|
RtlCopyMemory(StreamName, L":", Length[0]);\
|
||||||
|
StreamName += Length[0] / sizeof(WCHAR);\
|
||||||
|
RtlCopyMemory(StreamName, StreamInfo->StreamNameBuf, Length[1]);\
|
||||||
|
StreamName += Length[1] / sizeof(WCHAR);\
|
||||||
|
RtlCopyMemory(StreamName, L"" STREAM_TYPE, Length[2]);\
|
||||||
|
}\
|
||||||
|
} while (0,0)
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
NTSTATUS Result = STATUS_SUCCESS;
|
||||||
|
PUINT8 StreamInfoEnd = (PUINT8)StreamInfo + StreamInfoSize;
|
||||||
|
PUINT8 DestBufBgn = (PUINT8)DestBuf;
|
||||||
|
PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen;
|
||||||
|
PVOID PrevDestBuf = 0;
|
||||||
|
ULONG StreamNameLength, CopyLength;
|
||||||
|
ULONG BaseInfoLen = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName);
|
||||||
|
|
||||||
|
*PDestLen = 0;
|
||||||
|
|
||||||
|
for (;
|
||||||
|
NT_SUCCESS(Result) && (PUINT8)StreamInfo + sizeof(StreamInfo->Size) <= StreamInfoEnd;
|
||||||
|
StreamInfo = (PVOID)((PUINT8)StreamInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(StreamInfoSize)))
|
||||||
|
{
|
||||||
|
StreamInfoSize = StreamInfo->Size;
|
||||||
|
|
||||||
|
if (sizeof(FSP_FSCTL_STREAM_INFO) > StreamInfoSize)
|
||||||
|
break;
|
||||||
|
|
||||||
|
StreamNameLength = StreamInfoSize - sizeof(FSP_FSCTL_STREAM_INFO) + STREAM_EXTRA_LENGTH;
|
||||||
|
|
||||||
|
/* CopyLength is the same as StreamNameLength except on STATUS_BUFFER_OVERFLOW */
|
||||||
|
CopyLength = StreamNameLength;
|
||||||
|
|
||||||
|
/* do we have enough space for this stream info? */
|
||||||
|
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
|
||||||
|
{
|
||||||
|
/* can we even copy the base info? */
|
||||||
|
if ((PUINT8)DestBuf + BaseInfoLen > DestBufEnd)
|
||||||
|
{
|
||||||
|
if (0 == *PDestLen)
|
||||||
|
/* if we haven't copied anything yet, buffer is too small */
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
else
|
||||||
|
/* *PDestLen contains bytes copied so far */
|
||||||
|
return STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy as much of the stream name as we can and return STATUS_BUFFER_OVERFLOW */
|
||||||
|
CopyLength = (ULONG)(DestBufEnd - ((PUINT8)DestBuf + BaseInfoLen));
|
||||||
|
Result = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill in NextEntryOffset */
|
||||||
|
if (0 != PrevDestBuf)
|
||||||
|
*(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf);
|
||||||
|
PrevDestBuf = DestBuf;
|
||||||
|
|
||||||
|
/* update bytes copied */
|
||||||
|
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
|
||||||
|
|
||||||
|
FILL_INFO();
|
||||||
|
|
||||||
|
/* advance DestBuf; make sure to align properly! */
|
||||||
|
DestBuf = (PVOID)((PUINT8)DestBuf +
|
||||||
|
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* our code flow should allow only these two status codes here */
|
||||||
|
ASSERT(STATUS_SUCCESS == Result || STATUS_BUFFER_OVERFLOW == Result);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
#undef FILL_INFO
|
||||||
|
#undef STREAM_EXTRA_LENGTH
|
||||||
|
#undef STREAM_TYPE_LENGTH
|
||||||
|
#undef STREAM_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolQueryStreamInformation(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (!FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.NamedStreams)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
|
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
ULONG Length = IrpSp->Parameters.QueryFile.Length;
|
||||||
|
PVOID StreamInfoBuffer;
|
||||||
|
ULONG StreamInfoBufferSize;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
|
FspFileNodeAcquireShared(FileNode, Main);
|
||||||
|
if (FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Main);
|
||||||
|
|
||||||
|
Result = FspFsvolQueryStreamInformationCopy(
|
||||||
|
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
|
||||||
|
|
||||||
|
FspFileNodeDereferenceStreamInfo(StreamInfoBuffer);
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = Length;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFileNodeAcquireShared(FileNode, Pgio);
|
||||||
|
|
||||||
|
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolQueryInformationRequestFini, &Request);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request->Kind = FspFsctlTransactQueryStreamInformationKind;
|
||||||
|
Request->Req.QueryStreamInformation.UserContext = FileNode->UserContext;
|
||||||
|
Request->Req.QueryStreamInformation.UserContext2 = FileDesc->UserContext2;
|
||||||
|
|
||||||
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||||
|
|
||||||
|
return FSP_STATUS_IOQ_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolQueryStreamInformationSuccess(
|
||||||
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (!FspFsvolDeviceExtension(IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->
|
||||||
|
VolumeParams.NamedStreams)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
ULONG Length = IrpSp->Parameters.QueryFile.Length;
|
||||||
|
PVOID StreamInfoBuffer = 0;
|
||||||
|
ULONG StreamInfoBufferSize = 0;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
BOOLEAN Success;
|
||||||
|
|
||||||
|
if (0 != FspIopRequestContext(Request, RequestFileNode))
|
||||||
|
{
|
||||||
|
/* check that the stream info we got back is valid */
|
||||||
|
if (Response->Buffer + Response->Rsp.QueryStreamInformation.Buffer.Size >
|
||||||
|
(PUINT8)Response + Response->Size)
|
||||||
|
{
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
return STATUS_INFO_LENGTH_MISMATCH; /* ???: what is the best code to return here? */
|
||||||
|
}
|
||||||
|
|
||||||
|
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
|
||||||
|
FspFileNodeStreamInfoChangeNumber(FileNode);
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||||
|
|
||||||
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
}
|
||||||
|
|
||||||
|
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main);
|
||||||
|
if (!Success)
|
||||||
|
{
|
||||||
|
FspIopRetryCompleteIrp(Irp, Response, &Result);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Success = !FspFileNodeTrySetStreamInfo(FileNode,
|
||||||
|
Response->Buffer, Response->Rsp.QueryStreamInformation.Buffer.Size,
|
||||||
|
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestInfoChangeNumber));
|
||||||
|
Success = Success &&
|
||||||
|
FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize);
|
||||||
|
FspFileNodeRelease(FileNode, Main);
|
||||||
|
if (Success)
|
||||||
|
{
|
||||||
|
Result = FspFsvolQueryStreamInformationCopy(
|
||||||
|
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
|
||||||
|
FspFileNodeDereferenceStreamInfo(StreamInfoBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StreamInfoBuffer = (PVOID)Response->Buffer;
|
||||||
|
StreamInfoBufferSize = Response->Rsp.QueryStreamInformation.Buffer.Size;
|
||||||
|
Result = FspFsvolQueryStreamInformationCopy(
|
||||||
|
StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = Length;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolQueryInformation(
|
static NTSTATUS FspFsvolQueryInformation(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
@ -358,8 +597,13 @@ static NTSTATUS FspFsvolQueryInformation(
|
|||||||
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
NTSTATUS Result;
|
|
||||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
||||||
|
|
||||||
|
/* special case FileStreamInformation */
|
||||||
|
if (FileStreamInformation == FileInformationClass)
|
||||||
|
return FspFsvolQueryStreamInformation(FsvolDeviceObject, Irp, IrpSp);
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
@ -415,9 +659,6 @@ static NTSTATUS FspFsvolQueryInformation(
|
|||||||
case FileStandardInformation:
|
case FileStandardInformation:
|
||||||
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0);
|
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0);
|
||||||
break;
|
break;
|
||||||
case FileStreamInformation:
|
|
||||||
Result = STATUS_INVALID_PARAMETER; /* !!!: no stream support yet! */
|
|
||||||
return Result;
|
|
||||||
default:
|
default:
|
||||||
Result = STATUS_INVALID_PARAMETER;
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
return Result;
|
return Result;
|
||||||
@ -496,6 +737,11 @@ NTSTATUS FspFsvolQueryInformationComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
||||||
|
|
||||||
|
/* special case FileStreamInformation */
|
||||||
|
if (FileStreamInformation == FileInformationClass)
|
||||||
|
FSP_RETURN(Result = FspFsvolQueryStreamInformationSuccess(Irp, Response));
|
||||||
|
|
||||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
|
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
@ -507,7 +753,8 @@ NTSTATUS FspFsvolQueryInformationComplete(
|
|||||||
|
|
||||||
if (0 != FspIopRequestContext(Request, RequestFileNode))
|
if (0 != FspIopRequestContext(Request, RequestFileNode))
|
||||||
{
|
{
|
||||||
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)FileNode->InfoChangeNumber;
|
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
|
||||||
|
FspFileNodeFileInfoChangeNumber(FileNode);
|
||||||
FspIopRequestContext(Request, RequestFileNode) = 0;
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||||
|
|
||||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
@ -869,7 +1116,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
|||||||
if (FileNode->IsRootDirectory)
|
if (FileNode->IsRootDirectory)
|
||||||
/* cannot rename root directory */
|
/* cannot rename root directory */
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
if (!FspUnicodePathIsValid(&FileNode->FileName, FALSE))
|
if (!FspUnicodePathIsValid(&FileNode->FileName, 0, 0))
|
||||||
/* cannot rename streams (WinFsp limitation) */
|
/* cannot rename streams (WinFsp limitation) */
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
@ -894,7 +1141,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
|||||||
if (L'\\' == Suffix.Buffer[0])
|
if (L'\\' == Suffix.Buffer[0])
|
||||||
FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix);
|
FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix);
|
||||||
|
|
||||||
if (!FspUnicodePathIsValid(&Remain, FALSE) || !FspUnicodePathIsValid(&Suffix, FALSE))
|
if (!FspUnicodePathIsValid(&Remain, 0, 0) || !FspUnicodePathIsValid(&Suffix, 0, 0))
|
||||||
{
|
{
|
||||||
/* cannot rename streams (WinFsp limitation) */
|
/* cannot rename streams (WinFsp limitation) */
|
||||||
Result = STATUS_INVALID_PARAMETER;
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
@ -982,9 +1229,8 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
|
|||||||
|
|
||||||
NewFileName.Length = NewFileName.MaximumLength =
|
NewFileName.Length = NewFileName.MaximumLength =
|
||||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size - sizeof(WCHAR);
|
Request->Req.SetInformation.Info.Rename.NewFileName.Size - sizeof(WCHAR);
|
||||||
NewFileName.Buffer = FspAllocMustSucceed(NewFileName.Length);
|
NewFileName.Buffer = (PVOID)
|
||||||
RtlCopyMemory(NewFileName.Buffer, Request->Buffer + Request->FileName.Size, NewFileName.Length);
|
(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
|
||||||
|
|
||||||
FspFileNodeRename(FileNode, &NewFileName);
|
FspFileNodeRename(FileNode, &NewFileName);
|
||||||
|
|
||||||
/* fastfat has some really arcane rules on rename notifications; simplify! */
|
/* fastfat has some really arcane rules on rename notifications; simplify! */
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
310
src/sys/fsctl.c
310
src/sys/fsctl.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -18,21 +18,36 @@
|
|||||||
#include <sys/driver.h>
|
#include <sys/driver.h>
|
||||||
|
|
||||||
static NTSTATUS FspFsctlFileSystemControl(
|
static NTSTATUS FspFsctlFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN IsWrite);
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||||
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
BOOLEAN IsWrite);
|
||||||
static NTSTATUS FspFsvolFileSystemControl(
|
static NTSTATUS FspFsvolFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
||||||
|
static FSP_IOP_REQUEST_FINI FspFsvolFileSystemControlRequestFini;
|
||||||
FSP_DRIVER_DISPATCH FspFileSystemControl;
|
FSP_DRIVER_DISPATCH FspFileSystemControl;
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
|
||||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
||||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
|
||||||
#pragma alloc_text(PAGE, FspFileSystemControl)
|
#pragma alloc_text(PAGE, FspFileSystemControl)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RequestFileNode = 0,
|
||||||
|
};
|
||||||
|
|
||||||
static NTSTATUS FspFsctlFileSystemControl(
|
static NTSTATUS FspFsctlFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
@ -44,32 +59,247 @@ static NTSTATUS FspFsctlFileSystemControl(
|
|||||||
{
|
{
|
||||||
case FSP_FSCTL_VOLUME_NAME:
|
case FSP_FSCTL_VOLUME_NAME:
|
||||||
if (0 != IrpSp->FileObject->FsContext2)
|
if (0 != IrpSp->FileObject->FsContext2)
|
||||||
Result = FspVolumeGetName(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_VOLUME_LIST:
|
case FSP_FSCTL_VOLUME_LIST:
|
||||||
Result = FspVolumeGetNameList(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeGetNameList(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_TRANSACT:
|
case FSP_FSCTL_TRANSACT:
|
||||||
case FSP_FSCTL_TRANSACT_BATCH:
|
case FSP_FSCTL_TRANSACT_BATCH:
|
||||||
if (0 != IrpSp->FileObject->FsContext2)
|
if (0 != IrpSp->FileObject->FsContext2)
|
||||||
Result = FspVolumeTransact(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_STOP:
|
case FSP_FSCTL_STOP:
|
||||||
if (0 != IrpSp->FileObject->FsContext2)
|
if (0 != IrpSp->FileObject->FsContext2)
|
||||||
Result = FspVolumeStop(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IRP_MN_MOUNT_VOLUME:
|
case IRP_MN_MOUNT_VOLUME:
|
||||||
Result = FspVolumeMount(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeMount(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN IsWrite)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
|
||||||
|
/* do we support reparse points? */
|
||||||
|
if (!FsvolDeviceExtension->VolumeParams.ReparsePoints)
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
/* is this a valid FileObject? */
|
||||||
|
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
|
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||||||
|
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
PVOID OutputBuffer = Irp->UserBuffer;
|
||||||
|
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||||
|
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||||
|
PREPARSE_DATA_BUFFER ReparseData;
|
||||||
|
PWSTR ReparseTargetPath;
|
||||||
|
USHORT ReparseTargetPathLength;
|
||||||
|
UINT16 TargetOnFileSystem = 0;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
|
if (IsWrite)
|
||||||
|
{
|
||||||
|
if (0 == InputBuffer || 0 == InputBufferLength ||
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX - (FileNode->FileName.Length + sizeof(WCHAR)) <
|
||||||
|
InputBufferLength)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(InputBufferLength, InputBuffer);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
ReparseData = (PREPARSE_DATA_BUFFER)InputBuffer;
|
||||||
|
|
||||||
|
if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag)
|
||||||
|
{
|
||||||
|
/* NTFS severely limits symbolic links; we will not do that unless our file system asks */
|
||||||
|
if (FsvolDeviceExtension->VolumeParams.ReparsePointsAccessCheck)
|
||||||
|
{
|
||||||
|
if (KernelMode != Irp->RequestorMode &&
|
||||||
|
!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE),
|
||||||
|
UserMode))
|
||||||
|
return STATUS_PRIVILEGE_NOT_HELD;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReparseTargetPath = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
||||||
|
ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||||
|
|
||||||
|
/* is this an absolute path? determine if target resides on same device as link */
|
||||||
|
if (!FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE) &&
|
||||||
|
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
|
||||||
|
{
|
||||||
|
UNICODE_STRING TargetObjectName;
|
||||||
|
PDEVICE_OBJECT TargetDeviceObject;
|
||||||
|
PFILE_OBJECT TargetFileObject;
|
||||||
|
ULONG TargetFileNameIndex;
|
||||||
|
ULONG32 TargetProviderId;
|
||||||
|
FSRTL_MUP_PROVIDER_INFO_LEVEL_1 ProviderInfo;
|
||||||
|
ULONG ProviderInfoSize;
|
||||||
|
|
||||||
|
TargetObjectName.Length = TargetObjectName.MaximumLength = ReparseTargetPathLength;
|
||||||
|
TargetObjectName.Buffer = ReparseTargetPath;
|
||||||
|
|
||||||
|
/* get a pointer to the target device */
|
||||||
|
Result = FspGetDeviceObjectPointer(&TargetObjectName, FILE_READ_DATA,
|
||||||
|
&TargetFileNameIndex, &TargetFileObject, &TargetDeviceObject);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto target_check_exit;
|
||||||
|
|
||||||
|
/* is the target device the same as ours? */
|
||||||
|
if (TargetFileNameIndex < ReparseTargetPathLength &&
|
||||||
|
IoGetRelatedDeviceObject(FileObject) == TargetDeviceObject)
|
||||||
|
{
|
||||||
|
if (0 == FsvolDeviceExtension->VolumePrefix.Length)
|
||||||
|
/* not going thru MUP: DONE! */
|
||||||
|
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* going thru MUP cases: \Device\Volume{GUID} and \??\UNC\{VolumePrefix} */
|
||||||
|
ProviderInfoSize = sizeof ProviderInfo;
|
||||||
|
Result = FsRtlMupGetProviderInfoFromFileObject(TargetFileObject, 1,
|
||||||
|
&ProviderInfo, &ProviderInfoSize);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
/* case \Device\Volume{GUID}: is the targer provider id same as ours? */
|
||||||
|
|
||||||
|
TargetProviderId = ProviderInfo.ProviderId;
|
||||||
|
|
||||||
|
ProviderInfoSize = sizeof ProviderInfo;
|
||||||
|
Result = FsRtlMupGetProviderInfoFromFileObject(FileObject, 1,
|
||||||
|
&ProviderInfo, &ProviderInfoSize);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto target_check_exit;
|
||||||
|
|
||||||
|
if (ProviderInfo.ProviderId == TargetProviderId)
|
||||||
|
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* case \??\UNC\{VolumePrefix}: is the target volume prefix same as ours? */
|
||||||
|
|
||||||
|
TargetObjectName.Length = TargetObjectName.MaximumLength =
|
||||||
|
FsvolDeviceExtension->VolumePrefix.Length;
|
||||||
|
TargetObjectName.Buffer = ReparseTargetPath +
|
||||||
|
TargetFileNameIndex / sizeof(WCHAR);
|
||||||
|
|
||||||
|
TargetFileNameIndex += FsvolDeviceExtension->VolumePrefix.Length;
|
||||||
|
|
||||||
|
if (TargetFileNameIndex < ReparseTargetPathLength &&
|
||||||
|
RtlEqualUnicodeString(&FsvolDeviceExtension->VolumePrefix,
|
||||||
|
&TargetObjectName,
|
||||||
|
FSP_VOLUME_PREFIX_CASE_INS))
|
||||||
|
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObDereferenceObject(TargetFileObject);
|
||||||
|
|
||||||
|
target_check_exit:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (0 == OutputBuffer || 0 == OutputBufferLength)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NtFsControlFile (IopXxxControlFile) will setup Irp->AssociatedIrp.SystemBuffer
|
||||||
|
* with enough space for either InputBufferLength or OutputBufferLength. There is
|
||||||
|
* no need to call FspBufferUserBuffer ourselves.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FspFileNodeAcquireShared(FileNode, Full);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, IsWrite ? InputBufferLength : 0,
|
||||||
|
FspFsvolFileSystemControlRequestFini, &Request);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request->Kind = FspFsctlTransactFileSystemControlKind;
|
||||||
|
Request->Req.FileSystemControl.UserContext = FileNode->UserContext;
|
||||||
|
Request->Req.FileSystemControl.UserContext2 = FileDesc->UserContext2;
|
||||||
|
Request->Req.FileSystemControl.FsControlCode = FsControlCode;
|
||||||
|
if (IsWrite)
|
||||||
|
{
|
||||||
|
Request->Req.FileSystemControl.Buffer.Offset = Request->FileName.Size;
|
||||||
|
Request->Req.FileSystemControl.Buffer.Size = (UINT16)InputBufferLength;
|
||||||
|
RtlCopyMemory(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||||
|
InputBuffer, InputBufferLength);
|
||||||
|
|
||||||
|
Request->Req.FileSystemControl.TargetOnFileSystem = TargetOnFileSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||||
|
|
||||||
|
return FSP_STATUS_IOQ_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||||
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
BOOLEAN IsWrite)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (IsWrite)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||||
|
|
||||||
|
if (Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset +
|
||||||
|
Response->Rsp.FileSystemControl.Buffer.Size > (PUINT8)Response + Response->Size)
|
||||||
|
return STATUS_IO_REPARSE_DATA_INVALID;
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.FileSystemControl.Buffer.Size,
|
||||||
|
(PVOID)(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset));
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
if (Response->Rsp.FileSystemControl.Buffer.Size > OutputBufferLength)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
RtlCopyMemory(OutputBuffer, Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||||
|
Response->Rsp.FileSystemControl.Buffer.Size);
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = Response->Rsp.FileSystemControl.Buffer.Size;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolFileSystemControl(
|
static NTSTATUS FspFsvolFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
@ -81,7 +311,14 @@ static NTSTATUS FspFsvolFileSystemControl(
|
|||||||
{
|
{
|
||||||
case FSP_FSCTL_WORK:
|
case FSP_FSCTL_WORK:
|
||||||
case FSP_FSCTL_WORK_BEST_EFFORT:
|
case FSP_FSCTL_WORK_BEST_EFFORT:
|
||||||
Result = FspVolumeWork(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
|
||||||
|
break;
|
||||||
|
case FSCTL_GET_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, FALSE);
|
||||||
|
break;
|
||||||
|
case FSCTL_SET_REPARSE_POINT:
|
||||||
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -95,6 +332,43 @@ NTSTATUS FspFsvolFileSystemControlComplete(
|
|||||||
{
|
{
|
||||||
FSP_ENTER_IOC(PAGED_CODE());
|
FSP_ENTER_IOC(PAGED_CODE());
|
||||||
|
|
||||||
|
/* exit now if we do not have a FileObject (FSP_FSCTL_WORK*) */
|
||||||
|
if (0 == IrpSp->FileObject)
|
||||||
|
FSP_RETURN();
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||||
|
{
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
Result = Response->IoStatus.Status;
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
|
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
|
||||||
|
Result = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
switch (IrpSp->MinorFunction)
|
||||||
|
{
|
||||||
|
case IRP_MN_USER_FS_REQUEST:
|
||||||
|
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
|
||||||
|
{
|
||||||
|
case FSCTL_GET_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, FALSE);
|
||||||
|
break;
|
||||||
|
case FSCTL_SET_REPARSE_POINT:
|
||||||
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, TRUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(STATUS_INVALID_DEVICE_REQUEST != Result);
|
||||||
|
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||||
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
|
||||||
FSP_LEAVE_IOC(
|
FSP_LEAVE_IOC(
|
||||||
"%s%sFileObject=%p",
|
"%s%sFileObject=%p",
|
||||||
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
||||||
@ -103,6 +377,16 @@ NTSTATUS FspFsvolFileSystemControlComplete(
|
|||||||
IrpSp->FileObject);
|
IrpSp->FileObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VOID FspFsvolFileSystemControlRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||||
|
|
||||||
|
if (0 != FileNode)
|
||||||
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS FspFileSystemControl(
|
NTSTATUS FspFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
{
|
{
|
||||||
|
150
src/sys/ioctl.i
150
src/sys/ioctl.i
@ -89,82 +89,82 @@ SYM(FSCTL_DFSR_SET_GHOST_HANDLE_STATE)
|
|||||||
SYM(FSCTL_TXFS_LIST_TRANSACTIONS)
|
SYM(FSCTL_TXFS_LIST_TRANSACTIONS)
|
||||||
SYM(FSCTL_QUERY_PAGEFILE_ENCRYPTION)
|
SYM(FSCTL_QUERY_PAGEFILE_ENCRYPTION)
|
||||||
SYM(FSCTL_RESET_VOLUME_ALLOCATION_HINTS)
|
SYM(FSCTL_RESET_VOLUME_ALLOCATION_HINTS)
|
||||||
SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
|
//SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
|
||||||
SYM(FSCTL_SD_GLOBAL_CHANGE)
|
//SYM(FSCTL_SD_GLOBAL_CHANGE)
|
||||||
SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
|
SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
|
||||||
SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
|
//SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
|
||||||
SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
|
//SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
|
||||||
SYM(FSCTL_FILE_TYPE_NOTIFICATION)
|
//SYM(FSCTL_FILE_TYPE_NOTIFICATION)
|
||||||
SYM(FSCTL_FILE_LEVEL_TRIM)
|
//SYM(FSCTL_FILE_LEVEL_TRIM)
|
||||||
SYM(FSCTL_GET_BOOT_AREA_INFO)
|
//SYM(FSCTL_GET_BOOT_AREA_INFO)
|
||||||
SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
|
//SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
|
||||||
SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
|
//SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
|
||||||
SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
|
//SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
|
||||||
SYM(FSCTL_REQUEST_OPLOCK)
|
//SYM(FSCTL_REQUEST_OPLOCK)
|
||||||
SYM(FSCTL_CSV_TUNNEL_REQUEST)
|
//SYM(FSCTL_CSV_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_IS_CSV_FILE)
|
//SYM(FSCTL_IS_CSV_FILE)
|
||||||
SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
|
//SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
|
||||||
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
|
//SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
|
||||||
SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
|
//SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
|
||||||
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
|
//SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
|
||||||
SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
|
//SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
|
||||||
SYM(FSCTL_CORRUPTION_HANDLING)
|
//SYM(FSCTL_CORRUPTION_HANDLING)
|
||||||
SYM(FSCTL_OFFLOAD_READ)
|
//SYM(FSCTL_OFFLOAD_READ)
|
||||||
SYM(FSCTL_OFFLOAD_WRITE)
|
//SYM(FSCTL_OFFLOAD_WRITE)
|
||||||
SYM(FSCTL_CSV_INTERNAL)
|
//SYM(FSCTL_CSV_INTERNAL)
|
||||||
SYM(FSCTL_SET_PURGE_FAILURE_MODE)
|
//SYM(FSCTL_SET_PURGE_FAILURE_MODE)
|
||||||
SYM(FSCTL_QUERY_FILE_LAYOUT)
|
//SYM(FSCTL_QUERY_FILE_LAYOUT)
|
||||||
SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
|
//SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
|
||||||
SYM(FSCTL_GET_INTEGRITY_INFORMATION)
|
//SYM(FSCTL_GET_INTEGRITY_INFORMATION)
|
||||||
SYM(FSCTL_SET_INTEGRITY_INFORMATION)
|
//SYM(FSCTL_SET_INTEGRITY_INFORMATION)
|
||||||
SYM(FSCTL_QUERY_FILE_REGIONS)
|
//SYM(FSCTL_QUERY_FILE_REGIONS)
|
||||||
SYM(FSCTL_DEDUP_FILE)
|
//SYM(FSCTL_DEDUP_FILE)
|
||||||
SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
|
//SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
|
||||||
SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
|
//SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
|
||||||
SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
|
//SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
|
||||||
SYM(FSCTL_RKF_INTERNAL)
|
//SYM(FSCTL_RKF_INTERNAL)
|
||||||
SYM(FSCTL_SCRUB_DATA)
|
//SYM(FSCTL_SCRUB_DATA)
|
||||||
SYM(FSCTL_REPAIR_COPIES)
|
//SYM(FSCTL_REPAIR_COPIES)
|
||||||
SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
|
//SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
|
||||||
SYM(FSCTL_CSV_MGMT_LOCK)
|
//SYM(FSCTL_CSV_MGMT_LOCK)
|
||||||
SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
|
//SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
|
||||||
SYM(FSCTL_ADVANCE_FILE_ID)
|
//SYM(FSCTL_ADVANCE_FILE_ID)
|
||||||
SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
|
//SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
|
//SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
|
||||||
SYM(FSCTL_WRITE_USN_REASON)
|
//SYM(FSCTL_WRITE_USN_REASON)
|
||||||
SYM(FSCTL_CSV_CONTROL)
|
//SYM(FSCTL_CSV_CONTROL)
|
||||||
SYM(FSCTL_GET_REFS_VOLUME_DATA)
|
//SYM(FSCTL_GET_REFS_VOLUME_DATA)
|
||||||
SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
|
//SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_QUERY_STORAGE_CLASSES)
|
//SYM(FSCTL_QUERY_STORAGE_CLASSES)
|
||||||
SYM(FSCTL_QUERY_REGION_INFO)
|
//SYM(FSCTL_QUERY_REGION_INFO)
|
||||||
SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
|
//SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
|
||||||
SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
|
//SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
|
||||||
SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
|
//SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
|
//SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
|
||||||
SYM(FSCTL_SET_EXTERNAL_BACKING)
|
//SYM(FSCTL_SET_EXTERNAL_BACKING)
|
||||||
SYM(FSCTL_GET_EXTERNAL_BACKING)
|
//SYM(FSCTL_GET_EXTERNAL_BACKING)
|
||||||
SYM(FSCTL_DELETE_EXTERNAL_BACKING)
|
//SYM(FSCTL_DELETE_EXTERNAL_BACKING)
|
||||||
SYM(FSCTL_ENUM_EXTERNAL_BACKING)
|
//SYM(FSCTL_ENUM_EXTERNAL_BACKING)
|
||||||
SYM(FSCTL_ENUM_OVERLAY)
|
//SYM(FSCTL_ENUM_OVERLAY)
|
||||||
SYM(FSCTL_ADD_OVERLAY)
|
//SYM(FSCTL_ADD_OVERLAY)
|
||||||
SYM(FSCTL_REMOVE_OVERLAY)
|
//SYM(FSCTL_REMOVE_OVERLAY)
|
||||||
SYM(FSCTL_UPDATE_OVERLAY)
|
//SYM(FSCTL_UPDATE_OVERLAY)
|
||||||
SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
|
//SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
|
||||||
SYM(FSCTL_SPARSE_OVERALLOCATE)
|
//SYM(FSCTL_SPARSE_OVERALLOCATE)
|
||||||
SYM(FSCTL_STORAGE_QOS_CONTROL)
|
//SYM(FSCTL_STORAGE_QOS_CONTROL)
|
||||||
SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
|
//SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
|
||||||
SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
|
//SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
|
||||||
SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
|
//SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_GET_WOF_VERSION)
|
//SYM(FSCTL_GET_WOF_VERSION)
|
||||||
SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
|
//SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
|
//SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
|
||||||
SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
|
//SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
|
||||||
SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
|
//SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
|
||||||
SYM(FSCTL_CLEAN_VOLUME_METADATA)
|
//SYM(FSCTL_CLEAN_VOLUME_METADATA)
|
||||||
SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
|
//SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
|
||||||
SYM(FSCTL_SUSPEND_OVERLAY)
|
//SYM(FSCTL_SUSPEND_OVERLAY)
|
||||||
SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
|
//SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
|
||||||
SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
|
//SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
|
||||||
SYM(FSCTL_LMR_GET_LINK_TRACKING_INFORMATION)
|
SYM(FSCTL_LMR_GET_LINK_TRACKING_INFORMATION)
|
||||||
SYM(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION)
|
SYM(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION)
|
||||||
SYM(IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
|
SYM(IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -48,10 +48,12 @@ NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Requests (and RequestHeaders) must be 16-byte aligned, because we use the low 4 bits for flags */
|
/* Requests (and RequestHeaders) must be 16-byte aligned, because we use the low 4 bits for flags */
|
||||||
#if 16 != MEMORY_ALLOCATION_ALIGNMENT
|
#if REQ_ALIGN_SIZE <= MEMORY_ALLOCATION_ALIGNMENT
|
||||||
#define REQ_HEADER_ALIGNMASK 15
|
#define REQ_HEADER_ALIGN_MASK 0
|
||||||
|
#define REQ_HEADER_ALIGN_OVERHEAD 0
|
||||||
#else
|
#else
|
||||||
#define REQ_HEADER_ALIGNMASK 0
|
#define REQ_HEADER_ALIGN_MASK (REQ_ALIGN_SIZE - 1)
|
||||||
|
#define REQ_HEADER_ALIGN_OVERHEAD (sizeof(PVOID) + REQ_HEADER_ALIGN_MASK)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NTSTATUS FspIopCreateRequestFunnel(
|
NTSTATUS FspIopCreateRequestFunnel(
|
||||||
@ -74,20 +76,23 @@ NTSTATUS FspIopCreateRequestFunnel(
|
|||||||
if (FlagOn(Flags, FspIopRequestMustSucceed))
|
if (FlagOn(Flags, FspIopRequestMustSucceed))
|
||||||
RequestHeader = FspAllocatePoolMustSucceed(
|
RequestHeader = FspAllocatePoolMustSucceed(
|
||||||
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
||||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGNMASK,
|
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
||||||
FSP_ALLOC_INTERNAL_TAG);
|
FSP_ALLOC_INTERNAL_TAG);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RequestHeader = ExAllocatePoolWithTag(
|
RequestHeader = ExAllocatePoolWithTag(
|
||||||
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
||||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGNMASK,
|
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
||||||
FSP_ALLOC_INTERNAL_TAG);
|
FSP_ALLOC_INTERNAL_TAG);
|
||||||
if (0 == RequestHeader)
|
if (0 == RequestHeader)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 != REQ_HEADER_ALIGNMASK
|
#if 0 != REQ_HEADER_ALIGN_MASK
|
||||||
RequestHeader = (PVOID)(((UINT_PTR)RequestHeader + REQ_HEADER_ALIGNMASK) & REQ_HEADER_ALIGNMASK);
|
PVOID Allocation = RequestHeader;
|
||||||
|
RequestHeader = (PVOID)(((UINT_PTR)RequestHeader + REQ_HEADER_ALIGN_OVERHEAD) &
|
||||||
|
~REQ_HEADER_ALIGN_MASK);
|
||||||
|
((PVOID *)RequestHeader)[-1] = Allocation;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
|
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
|
||||||
@ -127,6 +132,10 @@ VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
if (0 != RequestHeader->Response)
|
if (0 != RequestHeader->Response)
|
||||||
FspFree(RequestHeader->Response);
|
FspFree(RequestHeader->Response);
|
||||||
|
|
||||||
|
#if 0 != REQ_HEADER_ALIGN_MASK
|
||||||
|
RequestHeader = ((PVOID *)RequestHeader)[-1];
|
||||||
|
#endif
|
||||||
|
|
||||||
FspFree(RequestHeader);
|
FspFree(RequestHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +227,7 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference)
|
|||||||
/* get the device object out of the IRP before completion */
|
/* get the device object out of the IRP before completion */
|
||||||
PDEVICE_OBJECT DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
|
PDEVICE_OBJECT DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
|
||||||
|
|
||||||
if (STATUS_SUCCESS != Result && STATUS_BUFFER_OVERFLOW != Result)
|
if (STATUS_SUCCESS != Result && STATUS_REPARSE != Result && STATUS_BUFFER_OVERFLOW != Result)
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
Irp->IoStatus.Status = Result;
|
Irp->IoStatus.Status = Result;
|
||||||
IoCompleteRequest(Irp, FSP_IO_INCREMENT);
|
IoCompleteRequest(Irp, FSP_IO_INCREMENT);
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -20,6 +20,11 @@
|
|||||||
/*
|
/*
|
||||||
* Overview
|
* Overview
|
||||||
*
|
*
|
||||||
|
* [NOTE: this comment no longer describes accurately an FSP_IOQ. The main
|
||||||
|
* difference is that an FSP_IOQ now has a third queue which is used to
|
||||||
|
* retry IRP completions. However the main ideas below are still valid, so
|
||||||
|
* I am leaving the rest of the comment intact.]
|
||||||
|
*
|
||||||
* An FSP_IOQ encapsulates the main FSP mechanism for handling IRP's.
|
* An FSP_IOQ encapsulates the main FSP mechanism for handling IRP's.
|
||||||
* It has two queues: a "Pending" queue for managing newly arrived IRP's
|
* It has two queues: a "Pending" queue for managing newly arrived IRP's
|
||||||
* and a "Processing" queue for managing IRP's currently being processed
|
* and a "Processing" queue for managing IRP's currently being processed
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -146,7 +146,8 @@ NTSTATUS FspFsvolQuerySecurityComplete(
|
|||||||
FSP_RETURN();
|
FSP_RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
FspIopRequestContext(Request, RequestSecurityChangeNumber) = (PVOID)FileNode->SecurityChangeNumber;
|
FspIopRequestContext(Request, RequestSecurityChangeNumber) = (PVOID)
|
||||||
|
FspFileNodeSecurityChangeNumber(FileNode);
|
||||||
FspIopRequestContext(Request, RequestFileNode) = 0;
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||||
|
|
||||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
179
src/sys/util.c
179
src/sys/util.c
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -17,9 +17,12 @@
|
|||||||
|
|
||||||
#include <sys/driver.h>
|
#include <sys/driver.h>
|
||||||
|
|
||||||
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams);
|
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
|
||||||
|
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
|
||||||
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
|
VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
|
||||||
NTSTATUS FspCreateGuid(GUID *Guid);
|
NTSTATUS FspCreateGuid(GUID *Guid);
|
||||||
|
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
|
||||||
|
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
|
||||||
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||||
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
|
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
|
||||||
static NTSTATUS FspSendSetInformationIrpCompletion(
|
static NTSTATUS FspSendSetInformationIrpCompletion(
|
||||||
@ -86,8 +89,10 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
|
|||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspUnicodePathIsValid)
|
#pragma alloc_text(PAGE, FspUnicodePathIsValid)
|
||||||
|
#pragma alloc_text(PAGE, FspUnicodePathIsValidPattern)
|
||||||
#pragma alloc_text(PAGE, FspUnicodePathSuffix)
|
#pragma alloc_text(PAGE, FspUnicodePathSuffix)
|
||||||
#pragma alloc_text(PAGE, FspCreateGuid)
|
#pragma alloc_text(PAGE, FspCreateGuid)
|
||||||
|
#pragma alloc_text(PAGE, FspGetDeviceObjectPointer)
|
||||||
#pragma alloc_text(PAGE, FspSendSetInformationIrp)
|
#pragma alloc_text(PAGE, FspSendSetInformationIrp)
|
||||||
#pragma alloc_text(PAGE, FspBufferUserBuffer)
|
#pragma alloc_text(PAGE, FspBufferUserBuffer)
|
||||||
#pragma alloc_text(PAGE, FspLockUserBuffer)
|
#pragma alloc_text(PAGE, FspLockUserBuffer)
|
||||||
@ -166,32 +171,138 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams)
|
BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType)
|
||||||
{
|
{
|
||||||
/* this does NOT check if the Path contains invalid file name chars (*, ?, etc.) */
|
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* if StreamPart is not NULL, StreamType must also be not NULL */
|
||||||
|
ASSERT(0 == StreamPart || 0 != StreamType);
|
||||||
|
|
||||||
if (0 != Path->Length % sizeof(WCHAR))
|
if (0 != Path->Length % sizeof(WCHAR))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
PWSTR PathBgn, PathEnd, PathPtr;
|
PWSTR PathBgn, PathEnd, PathPtr, StreamTypeStr = 0;
|
||||||
|
UCHAR Flags = FSRTL_NTFS_LEGAL;
|
||||||
|
ULONG Colons = 0;
|
||||||
|
WCHAR Char;
|
||||||
|
|
||||||
PathBgn = Path->Buffer;
|
PathBgn = Path->Buffer;
|
||||||
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
|
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
|
||||||
PathPtr = PathBgn;
|
PathPtr = PathBgn;
|
||||||
|
|
||||||
while (PathEnd > PathPtr)
|
while (PathEnd > PathPtr)
|
||||||
if (L'\\' == *PathPtr)
|
{
|
||||||
|
Char = *PathPtr;
|
||||||
|
|
||||||
|
if (L'\\' == Char)
|
||||||
{
|
{
|
||||||
|
/* stream names can only appear as the last path component */
|
||||||
|
if (0 < Colons)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
PathPtr++;
|
PathPtr++;
|
||||||
|
|
||||||
|
/* don't like multiple backslashes */
|
||||||
if (PathEnd > PathPtr && L'\\' == *PathPtr)
|
if (PathEnd > PathPtr && L'\\' == *PathPtr)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (!AllowStreams && L':' == *PathPtr)
|
else if (L':' == Char)
|
||||||
|
{
|
||||||
|
if (0 == StreamPart)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Where are the docs on legal stream names?
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* stream characters now allowed */
|
||||||
|
Flags = FSRTL_NTFS_STREAM_LEGAL;
|
||||||
|
|
||||||
|
PathPtr++;
|
||||||
|
Colons++;
|
||||||
|
|
||||||
|
if (1 == Colons)
|
||||||
|
{
|
||||||
|
/* first time through: set up StreamPart */
|
||||||
|
StreamPart->Length = StreamPart->MaximumLength = (USHORT)
|
||||||
|
((PUINT8)PathEnd - (PUINT8)PathPtr);
|
||||||
|
StreamPart->Buffer = PathPtr;
|
||||||
|
}
|
||||||
|
else if (2 == Colons)
|
||||||
|
{
|
||||||
|
/* second time through: fix StreamPart length to not include 2nd colon */
|
||||||
|
StreamPart->Length = (USHORT)
|
||||||
|
((PUINT8)PathPtr - (PUINT8)StreamPart->Buffer - sizeof(WCHAR));
|
||||||
|
|
||||||
|
StreamTypeStr = PathPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, FALSE, Flags))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else
|
else
|
||||||
PathPtr++;
|
PathPtr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we had no colons the path is valid */
|
||||||
|
if (0 == Colons)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
ASSERT(0 != StreamPart && 0 != StreamType);
|
||||||
|
|
||||||
|
*StreamType = FspUnicodePathStreamTypeNone;
|
||||||
|
|
||||||
|
/* if we had no stream type the path is valid if there was an actual stream name */
|
||||||
|
if (0 == StreamTypeStr)
|
||||||
|
return 0 != StreamPart->Length;
|
||||||
|
|
||||||
|
/* if we had a stream type the path is valid if the stream type was "$DATA" only */
|
||||||
|
if (StreamTypeStr + 5 == PathEnd &&
|
||||||
|
L'$' == StreamTypeStr[0] &&
|
||||||
|
L'D' == StreamTypeStr[1] &&
|
||||||
|
L'A' == StreamTypeStr[2] &&
|
||||||
|
L'T' == StreamTypeStr[3] &&
|
||||||
|
L'A' == StreamTypeStr[4])
|
||||||
|
{
|
||||||
|
*StreamType = FspUnicodePathStreamTypeData;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Path)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (0 != Path->Length % sizeof(WCHAR))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
PWSTR PathBgn, PathEnd, PathPtr;
|
||||||
|
WCHAR Char;
|
||||||
|
|
||||||
|
PathBgn = Path->Buffer;
|
||||||
|
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
|
||||||
|
PathPtr = PathBgn;
|
||||||
|
|
||||||
|
while (PathEnd > PathPtr)
|
||||||
|
{
|
||||||
|
Char = *PathPtr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A pattern is allowed to have wildcards. It cannot consist of multiple
|
||||||
|
* path components (have a backslash) and it cannot reference a stream (have
|
||||||
|
* a colon).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (L'\\' == Char)
|
||||||
|
return FALSE;
|
||||||
|
else if (L':' == Char)
|
||||||
|
return FALSE;
|
||||||
|
else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, TRUE, FSRTL_NTFS_LEGAL))
|
||||||
|
return FALSE;
|
||||||
|
else
|
||||||
|
PathPtr++;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -243,6 +354,54 @@ NTSTATUS FspCreateGuid(GUID *Guid)
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
|
||||||
|
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
UNICODE_STRING PartialName;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE Handle;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
PartialName.Length = 0;
|
||||||
|
PartialName.MaximumLength = ObjectName->Length;
|
||||||
|
PartialName.Buffer = ObjectName->Buffer;
|
||||||
|
|
||||||
|
Result = STATUS_NO_SUCH_DEVICE;
|
||||||
|
while (PartialName.MaximumLength > PartialName.Length)
|
||||||
|
{
|
||||||
|
while (PartialName.MaximumLength > PartialName.Length &&
|
||||||
|
L'\\' == PartialName.Buffer[PartialName.Length / sizeof(WCHAR)])
|
||||||
|
PartialName.Length += sizeof(WCHAR);
|
||||||
|
while (PartialName.MaximumLength > PartialName.Length &&
|
||||||
|
L'\\' != PartialName.Buffer[PartialName.Length / sizeof(WCHAR)])
|
||||||
|
PartialName.Length += sizeof(WCHAR);
|
||||||
|
|
||||||
|
Result = IoGetDeviceObjectPointer(&PartialName, DesiredAccess, PFileObject, PDeviceObject);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
*PFileNameIndex = PartialName.Length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &PartialName, OBJ_KERNEL_HANDLE, 0, 0);
|
||||||
|
Result = ZwOpenDirectoryObject(&Handle, 0, &ObjectAttributes);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = ZwOpenSymbolicLinkObject(&Handle, 0, &ObjectAttributes);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = STATUS_NO_SUCH_DEVICE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ZwClose(Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IO_STATUS_BLOCK IoStatus;
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -79,6 +79,10 @@ static NTSTATUS FspFsvolQueryFsAttributeInformation(
|
|||||||
PFILE_FS_ATTRIBUTE_INFORMATION Info = (PFILE_FS_ATTRIBUTE_INFORMATION)*PBuffer;
|
PFILE_FS_ATTRIBUTE_INFORMATION Info = (PFILE_FS_ATTRIBUTE_INFORMATION)*PBuffer;
|
||||||
PUINT8 Buffer = (PUINT8)Info->FileSystemName;
|
PUINT8 Buffer = (PUINT8)Info->FileSystemName;
|
||||||
ULONG CopyLength;
|
ULONG CopyLength;
|
||||||
|
UNICODE_STRING FileSystemName;
|
||||||
|
WCHAR FileSystemNameBuf[16 + FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||||
|
|
||||||
|
ASSERT(sizeof FileSystemNameBuf >= sizeof L"" DRIVER_NAME + FSP_FSCTL_VOLUME_FSNAME_SIZE);
|
||||||
|
|
||||||
Info->FileSystemAttributes =
|
Info->FileSystemAttributes =
|
||||||
(FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch ? FILE_CASE_SENSITIVE_SEARCH : 0) |
|
(FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch ? FILE_CASE_SENSITIVE_SEARCH : 0) |
|
||||||
@ -91,15 +95,27 @@ static NTSTATUS FspFsvolQueryFsAttributeInformation(
|
|||||||
//(FsvolDeviceExtension->VolumeParams.ExtendedAttributes ? FILE_SUPPORTS_EXTENDED_ATTRIBUTES : 0) |
|
//(FsvolDeviceExtension->VolumeParams.ExtendedAttributes ? FILE_SUPPORTS_EXTENDED_ATTRIBUTES : 0) |
|
||||||
(FsvolDeviceExtension->VolumeParams.ReadOnlyVolume ? FILE_READ_ONLY_VOLUME : 0);
|
(FsvolDeviceExtension->VolumeParams.ReadOnlyVolume ? FILE_READ_ONLY_VOLUME : 0);
|
||||||
Info->MaximumComponentNameLength = FsvolDeviceExtension->VolumeParams.MaxComponentLength;
|
Info->MaximumComponentNameLength = FsvolDeviceExtension->VolumeParams.MaxComponentLength;
|
||||||
Info->FileSystemNameLength = sizeof L"" DRIVER_NAME - sizeof(WCHAR);
|
|
||||||
|
|
||||||
CopyLength = Info->FileSystemNameLength;
|
RtlInitUnicodeString(&FileSystemName, FsvolDeviceExtension->VolumeParams.FileSystemName);
|
||||||
|
|
||||||
|
CopyLength = sizeof L"" DRIVER_NAME - sizeof(WCHAR);
|
||||||
|
RtlCopyMemory(FileSystemNameBuf, L"" DRIVER_NAME, CopyLength);
|
||||||
|
if (0 != FileSystemName.Length)
|
||||||
|
{
|
||||||
|
FileSystemNameBuf[CopyLength / sizeof(WCHAR)] = L'-';
|
||||||
|
CopyLength += sizeof(WCHAR);
|
||||||
|
RtlCopyMemory(FileSystemNameBuf + CopyLength / sizeof(WCHAR), FileSystemName.Buffer,
|
||||||
|
FileSystemName.Length);
|
||||||
|
CopyLength += FileSystemName.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info->FileSystemNameLength = CopyLength;
|
||||||
if (Buffer + CopyLength > BufferEnd)
|
if (Buffer + CopyLength > BufferEnd)
|
||||||
{
|
{
|
||||||
CopyLength = (ULONG)(BufferEnd - Buffer);
|
CopyLength = (ULONG)(BufferEnd - Buffer);
|
||||||
Result = STATUS_BUFFER_OVERFLOW;
|
Result = STATUS_BUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
RtlCopyMemory(Buffer, L"" DRIVER_NAME, CopyLength);
|
RtlCopyMemory(Buffer, FileSystemNameBuf, CopyLength);
|
||||||
Buffer += CopyLength;
|
Buffer += CopyLength;
|
||||||
|
|
||||||
*PBuffer = Buffer;
|
*PBuffer = Buffer;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -169,6 +169,7 @@ static NTSTATUS FspVolumeCreateNoLock(
|
|||||||
if (I == PrefixLength)
|
if (I == PrefixLength)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
VolumeParams.FileSystemName[sizeof VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
|
||||||
|
|
||||||
/* create volume guid */
|
/* create volume guid */
|
||||||
Result = FspCreateGuid(&Guid);
|
Result = FspCreateGuid(&Guid);
|
||||||
@ -505,9 +506,7 @@ NTSTATUS FspVolumeRedirQueryPathEx(
|
|||||||
if (!FspIoqStopped(FsvolDeviceExtension->Ioq))
|
if (!FspIoqStopped(FsvolDeviceExtension->Ioq))
|
||||||
{
|
{
|
||||||
if (0 < FsvolDeviceExtension->VolumePrefix.Length &&
|
if (0 < FsvolDeviceExtension->VolumePrefix.Length &&
|
||||||
QueryPathRequest->PathName.Length >= FsvolDeviceExtension->VolumePrefix.Length &&
|
FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &QueryPathRequest->PathName) &&
|
||||||
RtlEqualMemory(QueryPathRequest->PathName.Buffer,
|
|
||||||
FsvolDeviceExtension->VolumePrefix.Buffer, FsvolDeviceExtension->VolumePrefix.Length) &&
|
|
||||||
(QueryPathRequest->PathName.Length == FsvolDeviceExtension->VolumePrefix.Length ||
|
(QueryPathRequest->PathName.Length == FsvolDeviceExtension->VolumePrefix.Length ||
|
||||||
'\\' == QueryPathRequest->PathName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)]))
|
'\\' == QueryPathRequest->PathName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)]))
|
||||||
{
|
{
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -151,8 +151,9 @@ static NTSTATUS FspFsvolWriteCached(
|
|||||||
ASSERT(FspTimeoutInfinity32 ==
|
ASSERT(FspTimeoutInfinity32 ==
|
||||||
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
|
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
|
||||||
FspFileNodeGetFileInfo(FileNode, &FileInfo);
|
FspFileNodeGetFileInfo(FileNode, &FileInfo);
|
||||||
WriteEndOffset = WriteToEndOfFile ?
|
if (WriteToEndOfFile)
|
||||||
FileInfo.FileSize + WriteLength : WriteOffset.QuadPart + WriteLength;
|
WriteOffset.QuadPart = FileInfo.FileSize;
|
||||||
|
WriteEndOffset = WriteOffset.QuadPart + WriteLength;
|
||||||
ExtendingFile = FileInfo.FileSize < WriteEndOffset;
|
ExtendingFile = FileInfo.FileSize < WriteEndOffset;
|
||||||
if (ExtendingFile && !CanWait)
|
if (ExtendingFile && !CanWait)
|
||||||
{
|
{
|
||||||
|
33
tools/diag.bat
Normal file
33
tools/diag.bat
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
echo WINFSP INSTALLATION DIRECTORY
|
||||||
|
reg query HKLM\SOFTWARE\WinFsp /reg:32
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo WINFSP DLL REGISTRATIONS
|
||||||
|
reg query HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
|
||||||
|
reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Np\NetworkProvider
|
||||||
|
reg query HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\WinFsp
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo WINFSP LAUNCHER REGISTRATIONS
|
||||||
|
reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services /s
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo WINFSP FSD CONFIGURATION AND STATUS
|
||||||
|
sc query WinFsp
|
||||||
|
sc qc WinFsp
|
||||||
|
sc sdshow WinFsp
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo WINFSP LAUNCHER SERVICE CONFIGURATION AND STATUS
|
||||||
|
sc query WinFsp.Launcher
|
||||||
|
sc qc WinFsp.Launcher
|
||||||
|
sc sdshow WinFsp.Launcher
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo OS INFORMATION
|
||||||
|
systeminfo
|
||||||
|
echo.
|
14
tools/ntstatus.bat
Normal file
14
tools/ntstatus.bat
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
if X%1==X (echo usage: %~n0 VALUE >&2 & exit /b 1)
|
||||||
|
|
||||||
|
set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
|
||||||
|
set RegVal="KitsRoot10"
|
||||||
|
reg query %RegKey% /v %RegVal% >nul 2>&1 || (echo Cannot find Windows Kit >&2 & exit /b 1)
|
||||||
|
for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%') do (
|
||||||
|
set KitRoot=%%j
|
||||||
|
)
|
||||||
|
|
||||||
|
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\10.0.10586.0\shared\%~n0.h"
|
@ -1,6 +1,7 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
setlocal
|
setlocal
|
||||||
|
setlocal EnableDelayedExpansion
|
||||||
|
|
||||||
set Configuration=Release
|
set Configuration=Release
|
||||||
if not X%1==X set Configuration=%1
|
if not X%1==X set Configuration=%1
|
||||||
@ -36,7 +37,7 @@ for %%f in (winfsp-tests-x64 winfsp-tests-x86 :fsx-memfs-x64 :fsx-memfs-x86 :win
|
|||||||
call %%f
|
call %%f
|
||||||
popd
|
popd
|
||||||
|
|
||||||
if errorlevel 1 (
|
if !ERRORLEVEL! neq 0 (
|
||||||
set /a testfail=testfail+1
|
set /a testfail=testfail+1
|
||||||
|
|
||||||
echo === Failed %%f
|
echo === Failed %%f
|
||||||
@ -74,34 +75,42 @@ exit /b 1
|
|||||||
M:
|
M:
|
||||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
|
||||||
|
if errorlevel 1 goto fail
|
||||||
N:
|
N:
|
||||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
|
||||||
|
if errorlevel 1 goto fail
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
:fsx-memfs-x86
|
:fsx-memfs-x86
|
||||||
O:
|
O:
|
||||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
|
||||||
|
if errorlevel 1 goto fail
|
||||||
P:
|
P:
|
||||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
|
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
|
||||||
|
if errorlevel 1 goto fail
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
:winfstest-memfs-x64
|
:winfstest-memfs-x64
|
||||||
M:
|
M:
|
||||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
N:
|
N:
|
||||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
:winfstest-memfs-x86
|
:winfstest-memfs-x86
|
||||||
O:
|
O:
|
||||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
P:
|
P:
|
||||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat" base
|
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
14
tools/winerror.bat
Normal file
14
tools/winerror.bat
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
if X%1==X (echo usage: %~n0 VALUE >&2 & exit /b 1)
|
||||||
|
|
||||||
|
set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
|
||||||
|
set RegVal="KitsRoot10"
|
||||||
|
reg query %RegKey% /v %RegVal% >nul 2>&1 || (echo Cannot find Windows Kit >&2 & exit /b 1)
|
||||||
|
for /f "tokens=2,*" %%i in ('reg query %RegKey% /v %RegVal% ^| findstr %RegVal%') do (
|
||||||
|
set KitRoot=%%j
|
||||||
|
)
|
||||||
|
|
||||||
|
findstr /R /I "\<0*[Xx]*%1[Ll]*\>" "%KitRoot%Include\10.0.10586.0\shared\%~n0.h"
|
@ -11,9 +11,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -38,6 +38,7 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
{
|
{
|
||||||
wchar_t **argp, **arge;
|
wchar_t **argp, **arge;
|
||||||
ULONG DebugFlags = 0;
|
ULONG DebugFlags = 0;
|
||||||
|
PWSTR DebugLogFile = 0;
|
||||||
ULONG Flags = MemfsDisk;
|
ULONG Flags = MemfsDisk;
|
||||||
ULONG FileInfoTimeout = INFINITE;
|
ULONG FileInfoTimeout = INFINITE;
|
||||||
ULONG MaxFileNodes = 1024;
|
ULONG MaxFileNodes = 1024;
|
||||||
@ -45,6 +46,7 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
PWSTR MountPoint = 0;
|
PWSTR MountPoint = 0;
|
||||||
PWSTR VolumePrefix = 0;
|
PWSTR VolumePrefix = 0;
|
||||||
PWSTR RootSddl = 0;
|
PWSTR RootSddl = 0;
|
||||||
|
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
|
||||||
MEMFS *Memfs = 0;
|
MEMFS *Memfs = 0;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
@ -59,6 +61,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
case L'd':
|
case L'd':
|
||||||
argtol(DebugFlags);
|
argtol(DebugFlags);
|
||||||
break;
|
break;
|
||||||
|
case L'D':
|
||||||
|
argtos(DebugLogFile);
|
||||||
|
break;
|
||||||
case L'm':
|
case L'm':
|
||||||
argtos(MountPoint);
|
argtos(MountPoint);
|
||||||
break;
|
break;
|
||||||
@ -90,6 +95,28 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
if (MemfsDisk == Flags && 0 == MountPoint)
|
if (MemfsDisk == Flags && 0 == MountPoint)
|
||||||
goto usage;
|
goto usage;
|
||||||
|
|
||||||
|
if (0 != DebugLogFile)
|
||||||
|
{
|
||||||
|
if (0 == wcscmp(L"-", DebugLogFile))
|
||||||
|
DebugLogHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
else
|
||||||
|
DebugLogHandle = CreateFileW(
|
||||||
|
DebugLogFile,
|
||||||
|
FILE_APPEND_DATA,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
0,
|
||||||
|
OPEN_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0);
|
||||||
|
if (INVALID_HANDLE_VALUE == DebugLogHandle)
|
||||||
|
{
|
||||||
|
fail(L"cannot open debug log file");
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspDebugLogSetHandle(DebugLogHandle);
|
||||||
|
}
|
||||||
|
|
||||||
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
|
Result = MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl,
|
||||||
&Memfs);
|
&Memfs);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -142,6 +169,7 @@ usage:
|
|||||||
"\n"
|
"\n"
|
||||||
"options:\n"
|
"options:\n"
|
||||||
" -d DebugFlags [-1: enable all debug logs]\n"
|
" -d DebugFlags [-1: enable all debug logs]\n"
|
||||||
|
" -D DebugLogFile [file path; use - for stdout]\n"
|
||||||
" -t FileInfoTimeout [millis]\n"
|
" -t FileInfoTimeout [millis]\n"
|
||||||
" -n MaxFileNodes\n"
|
" -n MaxFileNodes\n"
|
||||||
" -s MaxFileSize [bytes]\n"
|
" -s MaxFileSize [bytes]\n"
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
@ -20,6 +20,12 @@
|
|||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <VersionHelpers.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define the MEMFS_NAMED_STREAMS macro to include named streams support.
|
||||||
|
*/
|
||||||
|
#define MEMFS_NAMED_STREAMS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
||||||
@ -49,7 +55,16 @@ int MemfsFileNameCompare(PWSTR a, PWSTR b)
|
|||||||
static inline
|
static inline
|
||||||
BOOLEAN MemfsFileNameHasPrefix(PWSTR a, PWSTR b)
|
BOOLEAN MemfsFileNameHasPrefix(PWSTR a, PWSTR b)
|
||||||
{
|
{
|
||||||
return 0 == wcsncmp(a, b, wcslen(b));
|
size_t alen = wcslen(a);
|
||||||
|
size_t blen = wcslen(b);
|
||||||
|
|
||||||
|
return alen >= blen && 0 == memcmp(a, b, blen * sizeof(WCHAR)) &&
|
||||||
|
(alen == blen || (1 == blen && L'\\' == b[0]) ||
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
(L'\\' == a[blen] || L':' == a[blen]));
|
||||||
|
#else
|
||||||
|
(L'\\' == a[blen]));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _MEMFS_FILE_NODE
|
typedef struct _MEMFS_FILE_NODE
|
||||||
@ -59,7 +74,12 @@ typedef struct _MEMFS_FILE_NODE
|
|||||||
SIZE_T FileSecuritySize;
|
SIZE_T FileSecuritySize;
|
||||||
PVOID FileSecurity;
|
PVOID FileSecurity;
|
||||||
PVOID FileData;
|
PVOID FileData;
|
||||||
|
SIZE_T ReparseDataSize;
|
||||||
|
PVOID ReparseData;
|
||||||
ULONG RefCount;
|
ULONG RefCount;
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
struct _MEMFS_FILE_NODE *MainFileNode;
|
||||||
|
#endif
|
||||||
} MEMFS_FILE_NODE;
|
} MEMFS_FILE_NODE;
|
||||||
|
|
||||||
struct MEMFS_FILE_NODE_LESS
|
struct MEMFS_FILE_NODE_LESS
|
||||||
@ -112,11 +132,31 @@ NTSTATUS MemfsFileNodeCreate(PWSTR FileName, MEMFS_FILE_NODE **PFileNode)
|
|||||||
static inline
|
static inline
|
||||||
VOID MemfsFileNodeDelete(MEMFS_FILE_NODE *FileNode)
|
VOID MemfsFileNodeDelete(MEMFS_FILE_NODE *FileNode)
|
||||||
{
|
{
|
||||||
|
free(FileNode->ReparseData);
|
||||||
free(FileNode->FileData);
|
free(FileNode->FileData);
|
||||||
free(FileNode->FileSecurity);
|
free(FileNode->FileSecurity);
|
||||||
free(FileNode);
|
free(FileNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
VOID MemfsFileNodeGetFileInfo(MEMFS_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
|
{
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 == FileNode->MainFileNode)
|
||||||
|
*FileInfo = FileNode->FileInfo;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*FileInfo = FileNode->MainFileNode->FileInfo;
|
||||||
|
FileInfo->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
/* named streams cannot be directories */
|
||||||
|
FileInfo->AllocationSize = FileNode->FileInfo.AllocationSize;
|
||||||
|
FileInfo->FileSize = FileNode->FileInfo.FileSize;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
*FileInfo = FileNode->FileInfo;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
VOID MemfsFileNodeMapDump(MEMFS_FILE_NODE_MAP *FileNodeMap)
|
VOID MemfsFileNodeMapDump(MEMFS_FILE_NODE_MAP *FileNodeMap)
|
||||||
{
|
{
|
||||||
@ -167,6 +207,23 @@ MEMFS_FILE_NODE *MemfsFileNodeMapGet(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR Fil
|
|||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
static inline
|
||||||
|
MEMFS_FILE_NODE *MemfsFileNodeMapGetMain(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR FileName0)
|
||||||
|
{
|
||||||
|
WCHAR FileName[MAX_PATH];
|
||||||
|
wcscpy_s(FileName, sizeof FileName / sizeof(WCHAR), FileName0);
|
||||||
|
PWSTR StreamName = wcschr(FileName, L':');
|
||||||
|
if (0 == StreamName)
|
||||||
|
return 0;
|
||||||
|
StreamName[0] = L'\0';
|
||||||
|
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->find(FileName);
|
||||||
|
if (iter == FileNodeMap->end())
|
||||||
|
return 0;
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
MEMFS_FILE_NODE *MemfsFileNodeMapGetParent(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR FileName0,
|
MEMFS_FILE_NODE *MemfsFileNodeMapGetParent(MEMFS_FILE_NODE_MAP *FileNodeMap, PWSTR FileName0,
|
||||||
PNTSTATUS PResult)
|
PNTSTATUS PResult)
|
||||||
@ -219,15 +276,21 @@ VOID MemfsFileNodeMapRemove(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *F
|
|||||||
static inline
|
static inline
|
||||||
BOOLEAN MemfsFileNodeMapHasChild(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode)
|
BOOLEAN MemfsFileNodeMapHasChild(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode)
|
||||||
{
|
{
|
||||||
BOOLEAN Result;
|
BOOLEAN Result = FALSE;
|
||||||
WCHAR Root[2] = L"\\";
|
WCHAR Root[2] = L"\\";
|
||||||
PWSTR Remain, Suffix;
|
PWSTR Remain, Suffix;
|
||||||
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
|
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
|
||||||
if (iter == FileNodeMap->end())
|
for (; FileNodeMap->end() != iter; ++iter)
|
||||||
return FALSE;
|
{
|
||||||
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
Result = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
|
if (0 != wcschr(iter->second->FileName, L':'))
|
||||||
FspPathCombine(iter->second->FileName, Suffix);
|
continue;
|
||||||
|
#endif
|
||||||
|
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
||||||
|
Result = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
|
||||||
|
FspPathCombine(iter->second->FileName, Suffix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,15 +301,18 @@ BOOLEAN MemfsFileNodeMapEnumerateChildren(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMF
|
|||||||
WCHAR Root[2] = L"\\";
|
WCHAR Root[2] = L"\\";
|
||||||
PWSTR Remain, Suffix;
|
PWSTR Remain, Suffix;
|
||||||
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
|
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
|
||||||
BOOLEAN Equal;
|
BOOLEAN IsDirectoryChild;
|
||||||
for (; FileNodeMap->end() != iter; ++iter)
|
for (; FileNodeMap->end() != iter; ++iter)
|
||||||
{
|
{
|
||||||
if (!MemfsFileNameHasPrefix(iter->second->FileName, FileNode->FileName))
|
if (!MemfsFileNameHasPrefix(iter->second->FileName, FileNode->FileName))
|
||||||
break;
|
break;
|
||||||
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
||||||
Equal = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
|
IsDirectoryChild = 0 == MemfsFileNameCompare(Remain, FileNode->FileName);
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
IsDirectoryChild = IsDirectoryChild && 0 == wcschr(Suffix, L':');
|
||||||
|
#endif
|
||||||
FspPathCombine(iter->second->FileName, Suffix);
|
FspPathCombine(iter->second->FileName, Suffix);
|
||||||
if (Equal)
|
if (IsDirectoryChild)
|
||||||
{
|
{
|
||||||
if (!EnumFn(iter->second, Context))
|
if (!EnumFn(iter->second, Context))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -255,6 +321,25 @@ BOOLEAN MemfsFileNodeMapEnumerateChildren(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMF
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
static inline
|
||||||
|
BOOLEAN MemfsFileNodeMapEnumerateNamedStreams(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode,
|
||||||
|
BOOLEAN (*EnumFn)(MEMFS_FILE_NODE *, PVOID), PVOID Context)
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE_MAP::iterator iter = FileNodeMap->upper_bound(FileNode->FileName);
|
||||||
|
for (; FileNodeMap->end() != iter; ++iter)
|
||||||
|
{
|
||||||
|
if (!MemfsFileNameHasPrefix(iter->second->FileName, FileNode->FileName))
|
||||||
|
break;
|
||||||
|
if (L':' != iter->second->FileName[wcslen(FileNode->FileName)])
|
||||||
|
break;
|
||||||
|
if (!EnumFn(iter->second, Context))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode,
|
BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NODE *FileNode,
|
||||||
BOOLEAN (*EnumFn)(MEMFS_FILE_NODE *, PVOID), PVOID Context)
|
BOOLEAN (*EnumFn)(MEMFS_FILE_NODE *, PVOID), PVOID Context)
|
||||||
@ -271,6 +356,10 @@ BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, M
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS GetReparsePointByName(
|
||||||
|
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||||
|
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
|
||||||
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
@ -324,12 +413,30 @@ static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 == FileNode)
|
if (0 == FileNode)
|
||||||
{
|
{
|
||||||
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
MemfsFileNodeMapGetParent(Memfs->FileNodeMap, FileName, &Result);
|
|
||||||
|
if (FspFileSystemFindReparsePoint(FileSystem, GetReparsePointByName, 0,
|
||||||
|
FileName, PFileAttributes))
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
else
|
||||||
|
MemfsFileNodeMapGetParent(Memfs->FileNodeMap, FileName, &Result);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
UINT32 FileAttributesMask = ~(UINT32)0;
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
{
|
||||||
|
FileAttributesMask = ~(UINT32)FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != PFileAttributes)
|
||||||
|
*PFileAttributes = FileNode->FileInfo.FileAttributes & FileAttributesMask;
|
||||||
|
#else
|
||||||
if (0 != PFileAttributes)
|
if (0 != PFileAttributes)
|
||||||
*PFileAttributes = FileNode->FileInfo.FileAttributes;
|
*PFileAttributes = FileNode->FileInfo.FileAttributes;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (0 != PSecurityDescriptorSize)
|
if (0 != PSecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
@ -378,6 +485,10 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
FileNode->MainFileNode = MemfsFileNodeMapGetMain(Memfs->FileNodeMap, FileName);
|
||||||
|
#endif
|
||||||
|
|
||||||
FileNode->FileInfo.FileAttributes = (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
|
FileNode->FileInfo.FileAttributes = (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
|
||||||
FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
|
FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
|
||||||
|
|
||||||
@ -415,7 +526,7 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
FileNode->RefCount++;
|
FileNode->RefCount++;
|
||||||
*PFileNode = FileNode;
|
*PFileNode = FileNode;
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -453,7 +564,7 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
FileNode->RefCount++;
|
FileNode->RefCount++;
|
||||||
*PFileNode = FileNode;
|
*PFileNode = FileNode;
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -475,11 +586,28 @@ NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FileNode->FileInfo.LastWriteTime =
|
FileNode->FileInfo.LastWriteTime =
|
||||||
FileNode->FileInfo.LastAccessTime = MemfsGetSystemTime();
|
FileNode->FileInfo.LastAccessTime = MemfsGetSystemTime();
|
||||||
|
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
typedef struct _MEMFS_CLEANUP_CONTEXT
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE **FileNodes;
|
||||||
|
ULONG Count;
|
||||||
|
} MEMFS_CLEANUP_CONTEXT;
|
||||||
|
|
||||||
|
static BOOLEAN CleanupEnumFn(MEMFS_FILE_NODE *FileNode, PVOID Context0)
|
||||||
|
{
|
||||||
|
MEMFS_CLEANUP_CONTEXT *Context = (MEMFS_CLEANUP_CONTEXT *)Context0;
|
||||||
|
|
||||||
|
Context->FileNodes[Context->Count++] = FileNode;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
|
static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode0, PWSTR FileName, BOOLEAN Delete)
|
PVOID FileNode0, PWSTR FileName, BOOLEAN Delete)
|
||||||
@ -488,9 +616,26 @@ static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
assert(0 == FileName || 0 == wcscmp(FileNode->FileName, FileName));
|
assert(0 == FileName || 0 == wcscmp(FileNode->FileName, FileName));
|
||||||
|
assert(Delete); /* the new FSP_FSCTL_VOLUME_PARAMS::PostCleanupOnDeleteOnly ensures this */
|
||||||
|
|
||||||
if (Delete && !MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
|
if (Delete && !MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
|
||||||
|
{
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
MEMFS_CLEANUP_CONTEXT Context = { 0 };
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
|
Context.FileNodes = (MEMFS_FILE_NODE **)malloc(Memfs->MaxFileNodes * sizeof Context.FileNodes[0]);
|
||||||
|
if (0 != Context.FileNodes)
|
||||||
|
{
|
||||||
|
MemfsFileNodeMapEnumerateNamedStreams(Memfs->FileNodeMap, FileNode, CleanupEnumFn, &Context);
|
||||||
|
for (Index = 0; Context.Count > Index; Index++)
|
||||||
|
MemfsFileNodeMapRemove(Memfs->FileNodeMap, Context.FileNodes[Index]);
|
||||||
|
free(Context.FileNodes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
MemfsFileNodeMapRemove(Memfs->FileNodeMap, FileNode);
|
MemfsFileNodeMapRemove(Memfs->FileNodeMap, FileNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID Close(FSP_FILE_SYSTEM *FileSystem,
|
static VOID Close(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -539,7 +684,8 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
*P = *P | 0;
|
*P = *P | 0;
|
||||||
assert(0);
|
assert(!IsWindows8OrGreater());
|
||||||
|
/* only on Windows 8 we can make the buffer read-only! */
|
||||||
}
|
}
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
@ -570,7 +716,7 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
|
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
|
||||||
|
|
||||||
*PBytesTransferred = (ULONG)(EndOffset - Offset);
|
*PBytesTransferred = (ULONG)(EndOffset - Offset);
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -590,7 +736,7 @@ static NTSTATUS GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -603,6 +749,11 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (INVALID_FILE_ATTRIBUTES != FileAttributes)
|
if (INVALID_FILE_ATTRIBUTES != FileAttributes)
|
||||||
FileNode->FileInfo.FileAttributes = FileAttributes;
|
FileNode->FileInfo.FileAttributes = FileAttributes;
|
||||||
if (0 != CreationTime)
|
if (0 != CreationTime)
|
||||||
@ -612,7 +763,7 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 != LastWriteTime)
|
if (0 != LastWriteTime)
|
||||||
FileNode->FileInfo.LastWriteTime = LastWriteTime;
|
FileNode->FileInfo.LastWriteTime = LastWriteTime;
|
||||||
|
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -665,7 +816,7 @@ static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*FileInfo = FileNode->FileInfo;
|
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -799,6 +950,11 @@ static NTSTATUS GetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (FileNode->FileSecuritySize > *PSecurityDescriptorSize)
|
if (FileNode->FileSecuritySize > *PSecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
*PSecurityDescriptorSize = FileNode->FileSecuritySize;
|
*PSecurityDescriptorSize = FileNode->FileSecuritySize;
|
||||||
@ -822,6 +978,11 @@ static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
SIZE_T FileSecuritySize;
|
SIZE_T FileSecuritySize;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
#endif
|
||||||
|
|
||||||
Result = FspSetSecurityDescriptor(FileSystem, Request, FileNode->FileSecurity,
|
Result = FspSetSecurityDescriptor(FileSystem, Request, FileNode->FileSecurity,
|
||||||
&NewSecurityDescriptor);
|
&NewSecurityDescriptor);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -930,6 +1091,211 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
||||||
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
return FspFileSystemResolveReparsePoints(FileSystem, GetReparsePointByName, 0,
|
||||||
|
FileName, ReparsePointIndex, ResolveLastPathComponent,
|
||||||
|
PIoStatus, Buffer, PSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS GetReparsePointByName(
|
||||||
|
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||||
|
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
|
MEMFS_FILE_NODE *FileNode;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
/* GetReparsePointByName will never receive a named stream */
|
||||||
|
assert(0 == wcschr(FileName, L':'));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FileNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, FileName);
|
||||||
|
if (0 == FileNode)
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||||
|
return STATUS_NOT_A_REPARSE_POINT;
|
||||||
|
|
||||||
|
if (0 != Buffer)
|
||||||
|
{
|
||||||
|
if (FileNode->ReparseDataSize > *PSize)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
*PSize = FileNode->ReparseDataSize;
|
||||||
|
memcpy(Buffer, FileNode->ReparseData, FileNode->ReparseDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0,
|
||||||
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||||
|
return STATUS_NOT_A_REPARSE_POINT;
|
||||||
|
|
||||||
|
if (FileNode->ReparseDataSize > *PSize)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
*PSize = FileNode->ReparseDataSize;
|
||||||
|
memcpy(Buffer, FileNode->ReparseData, FileNode->ReparseDataSize);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
|
{
|
||||||
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
PVOID ReparseData;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
|
||||||
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
||||||
|
|
||||||
|
if (0 != FileNode->ReparseData)
|
||||||
|
{
|
||||||
|
Result = FspFileSystemCanReplaceReparsePoint(
|
||||||
|
FileNode->ReparseData, FileNode->ReparseDataSize,
|
||||||
|
Buffer, Size);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReparseData = realloc(FileNode->ReparseData, Size);
|
||||||
|
if (0 == ReparseData && 0 != Size)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
FileNode->FileInfo.ReparseTag = *(PULONG)Buffer;
|
||||||
|
/* the first field in a reparse buffer is the reparse tag */
|
||||||
|
FileNode->ReparseDataSize = Size;
|
||||||
|
FileNode->ReparseData = ReparseData;
|
||||||
|
memcpy(FileNode->ReparseData, Buffer, Size);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (0 != FileNode->ReparseData)
|
||||||
|
{
|
||||||
|
Result = FspFileSystemCanReplaceReparsePoint(
|
||||||
|
FileNode->ReparseData, FileNode->ReparseDataSize,
|
||||||
|
Buffer, Size);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return STATUS_NOT_A_REPARSE_POINT;
|
||||||
|
|
||||||
|
free(FileNode->ReparseData);
|
||||||
|
|
||||||
|
FileNode->FileInfo.FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
FileNode->FileInfo.ReparseTag = 0;
|
||||||
|
FileNode->ReparseDataSize = 0;
|
||||||
|
FileNode->ReparseData = 0;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
typedef struct _MEMFS_GET_STREAM_INFO_CONTEXT
|
||||||
|
{
|
||||||
|
PVOID Buffer;
|
||||||
|
ULONG Length;
|
||||||
|
PULONG PBytesTransferred;
|
||||||
|
} MEMFS_GET_STREAM_INFO_CONTEXT;
|
||||||
|
|
||||||
|
static BOOLEAN AddStreamInfo(MEMFS_FILE_NODE *FileNode,
|
||||||
|
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
|
||||||
|
{
|
||||||
|
UINT8 StreamInfoBuf[sizeof(FSP_FSCTL_STREAM_INFO) + sizeof FileNode->FileName];
|
||||||
|
FSP_FSCTL_STREAM_INFO *StreamInfo = (FSP_FSCTL_STREAM_INFO *)StreamInfoBuf;
|
||||||
|
PWSTR StreamName;
|
||||||
|
|
||||||
|
StreamName = wcschr(FileNode->FileName, L':');
|
||||||
|
if (0 != StreamName)
|
||||||
|
StreamName++;
|
||||||
|
else
|
||||||
|
StreamName = L"";
|
||||||
|
|
||||||
|
StreamInfo->Size = (UINT16)(sizeof(FSP_FSCTL_STREAM_INFO) + wcslen(StreamName) * sizeof(WCHAR));
|
||||||
|
StreamInfo->StreamSize = FileNode->FileInfo.FileSize;
|
||||||
|
StreamInfo->StreamAllocationSize = FileNode->FileInfo.AllocationSize;
|
||||||
|
memcpy(StreamInfo->StreamNameBuf, StreamName, StreamInfo->Size - sizeof(FSP_FSCTL_STREAM_INFO));
|
||||||
|
|
||||||
|
return FspFileSystemAddStreamInfo(StreamInfo, Buffer, Length, PBytesTransferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOLEAN GetStreamInfoEnumFn(MEMFS_FILE_NODE *FileNode, PVOID Context0)
|
||||||
|
{
|
||||||
|
MEMFS_GET_STREAM_INFO_CONTEXT *Context = (MEMFS_GET_STREAM_INFO_CONTEXT *)Context0;
|
||||||
|
|
||||||
|
return AddStreamInfo(FileNode,
|
||||||
|
Context->Buffer, Context->Length, Context->PBytesTransferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS GetStreamInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0, PVOID Buffer, ULONG Length,
|
||||||
|
PULONG PBytesTransferred)
|
||||||
|
{
|
||||||
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
MEMFS_GET_STREAM_INFO_CONTEXT Context;
|
||||||
|
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
|
||||||
|
Context.Buffer = Buffer;
|
||||||
|
Context.Length = Length;
|
||||||
|
Context.PBytesTransferred = PBytesTransferred;
|
||||||
|
|
||||||
|
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||||
|
!AddStreamInfo(FileNode, Buffer, Length, PBytesTransferred))
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (MemfsFileNodeMapEnumerateNamedStreams(Memfs->FileNodeMap, FileNode, GetStreamInfoEnumFn, &Context))
|
||||||
|
FspFileSystemAddStreamInfo(0, Buffer, Length, PBytesTransferred);
|
||||||
|
|
||||||
|
/* ???: how to handle out of response buffer condition? */
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||||
{
|
{
|
||||||
GetVolumeInfo,
|
GetVolumeInfo,
|
||||||
@ -951,6 +1317,15 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
|||||||
GetSecurity,
|
GetSecurity,
|
||||||
SetSecurity,
|
SetSecurity,
|
||||||
ReadDirectory,
|
ReadDirectory,
|
||||||
|
ResolveReparsePoints,
|
||||||
|
GetReparsePoint,
|
||||||
|
SetReparsePoint,
|
||||||
|
DeleteReparsePoint,
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
GetStreamInfo,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
NTSTATUS MemfsCreate(
|
NTSTATUS MemfsCreate(
|
||||||
@ -1011,8 +1386,15 @@ NTSTATUS MemfsCreate(
|
|||||||
VolumeParams.CasePreservedNames = 1;
|
VolumeParams.CasePreservedNames = 1;
|
||||||
VolumeParams.UnicodeOnDisk = 1;
|
VolumeParams.UnicodeOnDisk = 1;
|
||||||
VolumeParams.PersistentAcls = 1;
|
VolumeParams.PersistentAcls = 1;
|
||||||
|
VolumeParams.ReparsePoints = 1;
|
||||||
|
VolumeParams.ReparsePointsAccessCheck = 0;
|
||||||
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
|
VolumeParams.NamedStreams = 1;
|
||||||
|
#endif
|
||||||
|
VolumeParams.PostCleanupOnDeleteOnly = 1;
|
||||||
if (0 != VolumePrefix)
|
if (0 != VolumePrefix)
|
||||||
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
|
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
|
||||||
|
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR), L"MEMFS");
|
||||||
|
|
||||||
Result = FspFileSystemCreate(DevicePath, &VolumeParams, &MemfsInterface, &Memfs->FileSystem);
|
Result = FspFileSystemCreate(DevicePath, &VolumeParams, &MemfsInterface, &Memfs->FileSystem);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of WinFsp.
|
* This file is part of WinFsp.
|
||||||
*
|
*
|
||||||
* You can redistribute it and/or modify it under the terms of the
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
* GNU Affero General Public License version 3 as published by the
|
* General Public License version 3 as published by the Free Software
|
||||||
* Free Software Foundation.
|
* Foundation.
|
||||||
*
|
*
|
||||||
* Licensees holding a valid commercial license may use this file in
|
* Licensees holding a valid commercial license may use this file in
|
||||||
* accordance with the commercial license agreement provided with the
|
* accordance with the commercial license agreement provided with the
|
||||||
|
32
tst/secret/secret.c
Normal file
32
tst/secret/secret.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Compile:
|
||||||
|
* - cl secret.c
|
||||||
|
*
|
||||||
|
* Register:
|
||||||
|
* - secret.reg (fix Executable path first)
|
||||||
|
*
|
||||||
|
* Run:
|
||||||
|
* - launchctl-x64 startWithSecret secret 1 nopass
|
||||||
|
* - launchctl-x64 startWithSecret secret 1 foobar
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char pass[256];
|
||||||
|
|
||||||
|
gets(pass);
|
||||||
|
if (0 == strcmp("foobar", pass))
|
||||||
|
{
|
||||||
|
puts("OK");
|
||||||
|
fprintf(stderr, "OK secret=\"%s\"\n", pass);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("KO");
|
||||||
|
fprintf(stderr, "KO secret=\"%s\"\n", pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
tst/secret/secret.reg
Normal file
BIN
tst/secret/secret.reg
Normal file
Binary file not shown.
@ -4,13 +4,7 @@
|
|||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#include "memfs.h"
|
#include "memfs.h"
|
||||||
|
|
||||||
void *memfs_start(ULONG Flags);
|
#include "winfsp-tests.h"
|
||||||
void memfs_stop(void *data);
|
|
||||||
PWSTR memfs_volumename(void *data);
|
|
||||||
|
|
||||||
extern int NtfsTests;
|
|
||||||
extern int WinFspDiskTests;
|
|
||||||
extern int WinFspNetTests;
|
|
||||||
|
|
||||||
void create_dotest(ULONG Flags, PWSTR Prefix)
|
void create_dotest(ULONG Flags, PWSTR Prefix)
|
||||||
{
|
{
|
||||||
@ -74,6 +68,24 @@ void create_dotest(ULONG Flags, PWSTR Prefix)
|
|||||||
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* invalid chars (wildcards) not allowed */
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0*",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
|
||||||
|
Handle = CreateFileW(FilePath,
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||||
|
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
||||||
|
|
||||||
|
/* stream names can only appear as the last path component */
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\DOESNOTEXIST:foo\\file0*",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
|
||||||
|
Handle = CreateFileW(FilePath,
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||||
|
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
||||||
|
|
||||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
|
||||||
@ -424,10 +436,48 @@ void create_share_test(void)
|
|||||||
create_share_dotest(MemfsNet, L"\\\\memfs\\share");
|
create_share_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void create_curdir_dotest(ULONG Flags, PWSTR Prefix)
|
||||||
|
{
|
||||||
|
void *memfs = memfs_start(Flags);
|
||||||
|
|
||||||
|
WCHAR CurrentDirectory[MAX_PATH], FilePath[MAX_PATH];
|
||||||
|
BOOL Success;
|
||||||
|
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s%s",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
|
||||||
|
Prefix ? L"" : L"\\");
|
||||||
|
|
||||||
|
Success = GetCurrentDirectoryW(MAX_PATH, CurrentDirectory);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
Success = SetCurrentDirectoryW(FilePath);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
Success = SetCurrentDirectoryW(CurrentDirectory);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
memfs_stop(memfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_curdir_test(void)
|
||||||
|
{
|
||||||
|
if (NtfsTests)
|
||||||
|
{
|
||||||
|
WCHAR DirBuf[MAX_PATH] = L"\\\\?\\";
|
||||||
|
GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4);
|
||||||
|
create_curdir_dotest(-1, DirBuf);
|
||||||
|
}
|
||||||
|
if (WinFspDiskTests)
|
||||||
|
create_curdir_dotest(MemfsDisk, 0);
|
||||||
|
if (WinFspNetTests)
|
||||||
|
create_curdir_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||||
|
}
|
||||||
|
|
||||||
void create_tests(void)
|
void create_tests(void)
|
||||||
{
|
{
|
||||||
TEST(create_test);
|
TEST(create_test);
|
||||||
TEST(create_related_test);
|
TEST(create_related_test);
|
||||||
TEST(create_sd_test);
|
TEST(create_sd_test);
|
||||||
TEST(create_share_test);
|
TEST(create_share_test);
|
||||||
|
TEST(create_curdir_test);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user