Compare commits
227 Commits
v0.17
...
baseline-p
Author | SHA1 | Date | |
---|---|---|---|
56873406e3 | |||
40735c4687 | |||
08c283f2a9 | |||
4fc740588e | |||
54050c7e1d | |||
ff08d63a82 | |||
c37444b0ae | |||
bbb51b4971 | |||
6de998ff98 | |||
4b024ebe74 | |||
418c454a4a | |||
0b61c48cd6 | |||
945509ef93 | |||
3a65ce332b | |||
228f9e2708 | |||
ee3918436b | |||
1bb6d2a0e7 | |||
6d1b9e95db | |||
1d8d72129d | |||
2ad4e30754 | |||
26cba02091 | |||
3697defd16 | |||
69a22f1044 | |||
5a49115a66 | |||
82c8b0d00f | |||
d00b5d88af | |||
6d19176d7c | |||
e231b9c662 | |||
025a74e663 | |||
834adbdc36 | |||
25c687d5c5 | |||
200de2a7f9 | |||
8e7c241f32 | |||
e530e671a5 | |||
d804f5674d | |||
ac6f024715 | |||
a1af8ff921 | |||
f7ca9f0522 | |||
3518d7a8c2 | |||
281d92f2bc | |||
7769a2c062 | |||
595a77bd2e | |||
6860a6986a | |||
63e8cf1090 | |||
7bdca634aa | |||
535babc0d5 | |||
e86dcde1a1 | |||
6e10e0489b | |||
f82cad712a | |||
d12234bb01 | |||
10a8519294 | |||
1b6395fc91 | |||
f1a363b848 | |||
eea1a8fd8b | |||
5444ce7f50 | |||
29c140b9cd | |||
cdfd60877b | |||
e7931e28fd | |||
002a0262f7 | |||
1ffba78a18 | |||
1d3423d5fb | |||
a894e4a2af | |||
b6f084d71f | |||
ca6d0d2dcf | |||
d6d781355f | |||
851a6145cd | |||
aec7b34e13 | |||
38006ba553 | |||
ee469b40e7 | |||
1f385a9ab5 | |||
ba78fbb956 | |||
8f10ba4fc9 | |||
b0a59e42fc | |||
2e089b92c5 | |||
37362cb8cc | |||
127d4cc4eb | |||
ce551d4e0d | |||
53f60a698a | |||
aa23672b01 | |||
e4de0f0513 | |||
8750451e10 | |||
358db2a54f | |||
4294182c1a | |||
f17168f2fa | |||
959d8537c6 | |||
6a48087d5f | |||
0a59c5d685 | |||
5b1b8288c2 | |||
53e2f13e38 | |||
cb6b10385b | |||
f49cf412a8 | |||
764b772731 | |||
7518a6e418 | |||
2772af5478 | |||
f2535484ea | |||
97ee4fa77f | |||
7c34d738b7 | |||
93254bede4 | |||
f3894dbc7b | |||
dc684acd41 | |||
69935525da | |||
6ba6e16851 | |||
d33089331b | |||
74de84aaab | |||
a9b4fd4634 | |||
c6798b3060 | |||
f6e3b8e416 | |||
f05ebd9d20 | |||
e50c9ff649 | |||
fb70eccc9c | |||
7adbd7a56c | |||
55c7384c65 | |||
bc8962d2b6 | |||
2267eadbca | |||
154aa28381 | |||
2d98cda607 | |||
8395b22ddc | |||
809505d8a3 | |||
9df0920de1 | |||
c10c7cc672 | |||
a0cb134bd3 | |||
becfd2e1c5 | |||
1e93f0d10d | |||
adeb847c7e | |||
5a83c68f56 | |||
9d176643c3 | |||
b1d8192d59 | |||
bd3d462bce | |||
aa2d70d8de | |||
31c40d017d | |||
5c8da5518c | |||
a80a9d3d4c | |||
57580e91f5 | |||
1a43619c5e | |||
aae6a15e5a | |||
f54ce6a65d | |||
ab0c2fc25c | |||
fd439add27 | |||
8855a2b896 | |||
7c41ffd64e | |||
621eb63029 | |||
f1b96f8a28 | |||
4512dac0a9 | |||
deee32b743 | |||
5f1b723fab | |||
453f1732dc | |||
8c8d669be8 | |||
53077d990a | |||
c665812d76 | |||
b56379b542 | |||
83c1489b92 | |||
3e3aa7651f | |||
ec2cf5106d | |||
25322059b3 | |||
a255fa11e7 | |||
dbb8b5d3b9 | |||
4c6a61d2c9 | |||
ac4828ec11 | |||
e0f163e9ba | |||
9bcd8dcb8e | |||
096e5b7eb1 | |||
1c85fb94f0 | |||
4417ebcc92 | |||
5fa631339d | |||
26092211a8 | |||
50af8f6444 | |||
ee0031f995 | |||
75ff7f2c01 | |||
3e557e1b65 | |||
79bf651203 | |||
205a59dbc6 | |||
8f54152096 | |||
5e71992153 | |||
dfe45e1be5 | |||
ff7a446194 | |||
17056b4f3f | |||
b19621233a | |||
e07ef0712e | |||
0532cee99c | |||
b072a1f0da | |||
badaf82462 | |||
3f79b2e46d | |||
319e5d4ee6 | |||
66d5fe98df | |||
8abadf94f3 | |||
728c1b3402 | |||
8b31b1018b | |||
310fd23035 | |||
7f2426271c | |||
3cfa4156d2 | |||
23dadcf8a0 | |||
e0b0b1b367 | |||
a525e095d3 | |||
e16dfd8a43 | |||
3bf4140f91 | |||
b194a33406 | |||
0dd452fac1 | |||
df11a7d7ff | |||
51d29c172a | |||
2803a1b0cf | |||
067a0f1b37 | |||
03611b6210 | |||
2ff60e5e98 | |||
488993d22b | |||
3cba22b9a5 | |||
a3e577b091 | |||
9b287fb559 | |||
f642ea57be | |||
cb17b7e2e0 | |||
82a9c8e80f | |||
628dae38d7 | |||
958b5a47a8 | |||
8d38a0dac6 | |||
a653a010ce | |||
31eedbddb3 | |||
5bf913045e | |||
a10a09d4e9 | |||
3e0db6da07 | |||
77df532ac3 | |||
222da362ec | |||
3ed7847d84 | |||
5773c6eab7 | |||
5a5a1008de | |||
32c289fa34 | |||
0534225662 | |||
096b2dabde | |||
5770f2d901 |
@ -1,6 +1,18 @@
|
|||||||
= Changelog
|
= Changelog
|
||||||
|
|
||||||
|
|
||||||
|
v1.0RC1::
|
||||||
|
|
||||||
|
This is the first Release Candidate. It has been tested for robustness and correct file system semantics in a variety of scenarios. Some of the more important changes:
|
||||||
|
|
||||||
|
- API has been polished and finalized.
|
||||||
|
- Sharing a (disk) file system over the network is supported.
|
||||||
|
- Case insensitive file systems are supported.
|
||||||
|
- Directories are supported as mount points.
|
||||||
|
- Access checks are performed correctly in the absense of the traverse privilege.
|
||||||
|
- Access checks are performed correctly in the presence of the backup and restore privileges.
|
||||||
|
|
||||||
|
|
||||||
v0.17::
|
v0.17::
|
||||||
|
|
||||||
This release brings support for named streams.
|
This release brings support for named streams.
|
@ -23,7 +23,7 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
|
|||||||
The project source code is organized as follows:
|
The project source code is organized as follows:
|
||||||
|
|
||||||
* build/VStudio: WinFsp solution and project files.
|
* build/VStudio: WinFsp solution and project files.
|
||||||
* doc: WinFsp license, contributor agreement and additional documentation. The WinFsp design documents can be found here.
|
* doc: The WinFsp design documents and additional documentation can be found here.
|
||||||
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
|
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||||
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||||
* inc/winfsp: Public headers for the WinFsp API.
|
* inc/winfsp: Public headers for the WinFsp API.
|
||||||
|
22
appveyor.yml
@ -1,23 +1,33 @@
|
|||||||
version: '{build}'
|
version: '{build}'
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
CONFIGURATION: Release
|
matrix:
|
||||||
|
- CONFIGURATION: Release
|
||||||
|
TESTING: Perf
|
||||||
|
|
||||||
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
|
||||||
|
- if %TESTING%==Func verifier /standard /driver winfsp-x64.sys
|
||||||
|
- if exist %SystemRoot%\memory.dmp del %SystemRoot%\memory.dmp
|
||||||
- ps: Restart-Computer -Force
|
- ps: Restart-Computer -Force
|
||||||
- ps: Start-Sleep -s 10
|
- ps: Start-Sleep -s 60
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- appveyor AddMessage "Reboot complete" -Category Information
|
- appveyor AddMessage "Reboot complete" -Category Information
|
||||||
- bcdedit | findstr /i "testsigning"
|
|
||||||
- tools\build.bat %CONFIGURATION%
|
- tools\build.bat %CONFIGURATION%
|
||||||
|
|
||||||
test_script:
|
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%
|
- if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/winfsp/resources/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip
|
||||||
- tools\run-tests.bat %CONFIGURATION%
|
- if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn
|
||||||
|
- if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION%
|
||||||
|
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
|
||||||
|
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
|
||||||
|
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
|
||||||
|
- if exist %SystemRoot%\memory.dmp exit 1
|
||||||
|
|
||||||
|
on_finish:
|
||||||
|
- if exist %SystemRoot%\memory.dmp (7z a memory.dmp.zip %SystemRoot%\memory.dmp && appveyor PushArtifact memory.dmp.zip)
|
||||||
- verifier /query
|
- verifier /query
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
<Product
|
<Product
|
||||||
Id="*"
|
Id="*"
|
||||||
Name="$(var.MyProductName)"
|
Name="$(var.MyProductName) $(var.MyProductVersion)"
|
||||||
Manufacturer="$(var.MyCompanyName)"
|
Manufacturer="$(var.MyCompanyName)"
|
||||||
Version="$(var.MyVersion)"
|
Version="$(var.MyVersion)"
|
||||||
Language="1033"
|
Language="1033"
|
||||||
@ -17,8 +17,8 @@
|
|||||||
Disallow="yes"
|
Disallow="yes"
|
||||||
AllowDowngrades="no"
|
AllowDowngrades="no"
|
||||||
AllowSameVersionUpgrades="no"
|
AllowSameVersionUpgrades="no"
|
||||||
DisallowUpgradeErrorMessage="An older version of [ProductName] is already installed. You must uninstall it before you can install this version."
|
DisallowUpgradeErrorMessage="An older version of $(var.MyProductName) is already installed. You must uninstall it before you can install this version."
|
||||||
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
DowngradeErrorMessage="A newer version of $(var.MyProductName) is already installed." />
|
||||||
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
|
<Media Id="1" Cabinet="WinFsp.cab" EmbedCab="yes" />
|
||||||
|
|
||||||
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
|
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
|
||||||
@ -155,7 +155,7 @@
|
|||||||
<RegistryValue
|
<RegistryValue
|
||||||
Type="string"
|
Type="string"
|
||||||
Name="CommandLine"
|
Name="CommandLine"
|
||||||
Value="-u %1 -m %2" />
|
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
|
||||||
<RegistryValue
|
<RegistryValue
|
||||||
Type="string"
|
Type="string"
|
||||||
Name="Security"
|
Name="Security"
|
||||||
@ -181,7 +181,7 @@
|
|||||||
<RegistryValue
|
<RegistryValue
|
||||||
Type="string"
|
Type="string"
|
||||||
Name="CommandLine"
|
Name="CommandLine"
|
||||||
Value="-u %1 -m %2" />
|
Value="-i -n 65536 -s 67108864 -u %1 -m %2" />
|
||||||
<RegistryValue
|
<RegistryValue
|
||||||
Type="string"
|
Type="string"
|
||||||
Name="Security"
|
Name="Security"
|
||||||
@ -344,7 +344,7 @@
|
|||||||
<Feature
|
<Feature
|
||||||
Id="F.Main"
|
Id="F.Main"
|
||||||
Level="1"
|
Level="1"
|
||||||
Title="$(var.MyProductName) $(var.MyVersion)"
|
Title="$(var.MyProductName) $(var.MyProductVersion)"
|
||||||
Description="$(var.MyDescription)"
|
Description="$(var.MyDescription)"
|
||||||
Display="expand"
|
Display="expand"
|
||||||
ConfigurableDirectory="INSTALLDIR"
|
ConfigurableDirectory="INSTALLDIR"
|
||||||
@ -378,7 +378,7 @@
|
|||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
|
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
|
||||||
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyDevStage).bmp" />
|
<WixVariable Id="WixUIDialogBmp" Value="wixdialog-$(var.MyProductStage).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);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
|
<DefineConstants>Debug;MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);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);MyDevStage=$(MyDevStage);MyVersion=$(MyVersion)</DefineConstants>
|
<DefineConstants>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion)</DefineConstants>
|
||||||
<SuppressAllWarnings>False</SuppressAllWarnings>
|
<SuppressAllWarnings>False</SuppressAllWarnings>
|
||||||
<Pedantic>True</Pedantic>
|
<Pedantic>True</Pedantic>
|
||||||
<SuppressPdbOutput>True</SuppressPdbOutput>
|
<SuppressPdbOutput>True</SuppressPdbOutput>
|
||||||
|
@ -193,10 +193,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\..\..\src\launcher\launchctl-version.rc">
|
<ResourceCompile Include="..\..\..\src\launcher\launchctl-version.rc">
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -202,10 +202,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
|
<ResourceCompile Include="..\..\..\src\launcher\launcher-version.rc">
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
187
build/VStudio/testing/fsbench.vcxproj
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>fsbench</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\ext</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\ext\tlib\testsuite.c">
|
||||||
|
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">TurnOffAllWarnings</WarningLevel>
|
||||||
|
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</SDLCheck>
|
||||||
|
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">TurnOffAllWarnings</WarningLevel>
|
||||||
|
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</SDLCheck>
|
||||||
|
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">TurnOffAllWarnings</WarningLevel>
|
||||||
|
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</SDLCheck>
|
||||||
|
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">TurnOffAllWarnings</WarningLevel>
|
||||||
|
<SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\fsbench\fsbench.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\..\ext\tlib\testsuite.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
25
build/VStudio/testing/fsbench.vcxproj.filters
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source\tlib">
|
||||||
|
<UniqueIdentifier>{d76fc01e-0f8d-4596-bdef-c2a5d3fede2e}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\tst\fsbench\fsbench.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\ext\tlib\testsuite.c">
|
||||||
|
<Filter>Source\tlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||||
|
<Filter>Source\tlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
185
build/VStudio/testing/fscrash.vcxproj
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{10757011-749D-4954-873B-AE38D8145472}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>fscrash</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\tst\memfs;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\tst\fscrash\fscrash-main.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\fscrash\fscrash.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\..\tst\fscrash\fscrash.h" />
|
||||||
|
<ClInclude Include="..\..\..\tst\memfs\memfs.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\winfsp_dll.vcxproj">
|
||||||
|
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
28
build/VStudio/testing/fscrash.vcxproj.filters
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\tst\fscrash\fscrash-main.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\fscrash\fscrash.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\..\tst\memfs\memfs.h">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\tst\fscrash\fscrash.h">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -107,7 +107,7 @@
|
|||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -124,7 +124,7 @@
|
|||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -145,7 +145,7 @@
|
|||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -166,7 +166,7 @@
|
|||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -186,15 +186,17 @@
|
|||||||
<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\hooks.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" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c" />
|
||||||
<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\reparse-test.c" />
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\resilient.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\stream-tests.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
||||||
|
@ -64,10 +64,16 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c">
|
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\hook.c">
|
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
|
<ClCompile Include="..\..\..\tst\winfsp-tests\resilient.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -4,16 +4,23 @@
|
|||||||
<MyProductName>WinFsp</MyProductName>
|
<MyProductName>WinFsp</MyProductName>
|
||||||
<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-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
|
||||||
<MyDevStage>Beta</MyDevStage>
|
|
||||||
|
<MyCanonicalVersion>1.0</MyCanonicalVersion>
|
||||||
|
|
||||||
|
<MyProductVersion>$(MyCanonicalVersion) RC1</MyProductVersion>
|
||||||
|
<MyProductStage>RC</MyProductStage>
|
||||||
|
|
||||||
<!-- 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.17.$(MyBuildNumber)</MyVersion>
|
|
||||||
|
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>NTDDI_VERSION=0x06000000;_WIN32_WINNT=0x0600</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NTDDI_VERSION=0x06010000;_WIN32_WINNT=0x0601</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.25123.0
|
VisualStudioVersion = 14.0.25420.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
@ -45,6 +45,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launc
|
|||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
|
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
||||||
|
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsbench", "testing\fsbench.vcxproj", "{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@ -153,6 +161,38 @@ Global
|
|||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
|
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
|
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
|
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.Build.0 = Release|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.Build.0 = Release|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.Build.0 = Release|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.Build.0 = Release|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.Build.0 = Release|x64
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -164,5 +204,7 @@ Global
|
|||||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
||||||
|
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||||
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -78,10 +78,10 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc" />
|
<ResourceCompile Include="..\..\src\dll\eventlog\eventlog.rc" />
|
||||||
<ResourceCompile Include="..\..\src\dll\version.rc">
|
<ResourceCompile Include="..\..\src\dll\version.rc">
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_UNICODE;UNICODE;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
|
@ -173,6 +173,7 @@
|
|||||||
<ClCompile Include="..\..\src\sys\ioq.c" />
|
<ClCompile Include="..\..\src\sys\ioq.c" />
|
||||||
<ClCompile Include="..\..\src\sys\lockctl.c" />
|
<ClCompile Include="..\..\src\sys\lockctl.c" />
|
||||||
<ClCompile Include="..\..\src\sys\meta.c" />
|
<ClCompile Include="..\..\src\sys\meta.c" />
|
||||||
|
<ClCompile Include="..\..\src\sys\name.c" />
|
||||||
<ClCompile Include="..\..\src\sys\read.c" />
|
<ClCompile Include="..\..\src\sys\read.c" />
|
||||||
<ClCompile Include="..\..\src\sys\security.c" />
|
<ClCompile Include="..\..\src\sys\security.c" />
|
||||||
<ClCompile Include="..\..\src\sys\shutdown.c" />
|
<ClCompile Include="..\..\src\sys\shutdown.c" />
|
||||||
@ -188,10 +189,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\..\src\sys\version.rc">
|
<ResourceCompile Include="..\..\src\sys\version.rc">
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WIN64;_AMD64_=1;AMD64;%(PreprocessorDefinitions);MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas)</PreprocessorDefinitions>
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -92,6 +92,9 @@
|
|||||||
<ClCompile Include="..\..\src\sys\callbacks.c">
|
<ClCompile Include="..\..\src\sys\callbacks.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\sys\name.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\sys\driver.h">
|
<ClInclude Include="..\..\src\sys\driver.h">
|
||||||
|
21
doc/Makefile
@ -1,21 +0,0 @@
|
|||||||
web: \
|
|
||||||
web/winfsp-design.html \
|
|
||||||
web/service-architecture.html \
|
|
||||||
web/sshfs-port-case-study.html \
|
|
||||||
web/winfsp.h.html
|
|
||||||
|
|
||||||
web/winfsp-design.html:
|
|
||||||
mkdir -p web
|
|
||||||
asciidoc -b html4 -a hr= -s -o $@ winfsp-design.adoc
|
|
||||||
|
|
||||||
web/service-architecture.html:
|
|
||||||
mkdir -p web
|
|
||||||
asciidoc -b html4 -a hr= -s -o $@ service-architecture.adoc
|
|
||||||
|
|
||||||
web/sshfs-port-case-study.html:
|
|
||||||
mkdir -p web
|
|
||||||
asciidoc -b html4 -a hr= -s -o $@ sshfs-port-case-study.adoc
|
|
||||||
|
|
||||||
web/winfsp.h.html:
|
|
||||||
mkdir -p web
|
|
||||||
prettydoc -H-O -o web ../inc/winfsp/winfsp.h
|
|
192
doc/WinFsp-Performance-Testing.asciidoc
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
= Performance Testing
|
||||||
|
:caption:
|
||||||
|
|
||||||
|
This document discusses performance testing for WinFsp. The goal of this performance testing is to discover optimization opportunities for WinFsp and compare its performance to that of NTFS and Dokany.
|
||||||
|
|
||||||
|
== Executive Summary
|
||||||
|
|
||||||
|
This performance testing shows that WinFsp has excellent performance in all tested scenarios. It outperforms NTFS in most scenarios (an unfair comparison as NTFS is a disk file system and WinFsp is tested with an in-memory file system). It also outperforms Dokany in all scenarios, often by an order of magnitude.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::bar[data-uri="WinFsp-Performance-Testing/file_tests.csv",file="WinFsp-Performance-Testing/file_tests.png",opt="y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/file_tests.png[]]
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::bar[data-uri="WinFsp-Performance-Testing/rdwr_tests.csv",file="WinFsp-Performance-Testing/rdwr_tests.png",opt="y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_tests.png[]]
|
||||||
|
|
||||||
|
== Fsbench
|
||||||
|
|
||||||
|
All testing was performed using a new performance test suite developed as part of WinFsp, called https://github.com/billziss-gh/winfsp/blob/master/tst/fsbench/fsbench.c[fsbench]. Fsbench was developed because it allows the creation of tests that are important to file system developers; for example, it can answer questions of the type: "how long does it take to delete 1000 files" or "how long does it take to list a directory with 10000 files in it".
|
||||||
|
|
||||||
|
Fsbench is based on the https://github.com/billziss-gh/winfsp/tree/master/ext/tlib[tlib] library, originally from the *secfs* project. Tlib is usually used to develop regression test suites in C/C++, but can be also used to create performance tests.
|
||||||
|
|
||||||
|
Fsbench currently includes the following tests:
|
||||||
|
|
||||||
|
[width="100%",cols="20%,60%,20%",options="header"]
|
||||||
|
|===
|
||||||
|
|Test |Measures performance of |Parameters
|
||||||
|
|file_create_test |CreateFileW(CREATE_NEW) / CloseHandle |file count
|
||||||
|
|file_open_test |CreateFileW(OPEN_EXISTING) / CloseHandle |file count
|
||||||
|
|file_overwrite_test|CreateFileW(CREATE_ALWAYS) / CloseHandle with existing files|file count
|
||||||
|
|file_list_test |FindFirstFileW / FindNextFile / FindClose |iterations
|
||||||
|
|file_delete_test |DeleteFileW |file count
|
||||||
|
|file_mkdir_test |CreateDirectoryW |file count
|
||||||
|
|file_rmdir_test |RemoveDirectoryW |file count
|
||||||
|
|rdwr_cc_write_page_test |WriteFile (1 page; cached) |iterations
|
||||||
|
|rdwr_cc_read_page_test |ReadFile (1 page; cached) |iterations
|
||||||
|
|rdwr_nc_write_page_test |WriteFile (1 page; non-cached) |iterations
|
||||||
|
|rdwr_nc_read_page_test |ReadFile (1 page; non-cached) |iterations
|
||||||
|
|rdwr_cc_write_large_test |WriteFile (16 pages; cached) |iterations
|
||||||
|
|rdwr_cc_read_large_test |ReadFile (16 pages; cached) |iterations
|
||||||
|
|rdwr_nc_write_large_test |WriteFile (16 pages; non-cached) |iterations
|
||||||
|
|rdwr_nc_read_large_test |ReadFile (16 pages; non-cached) |iterations
|
||||||
|
|mmap_write_test |Memory mapped write test |iterations
|
||||||
|
|mmap_write_test |Memory mapped read test |iterations
|
||||||
|
|===
|
||||||
|
|
||||||
|
== Tested File Systems
|
||||||
|
|
||||||
|
=== NTFS
|
||||||
|
|
||||||
|
The comparison to NTFS is very important to establish a baseline. It is also very misleading because NTFS is a disk file system and MEMFS (either the WinFsp or Dokany variants) is an in memory file system. The tests will show that MEMFS is faster than NTFS. This should not be taken to mean that we are trying to make the (obvious) claim that an in memory file system is faster than a disk file system, but to show that the approach of writing a file system in user mode is a valid proposition and can be efficient.
|
||||||
|
|
||||||
|
=== WinFsp/MEMFS
|
||||||
|
|
||||||
|
MEMFS is the file system used to test WinFsp and shipped as a sample bundled with the WinFsp installer. MEMFS is a simple in memory file system and as such is very fast under most conditions. This is desirable because our goal with this performance testing is to measure the speed of the WinFsp system components rather the performance of a complex user mode file system. MEMFS has minimal overhead and is ideal for this purpose.
|
||||||
|
|
||||||
|
WinFsp/MEMFS can be run in different configurations, which enable or disable WinFsp caching features. The tested configurations were:
|
||||||
|
|
||||||
|
- An infinite FileInfoTimeout, which enables caching of metadata and data.
|
||||||
|
- A FileInfoTimeout of 1s (second), which enables caching of metadata but disables caching of data.
|
||||||
|
- A FileInfoTimeout of 0, which completely disables caching.
|
||||||
|
|
||||||
|
The WinFsp git commit at the time of testing was d804f5674d76f11ea86d14f4bcb1157e6e40e719.
|
||||||
|
|
||||||
|
=== Dokany/MEMFS
|
||||||
|
|
||||||
|
To achieve fairness when comparing Dokany to WinFsp the MEMFS file system has been ported to Dokany. Substantial care was taken to ensure that WinFsp/MEMFS and Dokany/MEMFS perform equally well, so that the performance of the Dokany FSD and user-mode components can be measured and compared accurately.
|
||||||
|
|
||||||
|
The Dokany/MEMFS project has its own https://github.com/billziss-gh/memfs-dokany[repository]. The project comes without a license, which means that it may not be used for any purpose other than as a reference.
|
||||||
|
|
||||||
|
The Dokany version used for testing was 1.0.1. The Dokany/MEMFS git commit was 27a678d7c0d5ee2fb3fb2ecc8e38210857ae941c.
|
||||||
|
|
||||||
|
== Test Environment
|
||||||
|
|
||||||
|
Tests were performed on an idle computer/VM. There was a reboot of both the computer and VM before each file system was tested. Each test was run twice and the smaller time value chosen. The assumption is that even in a seemingly idle desktop system there is some activity which will affect the results; the smaller value is the preferred one to use because it reflects the time when there is less or no other activity.
|
||||||
|
|
||||||
|
The test environment was as follows:
|
||||||
|
----
|
||||||
|
MacBook Pro (Retina, 13-inch, Early 2015)
|
||||||
|
3.1 GHz Intel Core i7
|
||||||
|
16 GB 1867 MHz DDR3
|
||||||
|
500 GB SSD
|
||||||
|
|
||||||
|
VirtualBox Version 5.0.20 r106931
|
||||||
|
1 CPU
|
||||||
|
4 GB RAM
|
||||||
|
80 GB Dynamically allocated differencing storage
|
||||||
|
|
||||||
|
Windows 10 (64-bit) Version 1511 (OS Build 10586.420)
|
||||||
|
----
|
||||||
|
|
||||||
|
== Test Results
|
||||||
|
|
||||||
|
In the graphs below we use consistent coloring to quickly identify a file system. Red is used for NTFS, yellow for WinFsp/MEMFS with a FileInfoTimeout of 0, green for WinFsp/MEMFS with a FileInfoTimeout of 1, light blue for WinFsp/MEMFS with an infinite FileInfoTimeout and deep blue for Dokany/MEMFS.
|
||||||
|
|
||||||
|
In all tests lower times are better (the file system is faster).
|
||||||
|
|
||||||
|
=== File Tests
|
||||||
|
|
||||||
|
These tests measure the performance of creating, opening, overwriting and listing files and directories.
|
||||||
|
|
||||||
|
==== file_create_test
|
||||||
|
|
||||||
|
This test measures the performance of CreateFileW(CREATE_NEW) / CloseHandle. WinFsp has the best performance here. Dokany follows and NTFS is last as it has to actually update its data structures on disk.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_create_test.csv",file="WinFsp-Performance-Testing/file_create_test.png",opt="x-label=file count,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/file_create_test.png[]]
|
||||||
|
|
||||||
|
==== file_open_test
|
||||||
|
|
||||||
|
This test measures the performance of CreateFileW(OPEN_EXISTING) / CloseHandle. WinFsp again has the best (although uneven) performance, followed by NTFS and then Dokany.
|
||||||
|
|
||||||
|
WinFsp appears to have very uneven performance here. In particular notice that opening 1000 files is slower than opening 2000 files, which makes no sense! I suspect that the test observes an initial acquisition of resouces when the test first starts, which is not necessary when the test runs for 2000 files at a later time. This uneven performance should probably be investigated in the future.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_open_test.csv",file="WinFsp-Performance-Testing/file_open_test.png",opt="x-label=file count,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/file_open_test.png[]]
|
||||||
|
|
||||||
|
==== file_overwrite_test
|
||||||
|
|
||||||
|
This test measures the performance of CreateFileW(CREATE_ALWAYS) / CloseHandle. WinFsp is fastest, followed by NTFS and then Dokany.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_overwrite_test.csv",file="WinFsp-Performance-Testing/file_overwrite_test.png",opt="x-label=file count,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/file_overwrite_test.png[]]
|
||||||
|
|
||||||
|
==== file_list_test
|
||||||
|
|
||||||
|
This test measures the performance of FindFirstFileW / FindNextFile / FindClose. NTFS wins this scenario, likely because it can satisfy the list operation from cache. WinFsp has overall good performance. Dokany appears to show slightly quadratic performance in this scenario.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_list_test.csv",file="WinFsp-Performance-Testing/file_list_test.png",opt="x-label=file count,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/file_list_test.png[]]
|
||||||
|
|
||||||
|
==== file_delete_test
|
||||||
|
|
||||||
|
This test measures the performance of DeleteFileW. WinFsp has the best performance, followed by Dokany and NTFS with very similar performance.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/file_delete_test.csv",file="WinFsp-Performance-Testing/file_delete_test.png",opt="x-label=file count,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/file_delete_test.png[]]
|
||||||
|
|
||||||
|
=== Read/Write Tests
|
||||||
|
|
||||||
|
These tests measure the performance of cached, non-cached and memory-mapped I/O.
|
||||||
|
|
||||||
|
==== rdwr_cc_write_page_test
|
||||||
|
|
||||||
|
This test measures the performance of cached WriteFile with 1 page writes. NTFS and WinFsp with an infinite FileInfoTimeout have the best performance, with a clear edge to NTFS (likely because of its use of FastIO, which WinFsp does not currently support). WinFsp with a FileInfoTimeout of 0 or 1 performance is next, because WinFsp does not use the NTOS Cache Manager in this scenario. Dokany performance is last.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_cc_write_page_test.csv",file="WinFsp-Performance-Testing/rdwr_cc_write_page_test.png",opt="x-label=iterations,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_cc_write_page_test.png[]]
|
||||||
|
|
||||||
|
==== rdwr_cc_read_page_test
|
||||||
|
|
||||||
|
This test measures the performance of cached ReadFile with 1 page reads. The results here are very similar to the rdwr_cc_write_page_test case and similar comments apply.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_cc_read_page_test.csv",file="WinFsp-Performance-Testing/rdwr_cc_read_page_test.png",opt="x-label=iterations,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_cc_read_page_test.png[]]
|
||||||
|
|
||||||
|
==== rdwr_nc_write_page_test
|
||||||
|
|
||||||
|
This test measures the performance of non-cached WriteFile with 1 page writes. WinFsp has the best performance, followed by Dokany. NTFS shows bad performance, which of course make sense as we are asking it to write all data to the disk.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_nc_write_page_test.csv",file="WinFsp-Performance-Testing/rdwr_nc_write_page_test.png",opt="x-label=iterations,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_nc_write_page_test.png[]]
|
||||||
|
|
||||||
|
==== rdwr_nc_read_page_test
|
||||||
|
|
||||||
|
This test measures the performance of non-cached ReadFile with 1 page reads. The results here are very similar to the rdwr_nc_write_page_test case and similar comments apply.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/rdwr_nc_read_page_test.csv",file="WinFsp-Performance-Testing/rdwr_nc_read_page_test.png",opt="x-label=iterations,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/rdwr_nc_read_page_test.png[]]
|
||||||
|
|
||||||
|
==== mmap_write_test
|
||||||
|
|
||||||
|
This test measures the performance of memory mapped writes. NTFS and WinFsp seem to have identical performance here, which actually makes sense because memory mapped I/O is effectively always cached and most of the actual I/O is done asynchronously by the system.
|
||||||
|
|
||||||
|
There are no results for Dokany as it seems to (still) not support memory mapped files:
|
||||||
|
|
||||||
|
----
|
||||||
|
Y:\>c:\Users\billziss\Projects\winfsp\build\VStudio\build\Release\fsbench-x64.exe --mmap=100 mmap*
|
||||||
|
mmap_write_test........................ KO
|
||||||
|
ASSERT(0 != Mapping) failed at fsbench.c:226:mmap_dotest
|
||||||
|
----
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/mmap_write_test.csv",file="WinFsp-Performance-Testing/mmap_write_test.png",opt="x-label=iterations,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/mmap_write_test.png[]]
|
||||||
|
|
||||||
|
==== mmap_read_test
|
||||||
|
|
||||||
|
This test measures the performance of memory mapped reads. Again NTFS and WinFsp seem to have identical performance here.
|
||||||
|
|
||||||
|
There are no results for Dokany as it faces the same issue as with mmap_write_test.
|
||||||
|
|
||||||
|
ifdef::env-browser[chart::line[data-uri="WinFsp-Performance-Testing/mmap_read_test.csv",file="WinFsp-Performance-Testing/mmap_read_test.png",opt="x-label=iterations,y-label=time"]]
|
||||||
|
ifndef::env-browser[image::WinFsp-Performance-Testing/mmap_read_test.png[]]
|
75
doc/WinFsp-Performance-Testing/ORIG/dokany-1.csv
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
file_create_test,1000,0.28
|
||||||
|
file_open_test,1000,0.14
|
||||||
|
file_overwrite_test,1000,0.33
|
||||||
|
file_list_test,1000,0.16
|
||||||
|
file_delete_test,1000,0.17
|
||||||
|
file_mkdir_test,1000,0.08
|
||||||
|
file_rmdir_test,1000,0.14
|
||||||
|
file_create_test,2000,0.67
|
||||||
|
file_open_test,2000,0.27
|
||||||
|
file_overwrite_test,2000,0.69
|
||||||
|
file_list_test,2000,0.36
|
||||||
|
file_delete_test,2000,0.36
|
||||||
|
file_mkdir_test,2000,0.33
|
||||||
|
file_rmdir_test,2000,0.23
|
||||||
|
file_create_test,3000,0.91
|
||||||
|
file_open_test,3000,0.42
|
||||||
|
file_overwrite_test,3000,1.03
|
||||||
|
file_list_test,3000,0.64
|
||||||
|
file_delete_test,3000,0.56
|
||||||
|
file_mkdir_test,3000,0.52
|
||||||
|
file_rmdir_test,3000,0.34
|
||||||
|
file_create_test,4000,1.25
|
||||||
|
file_open_test,4000,0.55
|
||||||
|
file_overwrite_test,4000,1.34
|
||||||
|
file_list_test,4000,0.97
|
||||||
|
file_delete_test,4000,0.72
|
||||||
|
file_mkdir_test,4000,0.66
|
||||||
|
file_rmdir_test,4000,0.47
|
||||||
|
file_create_test,5000,1.87
|
||||||
|
file_open_test,5000,0.67
|
||||||
|
file_overwrite_test,5000,1.64
|
||||||
|
file_list_test,5000,1.38
|
||||||
|
file_delete_test,5000,0.91
|
||||||
|
file_mkdir_test,5000,0.83
|
||||||
|
file_rmdir_test,5000,0.59
|
||||||
|
rdwr_cc_write_page_test,100,2.19
|
||||||
|
rdwr_cc_read_page_test,100,2.31
|
||||||
|
rdwr_cc_write_large_test,100,0.33
|
||||||
|
rdwr_cc_read_large_test,100,0.28
|
||||||
|
rdwr_cc_write_page_test,200,4.33
|
||||||
|
rdwr_cc_read_page_test,200,4.58
|
||||||
|
rdwr_cc_write_large_test,200,0.59
|
||||||
|
rdwr_cc_read_large_test,200,0.59
|
||||||
|
rdwr_cc_write_page_test,300,6.37
|
||||||
|
rdwr_cc_read_page_test,300,7.00
|
||||||
|
rdwr_cc_write_large_test,300,0.91
|
||||||
|
rdwr_cc_read_large_test,300,0.89
|
||||||
|
rdwr_cc_write_page_test,400,8.59
|
||||||
|
rdwr_cc_read_page_test,400,9.34
|
||||||
|
rdwr_cc_write_large_test,400,1.22
|
||||||
|
rdwr_cc_read_large_test,400,1.17
|
||||||
|
rdwr_cc_write_page_test,500,10.70
|
||||||
|
rdwr_cc_read_page_test,500,11.47
|
||||||
|
rdwr_cc_write_large_test,500,1.47
|
||||||
|
rdwr_cc_read_large_test,500,1.45
|
||||||
|
rdwr_nc_write_page_test,100,2.20
|
||||||
|
rdwr_nc_read_page_test,100,2.22
|
||||||
|
rdwr_nc_write_large_test,100,0.36
|
||||||
|
rdwr_nc_read_large_test,100,0.30
|
||||||
|
rdwr_nc_write_page_test,200,4.72
|
||||||
|
rdwr_nc_read_page_test,200,4.48
|
||||||
|
rdwr_nc_write_large_test,200,0.63
|
||||||
|
rdwr_nc_read_large_test,200,0.58
|
||||||
|
rdwr_nc_write_page_test,300,6.53
|
||||||
|
rdwr_nc_read_page_test,300,6.56
|
||||||
|
rdwr_nc_write_large_test,300,0.91
|
||||||
|
rdwr_nc_read_large_test,300,0.84
|
||||||
|
rdwr_nc_write_page_test,400,9.05
|
||||||
|
rdwr_nc_read_page_test,400,8.67
|
||||||
|
rdwr_nc_write_large_test,400,1.22
|
||||||
|
rdwr_nc_read_large_test,400,1.13
|
||||||
|
rdwr_nc_write_page_test,500,11.45
|
||||||
|
rdwr_nc_read_page_test,500,10.86
|
||||||
|
rdwr_nc_write_large_test,500,1.50
|
||||||
|
rdwr_nc_read_large_test,500,1.44
|
|
75
doc/WinFsp-Performance-Testing/ORIG/dokany-2.csv
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
file_create_test,1000,0.28
|
||||||
|
file_open_test,1000,0.15
|
||||||
|
file_overwrite_test,1000,0.33
|
||||||
|
file_list_test,1000,0.16
|
||||||
|
file_delete_test,1000,0.19
|
||||||
|
file_mkdir_test,1000,0.08
|
||||||
|
file_rmdir_test,1000,0.13
|
||||||
|
file_create_test,2000,0.69
|
||||||
|
file_open_test,2000,0.27
|
||||||
|
file_overwrite_test,2000,0.67
|
||||||
|
file_list_test,2000,0.37
|
||||||
|
file_delete_test,2000,0.36
|
||||||
|
file_mkdir_test,2000,0.33
|
||||||
|
file_rmdir_test,2000,0.25
|
||||||
|
file_create_test,3000,0.92
|
||||||
|
file_open_test,3000,0.41
|
||||||
|
file_overwrite_test,3000,1.08
|
||||||
|
file_list_test,3000,0.66
|
||||||
|
file_delete_test,3000,0.56
|
||||||
|
file_mkdir_test,3000,0.48
|
||||||
|
file_rmdir_test,3000,0.38
|
||||||
|
file_create_test,4000,1.31
|
||||||
|
file_open_test,4000,0.61
|
||||||
|
file_overwrite_test,4000,1.38
|
||||||
|
file_list_test,4000,1.00
|
||||||
|
file_delete_test,4000,0.73
|
||||||
|
file_mkdir_test,4000,0.66
|
||||||
|
file_rmdir_test,4000,0.53
|
||||||
|
file_create_test,5000,1.64
|
||||||
|
file_open_test,5000,0.67
|
||||||
|
file_overwrite_test,5000,1.67
|
||||||
|
file_list_test,5000,1.38
|
||||||
|
file_delete_test,5000,0.91
|
||||||
|
file_mkdir_test,5000,0.98
|
||||||
|
file_rmdir_test,5000,0.66
|
||||||
|
rdwr_cc_write_page_test,100,2.08
|
||||||
|
rdwr_cc_read_page_test,100,2.23
|
||||||
|
rdwr_cc_write_large_test,100,0.33
|
||||||
|
rdwr_cc_read_large_test,100,0.28
|
||||||
|
rdwr_cc_write_page_test,200,4.23
|
||||||
|
rdwr_cc_read_page_test,200,4.63
|
||||||
|
rdwr_cc_write_large_test,200,0.61
|
||||||
|
rdwr_cc_read_large_test,200,0.58
|
||||||
|
rdwr_cc_write_page_test,300,6.33
|
||||||
|
rdwr_cc_read_page_test,300,6.78
|
||||||
|
rdwr_cc_write_large_test,300,0.92
|
||||||
|
rdwr_cc_read_large_test,300,0.86
|
||||||
|
rdwr_cc_write_page_test,400,8.48
|
||||||
|
rdwr_cc_read_page_test,400,9.02
|
||||||
|
rdwr_cc_write_large_test,400,1.20
|
||||||
|
rdwr_cc_read_large_test,400,1.16
|
||||||
|
rdwr_cc_write_page_test,500,10.33
|
||||||
|
rdwr_cc_read_page_test,500,11.20
|
||||||
|
rdwr_cc_write_large_test,500,1.53
|
||||||
|
rdwr_cc_read_large_test,500,1.47
|
||||||
|
rdwr_nc_write_page_test,100,2.23
|
||||||
|
rdwr_nc_read_page_test,100,2.22
|
||||||
|
rdwr_nc_write_large_test,100,0.31
|
||||||
|
rdwr_nc_read_large_test,100,0.30
|
||||||
|
rdwr_nc_write_page_test,200,4.66
|
||||||
|
rdwr_nc_read_page_test,200,4.34
|
||||||
|
rdwr_nc_write_large_test,200,0.61
|
||||||
|
rdwr_nc_read_large_test,200,0.63
|
||||||
|
rdwr_nc_write_page_test,300,6.44
|
||||||
|
rdwr_nc_read_page_test,300,6.34
|
||||||
|
rdwr_nc_write_large_test,300,0.92
|
||||||
|
rdwr_nc_read_large_test,300,0.84
|
||||||
|
rdwr_nc_write_page_test,400,8.56
|
||||||
|
rdwr_nc_read_page_test,400,8.78
|
||||||
|
rdwr_nc_write_large_test,400,1.26
|
||||||
|
rdwr_nc_read_large_test,400,1.11
|
||||||
|
rdwr_nc_write_page_test,500,10.73
|
||||||
|
rdwr_nc_read_page_test,500,10.59
|
||||||
|
rdwr_nc_write_large_test,500,1.53
|
||||||
|
rdwr_nc_read_large_test,500,1.41
|
|
85
doc/WinFsp-Performance-Testing/ORIG/ntfs-1.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.92
|
||||||
|
file_open_test,1000,0.08
|
||||||
|
file_overwrite_test,1000,0.19
|
||||||
|
file_list_test,1000,0.08
|
||||||
|
file_delete_test,1000,0.19
|
||||||
|
file_mkdir_test,1000,0.16
|
||||||
|
file_rmdir_test,1000,0.11
|
||||||
|
file_create_test,2000,1.45
|
||||||
|
file_open_test,2000,0.17
|
||||||
|
file_overwrite_test,2000,0.38
|
||||||
|
file_list_test,2000,0.16
|
||||||
|
file_delete_test,2000,0.39
|
||||||
|
file_mkdir_test,2000,0.25
|
||||||
|
file_rmdir_test,2000,0.28
|
||||||
|
file_create_test,3000,1.11
|
||||||
|
file_open_test,3000,0.23
|
||||||
|
file_overwrite_test,3000,0.72
|
||||||
|
file_list_test,3000,0.23
|
||||||
|
file_delete_test,3000,0.56
|
||||||
|
file_mkdir_test,3000,0.56
|
||||||
|
file_rmdir_test,3000,0.36
|
||||||
|
file_create_test,4000,1.45
|
||||||
|
file_open_test,4000,0.36
|
||||||
|
file_overwrite_test,4000,0.97
|
||||||
|
file_list_test,4000,0.33
|
||||||
|
file_delete_test,4000,0.77
|
||||||
|
file_mkdir_test,4000,0.48
|
||||||
|
file_rmdir_test,4000,0.47
|
||||||
|
file_create_test,5000,2.47
|
||||||
|
file_open_test,5000,0.45
|
||||||
|
file_overwrite_test,5000,1.23
|
||||||
|
file_list_test,5000,0.41
|
||||||
|
file_delete_test,5000,1.03
|
||||||
|
file_mkdir_test,5000,0.70
|
||||||
|
file_rmdir_test,5000,0.70
|
||||||
|
rdwr_cc_write_page_test,100,0.25
|
||||||
|
rdwr_cc_read_page_test,100,0.19
|
||||||
|
rdwr_cc_write_large_test,100,0.09
|
||||||
|
rdwr_cc_read_large_test,100,0.08
|
||||||
|
rdwr_cc_write_page_test,200,0.47
|
||||||
|
rdwr_cc_read_page_test,200,0.52
|
||||||
|
rdwr_cc_write_large_test,200,0.22
|
||||||
|
rdwr_cc_read_large_test,200,0.16
|
||||||
|
rdwr_cc_write_page_test,300,0.72
|
||||||
|
rdwr_cc_read_page_test,300,0.62
|
||||||
|
rdwr_cc_write_large_test,300,0.30
|
||||||
|
rdwr_cc_read_large_test,300,0.23
|
||||||
|
rdwr_cc_write_page_test,400,0.92
|
||||||
|
rdwr_cc_read_page_test,400,0.88
|
||||||
|
rdwr_cc_write_large_test,400,0.41
|
||||||
|
rdwr_cc_read_large_test,400,0.31
|
||||||
|
rdwr_cc_write_page_test,500,1.20
|
||||||
|
rdwr_cc_read_page_test,500,0.97
|
||||||
|
rdwr_cc_write_large_test,500,0.50
|
||||||
|
rdwr_cc_read_large_test,500,0.39
|
||||||
|
rdwr_nc_write_page_test,100,7.56
|
||||||
|
rdwr_nc_read_page_test,100,10.14
|
||||||
|
rdwr_nc_write_large_test,100,0.88
|
||||||
|
rdwr_nc_read_large_test,100,0.56
|
||||||
|
rdwr_nc_write_page_test,200,14.36
|
||||||
|
rdwr_nc_read_page_test,200,21.39
|
||||||
|
rdwr_nc_write_large_test,200,1.72
|
||||||
|
rdwr_nc_read_large_test,200,1.34
|
||||||
|
rdwr_nc_write_page_test,300,21.86
|
||||||
|
rdwr_nc_read_page_test,300,19.56
|
||||||
|
rdwr_nc_write_large_test,300,2.53
|
||||||
|
rdwr_nc_read_large_test,300,1.64
|
||||||
|
rdwr_nc_write_page_test,400,28.52
|
||||||
|
rdwr_nc_read_page_test,400,26.11
|
||||||
|
rdwr_nc_write_large_test,400,3.42
|
||||||
|
rdwr_nc_read_large_test,400,2.22
|
||||||
|
rdwr_nc_write_page_test,500,35.45
|
||||||
|
rdwr_nc_read_page_test,500,33.05
|
||||||
|
rdwr_nc_write_large_test,500,4.33
|
||||||
|
rdwr_nc_read_large_test,500,2.77
|
||||||
|
mmap_write_test,100,0.16
|
||||||
|
mmap_read_test,100,0.20
|
||||||
|
mmap_write_test,200,0.30
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.44
|
||||||
|
mmap_read_test,300,0.59
|
||||||
|
mmap_write_test,400,0.58
|
||||||
|
mmap_read_test,400,0.78
|
||||||
|
mmap_write_test,500,0.72
|
||||||
|
mmap_read_test,500,1.06
|
|
85
doc/WinFsp-Performance-Testing/ORIG/ntfs-2.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.97
|
||||||
|
file_open_test,1000,0.08
|
||||||
|
file_overwrite_test,1000,0.19
|
||||||
|
file_list_test,1000,0.08
|
||||||
|
file_delete_test,1000,0.19
|
||||||
|
file_mkdir_test,1000,0.13
|
||||||
|
file_rmdir_test,1000,0.13
|
||||||
|
file_create_test,2000,1.38
|
||||||
|
file_open_test,2000,0.23
|
||||||
|
file_overwrite_test,2000,0.36
|
||||||
|
file_list_test,2000,0.17
|
||||||
|
file_delete_test,2000,0.41
|
||||||
|
file_mkdir_test,2000,0.25
|
||||||
|
file_rmdir_test,2000,0.36
|
||||||
|
file_create_test,3000,1.34
|
||||||
|
file_open_test,3000,0.28
|
||||||
|
file_overwrite_test,3000,0.78
|
||||||
|
file_list_test,3000,0.27
|
||||||
|
file_delete_test,3000,0.59
|
||||||
|
file_mkdir_test,3000,0.36
|
||||||
|
file_rmdir_test,3000,0.36
|
||||||
|
file_create_test,4000,1.33
|
||||||
|
file_open_test,4000,0.36
|
||||||
|
file_overwrite_test,4000,1.06
|
||||||
|
file_list_test,4000,0.33
|
||||||
|
file_delete_test,4000,0.81
|
||||||
|
file_mkdir_test,4000,0.67
|
||||||
|
file_rmdir_test,4000,0.41
|
||||||
|
file_create_test,5000,1.94
|
||||||
|
file_open_test,5000,0.48
|
||||||
|
file_overwrite_test,5000,1.14
|
||||||
|
file_list_test,5000,0.44
|
||||||
|
file_delete_test,5000,1.06
|
||||||
|
file_mkdir_test,5000,0.87
|
||||||
|
file_rmdir_test,5000,0.59
|
||||||
|
rdwr_cc_write_page_test,100,0.25
|
||||||
|
rdwr_cc_read_page_test,100,0.19
|
||||||
|
rdwr_cc_write_large_test,100,0.11
|
||||||
|
rdwr_cc_read_large_test,100,0.08
|
||||||
|
rdwr_cc_write_page_test,200,0.61
|
||||||
|
rdwr_cc_read_page_test,200,0.42
|
||||||
|
rdwr_cc_write_large_test,200,0.22
|
||||||
|
rdwr_cc_read_large_test,200,0.25
|
||||||
|
rdwr_cc_write_page_test,300,0.69
|
||||||
|
rdwr_cc_read_page_test,300,0.61
|
||||||
|
rdwr_cc_write_large_test,300,0.28
|
||||||
|
rdwr_cc_read_large_test,300,0.22
|
||||||
|
rdwr_cc_write_page_test,400,0.91
|
||||||
|
rdwr_cc_read_page_test,400,0.78
|
||||||
|
rdwr_cc_write_large_test,400,0.38
|
||||||
|
rdwr_cc_read_large_test,400,0.28
|
||||||
|
rdwr_cc_write_page_test,500,1.19
|
||||||
|
rdwr_cc_read_page_test,500,1.03
|
||||||
|
rdwr_cc_write_large_test,500,0.48
|
||||||
|
rdwr_cc_read_large_test,500,0.36
|
||||||
|
rdwr_nc_write_page_test,100,7.55
|
||||||
|
rdwr_nc_read_page_test,100,9.38
|
||||||
|
rdwr_nc_write_large_test,100,0.86
|
||||||
|
rdwr_nc_read_large_test,100,0.58
|
||||||
|
rdwr_nc_write_page_test,200,15.69
|
||||||
|
rdwr_nc_read_page_test,200,21.78
|
||||||
|
rdwr_nc_write_large_test,200,1.73
|
||||||
|
rdwr_nc_read_large_test,200,1.16
|
||||||
|
rdwr_nc_write_page_test,300,21.58
|
||||||
|
rdwr_nc_read_page_test,300,21.92
|
||||||
|
rdwr_nc_write_large_test,300,2.59
|
||||||
|
rdwr_nc_read_large_test,300,1.84
|
||||||
|
rdwr_nc_write_page_test,400,28.91
|
||||||
|
rdwr_nc_read_page_test,400,26.31
|
||||||
|
rdwr_nc_write_large_test,400,3.38
|
||||||
|
rdwr_nc_read_large_test,400,2.20
|
||||||
|
rdwr_nc_write_page_test,500,36.69
|
||||||
|
rdwr_nc_read_page_test,500,33.52
|
||||||
|
rdwr_nc_write_large_test,500,4.36
|
||||||
|
rdwr_nc_read_large_test,500,2.80
|
||||||
|
mmap_write_test,100,0.16
|
||||||
|
mmap_read_test,100,0.19
|
||||||
|
mmap_write_test,200,0.31
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.44
|
||||||
|
mmap_read_test,300,0.58
|
||||||
|
mmap_write_test,400,0.59
|
||||||
|
mmap_read_test,400,0.78
|
||||||
|
mmap_write_test,500,0.72
|
||||||
|
mmap_read_test,500,1.09
|
|
85
doc/WinFsp-Performance-Testing/ORIG/winfsp-t0-1.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.20
|
||||||
|
file_open_test,1000,0.08
|
||||||
|
file_overwrite_test,1000,0.06
|
||||||
|
file_list_test,1000,0.11
|
||||||
|
file_delete_test,1000,0.09
|
||||||
|
file_mkdir_test,1000,0.06
|
||||||
|
file_rmdir_test,1000,0.08
|
||||||
|
file_create_test,2000,0.48
|
||||||
|
file_open_test,2000,0.11
|
||||||
|
file_overwrite_test,2000,0.11
|
||||||
|
file_list_test,2000,0.23
|
||||||
|
file_delete_test,2000,0.19
|
||||||
|
file_mkdir_test,2000,0.09
|
||||||
|
file_rmdir_test,2000,0.14
|
||||||
|
file_create_test,3000,0.61
|
||||||
|
file_open_test,3000,0.30
|
||||||
|
file_overwrite_test,3000,0.17
|
||||||
|
file_list_test,3000,0.33
|
||||||
|
file_delete_test,3000,0.27
|
||||||
|
file_mkdir_test,3000,0.41
|
||||||
|
file_rmdir_test,3000,0.20
|
||||||
|
file_create_test,4000,0.64
|
||||||
|
file_open_test,4000,0.23
|
||||||
|
file_overwrite_test,4000,0.25
|
||||||
|
file_list_test,4000,0.47
|
||||||
|
file_delete_test,4000,0.48
|
||||||
|
file_mkdir_test,4000,0.53
|
||||||
|
file_rmdir_test,4000,0.27
|
||||||
|
file_create_test,5000,1.08
|
||||||
|
file_open_test,5000,0.28
|
||||||
|
file_overwrite_test,5000,0.30
|
||||||
|
file_list_test,5000,0.61
|
||||||
|
file_delete_test,5000,0.52
|
||||||
|
file_mkdir_test,5000,0.66
|
||||||
|
file_rmdir_test,5000,0.39
|
||||||
|
rdwr_cc_write_page_test,100,1.30
|
||||||
|
rdwr_cc_read_page_test,100,1.44
|
||||||
|
rdwr_cc_write_large_test,100,0.17
|
||||||
|
rdwr_cc_read_large_test,100,0.17
|
||||||
|
rdwr_cc_write_page_test,200,2.67
|
||||||
|
rdwr_cc_read_page_test,200,2.97
|
||||||
|
rdwr_cc_write_large_test,200,0.33
|
||||||
|
rdwr_cc_read_large_test,200,0.39
|
||||||
|
rdwr_cc_write_page_test,300,4.00
|
||||||
|
rdwr_cc_read_page_test,300,4.42
|
||||||
|
rdwr_cc_write_large_test,300,0.48
|
||||||
|
rdwr_cc_read_large_test,300,0.50
|
||||||
|
rdwr_cc_write_page_test,400,5.36
|
||||||
|
rdwr_cc_read_page_test,400,5.86
|
||||||
|
rdwr_cc_write_large_test,400,0.63
|
||||||
|
rdwr_cc_read_large_test,400,0.66
|
||||||
|
rdwr_cc_write_page_test,500,6.55
|
||||||
|
rdwr_cc_read_page_test,500,7.05
|
||||||
|
rdwr_cc_write_large_test,500,0.89
|
||||||
|
rdwr_cc_read_large_test,500,0.89
|
||||||
|
rdwr_nc_write_page_test,100,1.33
|
||||||
|
rdwr_nc_read_page_test,100,1.33
|
||||||
|
rdwr_nc_write_large_test,100,0.16
|
||||||
|
rdwr_nc_read_large_test,100,0.16
|
||||||
|
rdwr_nc_write_page_test,200,2.67
|
||||||
|
rdwr_nc_read_page_test,200,2.67
|
||||||
|
rdwr_nc_write_large_test,200,0.31
|
||||||
|
rdwr_nc_read_large_test,200,0.33
|
||||||
|
rdwr_nc_write_page_test,300,4.01
|
||||||
|
rdwr_nc_read_page_test,300,4.06
|
||||||
|
rdwr_nc_write_large_test,300,0.48
|
||||||
|
rdwr_nc_read_large_test,300,0.47
|
||||||
|
rdwr_nc_write_page_test,400,5.44
|
||||||
|
rdwr_nc_read_page_test,400,5.42
|
||||||
|
rdwr_nc_write_large_test,400,0.63
|
||||||
|
rdwr_nc_read_large_test,400,0.66
|
||||||
|
rdwr_nc_write_page_test,500,6.41
|
||||||
|
rdwr_nc_read_page_test,500,6.56
|
||||||
|
rdwr_nc_write_large_test,500,0.83
|
||||||
|
rdwr_nc_read_large_test,500,0.78
|
||||||
|
mmap_write_test,100,0.14
|
||||||
|
mmap_read_test,100,0.20
|
||||||
|
mmap_write_test,200,0.30
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.45
|
||||||
|
mmap_read_test,300,0.59
|
||||||
|
mmap_write_test,400,0.56
|
||||||
|
mmap_read_test,400,0.83
|
||||||
|
mmap_write_test,500,0.72
|
||||||
|
mmap_read_test,500,1.00
|
|
85
doc/WinFsp-Performance-Testing/ORIG/winfsp-t0-2.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.20
|
||||||
|
file_open_test,1000,0.06
|
||||||
|
file_overwrite_test,1000,0.05
|
||||||
|
file_list_test,1000,0.11
|
||||||
|
file_delete_test,1000,0.09
|
||||||
|
file_mkdir_test,1000,0.05
|
||||||
|
file_rmdir_test,1000,0.08
|
||||||
|
file_create_test,2000,0.47
|
||||||
|
file_open_test,2000,0.13
|
||||||
|
file_overwrite_test,2000,0.11
|
||||||
|
file_list_test,2000,0.22
|
||||||
|
file_delete_test,2000,0.19
|
||||||
|
file_mkdir_test,2000,0.11
|
||||||
|
file_rmdir_test,2000,0.14
|
||||||
|
file_create_test,3000,0.59
|
||||||
|
file_open_test,3000,0.27
|
||||||
|
file_overwrite_test,3000,0.17
|
||||||
|
file_list_test,3000,0.34
|
||||||
|
file_delete_test,3000,0.27
|
||||||
|
file_mkdir_test,3000,0.41
|
||||||
|
file_rmdir_test,3000,0.20
|
||||||
|
file_create_test,4000,0.62
|
||||||
|
file_open_test,4000,0.22
|
||||||
|
file_overwrite_test,4000,0.41
|
||||||
|
file_list_test,4000,0.47
|
||||||
|
file_delete_test,4000,0.34
|
||||||
|
file_mkdir_test,4000,0.55
|
||||||
|
file_rmdir_test,4000,0.28
|
||||||
|
file_create_test,5000,1.08
|
||||||
|
file_open_test,5000,0.28
|
||||||
|
file_overwrite_test,5000,0.30
|
||||||
|
file_list_test,5000,0.61
|
||||||
|
file_delete_test,5000,0.45
|
||||||
|
file_mkdir_test,5000,0.67
|
||||||
|
file_rmdir_test,5000,0.34
|
||||||
|
rdwr_cc_write_page_test,100,1.36
|
||||||
|
rdwr_cc_read_page_test,100,1.47
|
||||||
|
rdwr_cc_write_large_test,100,0.17
|
||||||
|
rdwr_cc_read_large_test,100,0.17
|
||||||
|
rdwr_cc_write_page_test,200,2.63
|
||||||
|
rdwr_cc_read_page_test,200,3.00
|
||||||
|
rdwr_cc_write_large_test,200,0.31
|
||||||
|
rdwr_cc_read_large_test,200,0.34
|
||||||
|
rdwr_cc_write_page_test,300,3.91
|
||||||
|
rdwr_cc_read_page_test,300,4.20
|
||||||
|
rdwr_cc_write_large_test,300,0.50
|
||||||
|
rdwr_cc_read_large_test,300,0.52
|
||||||
|
rdwr_cc_write_page_test,400,5.23
|
||||||
|
rdwr_cc_read_page_test,400,5.64
|
||||||
|
rdwr_cc_write_large_test,400,0.72
|
||||||
|
rdwr_cc_read_large_test,400,0.66
|
||||||
|
rdwr_cc_write_page_test,500,6.12
|
||||||
|
rdwr_cc_read_page_test,500,6.83
|
||||||
|
rdwr_cc_write_large_test,500,0.80
|
||||||
|
rdwr_cc_read_large_test,500,0.83
|
||||||
|
rdwr_nc_write_page_test,100,1.30
|
||||||
|
rdwr_nc_read_page_test,100,1.36
|
||||||
|
rdwr_nc_write_large_test,100,0.16
|
||||||
|
rdwr_nc_read_large_test,100,0.20
|
||||||
|
rdwr_nc_write_page_test,200,2.73
|
||||||
|
rdwr_nc_read_page_test,200,2.64
|
||||||
|
rdwr_nc_write_large_test,200,0.31
|
||||||
|
rdwr_nc_read_large_test,200,0.31
|
||||||
|
rdwr_nc_write_page_test,300,3.95
|
||||||
|
rdwr_nc_read_page_test,300,4.06
|
||||||
|
rdwr_nc_write_large_test,300,0.48
|
||||||
|
rdwr_nc_read_large_test,300,0.48
|
||||||
|
rdwr_nc_write_page_test,400,5.33
|
||||||
|
rdwr_nc_read_page_test,400,5.47
|
||||||
|
rdwr_nc_write_large_test,400,0.64
|
||||||
|
rdwr_nc_read_large_test,400,0.64
|
||||||
|
rdwr_nc_write_page_test,500,6.48
|
||||||
|
rdwr_nc_read_page_test,500,6.41
|
||||||
|
rdwr_nc_write_large_test,500,0.81
|
||||||
|
rdwr_nc_read_large_test,500,0.81
|
||||||
|
mmap_write_test,100,0.14
|
||||||
|
mmap_read_test,100,0.20
|
||||||
|
mmap_write_test,200,0.30
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.45
|
||||||
|
mmap_read_test,300,0.59
|
||||||
|
mmap_write_test,400,0.64
|
||||||
|
mmap_read_test,400,0.77
|
||||||
|
mmap_write_test,500,0.73
|
||||||
|
mmap_read_test,500,1.00
|
|
85
doc/WinFsp-Performance-Testing/ORIG/winfsp-t1-1.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.06
|
||||||
|
file_open_test,1000,0.16
|
||||||
|
file_overwrite_test,1000,0.05
|
||||||
|
file_list_test,1000,0.09
|
||||||
|
file_delete_test,1000,0.08
|
||||||
|
file_mkdir_test,1000,0.05
|
||||||
|
file_rmdir_test,1000,0.08
|
||||||
|
file_create_test,2000,0.42
|
||||||
|
file_open_test,2000,0.09
|
||||||
|
file_overwrite_test,2000,0.08
|
||||||
|
file_list_test,2000,0.22
|
||||||
|
file_delete_test,2000,0.14
|
||||||
|
file_mkdir_test,2000,0.09
|
||||||
|
file_rmdir_test,2000,0.13
|
||||||
|
file_create_test,3000,0.58
|
||||||
|
file_open_test,3000,0.22
|
||||||
|
file_overwrite_test,3000,0.25
|
||||||
|
file_list_test,3000,0.36
|
||||||
|
file_delete_test,3000,0.22
|
||||||
|
file_mkdir_test,3000,0.39
|
||||||
|
file_rmdir_test,3000,0.17
|
||||||
|
file_create_test,4000,0.59
|
||||||
|
file_open_test,4000,0.19
|
||||||
|
file_overwrite_test,4000,0.17
|
||||||
|
file_list_test,4000,0.58
|
||||||
|
file_delete_test,4000,0.33
|
||||||
|
file_mkdir_test,4000,0.55
|
||||||
|
file_rmdir_test,4000,0.22
|
||||||
|
file_create_test,5000,0.95
|
||||||
|
file_open_test,5000,0.22
|
||||||
|
file_overwrite_test,5000,0.23
|
||||||
|
file_list_test,5000,0.59
|
||||||
|
file_delete_test,5000,0.34
|
||||||
|
file_mkdir_test,5000,0.66
|
||||||
|
file_rmdir_test,5000,0.28
|
||||||
|
rdwr_cc_write_page_test,100,1.37
|
||||||
|
rdwr_cc_read_page_test,100,1.47
|
||||||
|
rdwr_cc_write_large_test,100,0.16
|
||||||
|
rdwr_cc_read_large_test,100,0.17
|
||||||
|
rdwr_cc_write_page_test,200,2.47
|
||||||
|
rdwr_cc_read_page_test,200,3.00
|
||||||
|
rdwr_cc_write_large_test,200,0.31
|
||||||
|
rdwr_cc_read_large_test,200,0.34
|
||||||
|
rdwr_cc_write_page_test,300,3.89
|
||||||
|
rdwr_cc_read_page_test,300,4.45
|
||||||
|
rdwr_cc_write_large_test,300,0.47
|
||||||
|
rdwr_cc_read_large_test,300,0.50
|
||||||
|
rdwr_cc_write_page_test,400,4.92
|
||||||
|
rdwr_cc_read_page_test,400,5.78
|
||||||
|
rdwr_cc_write_large_test,400,0.61
|
||||||
|
rdwr_cc_read_large_test,400,0.67
|
||||||
|
rdwr_cc_write_page_test,500,6.17
|
||||||
|
rdwr_cc_read_page_test,500,7.33
|
||||||
|
rdwr_cc_write_large_test,500,0.78
|
||||||
|
rdwr_cc_read_large_test,500,0.95
|
||||||
|
rdwr_nc_write_page_test,100,1.30
|
||||||
|
rdwr_nc_read_page_test,100,1.39
|
||||||
|
rdwr_nc_write_large_test,100,0.19
|
||||||
|
rdwr_nc_read_large_test,100,0.17
|
||||||
|
rdwr_nc_write_page_test,200,2.61
|
||||||
|
rdwr_nc_read_page_test,200,2.80
|
||||||
|
rdwr_nc_write_large_test,200,0.31
|
||||||
|
rdwr_nc_read_large_test,200,0.34
|
||||||
|
rdwr_nc_write_page_test,300,3.94
|
||||||
|
rdwr_nc_read_page_test,300,4.23
|
||||||
|
rdwr_nc_write_large_test,300,0.48
|
||||||
|
rdwr_nc_read_large_test,300,0.50
|
||||||
|
rdwr_nc_write_page_test,400,5.36
|
||||||
|
rdwr_nc_read_page_test,400,5.52
|
||||||
|
rdwr_nc_write_large_test,400,0.63
|
||||||
|
rdwr_nc_read_large_test,400,0.69
|
||||||
|
rdwr_nc_write_page_test,500,6.51
|
||||||
|
rdwr_nc_read_page_test,500,7.00
|
||||||
|
rdwr_nc_write_large_test,500,0.81
|
||||||
|
rdwr_nc_read_large_test,500,0.81
|
||||||
|
mmap_write_test,100,0.16
|
||||||
|
mmap_read_test,100,0.19
|
||||||
|
mmap_write_test,200,0.31
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.44
|
||||||
|
mmap_read_test,300,0.59
|
||||||
|
mmap_write_test,400,0.59
|
||||||
|
mmap_read_test,400,0.78
|
||||||
|
mmap_write_test,500,0.73
|
||||||
|
mmap_read_test,500,0.98
|
|
85
doc/WinFsp-Performance-Testing/ORIG/winfsp-t1-2.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.08
|
||||||
|
file_open_test,1000,0.16
|
||||||
|
file_overwrite_test,1000,0.05
|
||||||
|
file_list_test,1000,0.11
|
||||||
|
file_delete_test,1000,0.06
|
||||||
|
file_mkdir_test,1000,0.16
|
||||||
|
file_rmdir_test,1000,0.06
|
||||||
|
file_create_test,2000,0.36
|
||||||
|
file_open_test,2000,0.09
|
||||||
|
file_overwrite_test,2000,0.09
|
||||||
|
file_list_test,2000,0.20
|
||||||
|
file_delete_test,2000,0.16
|
||||||
|
file_mkdir_test,2000,0.09
|
||||||
|
file_rmdir_test,2000,0.12
|
||||||
|
file_create_test,3000,0.58
|
||||||
|
file_open_test,3000,0.20
|
||||||
|
file_overwrite_test,3000,0.16
|
||||||
|
file_list_test,3000,0.33
|
||||||
|
file_delete_test,3000,0.22
|
||||||
|
file_mkdir_test,3000,0.41
|
||||||
|
file_rmdir_test,3000,0.17
|
||||||
|
file_create_test,4000,0.58
|
||||||
|
file_open_test,4000,0.17
|
||||||
|
file_overwrite_test,4000,0.20
|
||||||
|
file_list_test,4000,0.44
|
||||||
|
file_delete_test,4000,0.38
|
||||||
|
file_mkdir_test,4000,0.59
|
||||||
|
file_rmdir_test,4000,0.25
|
||||||
|
file_create_test,5000,0.97
|
||||||
|
file_open_test,5000,0.22
|
||||||
|
file_overwrite_test,5000,0.22
|
||||||
|
file_list_test,5000,0.61
|
||||||
|
file_delete_test,5000,0.36
|
||||||
|
file_mkdir_test,5000,0.69
|
||||||
|
file_rmdir_test,5000,0.30
|
||||||
|
rdwr_cc_write_page_test,100,1.30
|
||||||
|
rdwr_cc_read_page_test,100,1.53
|
||||||
|
rdwr_cc_write_large_test,100,0.17
|
||||||
|
rdwr_cc_read_large_test,100,0.17
|
||||||
|
rdwr_cc_write_page_test,200,2.62
|
||||||
|
rdwr_cc_read_page_test,200,3.06
|
||||||
|
rdwr_cc_write_large_test,200,0.31
|
||||||
|
rdwr_cc_read_large_test,200,0.34
|
||||||
|
rdwr_cc_write_page_test,300,3.89
|
||||||
|
rdwr_cc_read_page_test,300,4.50
|
||||||
|
rdwr_cc_write_large_test,300,0.50
|
||||||
|
rdwr_cc_read_large_test,300,0.59
|
||||||
|
rdwr_cc_write_page_test,400,5.14
|
||||||
|
rdwr_cc_read_page_test,400,5.94
|
||||||
|
rdwr_cc_write_large_test,400,0.62
|
||||||
|
rdwr_cc_read_large_test,400,0.70
|
||||||
|
rdwr_cc_write_page_test,500,6.25
|
||||||
|
rdwr_cc_read_page_test,500,7.33
|
||||||
|
rdwr_cc_write_large_test,500,0.81
|
||||||
|
rdwr_cc_read_large_test,500,0.83
|
||||||
|
rdwr_nc_write_page_test,100,1.34
|
||||||
|
rdwr_nc_read_page_test,100,1.38
|
||||||
|
rdwr_nc_write_large_test,100,0.19
|
||||||
|
rdwr_nc_read_large_test,100,0.16
|
||||||
|
rdwr_nc_write_page_test,200,2.67
|
||||||
|
rdwr_nc_read_page_test,200,2.78
|
||||||
|
rdwr_nc_write_large_test,200,0.38
|
||||||
|
rdwr_nc_read_large_test,200,0.33
|
||||||
|
rdwr_nc_write_page_test,300,3.98
|
||||||
|
rdwr_nc_read_page_test,300,4.44
|
||||||
|
rdwr_nc_write_large_test,300,0.52
|
||||||
|
rdwr_nc_read_large_test,300,0.50
|
||||||
|
rdwr_nc_write_page_test,400,5.36
|
||||||
|
rdwr_nc_read_page_test,400,5.69
|
||||||
|
rdwr_nc_write_large_test,400,0.66
|
||||||
|
rdwr_nc_read_large_test,400,0.67
|
||||||
|
rdwr_nc_write_page_test,500,6.66
|
||||||
|
rdwr_nc_read_page_test,500,6.94
|
||||||
|
rdwr_nc_write_large_test,500,0.81
|
||||||
|
rdwr_nc_read_large_test,500,0.81
|
||||||
|
mmap_write_test,100,0.14
|
||||||
|
mmap_read_test,100,0.20
|
||||||
|
mmap_write_test,200,0.31
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.44
|
||||||
|
mmap_read_test,300,0.59
|
||||||
|
mmap_write_test,400,0.59
|
||||||
|
mmap_read_test,400,0.78
|
||||||
|
mmap_write_test,500,0.75
|
||||||
|
mmap_read_test,500,0.98
|
|
85
doc/WinFsp-Performance-Testing/ORIG/winfsp-tinf-1.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.06
|
||||||
|
file_open_test,1000,0.17
|
||||||
|
file_overwrite_test,1000,0.05
|
||||||
|
file_list_test,1000,0.11
|
||||||
|
file_delete_test,1000,0.06
|
||||||
|
file_mkdir_test,1000,0.05
|
||||||
|
file_rmdir_test,1000,0.06
|
||||||
|
file_create_test,2000,0.44
|
||||||
|
file_open_test,2000,0.08
|
||||||
|
file_overwrite_test,2000,0.09
|
||||||
|
file_list_test,2000,0.22
|
||||||
|
file_delete_test,2000,0.14
|
||||||
|
file_mkdir_test,2000,0.09
|
||||||
|
file_rmdir_test,2000,0.14
|
||||||
|
file_create_test,3000,0.56
|
||||||
|
file_open_test,3000,0.20
|
||||||
|
file_overwrite_test,3000,0.14
|
||||||
|
file_list_test,3000,0.33
|
||||||
|
file_delete_test,3000,0.20
|
||||||
|
file_mkdir_test,3000,0.41
|
||||||
|
file_rmdir_test,3000,0.16
|
||||||
|
file_create_test,4000,0.59
|
||||||
|
file_open_test,4000,0.16
|
||||||
|
file_overwrite_test,4000,0.19
|
||||||
|
file_list_test,4000,0.47
|
||||||
|
file_delete_test,4000,0.31
|
||||||
|
file_mkdir_test,4000,0.66
|
||||||
|
file_rmdir_test,4000,0.23
|
||||||
|
file_create_test,5000,0.98
|
||||||
|
file_open_test,5000,0.22
|
||||||
|
file_overwrite_test,5000,0.22
|
||||||
|
file_list_test,5000,0.59
|
||||||
|
file_delete_test,5000,0.36
|
||||||
|
file_mkdir_test,5000,0.66
|
||||||
|
file_rmdir_test,5000,0.31
|
||||||
|
rdwr_cc_write_page_test,100,0.34
|
||||||
|
rdwr_cc_read_page_test,100,0.28
|
||||||
|
rdwr_cc_write_large_test,100,0.11
|
||||||
|
rdwr_cc_read_large_test,100,0.08
|
||||||
|
rdwr_cc_write_page_test,200,0.67
|
||||||
|
rdwr_cc_read_page_test,200,0.58
|
||||||
|
rdwr_cc_write_large_test,200,0.22
|
||||||
|
rdwr_cc_read_large_test,200,0.22
|
||||||
|
rdwr_cc_write_page_test,300,1.01
|
||||||
|
rdwr_cc_read_page_test,300,0.88
|
||||||
|
rdwr_cc_write_large_test,300,0.34
|
||||||
|
rdwr_cc_read_large_test,300,0.25
|
||||||
|
rdwr_cc_write_page_test,400,1.38
|
||||||
|
rdwr_cc_read_page_test,400,1.12
|
||||||
|
rdwr_cc_write_large_test,400,0.42
|
||||||
|
rdwr_cc_read_large_test,400,0.33
|
||||||
|
rdwr_cc_write_page_test,500,1.70
|
||||||
|
rdwr_cc_read_page_test,500,1.48
|
||||||
|
rdwr_cc_write_large_test,500,0.64
|
||||||
|
rdwr_cc_read_large_test,500,0.44
|
||||||
|
rdwr_nc_write_page_test,100,1.31
|
||||||
|
rdwr_nc_read_page_test,100,1.36
|
||||||
|
rdwr_nc_write_large_test,100,0.17
|
||||||
|
rdwr_nc_read_large_test,100,0.16
|
||||||
|
rdwr_nc_write_page_test,200,2.56
|
||||||
|
rdwr_nc_read_page_test,200,2.81
|
||||||
|
rdwr_nc_write_large_test,200,0.33
|
||||||
|
rdwr_nc_read_large_test,200,0.31
|
||||||
|
rdwr_nc_write_page_test,300,3.86
|
||||||
|
rdwr_nc_read_page_test,300,3.95
|
||||||
|
rdwr_nc_write_large_test,300,0.47
|
||||||
|
rdwr_nc_read_large_test,300,0.48
|
||||||
|
rdwr_nc_write_page_test,400,5.11
|
||||||
|
rdwr_nc_read_page_test,400,5.19
|
||||||
|
rdwr_nc_write_large_test,400,0.64
|
||||||
|
rdwr_nc_read_large_test,400,0.64
|
||||||
|
rdwr_nc_write_page_test,500,6.42
|
||||||
|
rdwr_nc_read_page_test,500,6.58
|
||||||
|
rdwr_nc_write_large_test,500,0.78
|
||||||
|
rdwr_nc_read_large_test,500,0.78
|
||||||
|
mmap_write_test,100,0.16
|
||||||
|
mmap_read_test,100,0.20
|
||||||
|
mmap_write_test,200,0.30
|
||||||
|
mmap_read_test,200,0.39
|
||||||
|
mmap_write_test,300,0.44
|
||||||
|
mmap_read_test,300,0.59
|
||||||
|
mmap_write_test,400,0.59
|
||||||
|
mmap_read_test,400,0.78
|
||||||
|
mmap_write_test,500,0.75
|
||||||
|
mmap_read_test,500,1.03
|
|
85
doc/WinFsp-Performance-Testing/ORIG/winfsp-tinf-2.csv
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
file_create_test,1000,0.06
|
||||||
|
file_open_test,1000,0.16
|
||||||
|
file_overwrite_test,1000,0.05
|
||||||
|
file_list_test,1000,0.11
|
||||||
|
file_delete_test,1000,0.06
|
||||||
|
file_mkdir_test,1000,0.05
|
||||||
|
file_rmdir_test,1000,0.06
|
||||||
|
file_create_test,2000,0.44
|
||||||
|
file_open_test,2000,0.08
|
||||||
|
file_overwrite_test,2000,0.09
|
||||||
|
file_list_test,2000,0.20
|
||||||
|
file_delete_test,2000,0.16
|
||||||
|
file_mkdir_test,2000,0.09
|
||||||
|
file_rmdir_test,2000,0.13
|
||||||
|
file_create_test,3000,0.58
|
||||||
|
file_open_test,3000,0.22
|
||||||
|
file_overwrite_test,3000,0.13
|
||||||
|
file_list_test,3000,0.34
|
||||||
|
file_delete_test,3000,0.22
|
||||||
|
file_mkdir_test,3000,0.39
|
||||||
|
file_rmdir_test,3000,0.17
|
||||||
|
file_create_test,4000,0.61
|
||||||
|
file_open_test,4000,0.17
|
||||||
|
file_overwrite_test,4000,0.19
|
||||||
|
file_list_test,4000,0.44
|
||||||
|
file_delete_test,4000,0.27
|
||||||
|
file_mkdir_test,4000,0.67
|
||||||
|
file_rmdir_test,4000,0.22
|
||||||
|
file_create_test,5000,0.97
|
||||||
|
file_open_test,5000,0.20
|
||||||
|
file_overwrite_test,5000,0.23
|
||||||
|
file_list_test,5000,0.61
|
||||||
|
file_delete_test,5000,0.33
|
||||||
|
file_mkdir_test,5000,0.67
|
||||||
|
file_rmdir_test,5000,0.28
|
||||||
|
rdwr_cc_write_page_test,100,0.36
|
||||||
|
rdwr_cc_read_page_test,100,0.30
|
||||||
|
rdwr_cc_write_large_test,100,0.12
|
||||||
|
rdwr_cc_read_large_test,100,0.08
|
||||||
|
rdwr_cc_write_page_test,200,0.69
|
||||||
|
rdwr_cc_read_page_test,200,0.58
|
||||||
|
rdwr_cc_write_large_test,200,0.30
|
||||||
|
rdwr_cc_read_large_test,200,0.23
|
||||||
|
rdwr_cc_write_page_test,300,1.02
|
||||||
|
rdwr_cc_read_page_test,300,0.87
|
||||||
|
rdwr_cc_write_large_test,300,0.34
|
||||||
|
rdwr_cc_read_large_test,300,0.23
|
||||||
|
rdwr_cc_write_page_test,400,1.41
|
||||||
|
rdwr_cc_read_page_test,400,1.14
|
||||||
|
rdwr_cc_write_large_test,400,0.47
|
||||||
|
rdwr_cc_read_large_test,400,0.33
|
||||||
|
rdwr_cc_write_page_test,500,1.73
|
||||||
|
rdwr_cc_read_page_test,500,1.50
|
||||||
|
rdwr_cc_write_large_test,500,0.53
|
||||||
|
rdwr_cc_read_large_test,500,0.41
|
||||||
|
rdwr_nc_write_page_test,100,1.33
|
||||||
|
rdwr_nc_read_page_test,100,1.44
|
||||||
|
rdwr_nc_write_large_test,100,0.17
|
||||||
|
rdwr_nc_read_large_test,100,0.17
|
||||||
|
rdwr_nc_write_page_test,200,2.75
|
||||||
|
rdwr_nc_read_page_test,200,2.94
|
||||||
|
rdwr_nc_write_large_test,200,0.38
|
||||||
|
rdwr_nc_read_large_test,200,0.33
|
||||||
|
rdwr_nc_write_page_test,300,3.94
|
||||||
|
rdwr_nc_read_page_test,300,4.17
|
||||||
|
rdwr_nc_write_large_test,300,0.48
|
||||||
|
rdwr_nc_read_large_test,300,0.56
|
||||||
|
rdwr_nc_write_page_test,400,5.25
|
||||||
|
rdwr_nc_read_page_test,400,5.58
|
||||||
|
rdwr_nc_write_large_test,400,0.63
|
||||||
|
rdwr_nc_read_large_test,400,0.64
|
||||||
|
rdwr_nc_write_page_test,500,6.52
|
||||||
|
rdwr_nc_read_page_test,500,6.78
|
||||||
|
rdwr_nc_write_large_test,500,0.80
|
||||||
|
rdwr_nc_read_large_test,500,0.80
|
||||||
|
mmap_write_test,100,0.17
|
||||||
|
mmap_read_test,100,0.20
|
||||||
|
mmap_write_test,200,0.30
|
||||||
|
mmap_read_test,200,0.41
|
||||||
|
mmap_write_test,300,0.44
|
||||||
|
mmap_read_test,300,0.61
|
||||||
|
mmap_write_test,400,0.61
|
||||||
|
mmap_read_test,400,0.78
|
||||||
|
mmap_write_test,500,0.73
|
||||||
|
mmap_read_test,500,0.98
|
|
30
doc/WinFsp-Performance-Testing/file_create_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
1000,0.92
|
||||||
|
2000,1.38
|
||||||
|
3000,1.11
|
||||||
|
4000,1.33
|
||||||
|
5000,1.94
|
||||||
|
//winfsp-t0
|
||||||
|
1000,0.20
|
||||||
|
2000,0.47
|
||||||
|
3000,0.59
|
||||||
|
4000,0.62
|
||||||
|
5000,1.08
|
||||||
|
//winfsp-t1
|
||||||
|
1000,0.06
|
||||||
|
2000,0.36
|
||||||
|
3000,0.58
|
||||||
|
4000,0.58
|
||||||
|
5000,0.95
|
||||||
|
//winfsp-tinf
|
||||||
|
1000,0.06
|
||||||
|
2000,0.44
|
||||||
|
3000,0.56
|
||||||
|
4000,0.59
|
||||||
|
5000,0.97
|
||||||
|
//dokany
|
||||||
|
1000,0.28
|
||||||
|
2000,0.67
|
||||||
|
3000,0.91
|
||||||
|
4000,1.25
|
||||||
|
5000,1.64
|
|
BIN
doc/WinFsp-Performance-Testing/file_create_test.png
Normal file
After Width: | Height: | Size: 60 KiB |
30
doc/WinFsp-Performance-Testing/file_delete_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
1000,0.19
|
||||||
|
2000,0.39
|
||||||
|
3000,0.56
|
||||||
|
4000,0.77
|
||||||
|
5000,1.03
|
||||||
|
//winfsp-t0
|
||||||
|
1000,0.09
|
||||||
|
2000,0.19
|
||||||
|
3000,0.27
|
||||||
|
4000,0.34
|
||||||
|
5000,0.45
|
||||||
|
//winfsp-t1
|
||||||
|
1000,0.06
|
||||||
|
2000,0.14
|
||||||
|
3000,0.22
|
||||||
|
4000,0.33
|
||||||
|
5000,0.34
|
||||||
|
//winfsp-tinf
|
||||||
|
1000,0.06
|
||||||
|
2000,0.14
|
||||||
|
3000,0.20
|
||||||
|
4000,0.27
|
||||||
|
5000,0.33
|
||||||
|
//dokany
|
||||||
|
1000,0.17
|
||||||
|
2000,0.36
|
||||||
|
3000,0.56
|
||||||
|
4000,0.72
|
||||||
|
5000,0.91
|
|
BIN
doc/WinFsp-Performance-Testing/file_delete_test.png
Normal file
After Width: | Height: | Size: 59 KiB |
30
doc/WinFsp-Performance-Testing/file_list_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
1000,0.08
|
||||||
|
2000,0.16
|
||||||
|
3000,0.23
|
||||||
|
4000,0.33
|
||||||
|
5000,0.41
|
||||||
|
//winfsp-t0
|
||||||
|
1000,0.11
|
||||||
|
2000,0.22
|
||||||
|
3000,0.33
|
||||||
|
4000,0.47
|
||||||
|
5000,0.61
|
||||||
|
//winfsp-t1
|
||||||
|
1000,0.09
|
||||||
|
2000,0.20
|
||||||
|
3000,0.33
|
||||||
|
4000,0.44
|
||||||
|
5000,0.59
|
||||||
|
//winfsp-tinf
|
||||||
|
1000,0.11
|
||||||
|
2000,0.20
|
||||||
|
3000,0.33
|
||||||
|
4000,0.44
|
||||||
|
5000,0.59
|
||||||
|
//dokany
|
||||||
|
1000,0.16
|
||||||
|
2000,0.36
|
||||||
|
3000,0.64
|
||||||
|
4000,0.97
|
||||||
|
5000,1.38
|
|
BIN
doc/WinFsp-Performance-Testing/file_list_test.png
Normal file
After Width: | Height: | Size: 49 KiB |
30
doc/WinFsp-Performance-Testing/file_open_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
1000,0.08
|
||||||
|
2000,0.17
|
||||||
|
3000,0.23
|
||||||
|
4000,0.36
|
||||||
|
5000,0.45
|
||||||
|
//winfsp-t0
|
||||||
|
1000,0.06
|
||||||
|
2000,0.11
|
||||||
|
3000,0.27
|
||||||
|
4000,0.22
|
||||||
|
5000,0.28
|
||||||
|
//winfsp-t1
|
||||||
|
1000,0.16
|
||||||
|
2000,0.09
|
||||||
|
3000,0.20
|
||||||
|
4000,0.17
|
||||||
|
5000,0.22
|
||||||
|
//winfsp-tinf
|
||||||
|
1000,0.16
|
||||||
|
2000,0.08
|
||||||
|
3000,0.20
|
||||||
|
4000,0.16
|
||||||
|
5000,0.20
|
||||||
|
//dokany
|
||||||
|
1000,0.14
|
||||||
|
2000,0.27
|
||||||
|
3000,0.41
|
||||||
|
4000,0.55
|
||||||
|
5000,0.67
|
|
BIN
doc/WinFsp-Performance-Testing/file_open_test.png
Normal file
After Width: | Height: | Size: 55 KiB |
30
doc/WinFsp-Performance-Testing/file_overwrite_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
1000,0.19
|
||||||
|
2000,0.36
|
||||||
|
3000,0.72
|
||||||
|
4000,0.97
|
||||||
|
5000,1.14
|
||||||
|
//winfsp-t0
|
||||||
|
1000,0.05
|
||||||
|
2000,0.11
|
||||||
|
3000,0.17
|
||||||
|
4000,0.25
|
||||||
|
5000,0.30
|
||||||
|
//winfsp-t1
|
||||||
|
1000,0.05
|
||||||
|
2000,0.08
|
||||||
|
3000,0.16
|
||||||
|
4000,0.17
|
||||||
|
5000,0.22
|
||||||
|
//winfsp-tinf
|
||||||
|
1000,0.05
|
||||||
|
2000,0.09
|
||||||
|
3000,0.13
|
||||||
|
4000,0.19
|
||||||
|
5000,0.22
|
||||||
|
//dokany
|
||||||
|
1000,0.33
|
||||||
|
2000,0.67
|
||||||
|
3000,1.03
|
||||||
|
4000,1.34
|
||||||
|
5000,1.64
|
|
BIN
doc/WinFsp-Performance-Testing/file_overwrite_test.png
Normal file
After Width: | Height: | Size: 50 KiB |
30
doc/WinFsp-Performance-Testing/file_tests.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
file_create_test,1.94
|
||||||
|
file_open_test,0.45
|
||||||
|
file_overwrite_test,1.14
|
||||||
|
file_list_test,0.41
|
||||||
|
file_delete_test,1.03
|
||||||
|
//winfsp-t0
|
||||||
|
file_create_test,1.08
|
||||||
|
file_open_test,0.28
|
||||||
|
file_overwrite_test,0.30
|
||||||
|
file_list_test,0.61
|
||||||
|
file_delete_test,0.45
|
||||||
|
//winfsp-t1
|
||||||
|
file_create_test,0.95
|
||||||
|
file_open_test,0.22
|
||||||
|
file_overwrite_test,0.22
|
||||||
|
file_list_test,0.59
|
||||||
|
file_delete_test,0.34
|
||||||
|
//winfsp-tinf
|
||||||
|
file_create_test,0.97
|
||||||
|
file_open_test,0.20
|
||||||
|
file_overwrite_test,0.22
|
||||||
|
file_list_test,0.59
|
||||||
|
file_delete_test,0.33
|
||||||
|
//dokany
|
||||||
|
file_create_test,1.64
|
||||||
|
file_open_test,0.67
|
||||||
|
file_overwrite_test,1.64
|
||||||
|
file_list_test,1.38
|
||||||
|
file_delete_test,0.91
|
|
BIN
doc/WinFsp-Performance-Testing/file_tests.png
Normal file
After Width: | Height: | Size: 55 KiB |
24
doc/WinFsp-Performance-Testing/mmap_read_test.csv
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//ntfs
|
||||||
|
100,0.19
|
||||||
|
200,0.39
|
||||||
|
300,0.58
|
||||||
|
400,0.78
|
||||||
|
500,1.06
|
||||||
|
//winfsp-t0
|
||||||
|
100,0.20
|
||||||
|
200,0.39
|
||||||
|
300,0.59
|
||||||
|
400,0.77
|
||||||
|
500,1.00
|
||||||
|
//winfsp-t1
|
||||||
|
100,0.19
|
||||||
|
200,0.39
|
||||||
|
300,0.59
|
||||||
|
400,0.78
|
||||||
|
500,0.98
|
||||||
|
//winfsp-tinf
|
||||||
|
100,0.20
|
||||||
|
200,0.39
|
||||||
|
300,0.59
|
||||||
|
400,0.78
|
||||||
|
500,0.98
|
|
BIN
doc/WinFsp-Performance-Testing/mmap_read_test.png
Normal file
After Width: | Height: | Size: 44 KiB |
24
doc/WinFsp-Performance-Testing/mmap_write_test.csv
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//ntfs
|
||||||
|
100,0.16
|
||||||
|
200,0.30
|
||||||
|
300,0.44
|
||||||
|
400,0.58
|
||||||
|
500,0.72
|
||||||
|
//winfsp-t0
|
||||||
|
100,0.14
|
||||||
|
200,0.30
|
||||||
|
300,0.45
|
||||||
|
400,0.56
|
||||||
|
500,0.72
|
||||||
|
//winfsp-t1
|
||||||
|
100,0.14
|
||||||
|
200,0.31
|
||||||
|
300,0.44
|
||||||
|
400,0.59
|
||||||
|
500,0.73
|
||||||
|
//winfsp-tinf
|
||||||
|
100,0.16
|
||||||
|
200,0.30
|
||||||
|
300,0.44
|
||||||
|
400,0.59
|
||||||
|
500,0.73
|
|
BIN
doc/WinFsp-Performance-Testing/mmap_write_test.png
Normal file
After Width: | Height: | Size: 39 KiB |
74
doc/WinFsp-Performance-Testing/munge.py
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# usage: ./munge.py ORIG/*.csv
|
||||||
|
# munge CSV files into a format that asciidocFX understands
|
||||||
|
|
||||||
|
import csv, os, sys
|
||||||
|
|
||||||
|
snames = ["ntfs", "winfsp-t0", "winfsp-t1", "winfsp-tinf", "dokany"]
|
||||||
|
file_tnames = [
|
||||||
|
"file_create_test",
|
||||||
|
"file_open_test",
|
||||||
|
"file_overwrite_test",
|
||||||
|
"file_list_test",
|
||||||
|
"file_delete_test"]
|
||||||
|
#"file_mkdir_test",
|
||||||
|
#"file_rmdir_test"]
|
||||||
|
rdwr_tnames = [
|
||||||
|
"rdwr_cc_read_page_test",
|
||||||
|
"rdwr_cc_write_page_test",
|
||||||
|
"rdwr_nc_read_page_test",
|
||||||
|
"rdwr_nc_write_page_test",
|
||||||
|
"mmap_read_test",
|
||||||
|
"mmap_write_test"]
|
||||||
|
tnames = file_tnames + rdwr_tnames
|
||||||
|
aggregate = min
|
||||||
|
|
||||||
|
tests = {}
|
||||||
|
for arg in sys.argv[1:]:
|
||||||
|
name = os.path.splitext(os.path.basename(arg))[0]
|
||||||
|
if name[-1].isdigit() and name[-2] == '-':
|
||||||
|
name = name[:-2]
|
||||||
|
with open(arg, "r") as fin:
|
||||||
|
for row in csv.reader(fin):
|
||||||
|
tests.\
|
||||||
|
setdefault(row[0], {}).\
|
||||||
|
setdefault(name, {}).\
|
||||||
|
setdefault(int(row[1]), []).\
|
||||||
|
append(float(row[2]))
|
||||||
|
|
||||||
|
if False:
|
||||||
|
for tname in (tnames if tnames else sorted(tests.keys())):
|
||||||
|
print "%s:" % tname
|
||||||
|
test = tests[tname]
|
||||||
|
for sname in (snames if snames else sorted(test.keys())):
|
||||||
|
if sname not in test:
|
||||||
|
continue
|
||||||
|
print " %s:" % sname
|
||||||
|
series = test[sname]
|
||||||
|
for param in sorted(series.keys()):
|
||||||
|
print " %s: %s -> %.2f" % (param, series[param], aggregate(series[param]))
|
||||||
|
else:
|
||||||
|
for tname in (tnames if tnames else sorted(tests.keys())):
|
||||||
|
with open(tname + ".csv", "w") as fout:
|
||||||
|
test = tests[tname]
|
||||||
|
for sname in (snames if snames else sorted(test.keys())):
|
||||||
|
if sname not in test:
|
||||||
|
continue
|
||||||
|
fout.write("//%s\r\n" % sname)
|
||||||
|
series = test[sname]
|
||||||
|
for param in sorted(series.keys()):
|
||||||
|
fout.write("%s,%.2f\r\n" % (param, aggregate(series[param])))
|
||||||
|
def master_write(fname, tnames):
|
||||||
|
with open(fname + ".csv", "w") as fout:
|
||||||
|
for sname in snames:
|
||||||
|
fout.write("//%s\r\n" % sname)
|
||||||
|
for tname in (tnames if tnames else sorted(tests.keys())):
|
||||||
|
test = tests[tname]
|
||||||
|
if sname not in test:
|
||||||
|
continue
|
||||||
|
series = test[sname]
|
||||||
|
param = max(series.keys())
|
||||||
|
fout.write("%s,%.2f\r\n" % (tname, aggregate(series[param])))
|
||||||
|
master_write("file_tests", file_tnames)
|
||||||
|
master_write("rdwr_tests", rdwr_tnames)
|
30
doc/WinFsp-Performance-Testing/rdwr_cc_read_page_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
100,0.19
|
||||||
|
200,0.42
|
||||||
|
300,0.61
|
||||||
|
400,0.78
|
||||||
|
500,0.97
|
||||||
|
//winfsp-t0
|
||||||
|
100,1.44
|
||||||
|
200,2.97
|
||||||
|
300,4.20
|
||||||
|
400,5.64
|
||||||
|
500,6.83
|
||||||
|
//winfsp-t1
|
||||||
|
100,1.47
|
||||||
|
200,3.00
|
||||||
|
300,4.45
|
||||||
|
400,5.78
|
||||||
|
500,7.33
|
||||||
|
//winfsp-tinf
|
||||||
|
100,0.28
|
||||||
|
200,0.58
|
||||||
|
300,0.87
|
||||||
|
400,1.12
|
||||||
|
500,1.48
|
||||||
|
//dokany
|
||||||
|
100,2.23
|
||||||
|
200,4.58
|
||||||
|
300,6.78
|
||||||
|
400,9.02
|
||||||
|
500,11.20
|
|
BIN
doc/WinFsp-Performance-Testing/rdwr_cc_read_page_test.png
Normal file
After Width: | Height: | Size: 55 KiB |
30
doc/WinFsp-Performance-Testing/rdwr_cc_write_page_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
100,0.25
|
||||||
|
200,0.47
|
||||||
|
300,0.69
|
||||||
|
400,0.91
|
||||||
|
500,1.19
|
||||||
|
//winfsp-t0
|
||||||
|
100,1.30
|
||||||
|
200,2.63
|
||||||
|
300,3.91
|
||||||
|
400,5.23
|
||||||
|
500,6.12
|
||||||
|
//winfsp-t1
|
||||||
|
100,1.30
|
||||||
|
200,2.47
|
||||||
|
300,3.89
|
||||||
|
400,4.92
|
||||||
|
500,6.17
|
||||||
|
//winfsp-tinf
|
||||||
|
100,0.34
|
||||||
|
200,0.67
|
||||||
|
300,1.01
|
||||||
|
400,1.38
|
||||||
|
500,1.70
|
||||||
|
//dokany
|
||||||
|
100,2.08
|
||||||
|
200,4.23
|
||||||
|
300,6.33
|
||||||
|
400,8.48
|
||||||
|
500,10.33
|
|
BIN
doc/WinFsp-Performance-Testing/rdwr_cc_write_page_test.png
Normal file
After Width: | Height: | Size: 53 KiB |
30
doc/WinFsp-Performance-Testing/rdwr_nc_read_page_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
100,9.38
|
||||||
|
200,21.39
|
||||||
|
300,19.56
|
||||||
|
400,26.11
|
||||||
|
500,33.05
|
||||||
|
//winfsp-t0
|
||||||
|
100,1.33
|
||||||
|
200,2.64
|
||||||
|
300,4.06
|
||||||
|
400,5.42
|
||||||
|
500,6.41
|
||||||
|
//winfsp-t1
|
||||||
|
100,1.38
|
||||||
|
200,2.78
|
||||||
|
300,4.23
|
||||||
|
400,5.52
|
||||||
|
500,6.94
|
||||||
|
//winfsp-tinf
|
||||||
|
100,1.36
|
||||||
|
200,2.81
|
||||||
|
300,3.95
|
||||||
|
400,5.19
|
||||||
|
500,6.58
|
||||||
|
//dokany
|
||||||
|
100,2.22
|
||||||
|
200,4.34
|
||||||
|
300,6.34
|
||||||
|
400,8.67
|
||||||
|
500,10.59
|
|
BIN
doc/WinFsp-Performance-Testing/rdwr_nc_read_page_test.png
Normal file
After Width: | Height: | Size: 50 KiB |
30
doc/WinFsp-Performance-Testing/rdwr_nc_write_page_test.csv
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//ntfs
|
||||||
|
100,7.55
|
||||||
|
200,14.36
|
||||||
|
300,21.58
|
||||||
|
400,28.52
|
||||||
|
500,35.45
|
||||||
|
//winfsp-t0
|
||||||
|
100,1.30
|
||||||
|
200,2.67
|
||||||
|
300,3.95
|
||||||
|
400,5.33
|
||||||
|
500,6.41
|
||||||
|
//winfsp-t1
|
||||||
|
100,1.30
|
||||||
|
200,2.61
|
||||||
|
300,3.94
|
||||||
|
400,5.36
|
||||||
|
500,6.51
|
||||||
|
//winfsp-tinf
|
||||||
|
100,1.31
|
||||||
|
200,2.56
|
||||||
|
300,3.86
|
||||||
|
400,5.11
|
||||||
|
500,6.42
|
||||||
|
//dokany
|
||||||
|
100,2.20
|
||||||
|
200,4.66
|
||||||
|
300,6.44
|
||||||
|
400,8.56
|
||||||
|
500,10.73
|
|
BIN
doc/WinFsp-Performance-Testing/rdwr_nc_write_page_test.png
Normal file
After Width: | Height: | Size: 48 KiB |
33
doc/WinFsp-Performance-Testing/rdwr_tests.csv
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//ntfs
|
||||||
|
rdwr_cc_read_page_test,0.97
|
||||||
|
rdwr_cc_write_page_test,1.19
|
||||||
|
rdwr_nc_read_page_test,33.05
|
||||||
|
rdwr_nc_write_page_test,35.45
|
||||||
|
mmap_read_test,1.06
|
||||||
|
mmap_write_test,0.72
|
||||||
|
//winfsp-t0
|
||||||
|
rdwr_cc_read_page_test,6.83
|
||||||
|
rdwr_cc_write_page_test,6.12
|
||||||
|
rdwr_nc_read_page_test,6.41
|
||||||
|
rdwr_nc_write_page_test,6.41
|
||||||
|
mmap_read_test,1.00
|
||||||
|
mmap_write_test,0.72
|
||||||
|
//winfsp-t1
|
||||||
|
rdwr_cc_read_page_test,7.33
|
||||||
|
rdwr_cc_write_page_test,6.17
|
||||||
|
rdwr_nc_read_page_test,6.94
|
||||||
|
rdwr_nc_write_page_test,6.51
|
||||||
|
mmap_read_test,0.98
|
||||||
|
mmap_write_test,0.73
|
||||||
|
//winfsp-tinf
|
||||||
|
rdwr_cc_read_page_test,1.48
|
||||||
|
rdwr_cc_write_page_test,1.70
|
||||||
|
rdwr_nc_read_page_test,6.58
|
||||||
|
rdwr_nc_write_page_test,6.42
|
||||||
|
mmap_read_test,0.98
|
||||||
|
mmap_write_test,0.73
|
||||||
|
//dokany
|
||||||
|
rdwr_cc_read_page_test,11.20
|
||||||
|
rdwr_cc_write_page_test,10.33
|
||||||
|
rdwr_nc_read_page_test,10.59
|
||||||
|
rdwr_nc_write_page_test,10.73
|
|
BIN
doc/WinFsp-Performance-Testing/rdwr_tests.png
Normal file
After Width: | Height: | Size: 68 KiB |
180
doc/WinFsp-as-an-IPC-Mechanism.asciidoc
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
= WinFsp as an IPC Mechanism
|
||||||
|
|
||||||
|
WinFsp enables the creation of user mode file systems for Windows. At its core WinFsp is also an Inter-Process Communication (IPC) mechanism that uses the familiar file system interface for communication. This document discusses WinFsp from that viewpoint.
|
||||||
|
|
||||||
|
== Single File API Request
|
||||||
|
|
||||||
|
When a process uses the familiar file API to access a file on Windows, this API request gets packaged into an I/O Request Packet (IRP) and gets routed to the relevant File System Driver (FSD). The usual FSD's in Windows (NTFS, FastFat, etc.) will process the IRP and return a response to the process. For the remainder of this discussion, we will call this process the Originating Process (OP).
|
||||||
|
|
||||||
|
In the WinFsp case things are more complicated. WinFsp will forward IRP's to another process, which implements a user mode file system. This process will process the IRP and return a response, which WinFsp will eventually forward to the OP. We will call the process that implements the user mode file system, the File System process (FS).
|
||||||
|
|
||||||
|
In the following we will also use the notation [U] to denote user mode processing and [K] to denote kernel mode processing. Additionally because a Context Switch always goes through kernel mode, we will simplify the diagrams and omit this detail when it is not important.
|
||||||
|
|
||||||
|
Consider then what happens when an OP issues a synchronous (non-overlapped), non-cached (non-buffered) WriteFile call.
|
||||||
|
|
||||||
|
ifdef::env-browser[]
|
||||||
|
[uml,file="WinFsp-as-an-IPC-Mechanism/synchronous.png"]
|
||||||
|
--
|
||||||
|
hide footbox
|
||||||
|
|
||||||
|
participant "OP[U]" as OPU
|
||||||
|
participant "OP[K]" as OPK
|
||||||
|
participant "FS[K]" as FSK
|
||||||
|
participant "FS[U]" as FSU
|
||||||
|
|
||||||
|
activate OPU
|
||||||
|
OPU ->OPK: WriteFile
|
||||||
|
deactivate OPU
|
||||||
|
activate OPK #Salmon
|
||||||
|
OPK-->FSK: Context Switch
|
||||||
|
deactivate OPK
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK ->FSU: TRANSACT Req
|
||||||
|
deactivate FSK
|
||||||
|
activate FSU #Salmon
|
||||||
|
FSU ->FSU: Process
|
||||||
|
activate FSU
|
||||||
|
deactivate FSU
|
||||||
|
FSU ->FSK: TRANSACT Rsp
|
||||||
|
deactivate FSU
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK-->OPU: Context Switch and Return
|
||||||
|
deactivate FSK
|
||||||
|
activate OPU
|
||||||
|
note over FSK, FSU #Salmon
|
||||||
|
Salmon color denotes WinFsp processing.
|
||||||
|
end note
|
||||||
|
--
|
||||||
|
endif::env-browser[]
|
||||||
|
ifndef::env-browser[image::WinFsp-as-an-IPC-Mechanism/synchronous.png[]]
|
||||||
|
|
||||||
|
Let us now consider what happens when an OP issues an asynchronous (overlapped), non-cached (non-buffered) WriteFile call. This scenario does not show how the OP receives the WriteFile result.
|
||||||
|
|
||||||
|
ifdef::env-browser[]
|
||||||
|
[uml,file="WinFsp-as-an-IPC-Mechanism/asynchronous.png"]
|
||||||
|
--
|
||||||
|
hide footbox
|
||||||
|
|
||||||
|
participant "OP[U]" as OPU
|
||||||
|
participant "OP[K]" as OPK
|
||||||
|
participant "FS[K]" as FSK
|
||||||
|
participant "FS[U]" as FSU
|
||||||
|
|
||||||
|
activate OPU
|
||||||
|
OPU ->OPK: WriteFile
|
||||||
|
deactivate OPU
|
||||||
|
activate OPK #Salmon
|
||||||
|
OPK ->OPU: Return
|
||||||
|
deactivate OPK
|
||||||
|
activate OPU
|
||||||
|
OPU ->OPU: Process
|
||||||
|
activate OPU
|
||||||
|
deactivate OPU
|
||||||
|
OPU-->FSK: Context Switch
|
||||||
|
deactivate OPU
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK ->FSU: TRANSACT Req
|
||||||
|
deactivate FSK
|
||||||
|
activate FSU #Salmon
|
||||||
|
FSU ->FSU: Process
|
||||||
|
activate FSU
|
||||||
|
deactivate FSU
|
||||||
|
FSU ->FSK: TRANSACT Rsp
|
||||||
|
deactivate FSU
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK-->OPU: Context Switch
|
||||||
|
deactivate FSK
|
||||||
|
activate OPU
|
||||||
|
note over FSK, FSU #Salmon
|
||||||
|
Salmon color denotes WinFsp processing.
|
||||||
|
end note
|
||||||
|
--
|
||||||
|
endif::env-browser[]
|
||||||
|
ifndef::env-browser[image::WinFsp-as-an-IPC-Mechanism/asynchronous.png[]]
|
||||||
|
|
||||||
|
It should be noted that from the WinFsp perspective both cases look similar. WinFsp processing occurs:
|
||||||
|
|
||||||
|
- At *OP[K]* time immediately after receipt of an IRP. An IRP is said to be in the _Pending_ stage at this point.
|
||||||
|
- At *FS[K]* time after a context switch, but before the TRANSACT call. An IRP is said to be in the _Prepare_ stage at this point.
|
||||||
|
- At *FS[K]* time after the TRANSACT call. An IRP is said to be in the _Complete_ stage at this point. Upon completion of this stage the IRP will be completed and relinquished to the OS.
|
||||||
|
- AT *FS[U]* time between the two TRANSACT calls.
|
||||||
|
|
||||||
|
The TRANSACT calls are DeviceIoControl requests that the FS issues to WinFsp. A single TRANSACT call can be used to communicate a file system response and retrieve the next file system request.
|
||||||
|
|
||||||
|
## Multiple File API Requests
|
||||||
|
|
||||||
|
Let us now consider what may happen with two simultaneous API Requests from two different processes. For example, two WriteFile requests for different files.
|
||||||
|
|
||||||
|
ifdef::env-browser[]
|
||||||
|
[uml,file="WinFsp-as-an-IPC-Mechanism/multiple.png"]
|
||||||
|
--
|
||||||
|
hide footbox
|
||||||
|
|
||||||
|
participant "OP<sub>1</sub>[U]" as OP1U
|
||||||
|
participant "OP<sub>1</sub>[K]" as OP1K
|
||||||
|
participant "OP<sub>2</sub>[U]" as OP2U
|
||||||
|
participant "OP<sub>2</sub>[K]" as OP2K
|
||||||
|
participant "FS[K]" as FSK
|
||||||
|
participant "FS[U]" as FSU
|
||||||
|
|
||||||
|
activate OP1U
|
||||||
|
OP1U ->OP1K: WriteFile
|
||||||
|
deactivate OP1U
|
||||||
|
activate OP1K #Salmon
|
||||||
|
OP1K-->OP2U: Context Switch
|
||||||
|
deactivate OP1K
|
||||||
|
activate OP2U
|
||||||
|
OP2U ->OP2K: WriteFile
|
||||||
|
deactivate OP2U
|
||||||
|
activate OP2K #Salmon
|
||||||
|
OP2K-->FSK: Context Switch
|
||||||
|
deactivate OP2K
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK ->FSU: TRANSACT\nReq<sub>1</sub>
|
||||||
|
deactivate FSK
|
||||||
|
activate FSU #Salmon
|
||||||
|
FSU ->FSU: Process
|
||||||
|
activate FSU
|
||||||
|
deactivate FSU
|
||||||
|
FSU ->FSK: TRANSACT\nRsp<sub>1</sub>
|
||||||
|
deactivate FSU
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK ->FSU: TRANSACT\nReq<sub>2</sub>
|
||||||
|
deactivate FSK
|
||||||
|
activate FSU #Salmon
|
||||||
|
FSU ->FSU: Process
|
||||||
|
activate FSU
|
||||||
|
deactivate FSU
|
||||||
|
FSU ->FSK: TRANSACT\nRsp<sub>2</sub>
|
||||||
|
deactivate FSU
|
||||||
|
activate FSK #Salmon
|
||||||
|
FSK-->OP1U: Context Switch and Return
|
||||||
|
deactivate FSK
|
||||||
|
activate OP1U
|
||||||
|
OP1U ->OP1U: Process
|
||||||
|
activate OP1U
|
||||||
|
deactivate OP1U
|
||||||
|
OP1U-->OP2U: Context Switch and Return
|
||||||
|
deactivate OP1U
|
||||||
|
activate OP2U
|
||||||
|
note over FSK, FSU #Salmon
|
||||||
|
Salmon color denotes WinFsp processing.
|
||||||
|
end note
|
||||||
|
--
|
||||||
|
endif::env-browser[]
|
||||||
|
ifndef::env-browser[image::WinFsp-as-an-IPC-Mechanism/multiple.png[]]
|
||||||
|
|
||||||
|
Notice that it is possible for the FS to process multiple file system requests without context switching.
|
||||||
|
|
||||||
|
## I/O Queues and Performance
|
||||||
|
|
||||||
|
I/O Queues are the fundamental IPC mechanism in WinFsp. The purpose of the I/O Queue is to forward an IRP from the OP to the FS and when FS processing is complete to forward the response back to the OP. I/O Queues are discussed in detail in the WinFsp design document.
|
||||||
|
|
||||||
|
WinFsp owes its excellent performance primarily to the design of the I/O Queues. I/O Queues borrow heavily from the design of I/O completion ports and schedule threads in a similar manner:
|
||||||
|
|
||||||
|
- They have a Last-In First-Out (LIFO) wait discipline.
|
||||||
|
- They limit the number of threads that can be satisfied concurrently to the number of processors.
|
||||||
|
|
||||||
|
The first property ensures that when an FS thread finishes processing a file system request, it will very likely pick up the next one from the I/O Queue without blocking and context switching to another FS thread. Minimizing context switches results in better performance.
|
||||||
|
|
||||||
|
The second property ensures that even if there are multiple file system requests waiting to be serviced in the I/O Queue, it will not schedule more thread than the number of processors. Having more than one threads scheduled on each processor is counter-productive.
|
BIN
doc/WinFsp-as-an-IPC-Mechanism/asynchronous.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
doc/WinFsp-as-an-IPC-Mechanism/multiple.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
doc/WinFsp-as-an-IPC-Mechanism/synchronous.png
Normal file
After Width: | Height: | Size: 37 KiB |
120
doc/Winfsp-Testing.asciidoc
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
= WinFsp Testing Strategy
|
||||||
|
|
||||||
|
WinFsp maintains quality through rigorous testing under a variety of scenarios. This document discusses its testing strategy.
|
||||||
|
|
||||||
|
== Importance of Testing
|
||||||
|
|
||||||
|
A file system is a fundamental block of an OS. It provides the primary means for storing persistent information and capturing system state. A file system must not only be reliable and stable when the computer is running, it must also store data in a manner as to eliminate data loss or data corruption. Furthermore a file system must provide semantics that closely adhere to existing standards and conventions for its OS to avoid confusion or even accidental corruption from programs that use it. For these reasons rigorous and extensive testing of a file system is of paramount importance.
|
||||||
|
|
||||||
|
WinFsp enables the creation of user mode file systems that fully integrate with the Windows OS. WinFsp is a system component and the user mode file systems that integrate with it also become system components. The need for thorough testing of WinFsp becomes apparent.
|
||||||
|
|
||||||
|
== Test Suites
|
||||||
|
|
||||||
|
WinFsp currently has the following test suites:
|
||||||
|
|
||||||
|
- *Winfsp-tests*: This test suite provides comprehensive testing of WinFsp's capabilities under various scenarios. This includes general Win32 (and NTDLL) file API testing, but also includes WinFsp specific tests, such as incorrectly functioning user mode file systems. The non-WinFsp specific tests are verified against NTFS.
|
||||||
|
+
|
||||||
|
This test suite is developed together with WinFsp. It is written in C/C++ and provides a form of gray box testing.
|
||||||
|
|
||||||
|
- *Winfstest*: This is a file system test suite that was originally developed for the secfs.test collection of file system test programs by the WinFsp author. However none of its tests are WinFsp specific and all its tests pass on NTFS. Winfstest is used for testing by other Windows file systems.
|
||||||
|
+
|
||||||
|
This test suite is written in Python and C. It provides a form of black box testing.
|
||||||
|
|
||||||
|
- *FSX*: This is Apple's FSX ported to Windows by the WinFsp author. This FSX port is not WinFsp specific and is used for testing by other Windows file systems.
|
||||||
|
|
||||||
|
- *Fscrash*: This is a tool that simulates a faulty or crashing user mode file system. It is used to test the fault tolerance of WinFsp.
|
||||||
|
+
|
||||||
|
This test is WinFsp specific and is developed together with WinFsp. It is written in C/C++.
|
||||||
|
|
||||||
|
- *Fsbench*: This is a tool that can be used to test the performance of Windows file systems under different scenarios. It is not WinFsp specific.
|
||||||
|
+
|
||||||
|
This tool is currently developed together with WinFsp. It is written in C.
|
||||||
|
|
||||||
|
These test suites and a few smaller tests are run through Continuous Integration testing every time a push is made into the WinFsp repository.
|
||||||
|
|
||||||
|
=== Test File System
|
||||||
|
|
||||||
|
WinFsp includes a test user mode file system called *MEMFS*. This is a simple in memory file system written in C/C++. MEMFS attempts to achieve parity with NTFS (barring a few WinFsp limitations -- notably no support for hard links). MEMFS also performs some user mode file system checks during testing, for example, it checks that the buffer received during WRITE calls is read-only.
|
||||||
|
|
||||||
|
== Tested Scenarios
|
||||||
|
|
||||||
|
The combined test suites exercise the majority of Win32 file API's and a few NTDLL ones. The tested API's include:
|
||||||
|
|
||||||
|
- API's to create, open, close files/streams.
|
||||||
|
- API's to perform file/stream I/O in cached, non-cached, write-through, overlapped, etc. modes.
|
||||||
|
- API's to perform memory mapped I/O.
|
||||||
|
- API's to get or set file/stream metadata and security.
|
||||||
|
- API's to rename or delete files/streams.
|
||||||
|
- API's to enumerate directories and streams.
|
||||||
|
- API's that act on reparse points and symbolic links.
|
||||||
|
|
||||||
|
These tests are run under a variety of conditions:
|
||||||
|
|
||||||
|
- When the file system is a "disk" file system (+FILE_DEVICE_DISK_FILE_SYSTEM+).
|
||||||
|
- When the file system is a "network" file system (+FILE_DEVICE_NETWORK_FILE_SYSTEM+).
|
||||||
|
- When the file system is a "disk" file system exposed as a network share (+NetShareAdd+).
|
||||||
|
- When the file system is mapped as a drive (+DefineDosDeviceW+).
|
||||||
|
- When the file system is mounted on a directory (using junctions).
|
||||||
|
- When the file system is case-sensitive or case-insensitive.
|
||||||
|
- When the process making the API calls lacks the traverse privilege (+SE_CHANGE_NOTIFY_NAME+).
|
||||||
|
- When the process making the API calls has the backup or restore privilege (+SE_BACKUP_NAME+, +SE_RESTORE_NAME+).
|
||||||
|
|
||||||
|
Not all tests apply to all conditions. The test suites will disable/skip tests that do not apply to a particular scenario.
|
||||||
|
|
||||||
|
In addition the tests are run both on Debug and Release builds. Debug builds includes numerous ASSERT() statements that test various conditions within the WinFsp code.
|
||||||
|
|
||||||
|
=== Coverage
|
||||||
|
|
||||||
|
Windows File System Drivers (FSD) run in a variety of conditions that are not always easy to replicate during testing. For example, an FSD may not be able to get locks to perform an operation, in which case it may retry the operation later. Or it may be unable to allocate memory for a MustSucceed task, in which case it may wait a bit and retry.
|
||||||
|
|
||||||
|
Such situations may not arise during normal testing. For this reason, WinFsp uses the +DEBUGTEST()+ macro, which takes a single +Percent+ argument. In Release builds this macro always evaluates to +TRUE+. In Debug builds this macro may evaluate to +TRUE+ or +FALSE+ depending on the value of the +Percent+ argument, which specifies the percentage of times that +DEBUGTEST()+ should evaluate to +TRUE+. For example, a +DEBUGTEST(90)+ means that 90% of the time the macro should evaluate to +TRUE+ and 10% of the time it should evaluate to +FALSE+.
|
||||||
|
|
||||||
|
The WinFsp FSD uses the +DEBUGTEST()+ macro in various places where an operation may have to be retried. For example, here is how it handles deferred writes:
|
||||||
|
|
||||||
|
----
|
||||||
|
/* should we defer the write? */
|
||||||
|
Success = DEBUGTEST(90) && CcCanIWrite(FileObject, WriteLength, CanWait, Retrying);
|
||||||
|
if (!Success)
|
||||||
|
{
|
||||||
|
Result = FspWqCreateIrpWorkItem(Irp, FspFsvolWriteCached, 0);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
IoMarkIrpPending(Irp);
|
||||||
|
CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, Retrying);
|
||||||
|
|
||||||
|
return STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we are unable to defer we will go ahead and (try to) service the IRP now! */
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
In Release builds the +DEBUGTEST(90)+ macro will evaluate to +TRUE+ and the Cache Manager will be asked directly via +CcCanIWrite+ whether a WRITE should be deferred. In Debug builds the +DEBUGTEST(90)+ macro will evaluate to +FALSE+ sometimes (10% of the time) and the WRITE will be deferred, thus allowing us to test the retry code path.
|
||||||
|
|
||||||
|
== Fault Tolerance Testing
|
||||||
|
|
||||||
|
User mode file systems are normal user mode processes and as such they may fail in a variety of conditions. For example, a user mode file system may trigger an access violation while servicing a file operation. As another example, the developer of a user mode file system may terminate the file system process forcefully from within a debugger.
|
||||||
|
|
||||||
|
In such cases WinFsp is able to recover gracefully and clean up its resources and data structures. This is a fundamental capability of WinFsp and one that must be tested thoroughly.
|
||||||
|
|
||||||
|
For this purpose WinFsp is tested using the fscrash tool. Fscrash includes a special version of MEMFS, where file operations can potentially cause a crash. Fscrash also includes a simple test that is run in a loop until the included file system crashes. When the OS kills the process, the WinFsp FSD steps in and cleans up all resources used by the faulty file system. The intent of the test is to verify that WinFsp handles the crash properly, without leaving any leaks and without crashing the OS.
|
||||||
|
|
||||||
|
== Verifier
|
||||||
|
|
||||||
|
All development and testing of WinFsp is done under the Driver Verifier with standard settings enabled. The Driver Verifier is an invaluable tool for Windows Driver development. It has caught numerous issues within WinFsp, in most cases immediately after the faulty code was written and run for the first time.
|
||||||
|
|
||||||
|
=== Leak Testing
|
||||||
|
|
||||||
|
One of the most important aspects of the Driver Verifier is that it can track the pool (memory) usage of WinFsp. The WinFsp master test driver uses this to confirm that the WinFsp FSD does not leak memory. At the end of the tests the master test driver unmounts any remaining WinFsp file systems and then verifies that there are zero pool allocations for the WinFsp FSD.
|
||||||
|
|
||||||
|
== Performance Testing
|
||||||
|
|
||||||
|
The goal of performance testing is to evaluate and understand how software behaves under certain workloads. Performance testing can help identify cases where the software requires too much time or resources. It is also useful to establish a performance baseline to ensure that software performance does not degrade over time.
|
||||||
|
|
||||||
|
WinFsp uses a tool called fsbench for this purpose. Fsbench is able to test specific scenarios, for example: "how long does it take to delete 1000 files?" Fsbench has been very useful for WinFsp and has helped improve its performance: in one situation it helped identify quadratic behavior with the MEMFS ReadDirectory operation, in another situation it helped fine tune the performance of the WinFsp I/O Queue.
|
||||||
|
|
||||||
|
== Code Analysis
|
||||||
|
|
||||||
|
WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon.
|
||||||
|
|
||||||
|
WinFsp compiles cleanly without any warnings.
|
1785
doc/winfsp.h.markdown
Normal file
2
ext/test
@ -54,10 +54,19 @@ static char assert_buf[256];
|
|||||||
static void test_printf(const char *fmt, ...);
|
static void test_printf(const char *fmt, ...);
|
||||||
static double run_test(struct test *test)
|
static double run_test(struct test *test)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
#pragma comment(lib, "winmm.lib")
|
||||||
|
unsigned long __stdcall timeGetTime(void);
|
||||||
|
unsigned long t0 = timeGetTime();
|
||||||
|
test->fn();
|
||||||
|
unsigned long t1 = timeGetTime();
|
||||||
|
return (t1 - t0) / 1000.0;
|
||||||
|
#else
|
||||||
time_t t0 = time(0);
|
time_t t0 = time(0);
|
||||||
test->fn();
|
test->fn();
|
||||||
time_t t1 = time(0);
|
time_t t1 = time(0);
|
||||||
return difftime(t1, t0);
|
return difftime(t1, t0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
static void do_test_default(struct test *test, int testno)
|
static void do_test_default(struct test *test, int testno)
|
||||||
{
|
{
|
||||||
@ -73,7 +82,7 @@ static void do_test_default(struct test *test, int testno)
|
|||||||
dispname[sizeof dispname - 1] = '\0';
|
dispname[sizeof dispname - 1] = '\0';
|
||||||
test_printf("%s ", dispname);
|
test_printf("%s ", dispname);
|
||||||
double d = run_test(test);
|
double d = run_test(test);
|
||||||
test_printf("OK %.0fs\n", d);
|
test_printf("OK %.2fs\n", d);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
test_printf("--- COMPLETE ---\n");
|
test_printf("--- COMPLETE ---\n");
|
||||||
@ -131,6 +140,11 @@ void tlib_run_tests(int argc, char *argv[])
|
|||||||
no_abort = 1;
|
no_abort = 1;
|
||||||
else if (0 == strcmp("--repeat-forever", a))
|
else if (0 == strcmp("--repeat-forever", a))
|
||||||
repeat = ULONG_MAX;
|
repeat = ULONG_MAX;
|
||||||
|
else if ('-' == a[1])
|
||||||
|
{
|
||||||
|
fprintf(stderr, "tlib_run_tests: unknown option %s\n", a);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
match_any = 0;
|
match_any = 0;
|
||||||
|
@ -28,7 +28,7 @@ extern "C" {
|
|||||||
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
|
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
|
||||||
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(e,m)
|
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(e,m)
|
||||||
#else
|
#else
|
||||||
#define FSP_FSCTL_STATIC_ASSERT(e,m)
|
#define FSP_FSCTL_STATIC_ASSERT(e,m) static_assert(1,"")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
|
#define FSP_FSCTL_DRIVER_NAME "WinFsp"
|
||||||
@ -78,8 +78,6 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
|
|||||||
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
|
#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 */
|
||||||
@ -151,8 +149,9 @@ typedef struct
|
|||||||
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
|
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */
|
||||||
UINT32 KmReservedFlags:5;
|
UINT32 KmReservedFlags:5;
|
||||||
/* user-mode flags */
|
/* user-mode flags */
|
||||||
UINT32 UmFileNodeIsUserContext2:1; /* user mode: FileNode parameter is UserContext2 */
|
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
|
||||||
UINT32 UmReservedFlags:15;
|
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
|
||||||
|
UINT32 UmReservedFlags:14;
|
||||||
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)];
|
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||||
} FSP_FSCTL_VOLUME_PARAMS;
|
} FSP_FSCTL_VOLUME_PARAMS;
|
||||||
@ -174,13 +173,20 @@ typedef struct
|
|||||||
UINT64 LastWriteTime;
|
UINT64 LastWriteTime;
|
||||||
UINT64 ChangeTime;
|
UINT64 ChangeTime;
|
||||||
UINT64 IndexNumber;
|
UINT64 IndexNumber;
|
||||||
|
UINT32 HardLinks; /* unimplemented: set to 0 */
|
||||||
} FSP_FSCTL_FILE_INFO;
|
} FSP_FSCTL_FILE_INFO;
|
||||||
typedef struct
|
typedef struct
|
||||||
|
{
|
||||||
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
|
PWSTR NormalizedName;
|
||||||
|
UINT16 NormalizedNameSize;
|
||||||
|
} FSP_FSCTL_OPEN_FILE_INFO;
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT16 Size;
|
UINT16 Size;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
UINT64 NextOffset;
|
UINT64 NextOffset;
|
||||||
UINT8 Padding[24];
|
UINT8 Padding[16];
|
||||||
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
|
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
|
||||||
WCHAR FileNameBuf[];
|
WCHAR FileNameBuf[];
|
||||||
} FSP_FSCTL_DIR_INFO;
|
} FSP_FSCTL_DIR_INFO;
|
||||||
@ -192,6 +198,11 @@ typedef struct
|
|||||||
WCHAR StreamNameBuf[];
|
WCHAR StreamNameBuf[];
|
||||||
} FSP_FSCTL_STREAM_INFO;
|
} FSP_FSCTL_STREAM_INFO;
|
||||||
typedef struct
|
typedef struct
|
||||||
|
{
|
||||||
|
UINT64 UserContext;
|
||||||
|
UINT64 UserContext2;
|
||||||
|
} FSP_FSCTL_TRANSACT_FULL_CONTEXT;
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT16 Offset;
|
UINT16 Offset;
|
||||||
UINT16 Size;
|
UINT16 Size;
|
||||||
@ -212,13 +223,16 @@ typedef struct
|
|||||||
UINT64 AllocationSize; /* initial allocation size */
|
UINT64 AllocationSize; /* initial allocation size */
|
||||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
UINT64 AccessToken; /* request access token (HANDLE) */
|
||||||
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||||
|
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||||
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
|
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
|
||||||
FSP_FSCTL_TRANSACT_BUF Ea; /* reserved; not currently implemented */
|
FSP_FSCTL_TRANSACT_BUF Ea; /* reserved; not currently implemented */
|
||||||
UINT32 UserMode:1; /* request originated in user mode */
|
UINT32 UserMode:1; /* request originated in user mode */
|
||||||
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
|
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
|
||||||
|
UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */
|
||||||
|
UINT32 HasRestorePrivilege:1; /* requestor has TOKEN_HAS_RESTORE_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;
|
UINT32 ReservedFlags:26;
|
||||||
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
|
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
|
||||||
} Create;
|
} Create;
|
||||||
struct
|
struct
|
||||||
@ -226,6 +240,7 @@ typedef struct
|
|||||||
UINT64 UserContext;
|
UINT64 UserContext;
|
||||||
UINT64 UserContext2;
|
UINT64 UserContext2;
|
||||||
UINT32 FileAttributes; /* file attributes for overwritten/superseded files */
|
UINT32 FileAttributes; /* file attributes for overwritten/superseded files */
|
||||||
|
UINT64 AllocationSize; /* allocation size for overwritten/superseded files */
|
||||||
UINT32 Supersede:1; /* 0: FILE_OVERWRITE operation, 1: FILE_SUPERSEDE operation */
|
UINT32 Supersede:1; /* 0: FILE_OVERWRITE operation, 1: FILE_SUPERSEDE operation */
|
||||||
} Overwrite;
|
} Overwrite;
|
||||||
struct
|
struct
|
||||||
@ -320,6 +335,7 @@ typedef struct
|
|||||||
UINT64 Offset;
|
UINT64 Offset;
|
||||||
UINT32 Length;
|
UINT32 Length;
|
||||||
FSP_FSCTL_TRANSACT_BUF Pattern;
|
FSP_FSCTL_TRANSACT_BUF Pattern;
|
||||||
|
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
|
||||||
} QueryDirectory;
|
} QueryDirectory;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -339,7 +355,6 @@ typedef struct
|
|||||||
UINT64 UserContext;
|
UINT64 UserContext;
|
||||||
UINT64 UserContext2;
|
UINT64 UserContext2;
|
||||||
UINT32 SecurityInformation;
|
UINT32 SecurityInformation;
|
||||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
|
||||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||||
} SetSecurity;
|
} SetSecurity;
|
||||||
struct
|
struct
|
||||||
@ -348,7 +363,8 @@ typedef struct
|
|||||||
UINT64 UserContext2;
|
UINT64 UserContext2;
|
||||||
} QueryStreamInformation;
|
} QueryStreamInformation;
|
||||||
} Req;
|
} Req;
|
||||||
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */
|
FSP_FSCTL_TRANSACT_BUF FileName;
|
||||||
|
/* Create,Cleanup,SetInformation{Disposition,Rename},FileSystemControl{ReparsePoint} */
|
||||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
||||||
} FSP_FSCTL_TRANSACT_REQ;
|
} FSP_FSCTL_TRANSACT_REQ;
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -373,6 +389,8 @@ typedef struct
|
|||||||
UINT64 UserContext2; /* user context associated with file descriptor (handle) */
|
UINT64 UserContext2; /* user context associated with file descriptor (handle) */
|
||||||
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
|
FSP_FSCTL_TRANSACT_BUF FileName;
|
||||||
|
UINT32 DisableCache:1;
|
||||||
} Opened;
|
} Opened;
|
||||||
/* IoStatus.Status == STATUS_REPARSE */
|
/* IoStatus.Status == STATUS_REPARSE */
|
||||||
struct
|
struct
|
||||||
@ -424,6 +442,9 @@ typedef struct
|
|||||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
||||||
} FSP_FSCTL_TRANSACT_RSP;
|
} FSP_FSCTL_TRANSACT_RSP;
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX > FSP_FSCTL_TRANSACT_PATH_SIZEMAX,
|
||||||
|
"FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX must be greater than FSP_FSCTL_TRANSACT_PATH_SIZEMAX "
|
||||||
|
"to detect when a normalized name has been set during a Create/Open request.");
|
||||||
static inline BOOLEAN FspFsctlTransactCanProduceRequest(
|
static inline BOOLEAN FspFsctlTransactCanProduceRequest(
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, PVOID RequestBufEnd)
|
FSP_FSCTL_TRANSACT_REQ *Request, PVOID RequestBufEnd)
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,35 @@ typedef enum
|
|||||||
* File system interface.
|
* File system interface.
|
||||||
*
|
*
|
||||||
* The operations in this interface must be implemented by the user mode
|
* The operations in this interface must be implemented by the user mode
|
||||||
* file system.
|
* file system. Not all operations need be implemented. For example,
|
||||||
|
* a user mode file system that does not wish to support reparse points,
|
||||||
|
* need not implement the reparse point operations.
|
||||||
|
*
|
||||||
|
* Most of the operations accept a FileContext parameter. This parameter
|
||||||
|
* has different meanings depending on the value of the FSP_FSCTL_VOLUME_PARAMS
|
||||||
|
* flags UmFileContextIsUserContext2 and UmFileContextIsFullContext.
|
||||||
|
*
|
||||||
|
* There are three cases to consider:
|
||||||
|
* <ul>
|
||||||
|
* <li>When both of these flags are unset (default), the FileContext parameter
|
||||||
|
* represents the file node. The file node is a void pointer (or an integer
|
||||||
|
* that can fit in a pointer) that is used to uniquely identify an open file.
|
||||||
|
* Opening the same file name should always yield the same file node value
|
||||||
|
* for as long as the file with that name remains open anywhere in the system.
|
||||||
|
* </li>
|
||||||
|
* <li>When the UmFileContextIsUserContext2 is set, the FileContext parameter
|
||||||
|
* represents the file descriptor. The file descriptor is a void pointer (or
|
||||||
|
* an integer that can fit in a pointer) that is used to identify an open
|
||||||
|
* instance of a file. Opening the same file name may yield a different file
|
||||||
|
* descriptor.
|
||||||
|
* </li>
|
||||||
|
* <li>When the UmFileContextIsFullContext is set, the FileContext parameter
|
||||||
|
* is a pointer to a FSP_FSCTL_TRANSACT_FULL_CONTEXT. This allows a user mode
|
||||||
|
* file system to access the low-level UserContext and UserContext2 values.
|
||||||
|
* The UserContext is used to store the file node and the UserContext2 is
|
||||||
|
* used to store the file descriptor for an open file.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||||
{
|
{
|
||||||
@ -136,8 +164,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
|
||||||
* The request posted by the kernel mode FSD.
|
|
||||||
* @param VolumeInfo [out]
|
* @param VolumeInfo [out]
|
||||||
* 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.
|
||||||
@ -145,15 +171,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or 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_VOLUME_INFO *VolumeInfo);
|
FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||||
/**
|
/**
|
||||||
* Set volume label.
|
* Set volume label.
|
||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
|
||||||
* The request posted by the kernel mode FSD.
|
|
||||||
* @param VolumeLabel
|
* @param VolumeLabel
|
||||||
* The new label for the volume.
|
* The new label for the volume.
|
||||||
* @param VolumeInfo [out]
|
* @param VolumeInfo [out]
|
||||||
@ -163,7 +186,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PWSTR VolumeLabel,
|
PWSTR VolumeLabel,
|
||||||
FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||||
/**
|
/**
|
||||||
@ -202,13 +224,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
|
||||||
* The request posted by the kernel mode FSD.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The name of the file or directory to be created.
|
* The name of the file or directory to be created.
|
||||||
* @param CaseSensitive
|
|
||||||
* Whether to treat the FileName as case-sensitive or case-insensitive. Case-sensitive
|
|
||||||
* file systems always treat FileName as case-sensitive regardless of this parameter.
|
|
||||||
* @param CreateOptions
|
* @param CreateOptions
|
||||||
* Create options for this request. This parameter has the same meaning as the
|
* Create options for this request. This parameter has the same meaning as the
|
||||||
* CreateOptions parameter of the NtCreateFile API. User mode file systems should typically
|
* CreateOptions parameter of the NtCreateFile API. User mode file systems should typically
|
||||||
@ -216,20 +233,22 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* directory rather than a file. Some file systems may also want to pay attention to the
|
* directory rather than a file. Some file systems may also want to pay attention to the
|
||||||
* FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH flags, although these are
|
* FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH flags, although these are
|
||||||
* typically handled by the FSD component.
|
* typically handled by the FSD component.
|
||||||
|
* @param GrantedAccess
|
||||||
|
* Determines the specific access rights that have been granted for this request. Upon
|
||||||
|
* receiving this call all access checks have been performed and the user mode file system
|
||||||
|
* need not perform any additional checks. However this parameter may be useful to a user
|
||||||
|
* mode file system; for example the WinFsp-FUSE layer uses this parameter to determine
|
||||||
|
* which flags to use in its POSIX open() call.
|
||||||
* @param FileAttributes
|
* @param FileAttributes
|
||||||
* File attributes to apply to the newly created file or directory.
|
* File attributes to apply to the newly created file or directory.
|
||||||
* @param SecurityDescriptor
|
* @param SecurityDescriptor
|
||||||
* Security descriptor to apply to the newly created file or directory. This security
|
* Security descriptor to apply to the newly created file or directory. This security
|
||||||
* descriptor will always be in self-relative format. Its length can be retrieved using the
|
* descriptor will always be in self-relative format. Its length can be retrieved using the
|
||||||
* Windows GetSecurityDescriptorLength API.
|
* Windows GetSecurityDescriptorLength API. Will be NULL for named streams.
|
||||||
* @param AllocationSize
|
* @param AllocationSize
|
||||||
* Allocation size for the newly created file.
|
* Allocation size for the newly created file.
|
||||||
* @param PFileNode [out]
|
* @param PFileContext [out]
|
||||||
* Pointer that will receive the file node on successful return from this call. The file
|
* Pointer that will receive the file context on successful return from this call.
|
||||||
* node is a void pointer (or an integer that can fit in a pointer) that is used to
|
|
||||||
* uniquely identify an open file. Opening the same file name should always return the same
|
|
||||||
* file node value for as long as the file with that name remains open anywhere in the
|
|
||||||
* system. The file system can place any value it needs here.
|
|
||||||
* @param FileInfo [out]
|
* @param FileInfo [out]
|
||||||
* 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.
|
||||||
@ -237,34 +256,30 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||||
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
|
|
||||||
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
||||||
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
* Open a file or directory.
|
* Open a file or directory.
|
||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param Request
|
|
||||||
* The request posted by the kernel mode FSD.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The name of the file or directory to be opened.
|
* The name of the file or directory to be opened.
|
||||||
* @param CaseSensitive
|
|
||||||
* Whether to treat the FileName as case-sensitive or case-insensitive. Case-sensitive
|
|
||||||
* file systems always treat FileName as case-sensitive regardless of this parameter.
|
|
||||||
* @param CreateOptions
|
* @param CreateOptions
|
||||||
* Create options for this request. This parameter has the same meaning as the
|
* Create options for this request. This parameter has the same meaning as the
|
||||||
* CreateOptions parameter of the NtCreateFile API. User mode file systems typically
|
* CreateOptions parameter of the NtCreateFile API. User mode file systems typically
|
||||||
* do not need to do anything special with respect to this parameter. Some file systems may
|
* do not need to do anything special with respect to this parameter. Some file systems may
|
||||||
* also want to pay attention to the FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH
|
* also want to pay attention to the FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH
|
||||||
* flags, although these are typically handled by the FSD component.
|
* flags, although these are typically handled by the FSD component.
|
||||||
* @param PFileNode [out]
|
* @param GrantedAccess
|
||||||
* Pointer that will receive the file node on successful return from this call. The file
|
* Determines the specific access rights that have been granted for this request. Upon
|
||||||
* node is a void pointer (or an integer that can fit in a pointer) that is used to
|
* receiving this call all access checks have been performed and the user mode file system
|
||||||
* uniquely identify an open file. Opening the same file name should always return the same
|
* need not perform any additional checks. However this parameter may be useful to a user
|
||||||
* file node value for as long as the file with that name remains open anywhere in the
|
* mode file system; for example the WinFsp-FUSE layer uses this parameter to determine
|
||||||
* system. The file system can place any value it needs here.
|
* which flags to use in its POSIX open() call.
|
||||||
|
* @param PFileContext [out]
|
||||||
|
* Pointer that will receive the file context on successful return from this call.
|
||||||
* @param FileInfo [out]
|
* @param FileInfo [out]
|
||||||
* 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.
|
||||||
@ -272,23 +287,22 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||||
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
|
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
|
||||||
/**
|
/**
|
||||||
* Overwrite a file.
|
* Overwrite a file.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file to overwrite.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file to overwrite.
|
|
||||||
* @param FileAttributes
|
* @param FileAttributes
|
||||||
* File attributes to apply to the overwritten file.
|
* File attributes to apply to the overwritten file.
|
||||||
* @param ReplaceFileAttributes
|
* @param ReplaceFileAttributes
|
||||||
* When TRUE the existing file attributes should be replaced with the new ones.
|
* When TRUE the existing file attributes should be replaced with the new ones.
|
||||||
* When FALSE the existing file attributes should be merged (or'ed) with the new ones.
|
* When FALSE the existing file attributes should be merged (or'ed) with the new ones.
|
||||||
|
* @param AllocationSize
|
||||||
|
* Allocation size for the overwritten file.
|
||||||
* @param FileInfo [out]
|
* @param FileInfo [out]
|
||||||
* 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.
|
||||||
@ -296,8 +310,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
|
||||||
PVOID FileNode, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
* Cleanup a file.
|
* Cleanup a file.
|
||||||
@ -324,10 +337,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to cleanup.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to cleanup.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The name of the file or directory to cleanup. Sent only when a Delete is requested.
|
* The name of the file or directory to cleanup. Sent only when a Delete is requested.
|
||||||
* @param Delete
|
* @param Delete
|
||||||
@ -339,30 +350,24 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* CanDelete
|
* CanDelete
|
||||||
*/
|
*/
|
||||||
VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem,
|
VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, PWSTR FileName, BOOLEAN Delete);
|
||||||
PVOID FileNode, PWSTR FileName, BOOLEAN Delete);
|
|
||||||
/**
|
/**
|
||||||
* Close a file.
|
* Close a file.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to be closed.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to be closed.
|
|
||||||
*/
|
*/
|
||||||
VOID (*Close)(FSP_FILE_SYSTEM *FileSystem,
|
VOID (*Close)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext);
|
||||||
PVOID FileNode);
|
|
||||||
/**
|
/**
|
||||||
* Read a file.
|
* Read a file.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file to be read.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file to be read.
|
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
* Pointer to a buffer that will receive the results of the read operation.
|
* Pointer to a buffer that will receive the results of the read operation.
|
||||||
* @param Offset
|
* @param Offset
|
||||||
@ -376,18 +381,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
/**
|
/**
|
||||||
* Write a file.
|
* Write a file.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file to be written.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file to be written.
|
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
* Pointer to a buffer that contains the data to write.
|
* Pointer to a buffer that contains the data to write.
|
||||||
* @param Offset
|
* @param Offset
|
||||||
@ -409,8 +411,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
|
||||||
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
|
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
|
||||||
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo);
|
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
@ -420,25 +421,20 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file to be flushed. When NULL the whole volume is being flushed.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file to be flushed. When NULL the whole volume is being flushed.
|
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext);
|
||||||
PVOID FileNode);
|
|
||||||
/**
|
/**
|
||||||
* Get file or directory information.
|
* Get file or directory information.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to get information for.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to get information for.
|
|
||||||
* @param FileInfo [out]
|
* @param FileInfo [out]
|
||||||
* 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.
|
||||||
@ -446,18 +442,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
* Set file or directory basic information.
|
* Set file or directory basic information.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to set information for.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to set information for.
|
|
||||||
* @param FileAttributes
|
* @param FileAttributes
|
||||||
* File attributes to apply to the file or directory. If the value INVALID_FILE_ATTRIBUTES
|
* File attributes to apply to the file or directory. If the value INVALID_FILE_ATTRIBUTES
|
||||||
* is sent, the file attributes should not be changed.
|
* is sent, the file attributes should not be changed.
|
||||||
@ -477,8 +470,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, UINT32 FileAttributes,
|
||||||
PVOID FileNode, UINT32 FileAttributes,
|
|
||||||
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
@ -503,10 +495,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file to set the file/allocation size for.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file to set the file/allocation size for.
|
|
||||||
* @param NewSize
|
* @param NewSize
|
||||||
* New file/allocation size to apply to the file.
|
* New file/allocation size to apply to the file.
|
||||||
* @param SetAllocationSize
|
* @param SetAllocationSize
|
||||||
@ -518,8 +508,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo);
|
FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
/**
|
/**
|
||||||
* Determine whether a file or directory can be deleted.
|
* Determine whether a file or directory can be deleted.
|
||||||
@ -536,10 +525,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to test for deletion.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to test for deletion.
|
|
||||||
* @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
|
||||||
@ -548,8 +535,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Cleanup
|
* Cleanup
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*CanDelete)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*CanDelete)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, PWSTR FileName);
|
||||||
PVOID FileNode, PWSTR FileName);
|
|
||||||
/**
|
/**
|
||||||
* Renames a file or directory.
|
* Renames a file or directory.
|
||||||
*
|
*
|
||||||
@ -564,10 +550,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to be renamed.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to be renamed.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The current name of the file or directory to rename.
|
* The current name of the file or directory to rename.
|
||||||
* @param NewFileName
|
* @param NewFileName
|
||||||
@ -578,16 +562,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
|
||||||
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists);
|
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists);
|
||||||
/**
|
/**
|
||||||
* Get file or directory security descriptor.
|
* Get file or directory security descriptor.
|
||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param FileNode
|
* @param FileContext
|
||||||
* The file node of the file or directory to get the security descriptor for.
|
* The file context of the file or directory to get the security descriptor for.
|
||||||
* @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.
|
||||||
@ -599,44 +582,54 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize);
|
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize);
|
||||||
/**
|
/**
|
||||||
* Set file or directory security descriptor.
|
* Set file or directory security descriptor.
|
||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system on which this request is posted.
|
* The file system on which this request is posted.
|
||||||
* @param FileNode
|
* @param FileContext
|
||||||
* The file node of the file or directory to set the security descriptor for.
|
* The file context of the file or directory to set the security descriptor for.
|
||||||
* @param SecurityInformation
|
* @param SecurityInformation
|
||||||
* Indicates what part of the file or directory security descriptor to change.
|
* Describes what parts of the file or directory security descriptor should
|
||||||
* @param SecurityDescriptor
|
* be modified.
|
||||||
* Security descriptor to apply to the file or directory. This security descriptor will
|
* @param ModificationDescriptor
|
||||||
* always be in self-relative format.
|
* Describes the modifications to apply to the file or directory security descriptor.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* FspSetSecurityDescriptor
|
||||||
|
* FspDeleteSecurityDescriptor
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor);
|
||||||
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
|
|
||||||
/**
|
/**
|
||||||
* Read a directory.
|
* Read a directory.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the directory to be read.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the directory to be read.
|
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
* Pointer to a buffer that will receive the results of the read operation.
|
* Pointer to a buffer that will receive the results of the read operation.
|
||||||
* @param Offset
|
* @param Offset
|
||||||
* Offset within the directory to read from. The kernel does not interpret this value
|
* Offset within the directory to read from. The kernel does not interpret this value
|
||||||
* which is used solely by the file system to locate directory entries. However the
|
* which is used solely by the file system to locate directory entries. However the
|
||||||
* special value 0 indicates that the read should start from the first entries. The first
|
* special value 0 indicates that the read should start from the first entries. The first
|
||||||
* two entries returned by ReadDirectory should always be the "." and ".." entries.
|
* two entries returned by ReadDirectory should always be the "." and ".." entries,
|
||||||
|
* except for the root directory which does not have these entries.
|
||||||
|
*
|
||||||
|
* This parameter is used by the WinFsp FSD to break directory listings into chunks.
|
||||||
|
* In this case all 64-bits of the Offset are valid. In some cases the Windows kernel
|
||||||
|
* (NTOS) may also use this parameter. In this case only the lower 32-bits of this
|
||||||
|
* parameter will be valid. This is an unfortunate limitation of Windows (for more
|
||||||
|
* information see the documentation for IRP_MJ_DIRECTORY_CONTROL and the flag
|
||||||
|
* SL_INDEX_SPECIFIED).
|
||||||
|
*
|
||||||
|
* In practice this means that you should only rely on the lower 32-bits of this value
|
||||||
|
* to be valid.
|
||||||
* @param Length
|
* @param Length
|
||||||
* Length of data to read.
|
* Length of data to read.
|
||||||
* @param Pattern
|
* @param Pattern
|
||||||
@ -652,8 +645,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* FspFileSystemAddDirInfo
|
* FspFileSystemAddDirInfo
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
|
||||||
PWSTR Pattern,
|
PWSTR Pattern,
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
/**
|
/**
|
||||||
@ -705,10 +697,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the reparse point.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the reparse point.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The file name of the reparse point.
|
* The file name of the reparse point.
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
@ -723,18 +713,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* SetReparsePoint
|
* SetReparsePoint
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
|
||||||
PWSTR FileName, PVOID Buffer, PSIZE_T PSize);
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize);
|
||||||
/**
|
/**
|
||||||
* Set reparse point.
|
* Set reparse point.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the reparse point.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the reparse point.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The file name of the reparse point.
|
* The file name of the reparse point.
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
@ -748,18 +735,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* GetReparsePoint
|
* GetReparsePoint
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
|
||||||
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
/**
|
/**
|
||||||
* Delete reparse point.
|
* Delete reparse point.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the reparse point.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the reparse point.
|
|
||||||
* @param FileName
|
* @param FileName
|
||||||
* The file name of the reparse point.
|
* The file name of the reparse point.
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
@ -770,18 +754,15 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* STATUS_SUCCESS or error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*DeleteReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*DeleteReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext,
|
||||||
PVOID FileNode,
|
|
||||||
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
/**
|
/**
|
||||||
* Get named streams information.
|
* Get named streams information.
|
||||||
*
|
*
|
||||||
* @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 FileContext
|
||||||
* The request posted by the kernel mode FSD.
|
* The file context of the file or directory to get stream information for.
|
||||||
* @param FileNode
|
|
||||||
* The file node of the file or directory to get stream information for.
|
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
* Pointer to a buffer that will receive the stream information.
|
* Pointer to a buffer that will receive the stream information.
|
||||||
* @param Length
|
* @param Length
|
||||||
@ -794,8 +775,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* FspFileSystemAddStreamInfo
|
* FspFileSystemAddStreamInfo
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileContext, PVOID Buffer, ULONG Length,
|
||||||
PVOID FileNode, PVOID Buffer, ULONG Length,
|
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -823,8 +803,13 @@ 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;
|
BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext;
|
||||||
} FSP_FILE_SYSTEM;
|
} FSP_FILE_SYSTEM;
|
||||||
|
typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||||
|
} FSP_FILE_SYSTEM_OPERATION_CONTEXT;
|
||||||
/**
|
/**
|
||||||
* Create a file system object.
|
* Create a file system object.
|
||||||
*
|
*
|
||||||
@ -855,9 +840,13 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
/**
|
/**
|
||||||
* Set the mount point for a file system.
|
* Set the mount point for a file system.
|
||||||
*
|
*
|
||||||
* This function currently only supports drive letters (X:) as mount points. Refer to the
|
* This function supports drive letters (X:) or directories as mount points:
|
||||||
* documentation of the DefineDosDevice Windows API to better understand how drive letters are
|
* <ul>
|
||||||
* created.
|
* <li>Drive letters: Refer to the documentation of the DefineDosDevice Windows API
|
||||||
|
* to better understand how they are created.</li>
|
||||||
|
* <li>Directories: They can be used as mount points for disk based file systems. They cannot
|
||||||
|
* be used for network file systems. This is a limitation that Windows imposes on junctions.</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param FileSystem
|
* @param FileSystem
|
||||||
* The file system object.
|
* The file system object.
|
||||||
@ -920,6 +909,17 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
*/
|
*/
|
||||||
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
|
/**
|
||||||
|
* Get the current operation context.
|
||||||
|
*
|
||||||
|
* This function may be used only when servicing one of the FSP_FILE_SYSTEM_INTERFACE operations.
|
||||||
|
* The current operation context is stored in thread local storage. It allows access to the
|
||||||
|
* Request and Response associated with this operation.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The current operation context.
|
||||||
|
*/
|
||||||
|
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID);
|
||||||
static inline
|
static inline
|
||||||
PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
PWSTR FspFileSystemMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||||
{
|
{
|
||||||
@ -996,6 +996,14 @@ VOID FspFileSystemSetDebugLog(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
FileSystem->DebugLog = DebugLog;
|
FileSystem->DebugLog = DebugLog;
|
||||||
}
|
}
|
||||||
|
static inline
|
||||||
|
BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
|
||||||
|
return
|
||||||
|
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive ||
|
||||||
|
FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Operations
|
* Operations
|
||||||
@ -1040,6 +1048,54 @@ FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSyst
|
|||||||
/*
|
/*
|
||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Get open information buffer.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the Create and Open operations. It cannot be used with
|
||||||
|
* any other operations.
|
||||||
|
*
|
||||||
|
* The FileInfo parameter to Create and Open is typed as pointer to FSP_FSCTL_FILE_INFO. The
|
||||||
|
* true type of this parameter is pointer to FSP_FSCTL_OPEN_FILE_INFO. This simple function
|
||||||
|
* converts from one type to the other.
|
||||||
|
*
|
||||||
|
* The FSP_FSCTL_OPEN_FILE_INFO type contains a FSP_FSCTL_FILE_INFO as well as the fields
|
||||||
|
* NormalizedName and NormalizedNameSize. These fields can be used for file name normalization.
|
||||||
|
* File name normalization is used to ensure that the FSD and the OS know the correct case
|
||||||
|
* of a newly opened file name.
|
||||||
|
*
|
||||||
|
* For case-sensitive file systems this functionality should be ignored. The FSD will always
|
||||||
|
* assume that the normalized file name is the same as the file name used to open the file.
|
||||||
|
*
|
||||||
|
* For case-insensitive file systems this functionality may be ignored. In this case the FSD
|
||||||
|
* will assume that the normalized file name is the upper case version of the file name used
|
||||||
|
* to open the file. The file system will work correctly and the only way an application will
|
||||||
|
* be able to tell that the file system does not preserve case in normalized file names is by
|
||||||
|
* issuing a GetFinalPathNameByHandle API call (or NtQueryInformationFile with
|
||||||
|
* FileNameInformation/FileNormalizedNameInformation).
|
||||||
|
*
|
||||||
|
* For case-insensitive file systems this functionality may also be used. In this case the
|
||||||
|
* user mode file system may use the NormalizedName and NormalizedNameSize parameters to
|
||||||
|
* report to the FSD the normalized file name. It should be noted that the normalized file
|
||||||
|
* name may only differ in case from the file name used to open the file. The NormalizedName
|
||||||
|
* field will point to a buffer that can receive the normalized file name. The
|
||||||
|
* NormalizedNameSize field will contain the size of the normalized file name buffer. On
|
||||||
|
* completion of the Create or Open operation it should contain the actual size of the
|
||||||
|
* normalized file name copied into the normalized file name buffer. The normalized file name
|
||||||
|
* should not contain a terminating zero.
|
||||||
|
*
|
||||||
|
* @param FileInfo
|
||||||
|
* The FileInfo parameter as passed to Create or Open operation.
|
||||||
|
* @return
|
||||||
|
* A pointer to the open information buffer for this Create or Open operation.
|
||||||
|
* @see
|
||||||
|
* Create
|
||||||
|
* Open
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
FSP_FSCTL_OPEN_FILE_INFO *FspFileSystemGetOpenFileInfo(FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
|
{
|
||||||
|
return (FSP_FSCTL_OPEN_FILE_INFO *)FileInfo;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Add directory information to a buffer.
|
* Add directory information to a buffer.
|
||||||
*
|
*
|
||||||
@ -1214,10 +1270,49 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PSECURITY_DESCRIPTOR ParentDescriptor,
|
PSECURITY_DESCRIPTOR ParentDescriptor,
|
||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
||||||
FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
/**
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
* Modify security descriptor.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the SetSecurity operation.
|
||||||
|
*
|
||||||
|
* @param InputDescriptor
|
||||||
|
* The input security descriptor to be modified.
|
||||||
|
* @param SecurityInformation
|
||||||
|
* Describes what parts of the InputDescriptor should be modified. This should contain
|
||||||
|
* the same value passed to the SetSecurity SecurityInformation parameter.
|
||||||
|
* @param ModificationDescriptor
|
||||||
|
* Describes the modifications to apply to the InputDescriptor. This should contain
|
||||||
|
* the same value passed to the SetSecurity ModificationDescriptor parameter.
|
||||||
|
* @param PSecurityDescriptor [out]
|
||||||
|
* Pointer to a memory location that will receive the resulting security descriptor.
|
||||||
|
* This security descriptor can be later freed using FspDeleteSecurityDescriptor.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* SetSecurity
|
||||||
|
* FspDeleteSecurityDescriptor
|
||||||
|
*/
|
||||||
|
FSP_API NTSTATUS FspSetSecurityDescriptor(
|
||||||
PSECURITY_DESCRIPTOR InputDescriptor,
|
PSECURITY_DESCRIPTOR InputDescriptor,
|
||||||
|
SECURITY_INFORMATION SecurityInformation,
|
||||||
|
PSECURITY_DESCRIPTOR ModificationDescriptor,
|
||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
|
||||||
|
/**
|
||||||
|
* Delete security descriptor.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the SetSecurity operation.
|
||||||
|
*
|
||||||
|
* @param SecurityDescriptor
|
||||||
|
* The security descriptor to be deleted.
|
||||||
|
* @param CreateFunc
|
||||||
|
* Function used to create the security descriptor. This parameter should be
|
||||||
|
* set to FspSetSecurityDescriptor for the public API.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* SetSecurity
|
||||||
|
* FspSetSecurityDescriptor
|
||||||
|
*/
|
||||||
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
|
FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||||
NTSTATUS (*CreateFunc)());
|
NTSTATUS (*CreateFunc)());
|
||||||
static inline
|
static inline
|
||||||
|
@ -299,12 +299,16 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||||
&Sddl, 0);
|
&Sddl, 0);
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c] \"%S\", "
|
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
|
||||||
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
||||||
"AllocationSize=%lx:%lx, AccessToken=%p, DesiredAccess=%lx, ShareAccess=%lx\n",
|
"AllocationSize=%lx:%lx, "
|
||||||
|
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, "
|
||||||
|
"ShareAccess=%lx\n",
|
||||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||||
Request->Req.Create.UserMode ? 'U' : 'K',
|
Request->Req.Create.UserMode ? 'U' : 'K',
|
||||||
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
|
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
|
||||||
|
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
|
||||||
|
Request->Req.Create.HasRestorePrivilege ? 'R' : '-',
|
||||||
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
|
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
|
||||||
Request->Req.Create.CaseSensitive ? 'C' : '-',
|
Request->Req.Create.CaseSensitive ? 'C' : '-',
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
@ -317,6 +321,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
||||||
(PVOID)Request->Req.Create.AccessToken,
|
(PVOID)Request->Req.Create.AccessToken,
|
||||||
Request->Req.Create.DesiredAccess,
|
Request->Req.Create.DesiredAccess,
|
||||||
|
Request->Req.Create.GrantedAccess,
|
||||||
Request->Req.Create.ShareAccess);
|
Request->Req.Create.ShareAccess);
|
||||||
LocalFree(Sddl);
|
LocalFree(Sddl);
|
||||||
break;
|
break;
|
||||||
@ -598,7 +603,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||||
&Sddl, 0);
|
&Sddl, 0);
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
|
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
|
||||||
"SecurityInformation=%lx, AccessToken=%p, Security=%s%s%s\n",
|
"SecurityInformation=%lx, Security=%s%s%s\n",
|
||||||
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
|
||||||
Request->FileName.Size ? "\"" : "",
|
Request->FileName.Size ? "\"" : "",
|
||||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||||
@ -607,12 +612,21 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
Request->Req.SetSecurity.UserContext, Request->Req.SetSecurity.UserContext2,
|
Request->Req.SetSecurity.UserContext, Request->Req.SetSecurity.UserContext2,
|
||||||
UserContextBuf),
|
UserContextBuf),
|
||||||
Request->Req.SetSecurity.SecurityInformation,
|
Request->Req.SetSecurity.SecurityInformation,
|
||||||
(PVOID)Request->Req.SetSecurity.AccessToken,
|
|
||||||
Sddl ? "\"" : "",
|
Sddl ? "\"" : "",
|
||||||
Sddl ? Sddl : "NULL",
|
Sddl ? Sddl : "NULL",
|
||||||
Sddl ? "\"" : "");
|
Sddl ? "\"" : "");
|
||||||
LocalFree(Sddl);
|
LocalFree(Sddl);
|
||||||
break;
|
break;
|
||||||
|
case FspFsctlTransactQueryStreamInformationKind:
|
||||||
|
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %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.QueryStreamInformation.UserContext, Request->Req.QueryStreamInformation.UserContext2,
|
||||||
|
UserContextBuf));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FspDebugLogRequestVoid(Request, "INVALID");
|
FspDebugLogRequestVoid(Request, "INVALID");
|
||||||
break;
|
break;
|
||||||
@ -815,6 +829,9 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
|||||||
LocalFree(Sddl);
|
LocalFree(Sddl);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case FspFsctlTransactQueryStreamInformationKind:
|
||||||
|
FspDebugLogResponseStatus(Response, "QueryStreamInformation");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FspDebugLogResponseStatus(Response, "INVALID");
|
FspDebugLogResponseStatus(Response, "INVALID");
|
||||||
break;
|
break;
|
||||||
|
252
src/dll/fs.c
@ -25,6 +25,7 @@ enum
|
|||||||
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
|
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
|
||||||
|
|
||||||
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
|
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
|
||||||
|
static DWORD FspFileSystemTlsKey = TLS_OUT_OF_INDEXES;
|
||||||
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
||||||
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
|
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
|
||||||
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
|
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
|
||||||
@ -37,6 +38,8 @@ static BOOL WINAPI FspFileSystemInitialize(
|
|||||||
{
|
{
|
||||||
HANDLE Handle;
|
HANDLE Handle;
|
||||||
|
|
||||||
|
FspFileSystemTlsKey = TlsAlloc();
|
||||||
|
|
||||||
Handle = GetModuleHandleW(L"ntdll.dll");
|
Handle = GetModuleHandleW(L"ntdll.dll");
|
||||||
if (0 != Handle)
|
if (0 != Handle)
|
||||||
{
|
{
|
||||||
@ -55,6 +58,20 @@ static BOOL WINAPI FspFileSystemInitialize(
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID FspFileSystemFinalize(BOOLEAN Dynamic)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
|
||||||
|
* finalization tasks to a minimum.
|
||||||
|
*
|
||||||
|
* We must free our TLS key (if any). We only do so if the library
|
||||||
|
* is being explicitly unloaded (rather than the process exiting).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (Dynamic && TLS_OUT_OF_INDEXES != FspFileSystemTlsKey)
|
||||||
|
TlsFree(FspFileSystemTlsKey);
|
||||||
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||||
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
||||||
const FSP_FILE_SYSTEM_INTERFACE *Interface,
|
const FSP_FILE_SYSTEM_INTERFACE *Interface,
|
||||||
@ -65,10 +82,16 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
|||||||
|
|
||||||
*PFileSystem = 0;
|
*PFileSystem = 0;
|
||||||
|
|
||||||
|
if (VolumeParams->UmFileContextIsUserContext2 &&
|
||||||
|
VolumeParams->UmFileContextIsFullContext)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
if (0 == Interface)
|
if (0 == Interface)
|
||||||
Interface = &FspFileSystemNullInterface;
|
Interface = &FspFileSystemNullInterface;
|
||||||
|
|
||||||
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
|
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
|
||||||
|
if (TLS_OUT_OF_INDEXES == FspFileSystemTlsKey)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
FileSystem = MemAlloc(sizeof *FileSystem);
|
FileSystem = MemAlloc(sizeof *FileSystem);
|
||||||
if (0 == FileSystem)
|
if (0 == FileSystem)
|
||||||
@ -107,7 +130,8 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
|||||||
FileSystem->EnterOperation = FspFileSystemOpEnter;
|
FileSystem->EnterOperation = FspFileSystemOpEnter;
|
||||||
FileSystem->LeaveOperation = FspFileSystemOpLeave;
|
FileSystem->LeaveOperation = FspFileSystemOpLeave;
|
||||||
|
|
||||||
FileSystem->UmFileNodeIsUserContext2 = !!VolumeParams->UmFileNodeIsUserContext2;
|
FileSystem->UmFileContextIsUserContext2 = !!VolumeParams->UmFileContextIsUserContext2;
|
||||||
|
FileSystem->UmFileContextIsFullContext = !!VolumeParams->UmFileContextIsFullContext;
|
||||||
|
|
||||||
*PFileSystem = FileSystem;
|
*PFileSystem = FileSystem;
|
||||||
|
|
||||||
@ -121,6 +145,168 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
|
|||||||
MemFree(FileSystem);
|
MemFree(FileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFileSystemSetMountPoint_CreateDirectory(PWSTR MountPoint, PWSTR VolumeName)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
HANDLE DirHandle;
|
||||||
|
BOOL Success;
|
||||||
|
DWORD Backslashes, Bytes;
|
||||||
|
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
|
||||||
|
PREPARSE_DATA_BUFFER ReparseData = 0;
|
||||||
|
PWSTR P, PathBuffer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Windows does not allow mount points (junctions) to point to network file systems.
|
||||||
|
*
|
||||||
|
* Count how many backslashes our VolumeName. If it is 3 or more this is a network
|
||||||
|
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
|
||||||
|
*/
|
||||||
|
for (P = VolumeName, Backslashes = 0; *P; P++)
|
||||||
|
if (L'\\' == *P)
|
||||||
|
if (3 == ++Backslashes)
|
||||||
|
{
|
||||||
|
Result = STATUS_NETWORK_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateDirectoryW(MountPoint, 0))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirHandle = CreateFileW(MountPoint,
|
||||||
|
FILE_WRITE_ATTRIBUTES,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
0,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||||
|
0);
|
||||||
|
if (INVALID_HANDLE_VALUE == DirHandle)
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto rmdir_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
|
||||||
|
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
|
||||||
|
VolumeNameLength *= sizeof(WCHAR);
|
||||||
|
BackslashLength *= sizeof(WCHAR);
|
||||||
|
|
||||||
|
ReparseDataLength = (USHORT)(
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer)) +
|
||||||
|
2 * (VolumeNameLength + BackslashLength + sizeof(WCHAR));
|
||||||
|
ReparseData = MemAlloc(REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength);
|
||||||
|
if (0 == ReparseData)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto rmdir_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||||
|
ReparseData->ReparseDataLength = ReparseDataLength;
|
||||||
|
ReparseData->Reserved = 0;
|
||||||
|
ReparseData->MountPointReparseBuffer.SubstituteNameOffset = 0;
|
||||||
|
ReparseData->MountPointReparseBuffer.SubstituteNameLength =
|
||||||
|
VolumeNameLength + BackslashLength;
|
||||||
|
ReparseData->MountPointReparseBuffer.PrintNameOffset =
|
||||||
|
ReparseData->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
|
||||||
|
ReparseData->MountPointReparseBuffer.PrintNameLength =
|
||||||
|
VolumeNameLength + BackslashLength;
|
||||||
|
|
||||||
|
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer;
|
||||||
|
memcpy(PathBuffer, VolumeName, VolumeNameLength);
|
||||||
|
if (BackslashLength)
|
||||||
|
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
|
||||||
|
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
|
||||||
|
|
||||||
|
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer +
|
||||||
|
(ReparseData->MountPointReparseBuffer.PrintNameOffset) / sizeof(WCHAR);
|
||||||
|
memcpy(PathBuffer, VolumeName, VolumeNameLength);
|
||||||
|
if (BackslashLength)
|
||||||
|
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
|
||||||
|
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
|
||||||
|
|
||||||
|
Success = DeviceIoControl(DirHandle, FSCTL_SET_REPARSE_POINT,
|
||||||
|
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
|
||||||
|
0, 0,
|
||||||
|
&Bytes, 0);
|
||||||
|
CloseHandle(DirHandle);
|
||||||
|
if (!Success)
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto rmdir_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
MemFree(ReparseData);
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
rmdir_and_exit:
|
||||||
|
RemoveDirectoryW(MountPoint);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFileSystemSetMountPoint_MakeTemporary(PWSTR MountPoint, PHANDLE PMountHandle)
|
||||||
|
{
|
||||||
|
NTSTATUS Result = STATUS_SUCCESS;
|
||||||
|
HANDLE MountHandle = 0;
|
||||||
|
|
||||||
|
if (FspPathIsDrive(MountPoint))
|
||||||
|
{
|
||||||
|
if (0 != FspNtOpenSymbolicLinkObject)
|
||||||
|
{
|
||||||
|
WCHAR SymlinkBuf[6];
|
||||||
|
UNICODE_STRING Symlink;
|
||||||
|
OBJECT_ATTRIBUTES Obja;
|
||||||
|
|
||||||
|
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
|
||||||
|
SymlinkBuf[4] = MountPoint[0];
|
||||||
|
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
|
||||||
|
Symlink.Buffer = SymlinkBuf;
|
||||||
|
|
||||||
|
memset(&Obja, 0, sizeof Obja);
|
||||||
|
Obja.Length = sizeof Obja;
|
||||||
|
Obja.ObjectName = &Symlink;
|
||||||
|
Obja.Attributes = OBJ_CASE_INSENSITIVE;
|
||||||
|
|
||||||
|
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = FspNtMakeTemporaryObject(MountHandle);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspNtClose(MountHandle);
|
||||||
|
MountHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* open the directory for DELETE_ON_CLOSE; closing it will remove the directory */
|
||||||
|
MountHandle = CreateFileW(MountPoint,
|
||||||
|
FILE_READ_ATTRIBUTES,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
0,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE,
|
||||||
|
0);
|
||||||
|
if (INVALID_HANDLE_VALUE == MountHandle)
|
||||||
|
{
|
||||||
|
MountHandle = 0;
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*PMountHandle = MountHandle;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
|
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
|
||||||
{
|
{
|
||||||
if (0 != FileSystem->MountPoint)
|
if (0 != FileSystem->MountPoint)
|
||||||
@ -163,9 +349,7 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
|||||||
PWSTR P;
|
PWSTR P;
|
||||||
ULONG L;
|
ULONG L;
|
||||||
|
|
||||||
for (P = MountPoint; *P; P++)
|
L = (ULONG)((lstrlenW(MountPoint) + 1) * sizeof(WCHAR));
|
||||||
;
|
|
||||||
L = (ULONG)((P - MountPoint + 1) * sizeof(WCHAR));
|
|
||||||
|
|
||||||
P = MemAlloc(L);
|
P = MemAlloc(L);
|
||||||
if (0 == P)
|
if (0 == P)
|
||||||
@ -173,46 +357,23 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
|
|||||||
memcpy(P, MountPoint, L);
|
memcpy(P, MountPoint, L);
|
||||||
MountPoint = P;
|
MountPoint = P;
|
||||||
|
|
||||||
|
if (FspPathIsDrive(MountPoint))
|
||||||
|
{
|
||||||
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
|
if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName))
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
else
|
else
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
Result = FspFileSystemSetMountPoint_CreateDirectory(MountPoint, FileSystem->VolumeName);
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (NT_SUCCESS(Result) && 0 != FspNtOpenSymbolicLinkObject)
|
|
||||||
{
|
|
||||||
WCHAR SymlinkBuf[6];
|
|
||||||
UNICODE_STRING Symlink;
|
|
||||||
OBJECT_ATTRIBUTES Obja;
|
|
||||||
|
|
||||||
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
|
|
||||||
SymlinkBuf[4] = MountPoint[0];
|
|
||||||
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
|
|
||||||
Symlink.Buffer = SymlinkBuf;
|
|
||||||
|
|
||||||
memset(&Obja, 0, sizeof Obja);
|
|
||||||
Obja.Length = sizeof Obja;
|
|
||||||
Obja.ObjectName = &Symlink;
|
|
||||||
Obja.Attributes = OBJ_CASE_INSENSITIVE;
|
|
||||||
|
|
||||||
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
|
|
||||||
if (NT_SUCCESS(Result))
|
if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
Result = FspNtMakeTemporaryObject(MountHandle);
|
FspFileSystemSetMountPoint_MakeTemporary(MountPoint, &MountHandle);
|
||||||
if (!NT_SUCCESS(Result))
|
/* ignore result; this path always considered successful */
|
||||||
{
|
|
||||||
FspNtClose(MountHandle);
|
|
||||||
MountHandle = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this path always considered successful regardless if we made symlink temporary */
|
|
||||||
Result = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
|
||||||
{
|
|
||||||
FileSystem->MountPoint = MountPoint;
|
FileSystem->MountPoint = MountPoint;
|
||||||
FileSystem->MountHandle = MountHandle;
|
FileSystem->MountHandle = MountHandle;
|
||||||
}
|
}
|
||||||
@ -224,17 +385,29 @@ exit:
|
|||||||
|
|
||||||
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
|
||||||
{
|
{
|
||||||
|
BOOLEAN IsDrive;
|
||||||
|
|
||||||
if (0 == FileSystem->MountPoint)
|
if (0 == FileSystem->MountPoint)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
IsDrive = FspPathIsDrive(FileSystem->MountPoint);
|
||||||
|
if (IsDrive)
|
||||||
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||||
FileSystem->MountPoint, FileSystem->VolumeName);
|
FileSystem->MountPoint, FileSystem->VolumeName);
|
||||||
|
else
|
||||||
|
/* nothing to do! directory will be deleted when the MountHandle is closed */;
|
||||||
|
|
||||||
MemFree(FileSystem->MountPoint);
|
MemFree(FileSystem->MountPoint);
|
||||||
FileSystem->MountPoint = 0;
|
FileSystem->MountPoint = 0;
|
||||||
|
|
||||||
if (0 != FileSystem->MountHandle)
|
if (0 != FileSystem->MountHandle)
|
||||||
{
|
{
|
||||||
|
if (IsDrive)
|
||||||
FspNtClose(FileSystem->MountHandle);
|
FspNtClose(FileSystem->MountHandle);
|
||||||
|
else
|
||||||
|
/* CloseHandle really calls NtClose, but I like being defensive when programming */
|
||||||
|
CloseHandle(FileSystem->MountHandle);
|
||||||
|
|
||||||
FileSystem->MountHandle = 0;
|
FileSystem->MountHandle = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,6 +419,7 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
|||||||
SIZE_T RequestSize, ResponseSize;
|
SIZE_T RequestSize, ResponseSize;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request = 0;
|
FSP_FSCTL_TRANSACT_REQ *Request = 0;
|
||||||
FSP_FSCTL_TRANSACT_RSP *Response = 0;
|
FSP_FSCTL_TRANSACT_RSP *Response = 0;
|
||||||
|
FSP_FILE_SYSTEM_OPERATION_CONTEXT OperationContext;
|
||||||
HANDLE DispatcherThread = 0;
|
HANDLE DispatcherThread = 0;
|
||||||
|
|
||||||
Request = MemAlloc(FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN);
|
Request = MemAlloc(FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN);
|
||||||
@ -267,6 +441,10 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OperationContext.Request = Request;
|
||||||
|
OperationContext.Response = Response;
|
||||||
|
TlsSetValue(FspFileSystemTlsKey, &OperationContext);
|
||||||
|
|
||||||
memset(Response, 0, sizeof *Response);
|
memset(Response, 0, sizeof *Response);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -330,6 +508,7 @@ static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
TlsSetValue(FspFileSystemTlsKey, 0);
|
||||||
MemFree(Response);
|
MemFree(Response);
|
||||||
MemFree(Request);
|
MemFree(Request);
|
||||||
|
|
||||||
@ -407,3 +586,8 @@ FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FspFsctlStop(FileSystem->VolumeHandle);
|
FspFsctlStop(FileSystem->VolumeHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID)
|
||||||
|
{
|
||||||
|
return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey);
|
||||||
|
}
|
||||||
|
332
src/dll/fsop.c
@ -17,8 +17,28 @@
|
|||||||
|
|
||||||
#include <dll/library.h>
|
#include <dll/library.h>
|
||||||
|
|
||||||
#define USERCONTEXT(s) \
|
#define AddrOfFileContext(s) \
|
||||||
FSP_FSCTL_TRANSACT_USERCONTEXT(s, FileSystem->UmFileNodeIsUserContext2)
|
( \
|
||||||
|
(PVOID)&(((PUINT64)&(s).UserContext)[FileSystem->UmFileContextIsUserContext2])\
|
||||||
|
)
|
||||||
|
#define ValOfFileContext(s) \
|
||||||
|
( \
|
||||||
|
FileSystem->UmFileContextIsFullContext ?\
|
||||||
|
(PVOID)(&(s)) : \
|
||||||
|
(PVOID)(((PUINT64)&(s).UserContext)[FileSystem->UmFileContextIsUserContext2])\
|
||||||
|
)
|
||||||
|
#define SetFileContext(t, s) \
|
||||||
|
( \
|
||||||
|
FileSystem->UmFileContextIsFullContext ?\
|
||||||
|
(VOID)( \
|
||||||
|
(t).UserContext = (s).UserContext,\
|
||||||
|
(t).UserContext2 = (s).UserContext2\
|
||||||
|
) : \
|
||||||
|
(VOID)( \
|
||||||
|
((PUINT64)&(t).UserContext)[FileSystem->UmFileContextIsUserContext2] =\
|
||||||
|
((PUINT64)&(s).UserContext)[FileSystem->UmFileContextIsUserContext2]\
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
@ -28,6 +48,7 @@ FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
||||||
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
||||||
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
||||||
|
FspFsctlTransactOverwriteKind == Request->Kind ||
|
||||||
(FspFsctlTransactCleanupKind == Request->Kind &&
|
(FspFsctlTransactCleanupKind == Request->Kind &&
|
||||||
Request->Req.Cleanup.Delete) ||
|
Request->Req.Cleanup.Delete) ||
|
||||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||||
@ -66,6 +87,7 @@ FSP_API NTSTATUS FspFileSystemOpLeave(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
||||||
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
||||||
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
||||||
|
FspFsctlTransactOverwriteKind == Request->Kind ||
|
||||||
(FspFsctlTransactCleanupKind == Request->Kind &&
|
(FspFsctlTransactCleanupKind == Request->Kind &&
|
||||||
Request->Req.Cleanup.Delete) ||
|
Request->Req.Cleanup.Delete) ||
|
||||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||||
@ -137,7 +159,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
UINT32 GrantedAccess;
|
UINT32 ParentDesiredAccess, GrantedAccess;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CreateCheck does different checks depending on whether we are
|
* CreateCheck does different checks depending on whether we are
|
||||||
@ -161,9 +183,14 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
if (!Request->Req.Create.NamedStream)
|
if (!Request->Req.Create.NamedStream)
|
||||||
{
|
{
|
||||||
|
if (Request->Req.Create.HasRestorePrivilege)
|
||||||
|
ParentDesiredAccess = 0;
|
||||||
|
else if (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE)
|
||||||
|
ParentDesiredAccess = FILE_ADD_SUBDIRECTORY;
|
||||||
|
else
|
||||||
|
ParentDesiredAccess = FILE_ADD_FILE;
|
||||||
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
|
Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck,
|
||||||
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
|
ParentDesiredAccess,
|
||||||
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
|
|
||||||
&GrantedAccess, PSecurityDescriptor);
|
&GrantedAccess, PSecurityDescriptor);
|
||||||
if (STATUS_REPARSE == Result)
|
if (STATUS_REPARSE == Result)
|
||||||
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
|
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
|
||||||
@ -171,6 +198,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
|
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
|
||||||
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
|
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
|
||||||
|
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -190,6 +218,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
||||||
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
|
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
|
||||||
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
|
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
|
||||||
|
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +254,7 @@ NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
*PGrantedAccess = GrantedAccess;
|
*PGrantedAccess = GrantedAccess;
|
||||||
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
||||||
*PGrantedAccess &= ~DELETE | (Request->Req.Create.DesiredAccess & DELETE);
|
*PGrantedAccess &= ~DELETE | (Request->Req.Create.DesiredAccess & DELETE);
|
||||||
|
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@ -263,6 +293,7 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
||||||
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
|
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
|
||||||
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
|
(Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA));
|
||||||
|
*PGrantedAccess |= Request->Req.Create.GrantedAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@ -286,7 +317,7 @@ NTSTATUS FspFileSystemOpenTargetDirectoryCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (STATUS_REPARSE == Result)
|
if (STATUS_REPARSE == Result)
|
||||||
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
|
Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess);
|
||||||
else if (NT_SUCCESS(Result))
|
else if (NT_SUCCESS(Result))
|
||||||
*PGrantedAccess = GrantedAccess;
|
*PGrantedAccess = GrantedAccess | Request->Req.Create.GrantedAccess;
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -352,8 +383,8 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
UINT32 GrantedAccess;
|
UINT32 GrantedAccess;
|
||||||
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
|
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
|
||||||
PVOID FileNode;
|
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
|
||||||
|
|
||||||
Result = FspFileSystemCreateCheck(FileSystem, Request, Response, TRUE,
|
Result = FspFileSystemCreateCheck(FileSystem, Request, Response, TRUE,
|
||||||
&GrantedAccess, &ParentDescriptor);
|
&GrantedAccess, &ParentDescriptor);
|
||||||
@ -365,20 +396,31 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Create(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Create(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
|
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
|
||||||
&FileNode, &FileInfo);
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
|
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
|
||||||
|
{
|
||||||
|
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
|
||||||
|
Response->Rsp.Create.Opened.FileName.Offset = 0;
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
Response->IoStatus.Information = FILE_CREATED;
|
Response->IoStatus.Information = FILE_CREATED;
|
||||||
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
|
SetFileContext(Response->Rsp.Create.Opened, FullContext);
|
||||||
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
||||||
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
|
memcpy(&Response->Rsp.Create.Opened.FileInfo,
|
||||||
|
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,25 +429,36 @@ static NTSTATUS FspFileSystemOpCreate_FileOpen(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
UINT32 GrantedAccess;
|
UINT32 GrantedAccess;
|
||||||
PVOID FileNode;
|
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
|
||||||
|
|
||||||
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Open(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
&FileNode, &FileInfo);
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Open(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
|
||||||
|
{
|
||||||
|
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
|
||||||
|
Response->Rsp.Create.Opened.FileName.Offset = 0;
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
Response->IoStatus.Information = FILE_OPENED;
|
Response->IoStatus.Information = FILE_OPENED;
|
||||||
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
|
SetFileContext(Response->Rsp.Create.Opened, FullContext);
|
||||||
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
||||||
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
|
memcpy(&Response->Rsp.Create.Opened.FileInfo,
|
||||||
|
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,8 +468,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
UINT32 GrantedAccess;
|
UINT32 GrantedAccess;
|
||||||
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
|
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
|
||||||
PVOID FileNode;
|
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
|
||||||
BOOLEAN Create = FALSE;
|
BOOLEAN Create = FALSE;
|
||||||
|
|
||||||
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
@ -429,11 +482,14 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
if (!Create)
|
if (!Create)
|
||||||
{
|
{
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Open(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
&FileNode, &FileInfo);
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Open(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
||||||
@ -454,21 +510,32 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Create(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Create(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
|
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
|
||||||
&FileNode, &FileInfo);
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
|
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
|
||||||
|
{
|
||||||
|
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
|
||||||
|
Response->Rsp.Create.Opened.FileName.Offset = 0;
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OPENED;
|
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OPENED;
|
||||||
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
|
SetFileContext(Response->Rsp.Create.Opened, FullContext);
|
||||||
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
||||||
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
|
memcpy(&Response->Rsp.Create.Opened.FileInfo,
|
||||||
|
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,26 +544,37 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
UINT32 GrantedAccess;
|
UINT32 GrantedAccess;
|
||||||
PVOID FileNode;
|
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
|
||||||
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
|
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
|
||||||
|
|
||||||
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Open(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
&FileNode, &FileInfo);
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Open(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
|
||||||
|
{
|
||||||
|
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
|
||||||
|
Response->Rsp.Create.Opened.FileName.Offset = 0;
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
Response->IoStatus.Information = Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
|
Response->IoStatus.Information = Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
|
||||||
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
|
SetFileContext(Response->Rsp.Create.Opened, FullContext);
|
||||||
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
||||||
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
|
memcpy(&Response->Rsp.Create.Opened.FileInfo,
|
||||||
|
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,8 +584,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
UINT32 GrantedAccess;
|
UINT32 GrantedAccess;
|
||||||
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
|
PSECURITY_DESCRIPTOR ParentDescriptor, ObjectDescriptor;
|
||||||
PVOID FileNode;
|
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
|
||||||
BOOLEAN Create = FALSE;
|
BOOLEAN Create = FALSE;
|
||||||
|
|
||||||
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
@ -520,11 +598,14 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
|
|||||||
|
|
||||||
if (!Create)
|
if (!Create)
|
||||||
{
|
{
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Open(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
&FileNode, &FileInfo);
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Open(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
||||||
@ -545,21 +626,32 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
Result = FileSystem->Interface->Create(FileSystem, Request,
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
(PWSTR)Request->Buffer, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
|
Result = FileSystem->Interface->Create(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
|
Request->Req.Create.FileAttributes, ObjectDescriptor, Request->Req.Create.AllocationSize,
|
||||||
&FileNode, &FileInfo);
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
|
FspDeleteSecurityDescriptor(ObjectDescriptor, FspCreateSecurityDescriptor);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
|
||||||
|
{
|
||||||
|
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
|
||||||
|
Response->Rsp.Create.Opened.FileName.Offset = 0;
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OVERWRITTEN;
|
Response->IoStatus.Information = Create ? FILE_CREATED : FILE_OVERWRITTEN;
|
||||||
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
|
SetFileContext(Response->Rsp.Create.Opened, FullContext);
|
||||||
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
||||||
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
|
memcpy(&Response->Rsp.Create.Opened.FileInfo,
|
||||||
|
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,20 +662,23 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
|
|||||||
WCHAR Root[2] = L"\\";
|
WCHAR Root[2] = L"\\";
|
||||||
PWSTR Parent, Suffix;
|
PWSTR Parent, Suffix;
|
||||||
UINT32 GrantedAccess;
|
UINT32 GrantedAccess;
|
||||||
PVOID FileNode;
|
FSP_FSCTL_TRANSACT_FULL_CONTEXT FullContext;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
|
||||||
UINT32 Information;
|
UINT32 Information;
|
||||||
|
|
||||||
Result = FspFileSystemOpenTargetDirectoryCheck(FileSystem, Request, Response, &GrantedAccess);
|
Result = FspFileSystemOpenTargetDirectoryCheck(FileSystem, Request, Response, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FullContext.UserContext = 0;
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
FullContext.UserContext2 = 0;
|
||||||
|
memset(&OpenFileInfo, 0, sizeof OpenFileInfo);
|
||||||
|
OpenFileInfo.NormalizedName = (PVOID)Response->Buffer;
|
||||||
|
OpenFileInfo.NormalizedNameSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
FspPathSuffix((PWSTR)Request->Buffer, &Parent, &Suffix, Root);
|
FspPathSuffix((PWSTR)Request->Buffer, &Parent, &Suffix, Root);
|
||||||
Result = FileSystem->Interface->Open(FileSystem, Request,
|
Result = FileSystem->Interface->Open(FileSystem,
|
||||||
Parent, Request->Req.Create.CaseSensitive, Request->Req.Create.CreateOptions,
|
Parent, Request->Req.Create.CreateOptions, GrantedAccess,
|
||||||
&FileNode, &FileInfo);
|
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
|
||||||
FspPathCombine((PWSTR)Request->Buffer, Suffix);
|
FspPathCombine((PWSTR)Request->Buffer, Suffix);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
@ -595,10 +690,18 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
|
|||||||
Information = NT_SUCCESS(Result) ? FILE_EXISTS : FILE_DOES_NOT_EXIST;
|
Information = NT_SUCCESS(Result) ? FILE_EXISTS : FILE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX >= OpenFileInfo.NormalizedNameSize)
|
||||||
|
{
|
||||||
|
Response->Size = (UINT16)(sizeof *Response + OpenFileInfo.NormalizedNameSize);
|
||||||
|
Response->Rsp.Create.Opened.FileName.Offset = 0;
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size = (UINT16)OpenFileInfo.NormalizedNameSize;
|
||||||
|
}
|
||||||
|
|
||||||
Response->IoStatus.Information = Information;
|
Response->IoStatus.Information = Information;
|
||||||
USERCONTEXT(Response->Rsp.Create.Opened) = (UINT_PTR)FileNode;
|
SetFileContext(Response->Rsp.Create.Opened, FullContext);
|
||||||
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
Response->Rsp.Create.Opened.GrantedAccess = GrantedAccess;
|
||||||
memcpy(&Response->Rsp.Create.Opened.FileInfo, &FileInfo, sizeof FileInfo);
|
memcpy(&Response->Rsp.Create.Opened.FileInfo,
|
||||||
|
&OpenFileInfo.FileInfo, sizeof OpenFileInfo.FileInfo);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,16 +845,17 @@ FSP_API NTSTATUS FspFileSystemOpOverwrite(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
memset(&FileInfo, 0, sizeof FileInfo);
|
||||||
Result = FileSystem->Interface->Overwrite(FileSystem, Request,
|
Result = FileSystem->Interface->Overwrite(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.Overwrite),
|
(PVOID)ValOfFileContext(Request->Req.Overwrite),
|
||||||
Request->Req.Overwrite.FileAttributes,
|
Request->Req.Overwrite.FileAttributes,
|
||||||
Request->Req.Overwrite.Supersede,
|
Request->Req.Overwrite.Supersede,
|
||||||
|
Request->Req.Overwrite.AllocationSize,
|
||||||
&FileInfo);
|
&FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
if (0 != FileSystem->Interface->Close)
|
if (0 != FileSystem->Interface->Close)
|
||||||
FileSystem->Interface->Close(FileSystem, Request,
|
FileSystem->Interface->Close(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.Overwrite));
|
(PVOID)ValOfFileContext(Request->Req.Overwrite));
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,8 +867,8 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
{
|
{
|
||||||
if (0 != FileSystem->Interface->Cleanup)
|
if (0 != FileSystem->Interface->Cleanup)
|
||||||
FileSystem->Interface->Cleanup(FileSystem, Request,
|
FileSystem->Interface->Cleanup(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.Cleanup),
|
(PVOID)ValOfFileContext(Request->Req.Cleanup),
|
||||||
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0,
|
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0,
|
||||||
0 != Request->Req.Cleanup.Delete);
|
0 != Request->Req.Cleanup.Delete);
|
||||||
|
|
||||||
@ -775,8 +879,8 @@ FSP_API NTSTATUS FspFileSystemOpClose(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
{
|
{
|
||||||
if (0 != FileSystem->Interface->Close)
|
if (0 != FileSystem->Interface->Close)
|
||||||
FileSystem->Interface->Close(FileSystem, Request,
|
FileSystem->Interface->Close(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.Close));
|
(PVOID)ValOfFileContext(Request->Req.Close));
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -791,8 +895,8 @@ FSP_API NTSTATUS FspFileSystemOpRead(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
BytesTransferred = 0;
|
BytesTransferred = 0;
|
||||||
Result = FileSystem->Interface->Read(FileSystem, Request,
|
Result = FileSystem->Interface->Read(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.Read),
|
(PVOID)ValOfFileContext(Request->Req.Read),
|
||||||
(PVOID)Request->Req.Read.Address,
|
(PVOID)Request->Req.Read.Address,
|
||||||
Request->Req.Read.Offset,
|
Request->Req.Read.Offset,
|
||||||
Request->Req.Read.Length,
|
Request->Req.Read.Length,
|
||||||
@ -817,8 +921,8 @@ FSP_API NTSTATUS FspFileSystemOpWrite(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
BytesTransferred = 0;
|
BytesTransferred = 0;
|
||||||
Result = FileSystem->Interface->Write(FileSystem, Request,
|
Result = FileSystem->Interface->Write(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.Write),
|
(PVOID)ValOfFileContext(Request->Req.Write),
|
||||||
(PVOID)Request->Req.Write.Address,
|
(PVOID)Request->Req.Write.Address,
|
||||||
Request->Req.Write.Offset,
|
Request->Req.Write.Offset,
|
||||||
Request->Req.Write.Length,
|
Request->Req.Write.Length,
|
||||||
@ -844,8 +948,8 @@ FSP_API NTSTATUS FspFileSystemOpFlushBuffers(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 == FileSystem->Interface->Flush)
|
if (0 == FileSystem->Interface->Flush)
|
||||||
return STATUS_SUCCESS; /* liar! */
|
return STATUS_SUCCESS; /* liar! */
|
||||||
|
|
||||||
return FileSystem->Interface->Flush(FileSystem, Request,
|
return FileSystem->Interface->Flush(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.FlushBuffers));
|
(PVOID)ValOfFileContext(Request->Req.FlushBuffers));
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -858,8 +962,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryInformation(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
memset(&FileInfo, 0, sizeof FileInfo);
|
memset(&FileInfo, 0, sizeof FileInfo);
|
||||||
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
|
Result = FileSystem->Interface->GetFileInfo(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.QueryInformation), &FileInfo);
|
(PVOID)ValOfFileContext(Request->Req.QueryInformation), &FileInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
@ -879,8 +983,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
case 4/*FileBasicInformation*/:
|
case 4/*FileBasicInformation*/:
|
||||||
if (0 != FileSystem->Interface->SetBasicInfo)
|
if (0 != FileSystem->Interface->SetBasicInfo)
|
||||||
Result = FileSystem->Interface->SetBasicInfo(FileSystem, Request,
|
Result = FileSystem->Interface->SetBasicInfo(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetInformation),
|
(PVOID)ValOfFileContext(Request->Req.SetInformation),
|
||||||
Request->Req.SetInformation.Info.Basic.FileAttributes,
|
Request->Req.SetInformation.Info.Basic.FileAttributes,
|
||||||
Request->Req.SetInformation.Info.Basic.CreationTime,
|
Request->Req.SetInformation.Info.Basic.CreationTime,
|
||||||
Request->Req.SetInformation.Info.Basic.LastAccessTime,
|
Request->Req.SetInformation.Info.Basic.LastAccessTime,
|
||||||
@ -889,23 +993,23 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
break;
|
break;
|
||||||
case 19/*FileAllocationInformation*/:
|
case 19/*FileAllocationInformation*/:
|
||||||
if (0 != FileSystem->Interface->SetFileSize)
|
if (0 != FileSystem->Interface->SetFileSize)
|
||||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
Result = FileSystem->Interface->SetFileSize(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetInformation),
|
(PVOID)ValOfFileContext(Request->Req.SetInformation),
|
||||||
Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
|
Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
|
||||||
&FileInfo);
|
&FileInfo);
|
||||||
break;
|
break;
|
||||||
case 20/*FileEndOfFileInformation*/:
|
case 20/*FileEndOfFileInformation*/:
|
||||||
if (0 != FileSystem->Interface->SetFileSize)
|
if (0 != FileSystem->Interface->SetFileSize)
|
||||||
Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
|
Result = FileSystem->Interface->SetFileSize(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetInformation),
|
(PVOID)ValOfFileContext(Request->Req.SetInformation),
|
||||||
Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
|
Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
|
||||||
&FileInfo);
|
&FileInfo);
|
||||||
break;
|
break;
|
||||||
case 13/*FileDispositionInformation*/:
|
case 13/*FileDispositionInformation*/:
|
||||||
if (0 != FileSystem->Interface->GetFileInfo)
|
if (0 != FileSystem->Interface->GetFileInfo)
|
||||||
{
|
{
|
||||||
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
|
Result = FileSystem->Interface->GetFileInfo(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetInformation), &FileInfo);
|
(PVOID)ValOfFileContext(Request->Req.SetInformation), &FileInfo);
|
||||||
if (NT_SUCCESS(Result) && 0 != (FileInfo.FileAttributes & FILE_ATTRIBUTE_READONLY))
|
if (NT_SUCCESS(Result) && 0 != (FileInfo.FileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||||
{
|
{
|
||||||
Result = STATUS_CANNOT_DELETE;
|
Result = STATUS_CANNOT_DELETE;
|
||||||
@ -914,8 +1018,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
if (0 != FileSystem->Interface->CanDelete)
|
if (0 != FileSystem->Interface->CanDelete)
|
||||||
if (Request->Req.SetInformation.Info.Disposition.Delete)
|
if (Request->Req.SetInformation.Info.Disposition.Delete)
|
||||||
Result = FileSystem->Interface->CanDelete(FileSystem, Request,
|
Result = FileSystem->Interface->CanDelete(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetInformation),
|
(PVOID)ValOfFileContext(Request->Req.SetInformation),
|
||||||
(PWSTR)Request->Buffer);
|
(PWSTR)Request->Buffer);
|
||||||
else
|
else
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
@ -931,8 +1035,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Result = FileSystem->Interface->Rename(FileSystem, Request,
|
Result = FileSystem->Interface->Rename(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetInformation),
|
(PVOID)ValOfFileContext(Request->Req.SetInformation),
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||||
0 != Request->Req.SetInformation.Info.Rename.AccessToken);
|
0 != Request->Req.SetInformation.Info.Rename.AccessToken);
|
||||||
@ -957,7 +1061,7 @@ FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSyst
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
memset(&VolumeInfo, 0, sizeof VolumeInfo);
|
memset(&VolumeInfo, 0, sizeof VolumeInfo);
|
||||||
Result = FileSystem->Interface->GetVolumeInfo(FileSystem, Request, &VolumeInfo);
|
Result = FileSystem->Interface->GetVolumeInfo(FileSystem, &VolumeInfo);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
@ -977,7 +1081,7 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
|
|||||||
{
|
{
|
||||||
case 2/*FileFsLabelInformation*/:
|
case 2/*FileFsLabelInformation*/:
|
||||||
if (0 != FileSystem->Interface->SetVolumeLabel)
|
if (0 != FileSystem->Interface->SetVolumeLabel)
|
||||||
Result = FileSystem->Interface->SetVolumeLabel(FileSystem, Request,
|
Result = FileSystem->Interface->SetVolumeLabel(FileSystem,
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
&VolumeInfo);
|
&VolumeInfo);
|
||||||
break;
|
break;
|
||||||
@ -1000,8 +1104,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
BytesTransferred = 0;
|
BytesTransferred = 0;
|
||||||
Result = FileSystem->Interface->ReadDirectory(FileSystem, Request,
|
Result = FileSystem->Interface->ReadDirectory(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.QueryDirectory),
|
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
|
||||||
(PVOID)Request->Req.QueryDirectory.Address,
|
(PVOID)Request->Req.QueryDirectory.Address,
|
||||||
Request->Req.QueryDirectory.Offset,
|
Request->Req.QueryDirectory.Offset,
|
||||||
Request->Req.QueryDirectory.Length,
|
Request->Req.QueryDirectory.Length,
|
||||||
@ -1034,8 +1138,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
memset(ReparseData, 0, sizeof *ReparseData);
|
memset(ReparseData, 0, sizeof *ReparseData);
|
||||||
|
|
||||||
Size = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
Size = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
|
Result = FileSystem->Interface->GetReparsePoint(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
|
(PVOID)ValOfFileContext(Request->Req.FileSystemControl),
|
||||||
(PWSTR)Request->Buffer, ReparseData, &Size);
|
(PWSTR)Request->Buffer, ReparseData, &Size);
|
||||||
if (NT_SUCCESS(Result))
|
if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
@ -1051,8 +1155,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
ReparseData = (PREPARSE_DATA_BUFFER)
|
ReparseData = (PREPARSE_DATA_BUFFER)
|
||||||
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
||||||
|
|
||||||
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
Result = FileSystem->Interface->SetReparsePoint(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
|
(PVOID)ValOfFileContext(Request->Req.FileSystemControl),
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
ReparseData,
|
ReparseData,
|
||||||
Request->Req.FileSystemControl.Buffer.Size);
|
Request->Req.FileSystemControl.Buffer.Size);
|
||||||
@ -1064,8 +1168,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
ReparseData = (PREPARSE_DATA_BUFFER)
|
ReparseData = (PREPARSE_DATA_BUFFER)
|
||||||
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
||||||
|
|
||||||
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem, Request,
|
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.FileSystemControl),
|
(PVOID)ValOfFileContext(Request->Req.FileSystemControl),
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
ReparseData,
|
ReparseData,
|
||||||
Request->Req.FileSystemControl.Buffer.Size);
|
Request->Req.FileSystemControl.Buffer.Size);
|
||||||
@ -1086,8 +1190,8 @@ FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
SecurityDescriptorSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
SecurityDescriptorSize = FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX;
|
||||||
Result = FileSystem->Interface->GetSecurity(FileSystem, Request,
|
Result = FileSystem->Interface->GetSecurity(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.QuerySecurity),
|
(PVOID)ValOfFileContext(Request->Req.QuerySecurity),
|
||||||
Response->Buffer, &SecurityDescriptorSize);
|
Response->Buffer, &SecurityDescriptorSize);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return STATUS_BUFFER_OVERFLOW != Result ? Result : STATUS_INVALID_SECURITY_DESCR;
|
return STATUS_BUFFER_OVERFLOW != Result ? Result : STATUS_INVALID_SECURITY_DESCR;
|
||||||
@ -1104,8 +1208,8 @@ FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 == FileSystem->Interface->SetSecurity)
|
if (0 == FileSystem->Interface->SetSecurity)
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
return FileSystem->Interface->SetSecurity(FileSystem, Request,
|
return FileSystem->Interface->SetSecurity(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.SetSecurity),
|
(PVOID)ValOfFileContext(Request->Req.SetSecurity),
|
||||||
Request->Req.SetSecurity.SecurityInformation,
|
Request->Req.SetSecurity.SecurityInformation,
|
||||||
(PSECURITY_DESCRIPTOR)Request->Buffer);
|
(PSECURITY_DESCRIPTOR)Request->Buffer);
|
||||||
}
|
}
|
||||||
@ -1120,8 +1224,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSyst
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
BytesTransferred = 0;
|
BytesTransferred = 0;
|
||||||
Result = FileSystem->Interface->GetStreamInfo(FileSystem, Request,
|
Result = FileSystem->Interface->GetStreamInfo(FileSystem,
|
||||||
(PVOID)USERCONTEXT(Request->Req.QueryStreamInformation),
|
(PVOID)ValOfFileContext(Request->Req.QueryStreamInformation),
|
||||||
Response->Buffer,
|
Response->Buffer,
|
||||||
FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX,
|
FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX,
|
||||||
&BytesTransferred);
|
&BytesTransferred);
|
||||||
|
@ -524,7 +524,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
|||||||
opt_data.VolumeParams.NamedStreams = 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.PostCleanupOnDeleteOnly = TRUE;
|
||||||
opt_data.VolumeParams.UmFileNodeIsUserContext2 = TRUE;
|
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||||
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
||||||
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
||||||
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
||||||
|
FspFsctlTransactOverwriteKind == Request->Kind ||
|
||||||
(FspFsctlTransactCleanupKind == Request->Kind &&
|
(FspFsctlTransactCleanupKind == Request->Kind &&
|
||||||
Request->Req.Cleanup.Delete) ||
|
Request->Req.Cleanup.Delete) ||
|
||||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||||
@ -69,6 +70,7 @@ VOID fsp_fuse_op_leave_unlock(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
case FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE:
|
||||||
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
if ((FspFsctlTransactCreateKind == Request->Kind &&
|
||||||
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
FILE_OPEN != ((Request->Req.Create.CreateOptions >> 24) & 0xff)) ||
|
||||||
|
FspFsctlTransactOverwriteKind == Request->Kind ||
|
||||||
(FspFsctlTransactCleanupKind == Request->Kind &&
|
(FspFsctlTransactCleanupKind == Request->Kind &&
|
||||||
Request->Req.Cleanup.Delete) ||
|
Request->Req.Cleanup.Delete) ||
|
||||||
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
(FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||||
@ -143,8 +145,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
|
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
|
||||||
Token = (HANDLE)Request->Req.SetInformation.Info.Rename.AccessToken;
|
Token = (HANDLE)Request->Req.SetInformation.Info.Rename.AccessToken;
|
||||||
}
|
}
|
||||||
else if (FspFsctlTransactSetSecurityKind == Request->Kind)
|
|
||||||
Token = (HANDLE)Request->Req.SetSecurity.AccessToken;
|
|
||||||
|
|
||||||
if (0 != FileName)
|
if (0 != FileName)
|
||||||
{
|
{
|
||||||
@ -691,7 +691,6 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointByName(
|
|||||||
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
|
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -715,7 +714,6 @@ static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetVolumeLabel(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_SetVolumeLabel(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PWSTR VolumeLabel,
|
PWSTR VolumeLabel,
|
||||||
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||||
{
|
{
|
||||||
@ -758,8 +756,7 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||||
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
|
|
||||||
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
||||||
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
@ -914,8 +911,7 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||||
PWSTR FileName, BOOLEAN CaseSensitive, UINT32 CreateOptions,
|
|
||||||
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -941,7 +937,7 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&fi, 0, sizeof fi);
|
memset(&fi, 0, sizeof fi);
|
||||||
switch (Request->Req.Create.DesiredAccess & (FILE_READ_DATA | FILE_WRITE_DATA))
|
switch (GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case FILE_READ_DATA:
|
case FILE_READ_DATA:
|
||||||
@ -1017,8 +1013,7 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
PVOID FileNode, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
|
||||||
PVOID FileNode, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes,
|
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -1055,7 +1050,6 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
|
static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
|
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -1092,7 +1086,6 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
|
static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode)
|
PVOID FileNode)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -1126,7 +1119,6 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Read(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Read(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PULONG PBytesTransferred)
|
PULONG PBytesTransferred)
|
||||||
{
|
{
|
||||||
@ -1161,7 +1153,6 @@ static NTSTATUS fsp_fuse_intf_Read(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
|
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
|
||||||
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo)
|
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
@ -1224,7 +1215,6 @@ success:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode)
|
PVOID FileNode)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -1264,7 +1254,6 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
@ -1282,7 +1271,6 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, UINT32 FileAttributes,
|
PVOID FileNode, UINT32 FileAttributes,
|
||||||
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
@ -1361,7 +1349,6 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
|
||||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
{
|
{
|
||||||
@ -1445,7 +1432,6 @@ static int fsp_fuse_intf_CanDeleteAddDirInfoOld(fuse_dirh_t dh, const char *name
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, PWSTR FileName)
|
PVOID FileNode, PWSTR FileName)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
@ -1479,7 +1465,6 @@ static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists)
|
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists)
|
||||||
{
|
{
|
||||||
@ -1513,7 +1498,6 @@ static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptorBuf, SIZE_T *PSecurityDescriptorSize)
|
PSECURITY_DESCRIPTOR SecurityDescriptorBuf, SIZE_T *PSecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
@ -1531,9 +1515,8 @@ static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR Ignored)
|
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
struct fsp_fuse_file_desc *filedesc = FileNode;
|
struct fsp_fuse_file_desc *filedesc = FileNode;
|
||||||
@ -1560,7 +1543,10 @@ static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
Result = FspSetSecurityDescriptor(FileSystem, Request, SecurityDescriptor,
|
Result = FspSetSecurityDescriptor(
|
||||||
|
SecurityDescriptor,
|
||||||
|
SecurityInformation,
|
||||||
|
ModificationDescriptor,
|
||||||
&NewSecurityDescriptor);
|
&NewSecurityDescriptor);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -1663,7 +1649,6 @@ int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PWSTR Pattern,
|
PWSTR Pattern,
|
||||||
PULONG PBytesTransferred)
|
PULONG PBytesTransferred)
|
||||||
@ -1748,6 +1733,15 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (sizeof(struct fsp_fuse_dirinfo) > di->Size)
|
if (sizeof(struct fsp_fuse_dirinfo) > di->Size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1])
|
||||||
|
{
|
||||||
|
/* if this is the root directory do not add the dot entries */
|
||||||
|
|
||||||
|
if ('.' == di->PosixNameBuf[0] && ('\0' == di->PosixNameBuf[1] ||
|
||||||
|
('.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2])))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!di->FileInfoValid)
|
if (!di->FileInfoValid)
|
||||||
{
|
{
|
||||||
if (0 == PosixPath)
|
if (0 == PosixPath)
|
||||||
@ -1871,7 +1865,6 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
|
||||||
{
|
{
|
||||||
@ -1886,7 +1879,6 @@ static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
{
|
{
|
||||||
@ -1971,6 +1963,8 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) &&
|
if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) &&
|
||||||
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
|
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
|
||||||
{
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
|
||||||
|
|
||||||
/* we do not support absolute paths that point outside this file system */
|
/* we do not support absolute paths that point outside this file system */
|
||||||
if (0 == Request->Req.FileSystemControl.TargetOnFileSystem)
|
if (0 == Request->Req.FileSystemControl.TargetOnFileSystem)
|
||||||
return STATUS_ACCESS_DENIED;
|
return STATUS_ACCESS_DENIED;
|
||||||
@ -2081,7 +2075,6 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
{
|
{
|
||||||
|
@ -107,7 +107,7 @@ static void fsp_fuse_opt_match_templ(
|
|||||||
if ('%' == *p || '\0' == *p)
|
if ('%' == *p || '\0' == *p)
|
||||||
*pspec = p, *parg = q;
|
*pspec = p, *parg = q;
|
||||||
else
|
else
|
||||||
*parg = 0 == lstrcmpA(q, p) ?
|
*parg = 0 == invariant_strcmp(q, p) ?
|
||||||
fsp_fuse_opt_match_exact : fsp_fuse_opt_match_none;
|
fsp_fuse_opt_match_exact : fsp_fuse_opt_match_none;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -66,4 +66,14 @@ static inline ULONG FspPathSuffixIndex(PWSTR FileName)
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(
|
||||||
|
(L'A' <= FileName[0] && FileName[0] <= L'Z') ||
|
||||||
|
(L'a' <= FileName[0] && FileName[0] <= L'z')
|
||||||
|
) &&
|
||||||
|
L':' == FileName[1] || L'\0' == FileName[2];
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
21
src/dll/np.c
@ -100,12 +100,7 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
|
|||||||
|
|
||||||
static inline BOOLEAN FspNpCheckLocalName(PWSTR LocalName)
|
static inline BOOLEAN FspNpCheckLocalName(PWSTR LocalName)
|
||||||
{
|
{
|
||||||
return 0 != LocalName &&
|
return 0 != LocalName && FspPathIsDrive(LocalName);
|
||||||
(
|
|
||||||
(L'A' <= LocalName[0] && LocalName[0] <= L'Z') ||
|
|
||||||
(L'a' <= LocalName[0] && LocalName[0] <= L'z')
|
|
||||||
) &&
|
|
||||||
L':' == LocalName[1] || L'\0' == LocalName[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BOOLEAN FspNpCheckRemoteName(PWSTR RemoteName)
|
static inline BOOLEAN FspNpCheckRemoteName(PWSTR RemoteName)
|
||||||
@ -257,7 +252,7 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
|
|||||||
LocalNameBuf[0] = Drive;
|
LocalNameBuf[0] = Drive;
|
||||||
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
|
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
|
||||||
{
|
{
|
||||||
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
|
if (0 == invariant_wcscmp(VolumeNameBuf, VolumeName))
|
||||||
{
|
{
|
||||||
*PLogicalDrives &= ~(1 << (Drive - 'A'));
|
*PLogicalDrives &= ~(1 << (Drive - 'A'));
|
||||||
return Drive;
|
return Drive;
|
||||||
@ -437,7 +432,7 @@ DWORD APIENTRY NPGetConnection(
|
|||||||
{
|
{
|
||||||
if (L'\0' == *P)
|
if (L'\0' == *P)
|
||||||
{
|
{
|
||||||
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
|
if (0 == invariant_wcscmp(VolumeNameBuf, VolumeName))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Looks like this is a WinFsp device. Extract the VolumePrefix from the VolumeName.
|
* Looks like this is a WinFsp device. Extract the VolumePrefix from the VolumeName.
|
||||||
@ -609,7 +604,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
|
|||||||
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
|
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
|
||||||
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
|
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
|
||||||
if (WN_SUCCESS == NpResult)
|
if (WN_SUCCESS == NpResult)
|
||||||
NpResult = 0 == lstrcmpW(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
|
NpResult = 0 == invariant_wcscmp(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
|
||||||
else
|
else
|
||||||
NpResult = WN_NO_NETWORK;
|
NpResult = WN_NO_NETWORK;
|
||||||
}
|
}
|
||||||
@ -1041,9 +1036,7 @@ NTSTATUS FspNpRegister(VOID)
|
|||||||
{
|
{
|
||||||
if (L',' == *P || '\0' == *P)
|
if (L',' == *P || '\0' == *P)
|
||||||
{
|
{
|
||||||
if (CSTR_EQUAL == CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
|
if (0 == invariant_wcsncmp(Part, L"" FSP_NP_NAME, P - Part))
|
||||||
Part, (int)(P - Part),
|
|
||||||
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
|
|
||||||
{
|
{
|
||||||
FoundProvider = TRUE;
|
FoundProvider = TRUE;
|
||||||
break;
|
break;
|
||||||
@ -1104,9 +1097,7 @@ NTSTATUS FspNpUnregister(VOID)
|
|||||||
{
|
{
|
||||||
if (L',' == *P || '\0' == *P)
|
if (L',' == *P || '\0' == *P)
|
||||||
{
|
{
|
||||||
if (CSTR_EQUAL == CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
|
if (0 == invariant_wcsncmp(Part, L"" FSP_NP_NAME, P - Part))
|
||||||
Part, (int)(P - Part),
|
|
||||||
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
|
|
||||||
{
|
{
|
||||||
FoundProvider = TRUE;
|
FoundProvider = TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -116,28 +116,43 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Request->Req.Create.UserMode &&
|
if (Request->Req.Create.UserMode &&
|
||||||
AllowTraverseCheck && !Request->Req.Create.HasTraversePrivilege)
|
AllowTraverseCheck && !Request->Req.Create.HasTraversePrivilege &&
|
||||||
|
!(L'\\' == FileName[0] && L'\0' == FileName[1])/* no need to traverse check for root */)
|
||||||
{
|
{
|
||||||
Remain = (PWSTR)FileName;
|
Remain = FileName;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
FspPathPrefix(Remain, &Prefix, &Remain, TraverseCheckRoot);
|
while (L'\\' != *Remain)
|
||||||
if (L'\0' == Remain[0])
|
|
||||||
{
|
{
|
||||||
FspPathCombine(FileName, Remain);
|
if (L'\0' == *Remain || L':' == *Remain)
|
||||||
break;
|
goto traverse_check_done;
|
||||||
|
Remain++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*Remain = L'\0';
|
||||||
|
Prefix = Remain > FileName ? FileName : TraverseCheckRoot;
|
||||||
|
|
||||||
FileAttributes = 0;
|
FileAttributes = 0;
|
||||||
Result = FspGetSecurityByName(FileSystem, Prefix, &FileAttributes,
|
Result = FspGetSecurityByName(FileSystem, Prefix, &FileAttributes,
|
||||||
&SecurityDescriptor, &SecurityDescriptorSize);
|
&SecurityDescriptor, &SecurityDescriptorSize);
|
||||||
|
|
||||||
/* compute the ReparsePointIndex and place it in FileAttributes now */
|
/*
|
||||||
|
* We check to see if this is a reparse point and then compute the ReparsePointIndex
|
||||||
|
* and place it in FileAttributes. We do this check BEFORE the directory check,
|
||||||
|
* because contrary to NTFS we want to allow non-directory symlinks to directories.
|
||||||
|
*/
|
||||||
if (NT_SUCCESS(Result) && STATUS_REPARSE != Result &&
|
if (NT_SUCCESS(Result) && STATUS_REPARSE != Result &&
|
||||||
(FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
(FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||||
|
{
|
||||||
FileAttributes = FspPathSuffixIndex(Prefix);
|
FileAttributes = FspPathSuffixIndex(Prefix);
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
}
|
||||||
|
|
||||||
FspPathCombine(FileName, Remain);
|
*Remain = L'\\';
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Remain++;
|
||||||
|
} while (L'\\' == *Remain);
|
||||||
|
|
||||||
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
{
|
{
|
||||||
@ -146,27 +161,6 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
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.
|
* Check if this is a directory, otherwise the path is invalid.
|
||||||
*/
|
*/
|
||||||
@ -187,6 +181,8 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
traverse_check_done:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAttributes = 0;
|
FileAttributes = 0;
|
||||||
@ -197,7 +193,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
|
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
if (0 == DesiredAccess)
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
else if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
else
|
else
|
||||||
@ -400,16 +398,14 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspSetSecurityDescriptor(
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
|
||||||
PSECURITY_DESCRIPTOR InputDescriptor,
|
PSECURITY_DESCRIPTOR InputDescriptor,
|
||||||
|
SECURITY_INFORMATION SecurityInformation,
|
||||||
|
PSECURITY_DESCRIPTOR ModificationDescriptor,
|
||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
||||||
{
|
{
|
||||||
*PSecurityDescriptor = 0;
|
*PSecurityDescriptor = 0;
|
||||||
|
|
||||||
if (FspFsctlTransactSetSecurityKind != Request->Kind)
|
|
||||||
return STATUS_INVALID_PARAMETER;
|
|
||||||
|
|
||||||
if (0 == InputDescriptor)
|
if (0 == InputDescriptor)
|
||||||
return STATUS_NO_SECURITY_ON_OBJECT;
|
return STATUS_NO_SECURITY_ON_OBJECT;
|
||||||
|
|
||||||
@ -443,11 +439,11 @@ FSP_API NTSTATUS FspSetSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
InputDescriptor = CopiedDescriptor;
|
InputDescriptor = CopiedDescriptor;
|
||||||
|
|
||||||
if (!SetPrivateObjectSecurity(
|
if (!SetPrivateObjectSecurity(
|
||||||
Request->Req.SetSecurity.SecurityInformation,
|
SecurityInformation,
|
||||||
(PVOID)Request->Buffer,
|
ModificationDescriptor,
|
||||||
&InputDescriptor,
|
&InputDescriptor,
|
||||||
&FspFileGenericMapping,
|
&FspFileGenericMapping,
|
||||||
(HANDLE)Request->Req.SetSecurity.AccessToken))
|
0))
|
||||||
{
|
{
|
||||||
HeapFree(ProcessHeap, 0, CopiedDescriptor);
|
HeapFree(ProcessHeap, 0, CopiedDescriptor);
|
||||||
return FspNtStatusFromWin32(GetLastError());
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
@ -27,7 +27,7 @@ BEGIN
|
|||||||
VALUE "LegalCopyright", STR(MyCopyright)
|
VALUE "LegalCopyright", STR(MyCopyright)
|
||||||
VALUE "OriginalFilename", "winfsp.dll"
|
VALUE "OriginalFilename", "winfsp.dll"
|
||||||
VALUE "ProductName", STR(MyProductName)
|
VALUE "ProductName", STR(MyProductName)
|
||||||
VALUE "ProductVersion", STR(MyVersion)
|
VALUE "ProductVersion", STR(MyProductVersion)
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -27,7 +27,7 @@ BEGIN
|
|||||||
VALUE "LegalCopyright", STR(MyCopyright)
|
VALUE "LegalCopyright", STR(MyCopyright)
|
||||||
VALUE "OriginalFilename", "launchctl.exe"
|
VALUE "OriginalFilename", "launchctl.exe"
|
||||||
VALUE "ProductName", STR(MyProductName)
|
VALUE "ProductName", STR(MyProductName)
|
||||||
VALUE "ProductVersion", STR(MyVersion)
|
VALUE "ProductVersion", STR(MyProductVersion)
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -227,7 +227,7 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
if (0 == argc)
|
if (0 == argc)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
if (0 == lstrcmpW(L"start", argv[0]))
|
if (0 == invariant_wcscmp(L"start", argv[0]))
|
||||||
{
|
{
|
||||||
if (3 > argc || argc > 12)
|
if (3 > argc || argc > 12)
|
||||||
usage();
|
usage();
|
||||||
@ -236,7 +236,7 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
FALSE);
|
FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (0 == lstrcmpW(L"startWithSecret", argv[0]))
|
if (0 == invariant_wcscmp(L"startWithSecret", argv[0]))
|
||||||
{
|
{
|
||||||
if (4 > argc || argc > 13)
|
if (4 > argc || argc > 13)
|
||||||
usage();
|
usage();
|
||||||
@ -245,7 +245,7 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
TRUE);
|
TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (0 == lstrcmpW(L"stop", argv[0]))
|
if (0 == invariant_wcscmp(L"stop", argv[0]))
|
||||||
{
|
{
|
||||||
if (3 != argc)
|
if (3 != argc)
|
||||||
usage();
|
usage();
|
||||||
@ -253,7 +253,7 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
return stop(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
|
return stop(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (0 == lstrcmpW(L"info", argv[0]))
|
if (0 == invariant_wcscmp(L"info", argv[0]))
|
||||||
{
|
{
|
||||||
if (3 != argc)
|
if (3 != argc)
|
||||||
usage();
|
usage();
|
||||||
@ -261,7 +261,7 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
return getinfo(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
|
return getinfo(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (0 == lstrcmpW(L"list", argv[0]))
|
if (0 == invariant_wcscmp(L"list", argv[0]))
|
||||||
{
|
{
|
||||||
if (1 != argc)
|
if (1 != argc)
|
||||||
usage();
|
usage();
|
||||||
@ -269,7 +269,7 @@ int wmain(int argc, wchar_t **argv)
|
|||||||
return list(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
|
return list(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (0 == lstrcmpW(L"quit", argv[0]))
|
if (0 == invariant_wcscmp(L"quit", argv[0]))
|
||||||
{
|
{
|
||||||
if (1 != argc)
|
if (1 != argc)
|
||||||
usage();
|
usage();
|
||||||
|
@ -27,7 +27,7 @@ BEGIN
|
|||||||
VALUE "LegalCopyright", STR(MyCopyright)
|
VALUE "LegalCopyright", STR(MyCopyright)
|
||||||
VALUE "OriginalFilename", "launcher.exe"
|
VALUE "OriginalFilename", "launcher.exe"
|
||||||
VALUE "ProductName", STR(MyProductName)
|
VALUE "ProductName", STR(MyProductName)
|
||||||
VALUE "ProductVersion", STR(MyVersion)
|
VALUE "ProductVersion", STR(MyProductVersion)
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -157,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 == lstrcmpiW(ClassName, SvcInstance->ClassName) &&
|
if (0 == invariant_wcsicmp(ClassName, SvcInstance->ClassName) &&
|
||||||
0 == lstrcmpiW(InstanceName, SvcInstance->InstanceName))
|
0 == invariant_wcsicmp(InstanceName, SvcInstance->InstanceName))
|
||||||
return SvcInstance;
|
return SvcInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,41 @@ void *memmove(void *dst, const void *src, size_t siz)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WINFSP_SHARED_MINIMAL_STRCMP(NAME, TYPE, CONV)\
|
||||||
|
static inline\
|
||||||
|
int NAME(const TYPE *s, const TYPE *t)\
|
||||||
|
{\
|
||||||
|
int v = 0;\
|
||||||
|
while (0 == (v = CONV(*s) - CONV(*t)) && *t)\
|
||||||
|
++s, ++t;\
|
||||||
|
return v;/*(0 < v) - (0 > v);*/\
|
||||||
|
}
|
||||||
|
#define WINFSP_SHARED_MINIMAL_STRNCMP(NAME, TYPE, CONV)\
|
||||||
|
static inline\
|
||||||
|
int NAME(const TYPE *s, const TYPE *t, size_t n)\
|
||||||
|
{\
|
||||||
|
int v = 0;\
|
||||||
|
const void *e = t + n;\
|
||||||
|
while (e > (const void *)t && 0 == (v = CONV(*s) - CONV(*t)) && *t)\
|
||||||
|
++s, ++t;\
|
||||||
|
return v;/*(0 < v) - (0 > v);*/\
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
unsigned invariant_toupper(unsigned c)
|
||||||
|
{
|
||||||
|
return ('a' <= c && c <= 'z') ? c & ~0x20 : c;
|
||||||
|
}
|
||||||
|
WINFSP_SHARED_MINIMAL_STRCMP(invariant_strcmp, char, (unsigned))
|
||||||
|
WINFSP_SHARED_MINIMAL_STRCMP(invariant_stricmp, char, invariant_toupper)
|
||||||
|
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_strncmp, char, (unsigned))
|
||||||
|
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_strnicmp, char, invariant_toupper)
|
||||||
|
WINFSP_SHARED_MINIMAL_STRCMP(invariant_wcscmp, wchar_t, (unsigned))
|
||||||
|
WINFSP_SHARED_MINIMAL_STRCMP(invariant_wcsicmp, wchar_t, invariant_toupper)
|
||||||
|
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_wcsncmp, wchar_t, (unsigned))
|
||||||
|
WINFSP_SHARED_MINIMAL_STRNCMP(invariant_wcsnicmp, wchar_t, invariant_toupper)
|
||||||
|
#undef WINFSP_SHARED_MINIMAL_STRCMP
|
||||||
|
#undef WINFSP_SHARED_MINIMAL_STRNCMP
|
||||||
|
|
||||||
static inline void *MemAlloc(size_t Size)
|
static inline void *MemAlloc(size_t Size)
|
||||||
{
|
{
|
||||||
return HeapAlloc(GetProcessHeap(), 0, Size);
|
return HeapAlloc(GetProcessHeap(), 0, Size);
|
||||||
|
@ -175,6 +175,9 @@ static VOID FspFsvolCleanupRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Co
|
|||||||
FspFileNodeReleaseOwner(FileNode, Pgio, Request);
|
FspFileNodeReleaseOwner(FileNode, Pgio, Request);
|
||||||
|
|
||||||
FspFileNodeCleanupComplete(FileNode, FileObject);
|
FspFileNodeCleanupComplete(FileNode, FileObject);
|
||||||
|
if (!FileNode->IsDirectory)
|
||||||
|
FspFileNodeOplockCheck(FileNode, Irp);
|
||||||
|
SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
|
||||||
|
|
||||||
MainFileHandle = FileDesc->MainFileHandle;
|
MainFileHandle = FileDesc->MainFileHandle;
|
||||||
FileDesc->MainFileHandle = 0;
|
FileDesc->MainFileHandle = 0;
|
||||||
|
@ -74,7 +74,7 @@ static NTSTATUS FspFsvolClose(
|
|||||||
Request->Req.Close.UserContext = FileNode->UserContext;
|
Request->Req.Close.UserContext = FileNode->UserContext;
|
||||||
Request->Req.Close.UserContext2 = FileDesc->UserContext2;
|
Request->Req.Close.UserContext2 = FileDesc->UserContext2;
|
||||||
|
|
||||||
FspFileNodeClose(FileNode, FileObject);
|
FspFileNodeClose(FileNode, 0, FALSE);
|
||||||
|
|
||||||
/* 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); /* this will also close the MainFileObject if any */
|
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
|
||||||
|
468
src/sys/create.c
@ -35,6 +35,15 @@ static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc);
|
|||||||
static FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini;
|
static FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini;
|
||||||
static FSP_IOP_REQUEST_FINI FspFsvolCreateTryOpenRequestFini;
|
static FSP_IOP_REQUEST_FINI FspFsvolCreateTryOpenRequestFini;
|
||||||
static FSP_IOP_REQUEST_FINI FspFsvolCreateOverwriteRequestFini;
|
static FSP_IOP_REQUEST_FINI FspFsvolCreateOverwriteRequestFini;
|
||||||
|
static NTSTATUS FspFsvolCreateSharingViolationOplock(
|
||||||
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN CanWait);
|
||||||
|
static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
PNTSTATUS PResult);
|
||||||
|
static VOID FspFsvolCreateOpenOrOverwriteOplockPrepare(
|
||||||
|
PVOID Context, PIRP Irp);
|
||||||
|
static VOID FspFsvolCreateOpenOrOverwriteOplockComplete(
|
||||||
|
PVOID Context, PIRP Irp);
|
||||||
FSP_DRIVER_DISPATCH FspCreate;
|
FSP_DRIVER_DISPATCH FspCreate;
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
@ -49,6 +58,10 @@ FSP_DRIVER_DISPATCH FspCreate;
|
|||||||
#pragma alloc_text(PAGE, FspFsvolCreateRequestFini)
|
#pragma alloc_text(PAGE, FspFsvolCreateRequestFini)
|
||||||
#pragma alloc_text(PAGE, FspFsvolCreateTryOpenRequestFini)
|
#pragma alloc_text(PAGE, FspFsvolCreateTryOpenRequestFini)
|
||||||
#pragma alloc_text(PAGE, FspFsvolCreateOverwriteRequestFini)
|
#pragma alloc_text(PAGE, FspFsvolCreateOverwriteRequestFini)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolCreateSharingViolationOplock)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolCreateOpenOrOverwriteOplock)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolCreateOpenOrOverwriteOplockPrepare)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolCreateOpenOrOverwriteOplockComplete)
|
||||||
#pragma alloc_text(PAGE, FspCreate)
|
#pragma alloc_text(PAGE, FspCreate)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -163,23 +176,27 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
ULONG SecurityDescriptorSize = 0;
|
ULONG SecurityDescriptorSize = 0;
|
||||||
UINT64 AllocationSize = Irp->Overlay.AllocationSize.QuadPart;
|
UINT64 AllocationSize = Irp->Overlay.AllocationSize.QuadPart;
|
||||||
UINT64 AllocationUnit;
|
UINT64 AllocationUnit;
|
||||||
ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
|
ACCESS_MASK DesiredAccess = AccessState->RemainingDesiredAccess;
|
||||||
|
ACCESS_MASK GrantedAccess = AccessState->PreviouslyGrantedAccess;
|
||||||
USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess;
|
USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess;
|
||||||
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
|
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
//ULONG EaLength = IrpSp->Parameters.Create.EaLength;
|
//ULONG EaLength = IrpSp->Parameters.Create.EaLength;
|
||||||
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 =
|
BOOLEAN CaseSensitive =
|
||||||
CaseSensitiveRequested || FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
|
//BooleanFlagOn(Flags, SL_CASE_SENSITIVE) ||
|
||||||
|
!!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
|
||||||
BOOLEAN HasTraversePrivilege =
|
BOOLEAN HasTraversePrivilege =
|
||||||
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
|
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
|
||||||
|
BOOLEAN HasBackupPrivilege =
|
||||||
|
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE);
|
||||||
|
BOOLEAN HasRestorePrivilege =
|
||||||
|
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_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 };
|
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
|
||||||
ULONG StreamType = FspUnicodePathStreamTypeNone;
|
ULONG StreamType = FspFileNameStreamTypeNone;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
/* cannot open files by fileid */
|
/* cannot open files by fileid */
|
||||||
@ -276,7 +293,7 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
ASSERT(NT_SUCCESS(Result));
|
ASSERT(NT_SUCCESS(Result));
|
||||||
|
|
||||||
/* check filename validity */
|
/* check filename validity */
|
||||||
if (!FspUnicodePathIsValid(&FileNode->FileName,
|
if (!FspFileNameIsValid(&FileNode->FileName,
|
||||||
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
|
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
|
||||||
&StreamType))
|
&StreamType))
|
||||||
{
|
{
|
||||||
@ -297,7 +314,10 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
(0 == StreamPart.Length) * sizeof(WCHAR));
|
(0 == StreamPart.Length) * sizeof(WCHAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check and remove any volume prefix */
|
/*
|
||||||
|
* Check and remove any volume prefix. Only do this when RelatedFileObject is NULL,
|
||||||
|
* because the volume prefix has been removed already from the RelatedFileNode.
|
||||||
|
*/
|
||||||
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
|
if (0 == RelatedFileObject && 0 < FsvolDeviceExtension->VolumePrefix.Length)
|
||||||
{
|
{
|
||||||
if (!FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &FileNode->FileName) ||
|
if (!FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &FileNode->FileName) ||
|
||||||
@ -334,7 +354,7 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if a $DATA stream type, this cannot be a directory */
|
/* if a $DATA stream type, this cannot be a directory */
|
||||||
if (FspUnicodePathStreamTypeData == StreamType)
|
if (FspFileNameStreamTypeData == StreamType)
|
||||||
{
|
{
|
||||||
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
|
if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE))
|
||||||
{
|
{
|
||||||
@ -453,6 +473,7 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
FileDesc->FileNode = FileNode;
|
FileDesc->FileNode = FileNode;
|
||||||
FileDesc->CaseSensitive = CaseSensitive;
|
FileDesc->CaseSensitive = CaseSensitive;
|
||||||
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
|
FileDesc->HasTraversePrivilege = HasTraversePrivilege;
|
||||||
|
|
||||||
if (!MainFileOpen)
|
if (!MainFileOpen)
|
||||||
{
|
{
|
||||||
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
||||||
@ -470,13 +491,16 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
Request->Req.Create.AllocationSize = AllocationSize;
|
Request->Req.Create.AllocationSize = AllocationSize;
|
||||||
Request->Req.Create.AccessToken = 0;
|
Request->Req.Create.AccessToken = 0;
|
||||||
Request->Req.Create.DesiredAccess = DesiredAccess;
|
Request->Req.Create.DesiredAccess = DesiredAccess;
|
||||||
|
Request->Req.Create.GrantedAccess = GrantedAccess;
|
||||||
Request->Req.Create.ShareAccess = ShareAccess;
|
Request->Req.Create.ShareAccess = ShareAccess;
|
||||||
Request->Req.Create.Ea.Offset = 0;
|
Request->Req.Create.Ea.Offset = 0;
|
||||||
Request->Req.Create.Ea.Size = 0;
|
Request->Req.Create.Ea.Size = 0;
|
||||||
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.HasBackupPrivilege = HasBackupPrivilege;
|
||||||
|
Request->Req.Create.HasRestorePrivilege = HasRestorePrivilege;
|
||||||
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
|
Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY);
|
||||||
Request->Req.Create.CaseSensitive = CaseSensitiveRequested;
|
Request->Req.Create.CaseSensitive = CaseSensitive;
|
||||||
Request->Req.Create.NamedStream = MainFileName.Length;
|
Request->Req.Create.NamedStream = MainFileName.Length;
|
||||||
|
|
||||||
ASSERT(
|
ASSERT(
|
||||||
@ -488,6 +512,18 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
|
RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
|
||||||
SecurityDescriptor, SecurityDescriptorSize);
|
SecurityDescriptor, SecurityDescriptorSize);
|
||||||
|
|
||||||
|
/* fix FileNode->FileName if we are doing SL_OPEN_TARGET_DIRECTORY */
|
||||||
|
if (Request->Req.Create.OpenTargetDirectory)
|
||||||
|
{
|
||||||
|
UNICODE_STRING Suffix;
|
||||||
|
|
||||||
|
FspFileNameSuffix(&FileNode->FileName, &FileNode->FileName, &Suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zero Irp->IoStatus, because we now use it to maintain state in FspFsvolCreateComplete */
|
||||||
|
Irp->IoStatus.Status = 0;
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
|
||||||
return FSP_STATUS_IOQ_POST;
|
return FSP_STATUS_IOQ_POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,9 +588,20 @@ NTSTATUS FspFsvolCreatePrepare(
|
|||||||
FileObject = FspIopRequestContext(Request, RequestFileObject);
|
FileObject = FspIopRequestContext(Request, RequestFileObject);
|
||||||
|
|
||||||
/* lock the FileNode for overwriting */
|
/* lock the FileNode for overwriting */
|
||||||
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Full);
|
Result = STATUS_SUCCESS;
|
||||||
|
Success = DEBUGTEST(90) &&
|
||||||
|
FspFileNodeTryAcquireExclusive(FileNode, Full) &&
|
||||||
|
FspFsvolCreateOpenOrOverwriteOplock(Irp, 0, &Result);
|
||||||
if (!Success)
|
if (!Success)
|
||||||
{
|
{
|
||||||
|
if (STATUS_PENDING == Result)
|
||||||
|
return Result;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
FspIopRetryPrepareIrp(Irp, &Result);
|
FspIopRetryPrepareIrp(Irp, &Result);
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -592,11 +639,14 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
|
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
|
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
|
PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
|
||||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
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;
|
||||||
|
ULONG SharingViolationReason;
|
||||||
|
UNICODE_STRING NormalizedName;
|
||||||
PREPARSE_DATA_BUFFER ReparseData;
|
PREPARSE_DATA_BUFFER ReparseData;
|
||||||
UNICODE_STRING ReparseTargetPrefix0, ReparseTargetPrefix1, ReparseTargetPath;
|
UNICODE_STRING ReparseTargetPrefix0, ReparseTargetPrefix1, ReparseTargetPath;
|
||||||
|
|
||||||
@ -605,7 +655,8 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
/* did the user-mode file system sent us a failure code? */
|
/* did the user-mode file system sent us a failure code? */
|
||||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||||
{
|
{
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = STATUS_SHARING_VIOLATION == Response->IoStatus.Status ?
|
||||||
|
Response->IoStatus.Information : 0;
|
||||||
Result = Response->IoStatus.Status;
|
Result = Response->IoStatus.Status;
|
||||||
FSP_RETURN();
|
FSP_RETURN();
|
||||||
}
|
}
|
||||||
@ -751,15 +802,36 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
|
|
||||||
if (Request->Req.Create.OpenTargetDirectory)
|
|
||||||
{
|
|
||||||
UNICODE_STRING Suffix;
|
|
||||||
|
|
||||||
FspUnicodePathSuffix(&FileNode->FileName, &FileNode->FileName, &Suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* populate the FileNode/FileDesc fields from the Response */
|
/* populate the FileNode/FileDesc fields from the Response */
|
||||||
|
if (!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch)
|
||||||
|
{
|
||||||
|
/* is there a normalized file name as part of the response? */
|
||||||
|
if (0 == Response->Rsp.Create.Opened.FileName.Size)
|
||||||
|
{
|
||||||
|
/* if not, the default is to upper case the name */
|
||||||
|
|
||||||
|
FspFileNameUpcase(&FileNode->FileName, &FileNode->FileName, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* if yes, verify it and then set it */
|
||||||
|
|
||||||
|
if (Response->Buffer + Response->Rsp.Create.Opened.FileName.Size >
|
||||||
|
(PUINT8)Response + Response->Size)
|
||||||
|
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
|
||||||
|
|
||||||
|
NormalizedName.Length = NormalizedName.MaximumLength =
|
||||||
|
Response->Rsp.Create.Opened.FileName.Size;
|
||||||
|
NormalizedName.Buffer = (PVOID)Response->Buffer;
|
||||||
|
|
||||||
|
/* normalized file name can only differ in case from requested one */
|
||||||
|
if (0 != FspFileNameCompare(&FileNode->FileName, &NormalizedName, TRUE, 0))
|
||||||
|
FSP_RETURN(Result = STATUS_OBJECT_NAME_INVALID);
|
||||||
|
|
||||||
|
ASSERT(FileNode->FileName.Length == NormalizedName.Length);
|
||||||
|
RtlCopyMemory(FileNode->FileName.Buffer, NormalizedName.Buffer, NormalizedName.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
|
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
|
||||||
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
|
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
|
||||||
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
|
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
|
||||||
@ -770,11 +842,41 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
|
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
|
||||||
|
|
||||||
/* open the FileNode */
|
/* open the FileNode */
|
||||||
OpenedFileNode = FspFileNodeOpen(FileNode, FileObject,
|
Result = FspFileNodeOpen(FileNode, FileObject,
|
||||||
Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess,
|
Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess,
|
||||||
&Result);
|
&OpenedFileNode, &SharingViolationReason);
|
||||||
if (0 == OpenedFileNode)
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
|
if (STATUS_SHARING_VIOLATION == Result)
|
||||||
|
{
|
||||||
|
ASSERT(0 != OpenedFileNode);
|
||||||
|
|
||||||
|
if (STATUS_SHARING_VIOLATION != Irp->IoStatus.Status)
|
||||||
|
{
|
||||||
|
ASSERT(0 == Irp->IoStatus.Information ||
|
||||||
|
FILE_OPBATCH_BREAK_UNDERWAY == Irp->IoStatus.Information);
|
||||||
|
|
||||||
|
FspIopSetIrpResponse(Irp, Response);
|
||||||
|
FspIopRequestContext(Request, FspIopRequestExtraContext) = OpenedFileNode;
|
||||||
|
|
||||||
|
/* HACK: We have run out of Contexts. Store the sharing violation reason in the IRP. */
|
||||||
|
Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
|
||||||
|
Irp->IoStatus.Information = SharingViolationReason;
|
||||||
|
|
||||||
|
Result = FspFsvolCreateSharingViolationOplock(
|
||||||
|
FsvolDeviceObject, Irp, IrpSp, FALSE);
|
||||||
|
if (STATUS_PENDING == Result)
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FspFileNodeClose(OpenedFileNode, 0, TRUE);
|
||||||
|
FspFileNodeDereference(OpenedFileNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ASSERT(0 == OpenedFileNode);
|
||||||
|
|
||||||
/* unable to open the FileNode; post a Close request */
|
/* unable to open the FileNode; post a Close request */
|
||||||
FspFsvolCreatePostClose(FileDesc);
|
FspFsvolCreatePostClose(FileDesc);
|
||||||
|
|
||||||
@ -787,6 +889,10 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
FileDesc->FileNode = FileNode = OpenedFileNode;
|
FileDesc->FileNode = FileNode = OpenedFileNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set up the AccessState */
|
||||||
|
AccessState->RemainingDesiredAccess = 0;
|
||||||
|
AccessState->PreviouslyGrantedAccess = Response->Rsp.Create.Opened.GrantedAccess;
|
||||||
|
|
||||||
/* set up the FileObject */
|
/* set up the FileObject */
|
||||||
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
|
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
|
||||||
#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb")
|
#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb")
|
||||||
@ -796,7 +902,8 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
FileObject->FsContext = FileNode;
|
FileObject->FsContext = FileNode;
|
||||||
FileObject->FsContext2 = FileDesc;
|
FileObject->FsContext2 = FileDesc;
|
||||||
if (FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
|
if (FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout &&
|
||||||
!FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING))
|
!FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING) &&
|
||||||
|
!Response->Rsp.Create.Opened.DisableCache)
|
||||||
/* enable caching! */
|
/* enable caching! */
|
||||||
SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
|
SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
|
||||||
|
|
||||||
@ -826,6 +933,7 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
USHORT FileAttributes = IrpSp->Parameters.Create.FileAttributes;
|
USHORT FileAttributes = IrpSp->Parameters.Create.FileAttributes;
|
||||||
|
UINT64 AllocationSize = Request->Req.Create.AllocationSize;
|
||||||
|
|
||||||
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
|
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
|
||||||
if (FileNode->IsDirectory)
|
if (FileNode->IsDirectory)
|
||||||
@ -850,6 +958,7 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
Request->Req.Overwrite.UserContext = FileNode->UserContext;
|
Request->Req.Overwrite.UserContext = FileNode->UserContext;
|
||||||
Request->Req.Overwrite.UserContext2 = FileDesc->UserContext2;
|
Request->Req.Overwrite.UserContext2 = FileDesc->UserContext2;
|
||||||
Request->Req.Overwrite.FileAttributes = FileAttributes;
|
Request->Req.Overwrite.FileAttributes = FileAttributes;
|
||||||
|
Request->Req.Overwrite.AllocationSize = AllocationSize;
|
||||||
Request->Req.Overwrite.Supersede = FILE_SUPERSEDED == Response->IoStatus.Information;
|
Request->Req.Overwrite.Supersede = FILE_SUPERSEDED == Response->IoStatus.Information;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -887,6 +996,8 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* file was successfully overwritten/superseded */
|
/* file was successfully overwritten/superseded */
|
||||||
|
if (0 == FileNode->MainFileNode)
|
||||||
|
FspFileNodeOverwriteStreams(FileNode);
|
||||||
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
|
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
|
||||||
FspFileNodeNotifyChange(FileNode,
|
FspFileNodeNotifyChange(FileNode,
|
||||||
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
|
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
|
||||||
@ -897,7 +1008,7 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
/* SUCCESS! */
|
/* SUCCESS! */
|
||||||
FspIopRequestContext(Request, RequestFileDesc) = 0;
|
FspIopRequestContext(Request, RequestFileDesc) = 0;
|
||||||
Irp->IoStatus.Information = Request->Req.Overwrite.Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
|
Irp->IoStatus.Information = Request->Req.Overwrite.Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN;
|
||||||
Result = STATUS_SUCCESS;
|
Result = Irp->IoStatus.Status; /* get success value from oplock processing */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
@ -914,13 +1025,8 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
BOOLEAN Success;
|
|
||||||
|
|
||||||
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main);
|
|
||||||
if (!Success)
|
|
||||||
{
|
|
||||||
/* repost the IRP to retry later */
|
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
BOOLEAN Success;
|
||||||
|
|
||||||
if (FspFsctlTransactCreateKind == Request->Kind)
|
if (FspFsctlTransactCreateKind == Request->Kind)
|
||||||
{
|
{
|
||||||
@ -940,8 +1046,21 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
|
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
FspIopRetryCompleteIrp(Irp, Response, &Result);
|
Result = STATUS_SUCCESS;
|
||||||
|
Success = DEBUGTEST(90) &&
|
||||||
|
FspFileNodeTryAcquireExclusive(FileNode, Main) &&
|
||||||
|
FspFsvolCreateOpenOrOverwriteOplock(Irp, Response, &Result);
|
||||||
|
if (!Success)
|
||||||
|
{
|
||||||
|
if (STATUS_PENDING == Result)
|
||||||
|
return Result;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Main);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspIopRetryCompleteIrp(Irp, Response, &Result);
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -961,9 +1080,10 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
if (0 == Request)
|
if (0 == Request)
|
||||||
{
|
{
|
||||||
FspFsvolCreatePostClose(FileDesc);
|
FspFsvolCreatePostClose(FileDesc);
|
||||||
FspFileNodeClose(FileNode, FileObject);
|
FspFileNodeClose(FileNode, FileObject, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
|
return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -978,7 +1098,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
/* SUCCESS! */
|
/* SUCCESS! */
|
||||||
FspIopRequestContext(Request, RequestFileDesc) = 0;
|
FspIopRequestContext(Request, RequestFileDesc) = 0;
|
||||||
Irp->IoStatus.Information = Response->IoStatus.Information;
|
Irp->IoStatus.Information = Response->IoStatus.Information;
|
||||||
return STATUS_SUCCESS;
|
return Irp->IoStatus.Status; /* get success value from oplock processing */
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc)
|
static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc)
|
||||||
@ -1019,6 +1139,14 @@ static VOID FspFsvolCreateRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Con
|
|||||||
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
|
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
|
||||||
HANDLE AccessToken = Context[RequestAccessToken];
|
HANDLE AccessToken = Context[RequestAccessToken];
|
||||||
PEPROCESS Process = Context[RequestProcess];
|
PEPROCESS Process = Context[RequestProcess];
|
||||||
|
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
|
||||||
|
|
||||||
|
if (0 != ExtraFileNode)
|
||||||
|
{
|
||||||
|
ASSERT(FspFileNodeIsValid(ExtraFileNode));
|
||||||
|
FspFileNodeClose(ExtraFileNode, 0, TRUE);
|
||||||
|
FspFileNodeDereference(ExtraFileNode);
|
||||||
|
}
|
||||||
|
|
||||||
if (0 != FileDesc)
|
if (0 != FileDesc)
|
||||||
{
|
{
|
||||||
@ -1061,13 +1189,21 @@ static VOID FspFsvolCreateTryOpenRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV
|
|||||||
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
|
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
|
||||||
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
|
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
|
||||||
PFILE_OBJECT FileObject = Context[RequestFileObject];
|
PFILE_OBJECT FileObject = Context[RequestFileObject];
|
||||||
|
PIRP OplockIrp = FspIopRequestContext(Request, FspIopRequestExtraContext);
|
||||||
|
|
||||||
if (0 != FileDesc)
|
if (0 != FileDesc)
|
||||||
{
|
{
|
||||||
ASSERT(0 != FileObject);
|
ASSERT(0 != FileObject);
|
||||||
|
|
||||||
|
if (OplockIrp)
|
||||||
|
{
|
||||||
|
ASSERT(IO_TYPE_IRP == OplockIrp->Type);
|
||||||
|
FspFileNodeOplockCheckEx(FileDesc->FileNode, OplockIrp,
|
||||||
|
OPLOCK_FLAG_BACK_OUT_ATOMIC_OPLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
FspFsvolCreatePostClose(FileDesc);
|
FspFsvolCreatePostClose(FileDesc);
|
||||||
FspFileNodeClose(FileDesc->FileNode, FileObject);
|
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE);
|
||||||
FspFileNodeDereference(FileDesc->FileNode);
|
FspFileNodeDereference(FileDesc->FileNode);
|
||||||
FspFileDescDelete(FileDesc);
|
FspFileDescDelete(FileDesc);
|
||||||
}
|
}
|
||||||
@ -1084,6 +1220,7 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
|
|||||||
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
|
FSP_FILE_DESC *FileDesc = Context[RequestFileDesc];
|
||||||
PFILE_OBJECT FileObject = Context[RequestFileObject];
|
PFILE_OBJECT FileObject = Context[RequestFileObject];
|
||||||
ULONG State = (ULONG)(UINT_PTR)Context[RequestState];
|
ULONG State = (ULONG)(UINT_PTR)Context[RequestState];
|
||||||
|
PIRP OplockIrp = FspIopRequestContext(Request, FspIopRequestExtraContext);
|
||||||
|
|
||||||
if (0 != FileDesc)
|
if (0 != FileDesc)
|
||||||
{
|
{
|
||||||
@ -1094,7 +1231,14 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
|
|||||||
else if (RequestProcessing == State)
|
else if (RequestProcessing == State)
|
||||||
FspFileNodeReleaseOwner(FileDesc->FileNode, Full, Request);
|
FspFileNodeReleaseOwner(FileDesc->FileNode, Full, Request);
|
||||||
|
|
||||||
FspFileNodeClose(FileDesc->FileNode, FileObject);
|
if (OplockIrp)
|
||||||
|
{
|
||||||
|
ASSERT(IO_TYPE_IRP == OplockIrp->Type);
|
||||||
|
FspFileNodeOplockCheckEx(FileDesc->FileNode, OplockIrp,
|
||||||
|
OPLOCK_FLAG_BACK_OUT_ATOMIC_OPLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE);
|
||||||
FspFileNodeDereference(FileDesc->FileNode);
|
FspFileNodeDereference(FileDesc->FileNode);
|
||||||
FspFileDescDelete(FileDesc);
|
FspFileDescDelete(FileDesc);
|
||||||
}
|
}
|
||||||
@ -1103,6 +1247,258 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
|
|||||||
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
|
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolCreateSharingViolationOplock(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN CanWait)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform oplock checks in the case that we received STATUS_SHARING_VIOLATION.
|
||||||
|
* The logic below is rather tortured, because it tries to mimic what FastFat
|
||||||
|
* does in Win7 when a sharing violation happens. Here is an explanation.
|
||||||
|
*
|
||||||
|
* When this routine first gets called the CanWait parameter is FALSE. This is
|
||||||
|
* because it gets called in the context of a completion thread, which belongs
|
||||||
|
* to the user mode file system. This means that we cannot block this thread
|
||||||
|
* because the user mode file system may have a limited number of threads to
|
||||||
|
* service file system requests.
|
||||||
|
*
|
||||||
|
* When CanWait is FALSE the routine checks whether there are any oplocks on
|
||||||
|
* this file. If there are none it simply returns STATUS_SHARING_VIOLATION.
|
||||||
|
* Otherwise it posts a work item so that the routine can be executed in the
|
||||||
|
* context of a worker thread. When executed in the context of a worker thread
|
||||||
|
* the CanWait parameter is TRUE.
|
||||||
|
*
|
||||||
|
* When CanWait is TRUE the routine is free to wait for any oplocks breaks. We
|
||||||
|
* try to break both Batch and Handle oplocks and return the appropriate status
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
* We acquire the FileNode shared to allow oplock breaks to happen concurrently.
|
||||||
|
* See https://www.osronline.com/showthread.cfm?link=248984
|
||||||
|
*/
|
||||||
|
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||||
|
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
|
||||||
|
ULONG SharingViolationReason = (ULONG)Irp->IoStatus.Information;
|
||||||
|
NTSTATUS Result;
|
||||||
|
BOOLEAN Success;
|
||||||
|
|
||||||
|
ASSERT(FspFsctlTransactCreateKind == Request->Kind);
|
||||||
|
ASSERT(
|
||||||
|
FspFileNodeSharingViolationGeneral == SharingViolationReason ||
|
||||||
|
FspFileNodeSharingViolationMainFile == SharingViolationReason ||
|
||||||
|
FspFileNodeSharingViolationStream == SharingViolationReason);
|
||||||
|
|
||||||
|
Success = DEBUGTEST(90) &&
|
||||||
|
FspFileNodeTryAcquireSharedF(ExtraFileNode, FspFileNodeAcquireMain, CanWait);
|
||||||
|
if (!Success)
|
||||||
|
return FspWqRepostIrpWorkItem(Irp,
|
||||||
|
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
|
||||||
|
|
||||||
|
if (!CanWait)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If there is no Batch or Handle oplock we are done; else retry in a
|
||||||
|
* worker thread to break the oplocks.
|
||||||
|
*/
|
||||||
|
Success = DEBUGTEST(90) &&
|
||||||
|
!(FspFileNodeSharingViolationMainFile == SharingViolationReason) &&
|
||||||
|
!(FspFileNodeSharingViolationStream == SharingViolationReason) &&
|
||||||
|
!(FspFileNodeOplockIsBatch(ExtraFileNode)) &&
|
||||||
|
!(!FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) &&
|
||||||
|
FspFileNodeOplockIsHandle(ExtraFileNode));
|
||||||
|
|
||||||
|
FspFileNodeRelease(ExtraFileNode, Main);
|
||||||
|
|
||||||
|
if (!Success)
|
||||||
|
return FspWqRepostIrpWorkItem(Irp,
|
||||||
|
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
return STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
if (FspFileNodeSharingViolationMainFile == SharingViolationReason)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If a SUPERSEDE, OVERWRITE or OVERWRITE_IF operation is performed
|
||||||
|
* on an alternate data stream and FILE_SHARE_DELETE is not specified
|
||||||
|
* and there is a Batch or Filter oplock on the primary data stream,
|
||||||
|
* request a break of the Batch or Filter oplock on the primary data
|
||||||
|
* stream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
|
||||||
|
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
||||||
|
|
||||||
|
/* break Batch oplocks on the main file and this stream */
|
||||||
|
Result = FspFileNodeCheckBatchOplocksOnAllStreams(FsvolDeviceObject, Irp,
|
||||||
|
ExtraFileNode, FspFileNodeAcquireMain, &FileNode->FileName);
|
||||||
|
if (STATUS_SUCCESS != Result)
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (FspFileNodeSharingViolationStream == SharingViolationReason)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If a SUPERSEDE, OVERWRITE or OVERWRITE_IF operation is performed
|
||||||
|
* on the primary data stream and DELETE access has been requested
|
||||||
|
* and there are Batch or Filter oplocks on any alternate data stream,
|
||||||
|
* request a break of the Batch or Filter oplocks on all alternate data
|
||||||
|
* streams that have them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* break Batch oplocks on the main file and all our streams */
|
||||||
|
Result = FspFileNodeCheckBatchOplocksOnAllStreams(FsvolDeviceObject, Irp,
|
||||||
|
ExtraFileNode, FspFileNodeAcquireMain, 0);
|
||||||
|
if (STATUS_SUCCESS != Result)
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (FspFileNodeOplockIsBatch(ExtraFileNode))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(ExtraFileNode, Main);
|
||||||
|
|
||||||
|
/* wait for Batch oplock break to complete */
|
||||||
|
Result = FspFileNodeOplockCheck(ExtraFileNode, Irp);
|
||||||
|
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result);
|
||||||
|
if (STATUS_SUCCESS != Result)
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
else
|
||||||
|
Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) &&
|
||||||
|
FspFileNodeOplockIsHandle(ExtraFileNode))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(ExtraFileNode, Main);
|
||||||
|
|
||||||
|
/* wait for Handle oplock break to complete */
|
||||||
|
Result = FspFileNodeOplockBreakHandle(ExtraFileNode, Irp, 0);
|
||||||
|
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result);
|
||||||
|
if (STATUS_SUCCESS != Result)
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FspFileNodeRelease(ExtraFileNode, Main);
|
||||||
|
|
||||||
|
Response = FspIopIrpResponse(Irp);
|
||||||
|
|
||||||
|
if (STATUS_SUCCESS == Result)
|
||||||
|
{
|
||||||
|
FspFileNodeClose(ExtraFileNode, 0, TRUE);
|
||||||
|
FspFileNodeDereference(ExtraFileNode);
|
||||||
|
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Response->IoStatus.Status = (UINT32)Result;
|
||||||
|
Response->IoStatus.Information = (UINT32)Irp->IoStatus.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspIopRetryCompleteIrp(Irp, Response, &Result);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
PNTSTATUS PResult)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
UINT32 RequestKind = FspIrpRequest(Irp)->Kind;
|
||||||
|
ULONG OplockCount = 0;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
ASSERT(
|
||||||
|
FspFsctlTransactReservedKind == RequestKind ||
|
||||||
|
FspFsctlTransactOverwriteKind == RequestKind);
|
||||||
|
|
||||||
|
/* add oplock key to the file object */
|
||||||
|
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
|
||||||
|
OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
*PResult = Result;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current handle count */
|
||||||
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
OplockCount = FileNode->HandleCount;
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/* if there are more than one handles, perform oplock check */
|
||||||
|
if (1 < OplockCount)
|
||||||
|
{
|
||||||
|
Result = FspFileNodeOplockCheckAsyncEx(
|
||||||
|
FileNode,
|
||||||
|
FspFsctlTransactReservedKind == RequestKind ? FspFileNodeAcquireMain : FspFileNodeAcquireFull,
|
||||||
|
(PVOID)Response,
|
||||||
|
Irp,
|
||||||
|
FspFsvolCreateOpenOrOverwriteOplockComplete,
|
||||||
|
FspFsvolCreateOpenOrOverwriteOplockPrepare);
|
||||||
|
if (STATUS_PENDING == Result)
|
||||||
|
{
|
||||||
|
*PResult = Result;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is an oplock requested during Create? */
|
||||||
|
if (STATUS_SUCCESS == Result &&
|
||||||
|
FlagOn(IrpSp->Parameters.Create.Options, FILE_OPEN_REQUIRING_OPLOCK))
|
||||||
|
{
|
||||||
|
Result = FspFileNodeOplockFsctl(FileNode, Irp, OplockCount);
|
||||||
|
ASSERT(STATUS_PENDING != Result);
|
||||||
|
|
||||||
|
if (STATUS_SUCCESS == Result)
|
||||||
|
/* if we added an oplock, remember to remove it later in case of failure */
|
||||||
|
FspIopRequestContext(FspIrpRequest(Irp), FspIopRequestExtraContext) = Irp;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PResult = Irp->IoStatus.Status = Result;
|
||||||
|
return STATUS_SUCCESS == Result || STATUS_OPLOCK_BREAK_IN_PROGRESS == Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID FspFsvolCreateOpenOrOverwriteOplockPrepare(
|
||||||
|
PVOID Context, PIRP Irp)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSCTL_TRANSACT_RSP *Response = FspFileNodeReleaseForOplock(Context);
|
||||||
|
|
||||||
|
if (0 != Response)
|
||||||
|
FspIopSetIrpResponse(Irp, Response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID FspFsvolCreateOpenOrOverwriteOplockComplete(
|
||||||
|
PVOID Context, PIRP Irp)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (FspFsctlTransactReservedKind == Request->Kind)
|
||||||
|
FspIopRetryCompleteIrp(Irp, FspIopIrpResponse(Irp), &Result);
|
||||||
|
else
|
||||||
|
if (FspFsctlTransactOverwriteKind == Request->Kind)
|
||||||
|
FspIopRetryPrepareIrp(Irp, &Result);
|
||||||
|
else
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS FspCreate(
|
NTSTATUS FspCreate(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
{
|
{
|
||||||
@ -1131,7 +1527,7 @@ NTSTATUS FspCreate(
|
|||||||
"Ea=%p, EaLength=%ld",
|
"Ea=%p, EaLength=%ld",
|
||||||
IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName,
|
IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName,
|
||||||
IrpSp->Flags,
|
IrpSp->Flags,
|
||||||
IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
|
IrpSp->Parameters.Create.SecurityContext->AccessState->OriginalDesiredAccess,
|
||||||
IrpSp->Parameters.Create.ShareAccess,
|
IrpSp->Parameters.Create.ShareAccess,
|
||||||
IrpSp->Parameters.Create.Options,
|
IrpSp->Parameters.Create.Options,
|
||||||
IrpSp->Parameters.Create.FileAttributes,
|
IrpSp->Parameters.Create.FileAttributes,
|
||||||
|
@ -590,7 +590,9 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
|
|||||||
*PContextCount = 0;
|
*PContextCount = 0;
|
||||||
|
|
||||||
ContextCount = RtlNumberGenericTableElementsAvl(&FsvolDeviceExtension->ContextByNameTable);
|
ContextCount = RtlNumberGenericTableElementsAvl(&FsvolDeviceExtension->ContextByNameTable);
|
||||||
Contexts = FspAlloc(sizeof(PVOID) * ContextCount);
|
|
||||||
|
/* if ContextCount == 0 allocate an empty Context list */
|
||||||
|
Contexts = FspAlloc(sizeof(PVOID) * (0 != ContextCount ? ContextCount : 1));
|
||||||
if (0 == Contexts)
|
if (0 == Contexts)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
@ -631,9 +633,10 @@ PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE
|
|||||||
0, 0, NextFlag, &RestartKey->RestartKey, &RestartKey->DeleteCount, &FileName);
|
0, 0, NextFlag, &RestartKey->RestartKey, &RestartKey->DeleteCount, &FileName);
|
||||||
|
|
||||||
if (0 != Result &&
|
if (0 != Result &&
|
||||||
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&
|
FspFileNameIsPrefix(FileName, Result->FileName, CaseInsensitive, 0) &&
|
||||||
FileName->Length < Result->FileName->Length &&
|
(FileName->Length == Result->FileName->Length ||
|
||||||
'\\' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)])
|
(L'\\' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)] ||
|
||||||
|
L':' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)])))
|
||||||
return Result->Context;
|
return Result->Context;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
@ -699,7 +702,12 @@ static RTL_GENERIC_COMPARE_RESULTS NTAPI FspFsvolDeviceCompareContextByName(
|
|||||||
PUNICODE_STRING SecondFileName = *(PUNICODE_STRING *)SecondElement;
|
PUNICODE_STRING SecondFileName = *(PUNICODE_STRING *)SecondElement;
|
||||||
LONG ComparisonResult;
|
LONG ComparisonResult;
|
||||||
|
|
||||||
ComparisonResult = RtlCompareUnicodeString(FirstFileName, SecondFileName, CaseInsensitive);
|
/*
|
||||||
|
* Since FileNode FileName's are now always normalized, we could perhaps get away
|
||||||
|
* with using CaseInsensitive == FALSE at all times. For safety reasons we avoid
|
||||||
|
* doing so here.
|
||||||
|
*/
|
||||||
|
ComparisonResult = FspFileNameCompare(FirstFileName, SecondFileName, CaseInsensitive, 0);
|
||||||
|
|
||||||
if (0 > ComparisonResult)
|
if (0 > ComparisonResult)
|
||||||
return GenericLessThan;
|
return GenericLessThan;
|
||||||
|
@ -17,6 +17,15 @@
|
|||||||
|
|
||||||
#include <sys/driver.h>
|
#include <sys/driver.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE:
|
||||||
|
*
|
||||||
|
* FspIopCompleteIrpEx does some special processing for IRP_MJ_DIRECTORY_CONTROL /
|
||||||
|
* IRP_MN_QUERY_DIRECTORY IRP's that come from SRV2. If the processing of this IRP
|
||||||
|
* changes substantially (in particular if we eliminate our use of
|
||||||
|
* Irp->AssociatedIrp.SystemBuffer) we should also revisit FspIopCompleteIrpEx.
|
||||||
|
*/
|
||||||
|
|
||||||
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||||
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
||||||
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
|
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
|
||||||
@ -71,7 +80,7 @@ FSP_DRIVER_DISPATCH FspDirectoryControl;
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/* QueryDirectory */
|
/* QueryDirectory */
|
||||||
RequestFileNode = 0,
|
RequestIrp = 0,
|
||||||
RequestMdl = 1,
|
RequestMdl = 1,
|
||||||
RequestAddress = 2,
|
RequestAddress = 2,
|
||||||
RequestProcess = 3,
|
RequestProcess = 3,
|
||||||
@ -118,7 +127,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result = STATUS_SUCCESS;
|
NTSTATUS Result = STATUS_SUCCESS;
|
||||||
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer;
|
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match;
|
||||||
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
|
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
|
||||||
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
|
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
|
||||||
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
|
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
|
||||||
@ -182,7 +191,15 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
||||||
CopyLength = FileName.Length;
|
CopyLength = FileName.Length;
|
||||||
|
|
||||||
if (MatchAll || FsRtlIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0))
|
Match = MatchAll;
|
||||||
|
if (!Match)
|
||||||
|
{
|
||||||
|
Result = FspFileNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0, &Match);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Match)
|
||||||
{
|
{
|
||||||
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
|
if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd)
|
||||||
{
|
{
|
||||||
@ -340,7 +357,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
|||||||
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
|
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
|
||||||
|
|
||||||
ASSERT(DirInfo == DestBuf);
|
ASSERT(DirInfo == DestBuf);
|
||||||
static_assert(
|
FSP_FSCTL_STATIC_ASSERT(
|
||||||
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
|
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
|
||||||
FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName),
|
FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName),
|
||||||
"FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION");
|
"FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION");
|
||||||
@ -567,6 +584,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
|
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
|
||||||
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
|
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
|
||||||
Request->Req.QueryDirectory.Length = SystemBufferLength;
|
Request->Req.QueryDirectory.Length = SystemBufferLength;
|
||||||
|
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
|
||||||
|
|
||||||
if (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
|
if (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
|
||||||
{
|
{
|
||||||
@ -580,7 +598,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
FspIopRequestContext(Request, RequestIrp) = Irp;
|
||||||
|
|
||||||
return FSP_STATUS_IOQ_POST;
|
return FSP_STATUS_IOQ_POST;
|
||||||
|
|
||||||
@ -618,7 +636,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 && !FspUnicodePathIsValidPattern(FileName))
|
if (0 != FileName && !FspFileNameIsValidPattern(FileName))
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
/* is this an allowed file information class? */
|
/* is this an allowed file information class? */
|
||||||
@ -847,6 +865,10 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
|
||||||
|
if (Response->IoStatus.Information > Request->Req.QueryDirectory.Length)
|
||||||
|
FSP_RETURN(Result = STATUS_INTERNAL_ERROR);
|
||||||
|
|
||||||
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;
|
||||||
@ -930,7 +952,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
|||||||
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
|
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
|
||||||
|
|
||||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
FspIopRequestContext(Request, RequestIrp) = Irp;
|
||||||
|
|
||||||
FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result);
|
FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result);
|
||||||
}
|
}
|
||||||
@ -952,7 +974,7 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
PIRP Irp = Context[RequestIrp];
|
||||||
PMDL Mdl = Context[RequestMdl];
|
PMDL Mdl = Context[RequestMdl];
|
||||||
PVOID Address = Context[RequestAddress];
|
PVOID Address = Context[RequestAddress];
|
||||||
PEPROCESS Process = Context[RequestProcess];
|
PEPROCESS Process = Context[RequestProcess];
|
||||||
@ -977,8 +999,13 @@ static VOID FspFsvolQueryDirectoryRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
if (0 != Mdl)
|
if (0 != Mdl)
|
||||||
IoFreeMdl(Mdl);
|
IoFreeMdl(Mdl);
|
||||||
|
|
||||||
if (0 != FileNode)
|
if (0 != Irp)
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
FSP_FILE_NODE *FileNode = IrpSp->FileObject->FsContext;
|
||||||
|
|
||||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FspDirectoryControl(
|
NTSTATUS FspDirectoryControl(
|
||||||
|
@ -120,7 +120,6 @@ NTSTATUS DriverEntry(
|
|||||||
FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete;
|
FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete;
|
||||||
FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete;
|
FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete;
|
||||||
FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete;
|
FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete;
|
||||||
FspIopPrepareFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityPrepare;
|
|
||||||
FspIopCompleteFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityComplete;
|
FspIopCompleteFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityComplete;
|
||||||
|
|
||||||
/* setup fast I/O and resource acquisition */
|
/* setup fast I/O and resource acquisition */
|
||||||
@ -177,6 +176,8 @@ NTSTATUS DriverEntry(
|
|||||||
|
|
||||||
static VOID FspDriverMultiVersionInitialize(VOID)
|
static VOID FspDriverMultiVersionInitialize(VOID)
|
||||||
{
|
{
|
||||||
|
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||||
|
|
||||||
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
|
if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7))
|
||||||
{
|
{
|
||||||
UNICODE_STRING Name;
|
UNICODE_STRING Name;
|
||||||
|
452
src/sys/driver.h
@ -19,6 +19,8 @@
|
|||||||
#define WINFSP_SYS_DRIVER_H_INCLUDED
|
#define WINFSP_SYS_DRIVER_H_INCLUDED
|
||||||
|
|
||||||
#define WINFSP_SYS_INTERNAL
|
#define WINFSP_SYS_INTERNAL
|
||||||
|
|
||||||
|
#define POOL_NX_OPTIN 1
|
||||||
#include <ntifs.h>
|
#include <ntifs.h>
|
||||||
#include <ntstrsafe.h>
|
#include <ntstrsafe.h>
|
||||||
#include <wdmsec.h>
|
#include <wdmsec.h>
|
||||||
@ -33,8 +35,8 @@
|
|||||||
/* IoCreateDeviceSecure default SDDL's */
|
/* IoCreateDeviceSecure default SDDL's */
|
||||||
#define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
|
#define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
|
||||||
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */
|
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */
|
||||||
#define FSP_FSVRT_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
|
#define FSP_FSVRT_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGX;;;WD)"
|
||||||
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */
|
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ|GENERIC_EXECUTE */
|
||||||
|
|
||||||
/* private NTSTATUS codes */
|
/* private NTSTATUS codes */
|
||||||
#define FSP_STATUS_PRIVATE_BIT (0x20000000)
|
#define FSP_STATUS_PRIVATE_BIT (0x20000000)
|
||||||
@ -45,7 +47,6 @@
|
|||||||
#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
|
||||||
@ -123,8 +124,11 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
|
|||||||
#if DBG
|
#if DBG
|
||||||
#define DEBUGTEST(Percent) \
|
#define DEBUGTEST(Percent) \
|
||||||
(0 == (fsp_debug & fsp_debug_dt) || DebugRandom() <= (Percent) * 0x7fff / 100)
|
(0 == (fsp_debug & fsp_debug_dt) || DebugRandom() <= (Percent) * 0x7fff / 100)
|
||||||
|
#define DEBUGTEST_EX(C, Percent, Deflt) \
|
||||||
|
(0 != (fsp_debug & fsp_debug_dt) && (C) ? (DebugRandom() <= (Percent) * 0x7fff / 100) : (Deflt))
|
||||||
#else
|
#else
|
||||||
#define DEBUGTEST(Percent) (TRUE)
|
#define DEBUGTEST(Percent) (TRUE)
|
||||||
|
#define DEBUGTEST_EX(C, Percent, Deflt) (Deflt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* FSP_ENTER/FSP_LEAVE */
|
/* FSP_ENTER/FSP_LEAVE */
|
||||||
@ -319,7 +323,6 @@ FSP_IOCMPL_DISPATCH FspFsvolReadComplete;
|
|||||||
FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete;
|
||||||
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
|
FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare;
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete;
|
||||||
FSP_IOPREP_DISPATCH FspFsvolSetSecurityPrepare;
|
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete;
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete;
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete;
|
||||||
@ -428,17 +431,45 @@ BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime)
|
|||||||
return CurrentTime < ExpirationTime;
|
return CurrentTime < ExpirationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* utility */
|
/* names */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FspUnicodePathStreamTypeNone = 0,
|
FspFileNameStreamTypeNone = 0,
|
||||||
FspUnicodePathStreamTypeData = 1,
|
FspFileNameStreamTypeData = 1,
|
||||||
};
|
};
|
||||||
|
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType);
|
||||||
|
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern);
|
||||||
|
VOID FspFileNameSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
|
||||||
|
#if 0
|
||||||
|
NTSTATUS FspFileNameUpcase(
|
||||||
|
PUNICODE_STRING DestinationName,
|
||||||
|
PUNICODE_STRING SourceName,
|
||||||
|
PCWCH UpcaseTable);
|
||||||
|
LONG FspFileNameCompare(
|
||||||
|
PUNICODE_STRING Name1,
|
||||||
|
PUNICODE_STRING Name2,
|
||||||
|
BOOLEAN IgnoreCase,
|
||||||
|
PCWCH UpcaseTable);
|
||||||
|
BOOLEAN FspFileNameIsPrefix(
|
||||||
|
PCUNICODE_STRING Name1,
|
||||||
|
PCUNICODE_STRING Name2,
|
||||||
|
BOOLEAN IgnoreCase,
|
||||||
|
PCWCH UpcaseTable);
|
||||||
|
#else
|
||||||
|
#define FspFileNameUpcase(D,S,U) (ASSERT(0 == (U)), RtlUpcaseUnicodeString(D,S,FALSE))
|
||||||
|
#define FspFileNameCompare(N1,N2,I,U) (ASSERT(0 == (U)), RtlCompareUnicodeString(N1,N2,I))
|
||||||
|
#define FspFileNameIsPrefix(N1,N2,I,U) (ASSERT(0 == (U)), RtlPrefixUnicodeString(N1,N2,I))
|
||||||
|
#endif
|
||||||
|
NTSTATUS FspFileNameInExpression(
|
||||||
|
PUNICODE_STRING Expression,
|
||||||
|
PUNICODE_STRING Name,
|
||||||
|
BOOLEAN IgnoreCase,
|
||||||
|
PWCH UpcaseTable,
|
||||||
|
PBOOLEAN PResult);
|
||||||
|
|
||||||
|
/* utility */
|
||||||
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, PUNICODE_STRING StreamPart, PULONG StreamType);
|
|
||||||
BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern);
|
|
||||||
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,
|
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
|
||||||
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
|
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
|
||||||
@ -487,18 +518,42 @@ NTSTATUS FspNotifyFullReportChange(
|
|||||||
ULONG FilterMatch,
|
ULONG FilterMatch,
|
||||||
ULONG Action,
|
ULONG Action,
|
||||||
PVOID TargetContext);
|
PVOID TargetContext);
|
||||||
|
NTSTATUS FspOplockBreakH(
|
||||||
|
POPLOCK Oplock,
|
||||||
|
PIRP Irp,
|
||||||
|
ULONG Flags,
|
||||||
|
PVOID Context,
|
||||||
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
||||||
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
|
||||||
|
NTSTATUS FspCheckOplock(
|
||||||
|
POPLOCK Oplock,
|
||||||
|
PIRP Irp,
|
||||||
|
PVOID Context,
|
||||||
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
||||||
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
|
||||||
|
NTSTATUS FspCheckOplockEx(
|
||||||
|
POPLOCK Oplock,
|
||||||
|
PIRP Irp,
|
||||||
|
ULONG Flags,
|
||||||
|
PVOID Context,
|
||||||
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
||||||
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
|
||||||
|
NTSTATUS FspOplockFsctrl(
|
||||||
|
POPLOCK Oplock,
|
||||||
|
PIRP Irp,
|
||||||
|
ULONG OpenCount);
|
||||||
#define FspNotifyUninitializeSync(NS)\
|
#define FspNotifyUninitializeSync(NS)\
|
||||||
FsRtlNotifyUninitializeSync(NS)
|
FsRtlNotifyUninitializeSync(NS)
|
||||||
#define FspNotifyCleanupAll(NS, NL)\
|
#define FspNotifyCleanupAll(NS, NL)\
|
||||||
FsRtlNotifyCleanupAll(NS, NL)
|
FsRtlNotifyCleanupAll(NS, NL)
|
||||||
#define FspNotifyChangeDirectory(NS, NL, FC, FN, WT, CF, I)\
|
#define FspNotifyChangeDirectory(NS, NL, FC, FN, WT, CF, I)\
|
||||||
FspNotifyFullChangeDirectory(NS, NL, FC, (PSTRING)FN, WT, FALSE, CF, I, 0, 0)
|
FspNotifyFullChangeDirectory(NS, NL, FC, (PSTRING)(FN), WT, FALSE, CF, I, 0, 0)
|
||||||
#define FspNotifyCleanup(NS, NL, FC)\
|
#define FspNotifyCleanup(NS, NL, FC)\
|
||||||
FsRtlNotifyCleanup(NS, NL, FC)
|
FsRtlNotifyCleanup(NS, NL, FC)
|
||||||
#define FspNotifyDeletePending(NS, NL, FC)\
|
#define FspNotifyDeletePending(NS, NL, FC)\
|
||||||
FspNotifyFullChangeDirectory(NS, NL, FC, 0, 0, FALSE, 0, 0, 0, 0)
|
FspNotifyFullChangeDirectory(NS, NL, FC, 0, 0, FALSE, 0, 0, 0, 0)
|
||||||
#define FspNotifyReportChange(NS, NL, FN, FO, SN, F, A)\
|
#define FspNotifyReportChange(NS, NL, FN, FO, NP, F, A)\
|
||||||
FspNotifyFullReportChange(NS, NL, (PSTRING)FN, FO, (PSTRING)SN, 0, F, A, 0)
|
FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0)
|
||||||
|
|
||||||
/* utility: synchronous work queue */
|
/* utility: synchronous work queue */
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -585,7 +640,151 @@ VOID FspIrpSetTopFlags(PIRP Irp, ULONG Flags)
|
|||||||
Irp->Tail.Overlay.DriverContext[2] = (PVOID)((UINT_PTR)Request | (Flags << 2));
|
Irp->Tail.Overlay.DriverContext[2] = (PVOID)((UINT_PTR)Request | (Flags << 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Queued Events
|
||||||
|
*
|
||||||
|
* Queued Events are an implementation of SynchronizationEvent's using
|
||||||
|
* a KQUEUE. The reason we do this is because a KQUEUE has some desirable
|
||||||
|
* properties:
|
||||||
|
*
|
||||||
|
* - It has a LIFO wait discipline, which is advantageous in many situations.
|
||||||
|
* - It can limit the numbers of threads that can be satisfied concurrently.
|
||||||
|
*
|
||||||
|
* Queued Events must always be allocated in non-paged storage.
|
||||||
|
*
|
||||||
|
* Here is how Queued Events work. A queued event consists of a KQUEUE and a
|
||||||
|
* spin lock. There is also a LIST_ENTRY which is used as a dummy item to
|
||||||
|
* place in the KQUEUE.
|
||||||
|
*
|
||||||
|
* The KQUEUE is guaranteed to contain either 0 or 1 items. When the KQUEUE
|
||||||
|
* contains 0 items the queued event is considered non-signaled. When the
|
||||||
|
* KQUEUE contains 1 items the queued event is considered signaled.
|
||||||
|
*
|
||||||
|
* To transition from the non-signaled to the signaled state, we acquire the
|
||||||
|
* spin lock and then insert the dummy item in the KQUEUE using KeInsertQueue.
|
||||||
|
* To transition from the signaled to the non-signaled state, we simply (wait
|
||||||
|
* and) remove the dummy item from the KQUEUE using KeRemoveQueue (without
|
||||||
|
* the use of the spin lock).
|
||||||
|
*
|
||||||
|
* EventSet:
|
||||||
|
* AcquireSpinLock
|
||||||
|
* if (0 == KeReadState()) // if KQUEUE is empty
|
||||||
|
* KeInsertQueue(DUMMY);
|
||||||
|
* ReleaseSpinLock
|
||||||
|
*
|
||||||
|
* EventWait:
|
||||||
|
* KeRemoveQueue(); // (wait and) remove item
|
||||||
|
*
|
||||||
|
* First notice that EventSet is serialized by the use of the spin lock. This
|
||||||
|
* guarantees that the dummy item can be only inserted ONCE in the KQUEUE
|
||||||
|
* and that the only possible signaled state transitions for EventSet are 0->1
|
||||||
|
* and 1->1. This is how KeSetEvent works for a SynchronizationEvent.
|
||||||
|
*
|
||||||
|
* Second notice that EventWait is not protected by the spin lock, which means
|
||||||
|
* that it can happen at any time including concurrently with EventSet or
|
||||||
|
* another EventWait. Notice also that for EventWait the only possible
|
||||||
|
* transitions are 1->0 or 0->0 (0->block->0). This is how
|
||||||
|
* KeWaitForSingleObject works for a SynchronizationEvent.
|
||||||
|
*
|
||||||
|
* We now have to consider what happens when we have one EventSet concurrently
|
||||||
|
* with one or more EventWait's:
|
||||||
|
*
|
||||||
|
* 1. The EventWait(s) happen before KeReadState. If the KQUEUE has an
|
||||||
|
* item one EventWait gets satisfied, otherwise it blocks. In this case
|
||||||
|
* KeReadState will read the KQUEUE's state as 0 and KeInsertQueue will
|
||||||
|
* insert the dummy item, which will unblock the EventWait.
|
||||||
|
*
|
||||||
|
* 2. The EventWait(s) happen after KeReadState, but before KeInsertQueue.
|
||||||
|
* If the dummy item was already in the KQUEUE the KeReadState test will
|
||||||
|
* fail and KeInsertQueue will not be executed, but EventWait will be
|
||||||
|
* satisfied immediately. If the dummy item was not in the KQUEUE the
|
||||||
|
* KeReadState will succeed and EventWait will momentarily block until
|
||||||
|
* KeInsertQueue releases it.
|
||||||
|
*
|
||||||
|
* 3. The EventWait(s) happen after KeInsertQueue. In this case the dummy
|
||||||
|
* item in is the KQUEUE already and one EventWait will be satisfied
|
||||||
|
* immediately.
|
||||||
|
*
|
||||||
|
* A final note: Queued Events cannot cleanly support an EventClear operation.
|
||||||
|
* The obvious choice of using KeRemoveQueue with a 0 timeout is insufficient
|
||||||
|
* because it would associate the current thread with the KQUEUE and that is
|
||||||
|
* not desirable. KeRundownQueue cannot be used either because it
|
||||||
|
* disassociates all threads from the KQUEUE.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
KQUEUE Queue;
|
||||||
|
LIST_ENTRY DummyEntry;
|
||||||
|
KSPIN_LOCK SpinLock;
|
||||||
|
} FSP_QEVENT;
|
||||||
|
static inline
|
||||||
|
VOID FspQeventInitialize(FSP_QEVENT *Qevent, ULONG ThreadCount)
|
||||||
|
{
|
||||||
|
KeInitializeQueue(&Qevent->Queue, ThreadCount);
|
||||||
|
RtlZeroMemory(&Qevent->DummyEntry, sizeof Qevent->DummyEntry);
|
||||||
|
KeInitializeSpinLock(&Qevent->SpinLock);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
VOID FspQeventFinalize(FSP_QEVENT *Qevent)
|
||||||
|
{
|
||||||
|
KeRundownQueue(&Qevent->Queue);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
VOID FspQeventSetNoLock(FSP_QEVENT *Qevent)
|
||||||
|
{
|
||||||
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
|
if (0 == KeReadStateQueue(&Qevent->Queue))
|
||||||
|
KeInsertQueue(&Qevent->Queue, &Qevent->DummyEntry);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
VOID FspQeventSet(FSP_QEVENT *Qevent)
|
||||||
|
{
|
||||||
|
KIRQL Irql;
|
||||||
|
KeAcquireSpinLock(&Qevent->SpinLock, &Irql);
|
||||||
|
FspQeventSetNoLock(Qevent);
|
||||||
|
KeReleaseSpinLock(&Qevent->SpinLock, Irql);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspQeventWait(FSP_QEVENT *Qevent,
|
||||||
|
KPROCESSOR_MODE WaitMode, BOOLEAN Alertable, PLARGE_INTEGER PTimeout)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY ListEntry;
|
||||||
|
KeRemoveQueueEx(&Qevent->Queue, WaitMode, Alertable, PTimeout, &ListEntry, 1);
|
||||||
|
if (ListEntry == &Qevent->DummyEntry)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
return (NTSTATUS)(UINT_PTR)ListEntry;
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspQeventCancellableWait(FSP_QEVENT *Qevent,
|
||||||
|
PLARGE_INTEGER PTimeout, PIRP Irp)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
UINT64 ExpirationTime = 0, InterruptTime;
|
||||||
|
if (0 != PTimeout && 0 > PTimeout->QuadPart)
|
||||||
|
ExpirationTime = KeQueryInterruptTime() - PTimeout->QuadPart;
|
||||||
|
retry:
|
||||||
|
Result = FspQeventWait(Qevent, KernelMode, TRUE, PTimeout);
|
||||||
|
if (STATUS_ALERTED == Result)
|
||||||
|
{
|
||||||
|
if (PsIsThreadTerminating(PsGetCurrentThread()))
|
||||||
|
return STATUS_THREAD_IS_TERMINATING;
|
||||||
|
if (0 != Irp && Irp->Cancel)
|
||||||
|
return STATUS_CANCELLED;
|
||||||
|
if (0 != ExpirationTime)
|
||||||
|
{
|
||||||
|
InterruptTime = KeQueryInterruptTime();
|
||||||
|
if (ExpirationTime <= InterruptTime)
|
||||||
|
return STATUS_TIMEOUT;
|
||||||
|
PTimeout->QuadPart = (INT64)InterruptTime - (INT64)ExpirationTime;
|
||||||
|
}
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
/* I/O queue */
|
/* I/O queue */
|
||||||
|
#define FSP_IOQ_USE_QEVENT
|
||||||
|
#define FSP_IOQ_PROCESS_NO_CANCEL
|
||||||
#define FspIoqTimeout ((PIRP)1)
|
#define FspIoqTimeout ((PIRP)1)
|
||||||
#define FspIoqCancelled ((PIRP)2)
|
#define FspIoqCancelled ((PIRP)2)
|
||||||
#define FspIoqPostIrp(Q, I, R) FspIoqPostIrpEx(Q, I, FALSE, R)
|
#define FspIoqPostIrp(Q, I, R) FspIoqPostIrpEx(Q, I, FALSE, R)
|
||||||
@ -594,7 +793,11 @@ typedef struct
|
|||||||
{
|
{
|
||||||
KSPIN_LOCK SpinLock;
|
KSPIN_LOCK SpinLock;
|
||||||
BOOLEAN Stopped;
|
BOOLEAN Stopped;
|
||||||
|
#if defined(FSP_IOQ_USE_QEVENT)
|
||||||
|
FSP_QEVENT PendingIrpEvent;
|
||||||
|
#else
|
||||||
KEVENT PendingIrpEvent;
|
KEVENT PendingIrpEvent;
|
||||||
|
#endif
|
||||||
LIST_ENTRY PendingIrpList, ProcessIrpList, RetriedIrpList;
|
LIST_ENTRY PendingIrpList, ProcessIrpList, RetriedIrpList;
|
||||||
IO_CSQ PendingIoCsq, ProcessIoCsq, RetriedIoCsq;
|
IO_CSQ PendingIoCsq, ProcessIoCsq, RetriedIoCsq;
|
||||||
ULONG IrpTimeout;
|
ULONG IrpTimeout;
|
||||||
@ -649,45 +852,53 @@ VOID FspMetaCacheInvalidateItem(FSP_META_CACHE *MetaCache, UINT64 ItemIndex);
|
|||||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'W', METHOD_NEITHER, FILE_ANY_ACCESS)
|
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'W', METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
#define FSP_FSCTL_WORK_BEST_EFFORT \
|
#define FSP_FSCTL_WORK_BEST_EFFORT \
|
||||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'w', METHOD_NEITHER, FILE_ANY_ACCESS)
|
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'w', METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
#define FSP_FSCTL_TRANSACT_REQ_ALIGNMENT 16
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FspIopRequestMustSucceed = 0x01,
|
FspIopCreateRequestMustSucceedFlag = 0x01,
|
||||||
FspIopRequestNonPaged = 0x02,
|
FspIopCreateRequestNonPagedFlag = 0x02,
|
||||||
|
FspIopCreateRequestWorkItemFlag = 0x04,
|
||||||
|
};
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FspIopRequestExtraContext = 4,
|
||||||
};
|
};
|
||||||
#define FspIopCreateRequest(I, F, E, P) \
|
|
||||||
FspIopCreateRequestFunnel(I, F, E, 0, 0, P)
|
|
||||||
#define FspIopCreateRequestMustSucceed(I, F, E, P)\
|
|
||||||
FspIopCreateRequestFunnel(I, F, E, 0, FspIopRequestMustSucceed, P)
|
|
||||||
#define FspIopCreateRequestEx(I, F, E, RF, P)\
|
|
||||||
FspIopCreateRequestFunnel(I, F, E, RF, 0, P)
|
|
||||||
#define FspIopCreateRequestMustSucceedEx(I, F, E, RF, P)\
|
|
||||||
FspIopCreateRequestFunnel(I, F, E, RF, FspIopRequestMustSucceed, P)
|
|
||||||
#define FspIopCreateRequestWorkItem(I, E, RF, P)\
|
|
||||||
FspIopCreateRequestFunnel(I, 0, E, RF, FspIopRequestNonPaged, P)
|
|
||||||
#define FspIopRequestContext(Request, I)\
|
|
||||||
(*FspIopRequestContextAddress(Request, I))
|
|
||||||
#define FspIopPostWorkRequest(D, R) FspIopPostWorkRequestFunnel(D, R, FALSE)
|
|
||||||
#define FspIopPostWorkRequestBestEffort(D, R)\
|
|
||||||
FspIopPostWorkRequestFunnel(D, 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 NTSTATUS FSP_IOP_REQUEST_WORK(
|
||||||
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN CanWait);
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FSP_IOP_REQUEST_WORK *WorkRoutine;
|
||||||
|
WORK_QUEUE_ITEM WorkQueueItem;
|
||||||
|
} FSP_FSCTL_TRANSACT_REQ_WORK_ITEM;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
FSP_IOP_REQUEST_FINI *RequestFini;
|
FSP_IOP_REQUEST_FINI *RequestFini;
|
||||||
PVOID Context[4];
|
PVOID Context[4 + 1/*FspIopRequestExtraContext*/];
|
||||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||||
__declspec(align(REQ_ALIGN_SIZE)) UINT8 RequestBuf[];
|
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *WorkItem;
|
||||||
|
__declspec(align(FSP_FSCTL_TRANSACT_REQ_ALIGNMENT)) UINT8 RequestBuf[];
|
||||||
} FSP_FSCTL_TRANSACT_REQ_HEADER;
|
} FSP_FSCTL_TRANSACT_REQ_HEADER;
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FSCTL_TRANSACT_REQ_HEADER) <= 64,
|
||||||
|
"sizeof(FSP_FSCTL_TRANSACT_REQ_HEADER) assumed less or equal to 64; "
|
||||||
|
"see FSP_FSCTL_TRANSACT_REQ_SIZEMAX");
|
||||||
static inline
|
static inline
|
||||||
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
|
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
|
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
|
||||||
return &RequestHeader->Context[I];
|
return &RequestHeader->Context[I];
|
||||||
}
|
}
|
||||||
|
static inline
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *FspIopRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
|
||||||
|
return RequestHeader->WorkItem;
|
||||||
|
}
|
||||||
NTSTATUS FspIopCreateRequestFunnel(
|
NTSTATUS FspIopCreateRequestFunnel(
|
||||||
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_IOP_REQUEST_FINI *RequestFini,
|
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_IOP_REQUEST_FINI *RequestFini,
|
||||||
ULONG Flags, FSP_FSCTL_TRANSACT_REQ **PRequest);
|
ULONG Flags, FSP_FSCTL_TRANSACT_REQ **PRequest);
|
||||||
|
NTSTATUS FspIopCreateRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
VOID FspIopResetRequest(FSP_FSCTL_TRANSACT_REQ *Request, FSP_IOP_REQUEST_FINI *RequestFini);
|
VOID FspIopResetRequest(FSP_FSCTL_TRANSACT_REQ *Request, FSP_IOP_REQUEST_FINI *RequestFini);
|
||||||
NTSTATUS FspIopPostWorkRequestFunnel(PDEVICE_OBJECT DeviceObject,
|
NTSTATUS FspIopPostWorkRequestFunnel(PDEVICE_OBJECT DeviceObject,
|
||||||
@ -696,6 +907,7 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference);
|
|||||||
VOID FspIopCompleteCanceledIrp(PIRP Irp);
|
VOID FspIopCompleteCanceledIrp(PIRP Irp);
|
||||||
BOOLEAN FspIopRetryPrepareIrp(PIRP Irp, NTSTATUS *PResult);
|
BOOLEAN FspIopRetryPrepareIrp(PIRP Irp, NTSTATUS *PResult);
|
||||||
BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, NTSTATUS *PResult);
|
BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, NTSTATUS *PResult);
|
||||||
|
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
|
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
|
||||||
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
|
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
@ -709,17 +921,26 @@ VOID FspIrpDeleteRequest(PIRP Irp)
|
|||||||
FspIrpSetRequest(Irp, 0);
|
FspIrpSetRequest(Irp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#define FspIopCreateRequest(I, F, E, P) \
|
||||||
|
FspIopCreateRequestFunnel(I, F, E, 0, 0, P)
|
||||||
|
#define FspIopCreateRequestMustSucceed(I, F, E, P)\
|
||||||
|
FspIopCreateRequestFunnel(I, F, E, 0, FspIopCreateRequestMustSucceedFlag, P)
|
||||||
|
#define FspIopCreateRequestEx(I, F, E, RF, P)\
|
||||||
|
FspIopCreateRequestFunnel(I, F, E, RF, 0, P)
|
||||||
|
#define FspIopCreateRequestMustSucceedEx(I, F, E, RF, P)\
|
||||||
|
FspIopCreateRequestFunnel(I, F, E, RF, FspIopCreateRequestMustSucceedFlag, P)
|
||||||
|
#define FspIopCreateRequestAndWorkItem(I, E, RF, P)\
|
||||||
|
FspIopCreateRequestFunnel(I, 0, E, RF, FspIopCreateRequestWorkItemFlag, P)
|
||||||
|
#define FspIopRequestContext(Request, I)\
|
||||||
|
(*FspIopRequestContextAddress(Request, I))
|
||||||
|
#define FspIopPostWorkRequest(D, R) FspIopPostWorkRequestFunnel(D, R, FALSE)
|
||||||
|
#define FspIopPostWorkRequestBestEffort(D, R)\
|
||||||
|
FspIopPostWorkRequestFunnel(D, R, TRUE)
|
||||||
|
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
|
||||||
|
|
||||||
/* work queue processing */
|
/* work queue processing */
|
||||||
enum
|
|
||||||
{
|
|
||||||
FspWqRequestWorkRoutine = 3,
|
|
||||||
};
|
|
||||||
typedef NTSTATUS FSP_WQ_REQUEST_WORK(
|
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
|
||||||
BOOLEAN CanWait);
|
|
||||||
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
||||||
FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
|
FSP_IOP_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
|
||||||
BOOLEAN CreateAndPost);
|
BOOLEAN CreateAndPost);
|
||||||
VOID FspWqPostIrpWorkItem(PIRP Irp);
|
VOID FspWqPostIrpWorkItem(PIRP Irp);
|
||||||
#define FspWqCreateIrpWorkItem(I, RW, RF)\
|
#define FspWqCreateIrpWorkItem(I, RW, RF)\
|
||||||
@ -842,7 +1063,7 @@ static inline
|
|||||||
BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING String)
|
BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING String)
|
||||||
{
|
{
|
||||||
return RtlPrefixUnicodeString(&FspFsvolDeviceExtension(DeviceObject)->VolumePrefix, String,
|
return RtlPrefixUnicodeString(&FspFsvolDeviceExtension(DeviceObject)->VolumePrefix, String,
|
||||||
FSP_VOLUME_PREFIX_CASE_INS);
|
TRUE);
|
||||||
}
|
}
|
||||||
NTSTATUS FspDeviceCopyList(
|
NTSTATUS FspDeviceCopyList(
|
||||||
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
|
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
|
||||||
@ -897,6 +1118,12 @@ enum
|
|||||||
FspFileNodeFileKind = 'BZ',
|
FspFileNodeFileKind = 'BZ',
|
||||||
};
|
};
|
||||||
enum
|
enum
|
||||||
|
{
|
||||||
|
FspFileNodeSharingViolationGeneral = 'G',
|
||||||
|
FspFileNodeSharingViolationMainFile = 'M',
|
||||||
|
FspFileNodeSharingViolationStream = 'S',
|
||||||
|
};
|
||||||
|
enum
|
||||||
{
|
{
|
||||||
FspFileNodeAcquireMain = 1,
|
FspFileNodeAcquireMain = 1,
|
||||||
FspFileNodeAcquirePgio = 2,
|
FspFileNodeAcquirePgio = 2,
|
||||||
@ -944,6 +1171,9 @@ typedef struct FSP_FILE_NODE
|
|||||||
ULONG StreamInfoChangeNumber;
|
ULONG StreamInfoChangeNumber;
|
||||||
BOOLEAN TruncateOnClose;
|
BOOLEAN TruncateOnClose;
|
||||||
FILE_LOCK FileLock;
|
FILE_LOCK FileLock;
|
||||||
|
#if (NTDDI_VERSION < NTDDI_WIN8)
|
||||||
|
OPLOCK Oplock;
|
||||||
|
#endif
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
PVOID LazyWriteThread;
|
PVOID LazyWriteThread;
|
||||||
@ -1004,17 +1234,49 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
|||||||
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
||||||
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
||||||
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
||||||
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
static inline
|
||||||
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult);
|
VOID FspFileNodeAcquireSharedForeign(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
ExAcquireResourceSharedLite(FileNode->Header.Resource, TRUE);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
VOID FspFileNodeAcquireExclusiveForeign(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
ExAcquireResourceExclusiveLite(FileNode->Header.Resource, TRUE);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
if (0 != FileNode->MainFileNode)
|
||||||
|
FileNode = FileNode->MainFileNode;
|
||||||
|
ExReleaseResourceLite(FileNode->Header.Resource);
|
||||||
|
}
|
||||||
|
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||||
|
UINT32 GrantedAccess, UINT32 ShareAccess,
|
||||||
|
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
|
||||||
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||||
PBOOLEAN PDeletePending);
|
PBOOLEAN PDeletePending);
|
||||||
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
||||||
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
|
||||||
|
PFILE_OBJECT FileObject, /* non-0 to remove share access */
|
||||||
|
BOOLEAN HandleCleanup); /* TRUE to decrement handle count */
|
||||||
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
||||||
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
|
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
|
||||||
|
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode);
|
||||||
|
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
|
PIRP OplockIrp,
|
||||||
|
FSP_FILE_NODE *FileNode,
|
||||||
|
ULONG AcquireFlags,
|
||||||
|
PUNICODE_STRING StreamFileName);
|
||||||
|
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
|
||||||
|
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
|
||||||
|
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
|
||||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||||
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
|
|
||||||
PUNICODE_STRING FileName, BOOLEAN SubpathOnly);
|
|
||||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
@ -1113,6 +1375,90 @@ BOOLEAN FspMainFileOpenCheck(PIRP Irp)
|
|||||||
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
||||||
#define FspFileNodeDereferenceStreamInfo(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)
|
||||||
|
#if (NTDDI_VERSION < NTDDI_WIN8)
|
||||||
|
#define FspFileNodeAddrOfOplock(N) (&(N)->Oplock)
|
||||||
|
#else
|
||||||
|
#define FspFileNodeAddrOfOplock(N) (&(N)->Header.Oplock)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* oplock support */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FSP_FILE_NODE *FileNode;
|
||||||
|
ULONG AcquireFlags;
|
||||||
|
PVOID PrepareContext;
|
||||||
|
} FSP_FILE_NODE_OPLOCK_CONTEXT;
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileNodeOplockFsctl(FSP_FILE_NODE *FileNode, PIRP Irp, ULONG OpenCount)
|
||||||
|
{
|
||||||
|
return FspOplockFsctrl(FspFileNodeAddrOfOplock(FileNode), Irp, OpenCount);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
BOOLEAN FspFileNodeOplockIsBatch(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
return FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(FileNode));
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
BOOLEAN FspFileNodeOplockIsHandle(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
return FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(FileNode));
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileNodeOplockCheck(FSP_FILE_NODE *FileNode, PIRP Irp)
|
||||||
|
{
|
||||||
|
return FspCheckOplock(FspFileNodeAddrOfOplock(FileNode), Irp, 0, 0, 0);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileNodeOplockCheckEx(FSP_FILE_NODE *FileNode, PIRP Irp, ULONG Flags)
|
||||||
|
{
|
||||||
|
return FspCheckOplockEx(FspFileNodeAddrOfOplock(FileNode), Irp, Flags, 0, 0, 0);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileNodeOplockBreakHandle(FSP_FILE_NODE *FileNode, PIRP Irp, ULONG Flags)
|
||||||
|
{
|
||||||
|
return FspOplockBreakH(FspFileNodeAddrOfOplock(FileNode), Irp, Flags, 0, 0, 0);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileNodeOplockCheckAsyncEx(
|
||||||
|
FSP_FILE_NODE *FileNode, ULONG AcquireFlags, PVOID PrepareContext,
|
||||||
|
PIRP Irp,
|
||||||
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
||||||
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine)
|
||||||
|
{
|
||||||
|
FSP_FILE_NODE_OPLOCK_CONTEXT OplockContext;
|
||||||
|
NTSTATUS Result;
|
||||||
|
OplockContext.FileNode = FileNode;
|
||||||
|
OplockContext.AcquireFlags = AcquireFlags;
|
||||||
|
OplockContext.PrepareContext = PrepareContext;
|
||||||
|
Result = FspCheckOplock(
|
||||||
|
FspFileNodeAddrOfOplock(FileNode),
|
||||||
|
Irp,
|
||||||
|
&OplockContext,
|
||||||
|
CompletionRoutine,
|
||||||
|
PostIrpRoutine);
|
||||||
|
#if DBG
|
||||||
|
if (STATUS_SUCCESS == Result && DEBUGTEST(10))
|
||||||
|
{
|
||||||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
PostIrpRoutine(&OplockContext, Irp);
|
||||||
|
CompletionRoutine(&OplockContext, Irp);
|
||||||
|
Result = STATUS_PENDING;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
PVOID FspFileNodeReleaseForOplock(FSP_FILE_NODE_OPLOCK_CONTEXT *OplockContext)
|
||||||
|
{
|
||||||
|
FspFileNodeReleaseF(OplockContext->FileNode, OplockContext->AcquireFlags);
|
||||||
|
return OplockContext->PrepareContext;
|
||||||
|
}
|
||||||
|
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
|
||||||
|
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||||
|
#define FspFileNodeOplockCheckAsync(FileNode, AcquireFlags, PrepareContext, Irp)\
|
||||||
|
FspFileNodeOplockCheckAsyncEx(FileNode, AcquireFlags, (PVOID)(UINT_PTR)PrepareContext, Irp,\
|
||||||
|
FspFileNodeOplockComplete,FspFileNodeOplockPrepare)
|
||||||
|
|
||||||
/* multiversion support */
|
/* multiversion support */
|
||||||
typedef
|
typedef
|
||||||
@ -1144,16 +1490,6 @@ extern ULONG FspMvMdlMappingNoWrite;
|
|||||||
* Fixes
|
* 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! */
|
/* RtlEqualMemory: this is defined as memcmp, which does not exist on Win7 x86! */
|
||||||
#undef RtlEqualMemory
|
#undef RtlEqualMemory
|
||||||
static inline
|
static inline
|
||||||
|
697
src/sys/file.c
@ -31,17 +31,28 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
|||||||
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
||||||
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
||||||
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
||||||
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||||
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult);
|
UINT32 GrantedAccess, UINT32 ShareAccess,
|
||||||
|
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
|
||||||
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||||
PBOOLEAN PDeletePending);
|
PBOOLEAN PDeletePending);
|
||||||
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
||||||
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
|
||||||
|
PFILE_OBJECT FileObject, /* non-0 to remove share access */
|
||||||
|
BOOLEAN HandleCleanup); /* TRUE to decrement handle count */
|
||||||
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
||||||
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
|
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
|
||||||
|
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode);
|
||||||
|
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
|
PIRP OplockIrp,
|
||||||
|
FSP_FILE_NODE *FileNode,
|
||||||
|
ULONG AcquireFlags,
|
||||||
|
PUNICODE_STRING StreamFileName);
|
||||||
|
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
|
||||||
|
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
|
||||||
|
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
|
||||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||||
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
|
|
||||||
PUNICODE_STRING FileName, BOOLEAN SubpathOnly);
|
|
||||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
@ -82,6 +93,8 @@ NTSTATUS FspMainFileOpen(
|
|||||||
NTSTATUS FspMainFileClose(
|
NTSTATUS FspMainFileClose(
|
||||||
HANDLE MainFileHandle,
|
HANDLE MainFileHandle,
|
||||||
PFILE_OBJECT MainFileObject);
|
PFILE_OBJECT MainFileObject);
|
||||||
|
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
|
||||||
|
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspFileNodeCopyList)
|
#pragma alloc_text(PAGE, FspFileNodeCopyList)
|
||||||
@ -101,8 +114,10 @@ NTSTATUS FspMainFileClose(
|
|||||||
#pragma alloc_text(PAGE, FspFileNodeCleanupComplete)
|
#pragma alloc_text(PAGE, FspFileNodeCleanupComplete)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeClose)
|
#pragma alloc_text(PAGE, FspFileNodeClose)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeFlushAndPurgeCache)
|
#pragma alloc_text(PAGE, FspFileNodeFlushAndPurgeCache)
|
||||||
|
#pragma alloc_text(PAGE, FspFileNodeOverwriteStreams)
|
||||||
|
#pragma alloc_text(PAGE, FspFileNodeCheckBatchOplocksOnAllStreams)
|
||||||
|
#pragma alloc_text(PAGE, FspFileNodeRenameCheck)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeRename)
|
#pragma alloc_text(PAGE, FspFileNodeRename)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeHasOpenHandles)
|
|
||||||
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
|
||||||
@ -126,6 +141,8 @@ NTSTATUS FspMainFileClose(
|
|||||||
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
|
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
|
||||||
#pragma alloc_text(PAGE, FspMainFileOpen)
|
#pragma alloc_text(PAGE, FspMainFileOpen)
|
||||||
#pragma alloc_text(PAGE, FspMainFileClose)
|
#pragma alloc_text(PAGE, FspMainFileClose)
|
||||||
|
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
|
||||||
|
#pragma alloc_text(PAGE, FspFileNodeOplockComplete)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FSP_FILE_NODE_GET_FLAGS() \
|
#define FSP_FILE_NODE_GET_FLAGS() \
|
||||||
@ -217,6 +234,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
|
|||||||
RtlInitEmptyUnicodeString(&FileNode->FileName, FileNode->FileNameBuf, (USHORT)ExtraSize);
|
RtlInitEmptyUnicodeString(&FileNode->FileName, FileNode->FileNameBuf, (USHORT)ExtraSize);
|
||||||
|
|
||||||
FsRtlInitializeFileLock(&FileNode->FileLock, FspFileNodeCompleteLockIrp, 0);
|
FsRtlInitializeFileLock(&FileNode->FileLock, FspFileNodeCompleteLockIrp, 0);
|
||||||
|
FsRtlInitializeOplock(FspFileNodeAddrOfOplock(FileNode));
|
||||||
|
|
||||||
*PFileNode = FileNode;
|
*PFileNode = FileNode;
|
||||||
|
|
||||||
@ -230,6 +248,7 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
|
|||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
|
|
||||||
|
FsRtlUninitializeOplock(FspFileNodeAddrOfOplock(FileNode));
|
||||||
FsRtlUninitializeFileLock(&FileNode->FileLock);
|
FsRtlUninitializeFileLock(&FileNode->FileLock);
|
||||||
|
|
||||||
FsRtlTeardownPerStreamContexts(&FileNode->Header);
|
FsRtlTeardownPerStreamContexts(&FileNode->Header);
|
||||||
@ -444,8 +463,9 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
|||||||
FSP_FILE_NODE_CLR_FLAGS();
|
FSP_FILE_NODE_CLR_FLAGS();
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||||
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult)
|
UINT32 GrantedAccess, UINT32 ShareAccess,
|
||||||
|
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Attempt to insert our FileNode into the volume device's generic table.
|
* Attempt to insert our FileNode into the volume device's generic table.
|
||||||
@ -462,6 +482,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
BOOLEAN Inserted, DeletePending;
|
BOOLEAN Inserted, DeletePending;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
*PSharingViolationReason = FspFileNodeSharingViolationGeneral;
|
||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -489,6 +511,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
FlagOn(GrantedAccess,
|
FlagOn(GrantedAccess,
|
||||||
FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE))
|
FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE))
|
||||||
{
|
{
|
||||||
|
OpenedFileNode = FileNode->MainFileNode;
|
||||||
|
*PSharingViolationReason = FspFileNodeSharingViolationMainFile;
|
||||||
Result = STATUS_SHARING_VIOLATION;
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@ -539,6 +563,7 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
|
|
||||||
if (FlagOn(GrantedAccess, DELETE))
|
if (FlagOn(GrantedAccess, DELETE))
|
||||||
{
|
{
|
||||||
|
*PSharingViolationReason = FspFileNodeSharingViolationStream;
|
||||||
Result = STATUS_SHARING_VIOLATION;
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@ -593,13 +618,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
|||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) && STATUS_SHARING_VIOLATION != Result)
|
||||||
{
|
|
||||||
if (0 != PResult)
|
|
||||||
*PResult = Result;
|
|
||||||
|
|
||||||
OpenedFileNode = 0;
|
OpenedFileNode = 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != OpenedFileNode)
|
if (0 != OpenedFileNode)
|
||||||
{
|
{
|
||||||
@ -610,7 +630,9 @@ exit:
|
|||||||
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
return OpenedFileNode;
|
*POpenedFileNode = OpenedFileNode;
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||||
@ -695,9 +717,11 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
|
|||||||
{
|
{
|
||||||
PTruncateSize = &TruncateSize;
|
PTruncateSize = &TruncateSize;
|
||||||
|
|
||||||
if (0 == --FileNode->OpenCount)
|
|
||||||
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
|
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
|
||||||
&DeletedFromContextTable);
|
&DeletedFromContextTable);
|
||||||
|
ASSERT(DeletedFromContextTable);
|
||||||
|
|
||||||
|
FileNode->OpenCount = 0;
|
||||||
}
|
}
|
||||||
else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
|
else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
|
||||||
{
|
{
|
||||||
@ -718,7 +742,9 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
|
|||||||
FspFileNodeDereference(FileNode);
|
FspFileNodeDereference(FileNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
|
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
|
||||||
|
PFILE_OBJECT FileObject, /* non-0 to remove share access */
|
||||||
|
BOOLEAN HandleCleanup) /* TRUE to decrement handle count */
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Close the FileNode. If the OpenCount becomes zero remove it
|
* Close the FileNode. If the OpenCount becomes zero remove it
|
||||||
@ -734,9 +760,36 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
|
|||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
if (0 != FileObject)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HandleCleanup)
|
||||||
|
FileNode->HandleCount--;
|
||||||
|
|
||||||
if (0 < FileNode->OpenCount && 0 == --FileNode->OpenCount)
|
if (0 < FileNode->OpenCount && 0 == --FileNode->OpenCount)
|
||||||
|
{
|
||||||
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
|
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
|
||||||
&DeletedFromContextTable);
|
&DeletedFromContextTable);
|
||||||
|
ASSERT(DeletedFromContextTable);
|
||||||
|
}
|
||||||
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
@ -801,57 +854,440 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
|||||||
return IoStatus.Status;
|
return IoStatus.Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
|
#define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\
|
||||||
|
FSP_FILE_NODE *DescendantFileNode;\
|
||||||
|
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
|
||||||
|
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
|
||||||
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;\
|
||||||
|
DescendantFileNodes = DescendantFileNodeArray;\
|
||||||
|
DescendantFileNodeCount = 0;\
|
||||||
|
memset(&RestartKey, 0, sizeof RestartKey);\
|
||||||
|
for (;;) \
|
||||||
|
{ \
|
||||||
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
|
||||||
|
FILENAME, FALSE, &RestartKey);\
|
||||||
|
if (0 == DescendantFileNode) \
|
||||||
|
break; \
|
||||||
|
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
|
||||||
|
__VA_ARGS__; \
|
||||||
|
if (REFERENCE) \
|
||||||
|
FspFileNodeReference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
|
||||||
|
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)\
|
||||||
|
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;\
|
||||||
|
DescendantFileNodeCount++; \
|
||||||
|
} \
|
||||||
|
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount ||\
|
||||||
|
DEBUGTEST_EX(0 != DescendantFileNodeCount, 10, FALSE)) \
|
||||||
|
{ \
|
||||||
|
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));\
|
||||||
|
DescendantFileNodeIndex = 0; \
|
||||||
|
memset(&RestartKey, 0, sizeof RestartKey);\
|
||||||
|
for (;;) \
|
||||||
|
{ \
|
||||||
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
|
||||||
|
FILENAME, FALSE, &RestartKey);\
|
||||||
|
if (0 == DescendantFileNode)\
|
||||||
|
break; \
|
||||||
|
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
|
||||||
|
__VA_ARGS__; \
|
||||||
|
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;\
|
||||||
|
DescendantFileNodeIndex++; \
|
||||||
|
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);\
|
||||||
|
} \
|
||||||
|
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);\
|
||||||
|
} \
|
||||||
|
((VOID)0)
|
||||||
|
#define SCATTER_DESCENDANTS(REFERENCE) \
|
||||||
|
if (REFERENCE) \
|
||||||
|
{ \
|
||||||
|
for ( \
|
||||||
|
DescendantFileNodeIndex = 0;\
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;\
|
||||||
|
DescendantFileNodeIndex++) \
|
||||||
|
{ \
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];\
|
||||||
|
FspFileNodeDereference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (DescendantFileNodeArray != DescendantFileNodes)\
|
||||||
|
FspFree(DescendantFileNodes); \
|
||||||
|
((VOID)0)
|
||||||
|
|
||||||
|
VOID FspFileNodeOverwriteStreams(FSP_FILE_NODE *FileNode)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Called during Create processing. The device rename resource has been acquired shared.
|
||||||
|
* No concurrent renames are allowed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
ASSERT(0 == FileNode->MainFileNode);
|
||||||
|
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
||||||
|
USHORT FileNameLength = FileNode->FileName.Length;
|
||||||
|
|
||||||
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
GATHER_DESCENDANTS(&FileNode->FileName, FALSE,
|
||||||
|
if (DescendantFileNode->FileName.Length > FileNameLength &&
|
||||||
|
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
|
||||||
|
break;
|
||||||
|
if (FileNode == DescendantFileNode || 0 >= DescendantFileNode->HandleCount)
|
||||||
|
continue;
|
||||||
|
);
|
||||||
|
|
||||||
|
/* mark any open named streams as DeletePending */
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
DescendantFileNode->DeletePending = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
SCATTER_DESCENDANTS(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject,
|
||||||
|
PIRP OplockIrp,
|
||||||
|
FSP_FILE_NODE *FileNode,
|
||||||
|
ULONG AcquireFlags,
|
||||||
|
PUNICODE_STRING StreamFileName)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Called during Create processing. The device rename resource has been acquired shared.
|
||||||
|
* No concurrent renames are allowed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
ASSERT(0 == FileNode->MainFileNode);
|
||||||
|
|
||||||
|
USHORT FileNameLength = FileNode->FileName.Length;
|
||||||
|
BOOLEAN CaseInsensitive = !FspFsvolDeviceExtension(FsvolDeviceObject)->
|
||||||
|
VolumeParams.CaseSensitiveSearch;
|
||||||
|
ULONG IsBatchOplock, IsHandleOplock;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
GATHER_DESCENDANTS(&FileNode->FileName, TRUE,
|
||||||
|
if (DescendantFileNode->FileName.Length > FileNameLength &&
|
||||||
|
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
|
||||||
|
break;
|
||||||
|
if (0 >= DescendantFileNode->HandleCount)
|
||||||
|
continue;
|
||||||
|
if (0 != StreamFileName)
|
||||||
|
{
|
||||||
|
if (DescendantFileNode != FileNode &&
|
||||||
|
0 != FspFileNameCompare(&DescendantFileNode->FileName, StreamFileName,
|
||||||
|
CaseInsensitive, 0))
|
||||||
|
continue;
|
||||||
|
});
|
||||||
|
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/* break any Batch or Handle oplocks on descendants */
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
|
||||||
|
if (FspFileNodeOplockIsBatch(DescendantFileNode))
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockCheckEx(DescendantFileNode, OplockIrp,
|
||||||
|
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
|
||||||
|
if (STATUS_SUCCESS == Result0)
|
||||||
|
OplockIrp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
|
||||||
|
else
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
|
||||||
|
{
|
||||||
|
OplockIrp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
|
||||||
|
DescendantFileNodes[DescendantFileNodeIndex] =
|
||||||
|
(PVOID)((UINT_PTR)DescendantFileNode | 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (FspFileNodeOplockIsHandle(DescendantFileNode))
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp,
|
||||||
|
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
|
||||||
|
if (STATUS_SUCCESS == Result0)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
|
||||||
|
DescendantFileNodes[DescendantFileNodeIndex] =
|
||||||
|
(PVOID)((UINT_PTR)DescendantFileNode | 4);
|
||||||
|
else
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release the FileNode so that we can safely wait without deadlocks */
|
||||||
|
FspFileNodeReleaseF(FileNode, AcquireFlags);
|
||||||
|
|
||||||
|
/* wait for oplock breaks to finish */
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
IsBatchOplock = (UINT_PTR)DescendantFileNode & 2;
|
||||||
|
IsHandleOplock = (UINT_PTR)DescendantFileNode & 4;
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
|
||||||
|
|
||||||
|
if (IsBatchOplock)
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockCheck(DescendantFileNode, OplockIrp);
|
||||||
|
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
|
||||||
|
if (STATUS_SUCCESS != Result0)
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (IsHandleOplock)
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, 0);
|
||||||
|
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
|
||||||
|
if (STATUS_SUCCESS != Result0)
|
||||||
|
Result = STATUS_SHARING_VIOLATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCATTER_DESCENDANTS(TRUE);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
|
||||||
|
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
|
||||||
|
PUNICODE_STRING FileName, BOOLEAN CheckingOldName)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
ULONG HasHandles, IsBatchOplock, IsHandleOplock;
|
||||||
|
|
||||||
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
if (CheckingOldName && !FileNode->IsDirectory && 1 == FileNode->HandleCount)
|
||||||
|
{
|
||||||
|
/* quick exit */
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
GATHER_DESCENDANTS(FileName, TRUE,
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode |
|
||||||
|
(0 < DescendantFileNode->HandleCount)));
|
||||||
|
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
if (0 == DescendantFileNodeCount)
|
||||||
|
{
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this point all descendant FileNode's are enumerated and referenced.
|
||||||
|
* There can be no new FileNode's because Rename has acquired the device's
|
||||||
|
* "rename" resource exclusively, which disallows new Opens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!CheckingOldName)
|
||||||
|
{
|
||||||
|
/* replaced file cannot be a directory or mapped as an image */
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Windows file systems do not allow the replaced file to be a directory.
|
||||||
|
* However POSIX allows this (when the directory is empty).
|
||||||
|
*
|
||||||
|
* For this reason we will allow the case where the replaced file is a directory
|
||||||
|
* (without any open files within it). The user mode file system can always fail
|
||||||
|
* such requests if it wants.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((DescendantFileNode->FileName.Length > FileName->Length &&
|
||||||
|
L'\\' == DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)]) ||
|
||||||
|
(0 != DescendantFileNode->NonPaged->SectionObjectPointers.ImageSectionObject &&
|
||||||
|
!MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers,
|
||||||
|
MmFlushForDelete)))
|
||||||
|
{
|
||||||
|
/* release the FileNode in case of failure! */
|
||||||
|
FspFileNodeReleaseF(FileNode, AcquireFlags);
|
||||||
|
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* break any Batch or Handle oplocks on descendants */
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
HasHandles = (UINT_PTR)DescendantFileNode & 1;
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
|
||||||
|
|
||||||
|
if (!HasHandles)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (FspFileNodeOplockIsBatch(DescendantFileNode))
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockCheckEx(DescendantFileNode, OplockIrp,
|
||||||
|
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
|
||||||
|
if (STATUS_SUCCESS == Result0)
|
||||||
|
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
|
||||||
|
else
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
|
||||||
|
{
|
||||||
|
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
|
||||||
|
DescendantFileNodes[DescendantFileNodeIndex] =
|
||||||
|
(PVOID)((UINT_PTR)DescendantFileNode | 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (FspFileNodeOplockIsHandle(DescendantFileNode))
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp,
|
||||||
|
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
|
||||||
|
if (STATUS_SUCCESS == Result0)
|
||||||
|
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
|
||||||
|
else
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
|
||||||
|
{
|
||||||
|
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
|
||||||
|
DescendantFileNodes[DescendantFileNodeIndex] =
|
||||||
|
(PVOID)((UINT_PTR)DescendantFileNode | 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result || !NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
/* release the FileNode so that we can safely wait without deadlocks */
|
||||||
|
FspFileNodeReleaseF(FileNode, AcquireFlags);
|
||||||
|
|
||||||
|
/* wait for oplock breaks to finish */
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
IsBatchOplock = (UINT_PTR)DescendantFileNode & 2;
|
||||||
|
IsHandleOplock = (UINT_PTR)DescendantFileNode & 4;
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
|
||||||
|
|
||||||
|
if (IsBatchOplock)
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockCheck(DescendantFileNode, OplockIrp);
|
||||||
|
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
|
||||||
|
if (STATUS_SUCCESS != Result0)
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (IsHandleOplock)
|
||||||
|
{
|
||||||
|
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, 0);
|
||||||
|
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
|
||||||
|
if (STATUS_SUCCESS != Result0)
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/* recheck whether there are still files with open handles */
|
||||||
|
memset(&RestartKey, 0, sizeof RestartKey);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
||||||
|
FileName, FALSE, &RestartKey);
|
||||||
|
if (0 == DescendantFileNode)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* if this is the FileNode being renamed then HandleCount must be 1, else 0 */
|
||||||
|
if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount)
|
||||||
|
{
|
||||||
|
/* release the FileNode in case of failure! */
|
||||||
|
FspFileNodeReleaseF(FileNode, AcquireFlags);
|
||||||
|
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
SCATTER_DESCENDANTS(TRUE);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* FspFileNodeRename may block, because it attempts to acquire the Main
|
||||||
|
* resource of descendant file nodes. FspFileNodeRename is called at the
|
||||||
|
* completion path of IRP_MJ_SET_INFORMATION[Rename] and an IRP completion
|
||||||
|
* path should not block, with the notable exception of Rename.
|
||||||
|
*
|
||||||
|
* The original reason that Rename completion is allowed to block was that
|
||||||
|
* it was observed that IoCompleteRequest of a Rename could sometimes
|
||||||
|
* trigger a recursive call into the FSD (likely due to a filter). WinFsp
|
||||||
|
* was modified to accommodate this by allowing this recursive call to
|
||||||
|
* proceed on a different thread.
|
||||||
|
*
|
||||||
|
* Since WinFsp can already accommodate blocking on Rename completions,
|
||||||
|
* it is safe to acquire the Main resource of descendant file nodes.
|
||||||
|
*
|
||||||
|
* Note also that there can only be one rename at a time because of the
|
||||||
|
* device's FileRenameResource.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
||||||
FSP_FILE_NODE *DescendantFileNode;
|
BOOLEAN Deleted, Inserted, AcquireForeign;
|
||||||
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
|
FSP_FILE_NODE *InsertedFileNode;
|
||||||
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
|
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
|
|
||||||
BOOLEAN Deleted, Inserted;
|
|
||||||
USHORT FileNameLength;
|
USHORT FileNameLength;
|
||||||
PWSTR ExternalFileName;
|
PWSTR ExternalFileName;
|
||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
DescendantFileNodes = DescendantFileNodeArray;
|
GATHER_DESCENDANTS(&FileNode->FileName, FALSE, {});
|
||||||
DescendantFileNodes[0] = FileNode;
|
|
||||||
DescendantFileNodeCount = 1;
|
|
||||||
memset(&RestartKey, 0, sizeof RestartKey);
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
|
||||||
&FileNode->FileName, TRUE, &RestartKey);
|
|
||||||
if (0 == DescendantFileNode)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
|
|
||||||
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
|
|
||||||
DescendantFileNodeCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
|
|
||||||
{
|
|
||||||
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;
|
FileNameLength = FileNode->FileName.Length;
|
||||||
for (
|
for (
|
||||||
@ -862,6 +1298,11 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
|
|||||||
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
ASSERT(DescendantFileNode->FileName.Length >= FileNameLength);
|
ASSERT(DescendantFileNode->FileName.Length >= FileNameLength);
|
||||||
|
|
||||||
|
AcquireForeign = DescendantFileNode->FileName.Length > FileNameLength &&
|
||||||
|
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)];
|
||||||
|
if (AcquireForeign)
|
||||||
|
FspFileNodeAcquireExclusiveForeign(DescendantFileNode);
|
||||||
|
|
||||||
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, &Deleted);
|
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, &Deleted);
|
||||||
ASSERT(Deleted);
|
ASSERT(Deleted);
|
||||||
|
|
||||||
@ -885,38 +1326,41 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
|
|||||||
if (0 != ExternalFileName)
|
if (0 != ExternalFileName)
|
||||||
FspFree(ExternalFileName);
|
FspFree(ExternalFileName);
|
||||||
|
|
||||||
FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
|
InsertedFileNode = FspFsvolDeviceInsertContextByName(
|
||||||
|
FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
|
||||||
|
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
|
||||||
|
if (!Inserted)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Handle files that have been Cleanup'ed but not Close'd.
|
||||||
|
* For example, this can happen when the user has mapped and closed a file
|
||||||
|
* or immediately after breaking a Batch oplock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ASSERT(FspFileNodeIsValid(InsertedFileNode));
|
||||||
|
ASSERT(DescendantFileNode != InsertedFileNode);
|
||||||
|
ASSERT(0 == InsertedFileNode->HandleCount);
|
||||||
|
ASSERT(0 != InsertedFileNode->OpenCount);
|
||||||
|
|
||||||
|
InsertedFileNode->OpenCount = 0;
|
||||||
|
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &InsertedFileNode->FileName, &Deleted);
|
||||||
|
ASSERT(Deleted);
|
||||||
|
|
||||||
|
FspFileNodeDereference(InsertedFileNode);
|
||||||
|
|
||||||
|
FspFsvolDeviceInsertContextByName(
|
||||||
|
FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
|
||||||
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
|
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
|
||||||
ASSERT(Inserted);
|
ASSERT(Inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AcquireForeign)
|
||||||
|
FspFileNodeReleaseForeign(DescendantFileNode);
|
||||||
|
}
|
||||||
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
if (DescendantFileNodeArray != DescendantFileNodes)
|
SCATTER_DESCENDANTS(FALSE);
|
||||||
FspFree(DescendantFileNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
|
|
||||||
PUNICODE_STRING FileName, BOOLEAN SubpathOnly)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The ContextByNameTable must be already locked.
|
|
||||||
*/
|
|
||||||
|
|
||||||
PAGED_CODE();
|
|
||||||
|
|
||||||
FSP_FILE_NODE *FileNode;
|
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey = { 0 };
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
FileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, FileName, SubpathOnly,
|
|
||||||
&RestartKey);
|
|
||||||
if (0 == FileNode)
|
|
||||||
return FALSE;
|
|
||||||
if (0 < FileNode->HandleCount)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||||
@ -1009,9 +1453,52 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
|||||||
CcFileObject, (PCC_FILE_SIZES)&FileNode->Header.AllocationSize);
|
CcFileObject, (PCC_FILE_SIZES)&FileNode->Header.AllocationSize);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
DEBUGLOG("FspCcSetFileSizes error: %s", NtStatusSym(Result));
|
/*
|
||||||
DEBUGBREAK_CRIT();
|
* CcSetFileSizes failed. This is a hard case to handle, because it is
|
||||||
CcUninitializeCacheMap(CcFileObject, 0, 0);
|
* usually late in IRP processing. So we have the following strategy.
|
||||||
|
*
|
||||||
|
* Our goal is to completely stop all caching for this FileNode. The idea
|
||||||
|
* is that if some I/O arrives later for this FileNode, CcInitializeCacheMap
|
||||||
|
* will be executed (and possibly fail safely there). In fact we may decide
|
||||||
|
* later to make such CcInitializeCacheMap failures benign (by not using the
|
||||||
|
* cache when we cannot).
|
||||||
|
*
|
||||||
|
* In order to completely stop caching for the FileNode we do the following:
|
||||||
|
*
|
||||||
|
* - We flush the cache using CcFlushCache.
|
||||||
|
* - We purge the cache and uninitialize all PrivateCacheMap's using
|
||||||
|
* CcPurgeCacheSection with UninitializeCacheMaps==TRUE.
|
||||||
|
* - If the SharedCacheMap is still around, we perform an additional
|
||||||
|
* CcUninitializeCacheMap with an UninitializeEvent. At this point
|
||||||
|
* CcUninitializeCacheMap should delete the SharedCacheMap and
|
||||||
|
* signal the UninitializeEvent.
|
||||||
|
*
|
||||||
|
* One potential gotcha is whether there is any possibility for another
|
||||||
|
* system component to delay deletion of the SharedCacheMap and signaling
|
||||||
|
* of the UninitializeEvent. This could result in a deadlock, because we
|
||||||
|
* are already holding the FileNode exclusive and waiting for the
|
||||||
|
* UninitializeEvent. But the thread that would signal our event would have
|
||||||
|
* to first acquire our FileNode. Classic deadlock.
|
||||||
|
*
|
||||||
|
* I believe (but cannot prove) that this deadlock cannot happen. The reason
|
||||||
|
* is that we have flushed and purged the cache and we have closed all
|
||||||
|
* PrivateCacheMap's using this SharedCacheMap. There should be no reason for
|
||||||
|
* any system component to keep the SharedCacheMap around (famous last words).
|
||||||
|
*/
|
||||||
|
|
||||||
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
CACHE_UNINITIALIZE_EVENT UninitializeEvent;
|
||||||
|
|
||||||
|
FspCcFlushCache(CcFileObject->SectionObjectPointer, 0, 0, &IoStatus);
|
||||||
|
CcPurgeCacheSection(CcFileObject->SectionObjectPointer, 0, 0, TRUE);
|
||||||
|
if (0 != CcFileObject->SectionObjectPointer->SharedCacheMap)
|
||||||
|
{
|
||||||
|
UninitializeEvent.Next = 0;
|
||||||
|
KeInitializeEvent(&UninitializeEvent.Event, NotificationEvent, FALSE);
|
||||||
|
BOOLEAN CacheStopped = CcUninitializeCacheMap(CcFileObject, 0, &UninitializeEvent);
|
||||||
|
(VOID)CacheStopped; ASSERT(CacheStopped);
|
||||||
|
KeWaitForSingleObject(&UninitializeEvent.Event, Executive, KernelMode, FALSE, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1231,7 +1718,7 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode,
|
|||||||
UNICODE_STRING Parent, Suffix;
|
UNICODE_STRING Parent, Suffix;
|
||||||
FSP_FILE_NODE *ParentNode;
|
FSP_FILE_NODE *ParentNode;
|
||||||
|
|
||||||
FspUnicodePathSuffix(&FileNode->FileName, &Parent, &Suffix);
|
FspFileNameSuffix(&FileNode->FileName, &Parent, &Suffix);
|
||||||
|
|
||||||
switch (Action)
|
switch (Action)
|
||||||
{
|
{
|
||||||
@ -1428,7 +1915,7 @@ NTSTATUS FspMainFileOpen(
|
|||||||
PFILE_OBJECT MainFileObject;
|
PFILE_OBJECT MainFileObject;
|
||||||
|
|
||||||
/* assert that the supplied name is actually a main file name */
|
/* assert that the supplied name is actually a main file name */
|
||||||
ASSERT(FspUnicodePathIsValid(MainFileName, 0, 0));
|
ASSERT(FspFileNameIsValid(MainFileName, 0, 0));
|
||||||
|
|
||||||
*PMainFileHandle = 0;
|
*PMainFileHandle = 0;
|
||||||
*PMainFileObject = 0;
|
*PMainFileObject = 0;
|
||||||
@ -1570,6 +2057,36 @@ NTSTATUS FspMainFileClose(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_IOP_REQUEST_WORK *WorkRoutine = (FSP_IOP_REQUEST_WORK *)(UINT_PTR)
|
||||||
|
FspFileNodeReleaseForOplock(Context);
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
FSP_FSCTL_STATIC_ASSERT(sizeof(PVOID) == sizeof(VOID (*)(VOID)),
|
||||||
|
"Data and code pointers must have same size!");
|
||||||
|
|
||||||
|
Result = FspWqCreateIrpWorkItem(Irp, WorkRoutine, 0);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
/*
|
||||||
|
* Only way to communicate failure is through ExRaiseStatus.
|
||||||
|
* We will catch it in FspCheckOplock, etc.
|
||||||
|
*/
|
||||||
|
ExRaiseStatus(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (STATUS_SUCCESS == Irp->IoStatus.Status)
|
||||||
|
FspWqPostIrpWorkItem(Irp);
|
||||||
|
else
|
||||||
|
FspIopCompleteIrp(Irp, Irp->IoStatus.Status);
|
||||||
|
}
|
||||||
|
|
||||||
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
|
WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*";
|
||||||
|
|
||||||
// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B}
|
// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B}
|
||||||
|
@ -26,6 +26,8 @@ static NTSTATUS FspFsvolQueryAttributeTagInformation(PFILE_OBJECT FileObject,
|
|||||||
static NTSTATUS FspFsvolQueryBasicInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryBasicInformation(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 FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
|
||||||
|
PVOID *PBuffer, PVOID BufferEnd);
|
||||||
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
||||||
PVOID *PBuffer, PVOID BufferEnd);
|
PVOID *PBuffer, PVOID BufferEnd);
|
||||||
static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
|
||||||
@ -80,6 +82,7 @@ FSP_DRIVER_DISPATCH FspSetInformation;
|
|||||||
#pragma alloc_text(PAGE, FspFsvolQueryAllInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryAllInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolQueryEaInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
|
||||||
@ -119,7 +122,7 @@ enum
|
|||||||
//RequestFileNode = 0,
|
//RequestFileNode = 0,
|
||||||
RequestDeviceObject = 1,
|
RequestDeviceObject = 1,
|
||||||
/* Rename */
|
/* Rename */
|
||||||
RequestAccessToken = 2,
|
RequestSubjectContextOrAccessToken = 2,
|
||||||
RequestProcess = 3,
|
RequestProcess = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -216,6 +219,27 @@ static NTSTATUS FspFsvolQueryBasicInformation(PFILE_OBJECT FileObject,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
|
||||||
|
PVOID *PBuffer, PVOID BufferEnd)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
PFILE_EA_INFORMATION Info = (PFILE_EA_INFORMATION)*PBuffer;
|
||||||
|
|
||||||
|
if ((PVOID)(Info + 1) > BufferEnd)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No EA support currently. We must nevertheless respond to this query
|
||||||
|
* or SRV2 gets unhappy. Just tell them that we have 0 EA's.
|
||||||
|
*/
|
||||||
|
Info->EaSize = 0;
|
||||||
|
|
||||||
|
*PBuffer = (PVOID)(Info + 1);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
||||||
PVOID *PBuffer, PVOID BufferEnd)
|
PVOID *PBuffer, PVOID BufferEnd)
|
||||||
{
|
{
|
||||||
@ -546,7 +570,7 @@ static NTSTATUS FspFsvolQueryStreamInformationSuccess(
|
|||||||
(PUINT8)Response + Response->Size)
|
(PUINT8)Response + Response->Size)
|
||||||
{
|
{
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
return STATUS_INFO_LENGTH_MISMATCH; /* ???: what is the best code to return here? */
|
return STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
|
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)
|
||||||
@ -635,7 +659,8 @@ static NTSTATUS FspFsvolQueryInformation(
|
|||||||
Result = STATUS_INVALID_PARAMETER; /* no compression support */
|
Result = STATUS_INVALID_PARAMETER; /* no compression support */
|
||||||
return Result;
|
return Result;
|
||||||
case FileEaInformation:
|
case FileEaInformation:
|
||||||
Result = STATUS_INVALID_PARAMETER; /* no EA support currently */
|
Result = FspFsvolQueryEaInformation(FileObject, &Buffer, BufferEnd);
|
||||||
|
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
|
||||||
return Result;
|
return Result;
|
||||||
case FileHardLinkInformation:
|
case FileHardLinkInformation:
|
||||||
Result = STATUS_INVALID_PARAMETER; /* no hard link support */
|
Result = STATUS_INVALID_PARAMETER; /* no hard link support */
|
||||||
@ -871,6 +896,9 @@ static NTSTATUS FspFsvolSetAllocationInformation(PFILE_OBJECT FileObject,
|
|||||||
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
|
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
|
||||||
FileNode->TruncateOnClose = TRUE;
|
FileNode->TruncateOnClose = TRUE;
|
||||||
|
|
||||||
|
/* mark the file object as modified */
|
||||||
|
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||||
|
|
||||||
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
|
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,6 +999,9 @@ static NTSTATUS FspFsvolSetEndOfFileInformation(PFILE_OBJECT FileObject,
|
|||||||
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
|
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetInformation.FileInfo);
|
||||||
FileNode->TruncateOnClose = TRUE;
|
FileNode->TruncateOnClose = TRUE;
|
||||||
|
|
||||||
|
/* mark the file object as modified -- FastFat does this only for Allocation though! */
|
||||||
|
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||||
|
|
||||||
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
|
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,10 +1050,37 @@ static NTSTATUS FspFsvolSetDispositionInformation(
|
|||||||
/* cannot delete root directory */
|
/* cannot delete root directory */
|
||||||
return STATUS_CANNOT_DELETE;
|
return STATUS_CANNOT_DELETE;
|
||||||
|
|
||||||
|
retry:
|
||||||
FspFileNodeAcquireExclusive(FileNode, Full);
|
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||||
|
|
||||||
if (Info->DeleteFile)
|
if (Info->DeleteFile)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Perform oplock check.
|
||||||
|
*
|
||||||
|
* It is ok to block our thread during receipt of the SetInformation IRP.
|
||||||
|
* However we cannot acquire the FileNode exclusive and wait for oplock
|
||||||
|
* breaks to complete, because oplock break processing acquires the FileNode
|
||||||
|
* shared.
|
||||||
|
*
|
||||||
|
* Instead we initiate the oplock breaks and then check if any are in progress.
|
||||||
|
* If that is the case we release the FileNode and wait for the oplock breaks
|
||||||
|
* to complete. Once they are complete we retry the whole thing.
|
||||||
|
*/
|
||||||
|
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
|
||||||
|
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result ||
|
||||||
|
DEBUGTEST_EX(NT_SUCCESS(Result), 10, FALSE))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
Result = FspFileNodeOplockCheck(FileNode, Irp);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto unlock_exit;
|
||||||
|
|
||||||
/* make sure no process is mapping the file as an image */
|
/* make sure no process is mapping the file as an image */
|
||||||
Success = MmFlushImageSection(FileObject->SectionObjectPointer, MmFlushForDelete);
|
Success = MmFlushImageSection(FileObject->SectionObjectPointer, MmFlushForDelete);
|
||||||
if (!Success)
|
if (!Success)
|
||||||
@ -1095,17 +1153,19 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
|
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
|
||||||
|
BOOLEAN ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
|
||||||
PFILE_RENAME_INFORMATION Info = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
PFILE_RENAME_INFORMATION Info = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||||||
ULONG Length = IrpSp->Parameters.SetFile.Length;
|
ULONG Length = IrpSp->Parameters.SetFile.Length;
|
||||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ?
|
FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ?
|
||||||
TargetFileObject->FsContext : 0;
|
TargetFileObject->FsContext : 0;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request = 0;
|
||||||
UNICODE_STRING Remain, Suffix;
|
UNICODE_STRING Remain, Suffix;
|
||||||
UNICODE_STRING NewFileName;
|
UNICODE_STRING NewFileName;
|
||||||
PUINT8 NewFileNameBuffer;
|
PUINT8 NewFileNameBuffer;
|
||||||
BOOLEAN AppendBackslash;
|
BOOLEAN AppendBackslash;
|
||||||
|
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext = 0;
|
||||||
|
|
||||||
ASSERT(FileNode == FileDesc->FileNode);
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
@ -1116,7 +1176,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, 0, 0))
|
if (!FspFileNameIsValid(&FileNode->FileName, 0, 0))
|
||||||
/* cannot rename streams (WinFsp limitation) */
|
/* cannot rename streams (WinFsp limitation) */
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
@ -1129,19 +1189,28 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject);
|
FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject);
|
||||||
|
retry:
|
||||||
FspFileNodeAcquireExclusive(FileNode, Full);
|
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||||
|
|
||||||
|
if (0 == Request)
|
||||||
|
{
|
||||||
if (0 != TargetFileNode)
|
if (0 != TargetFileNode)
|
||||||
Remain = TargetFileNode->FileName;
|
Remain = TargetFileNode->FileName;
|
||||||
else
|
else
|
||||||
FspUnicodePathSuffix(&FileNode->FileName, &Remain, &Suffix);
|
FspFileNameSuffix(&FileNode->FileName, &Remain, &Suffix);
|
||||||
|
|
||||||
Suffix.Length = Suffix.MaximumLength = (USHORT)Info->FileNameLength;
|
Suffix.Length = (USHORT)Info->FileNameLength;
|
||||||
Suffix.Buffer = Info->FileName;
|
Suffix.Buffer = Info->FileName;
|
||||||
if (L'\\' == Suffix.Buffer[0])
|
/* if there is a backslash anywhere in the NewFileName get its suffix */
|
||||||
FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix);
|
for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++)
|
||||||
|
if (L'\\' == *P)
|
||||||
|
{
|
||||||
|
Suffix.Length = (USHORT)((EndP - P - 1) * sizeof(WCHAR));
|
||||||
|
Suffix.Buffer = P + 1;
|
||||||
|
}
|
||||||
|
Suffix.MaximumLength = Suffix.Length;
|
||||||
|
|
||||||
if (!FspUnicodePathIsValid(&Remain, 0, 0) || !FspUnicodePathIsValid(&Suffix, 0, 0))
|
if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0))
|
||||||
{
|
{
|
||||||
/* cannot rename streams (WinFsp limitation) */
|
/* cannot rename streams (WinFsp limitation) */
|
||||||
Result = STATUS_INVALID_PARAMETER;
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
@ -1173,11 +1242,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
|||||||
Request->Req.SetInformation.FileInformationClass = FileRenameInformation;
|
Request->Req.SetInformation.FileInformationClass = FileRenameInformation;
|
||||||
Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size;
|
Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size;
|
||||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR);
|
Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR);
|
||||||
|
}
|
||||||
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
|
||||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
|
||||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
|
||||||
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special rules for renaming open files:
|
* Special rules for renaming open files:
|
||||||
@ -1190,21 +1255,72 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
|||||||
* that has open handles (except in the batch-oplock case described earlier).
|
* that has open handles (except in the batch-oplock case described earlier).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Result = STATUS_SUCCESS;
|
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FileNode, FspFileNodeAcquireFull,
|
||||||
if (1 < FileNode->HandleCount ||
|
&FileNode->FileName, TRUE);
|
||||||
(FileNode->IsDirectory &&
|
/* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */
|
||||||
FspFileNodeHasOpenHandles(FsvolDeviceObject, &FileNode->FileName, TRUE)) ||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
|
||||||
FspFileNodeHasOpenHandles(FsvolDeviceObject, &NewFileName, FALSE))
|
goto retry;
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
{
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto rename_unlock_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != FspFileNameCompare(&FileNode->FileName, &NewFileName, !FileDesc->CaseSensitive, 0))
|
||||||
|
{
|
||||||
|
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
|
||||||
|
FileNode, FspFileNodeAcquireFull,
|
||||||
|
&NewFileName, FALSE);
|
||||||
|
/* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
|
||||||
|
goto retry;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto rename_unlock_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the new file name is *exactly* the same (including case) as the old one,
|
||||||
|
* there is no need to go to the user mode file system. Just return STATUS_SUCCESS.
|
||||||
|
* Our RequestFini will do any cleanup necessary.
|
||||||
|
*
|
||||||
|
* This check needs to be done *after* the open handle test above. This is what FASTFAT
|
||||||
|
* and NTFS do.
|
||||||
|
*/
|
||||||
|
if (0 == FspFileNameCompare(&FileNode->FileName, &NewFileName, FALSE, 0))
|
||||||
|
{
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* capture the security context */
|
||||||
|
if (ReplaceIfExists)
|
||||||
|
{
|
||||||
|
SecuritySubjectContext = FspAlloc(sizeof *SecuritySubjectContext);
|
||||||
|
if (0 == SecuritySubjectContext)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
SeCaptureSubjectContext(SecuritySubjectContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
|
||||||
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||||
|
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
|
||||||
|
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = SecuritySubjectContext;
|
||||||
|
|
||||||
return FSP_STATUS_IOQ_POST;
|
return FSP_STATUS_IOQ_POST;
|
||||||
|
|
||||||
unlock_exit:
|
unlock_exit:
|
||||||
FspFileNodeRelease(FileNode, Full);
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
rename_unlock_exit:
|
||||||
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
|
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@ -1308,16 +1424,54 @@ static NTSTATUS FspFsvolSetInformation(
|
|||||||
|
|
||||||
ASSERT(FileNode == FileDesc->FileNode);
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolSetInformationRequestFini, &Request);
|
retry:
|
||||||
|
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||||
|
|
||||||
|
if (FileAllocationInformation == FileInformationClass ||
|
||||||
|
FileEndOfFileInformation == FileInformationClass)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Perform oplock check.
|
||||||
|
*
|
||||||
|
* It is ok to block our thread during receipt of the SetInformation IRP.
|
||||||
|
* However we cannot acquire the FileNode exclusive and wait for oplock
|
||||||
|
* breaks to complete, because oplock break processing acquires the FileNode
|
||||||
|
* shared.
|
||||||
|
*
|
||||||
|
* Instead we initiate the oplock breaks and then check if any are in progress.
|
||||||
|
* If that is the case we release the FileNode and wait for the oplock breaks
|
||||||
|
* to complete. Once they are complete we retry the whole thing.
|
||||||
|
*/
|
||||||
|
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
|
||||||
|
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
|
||||||
|
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result ||
|
||||||
|
DEBUGTEST_EX(NT_SUCCESS(Result), 10, FALSE))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
Result = FspFileNodeOplockCheck(FileNode, Irp);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolSetInformationRequestFini, &Request);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
Request->Kind = FspFsctlTransactSetInformationKind;
|
Request->Kind = FspFsctlTransactSetInformationKind;
|
||||||
Request->Req.SetInformation.UserContext = FileNode->UserContext;
|
Request->Req.SetInformation.UserContext = FileNode->UserContext;
|
||||||
Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2;
|
Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2;
|
||||||
Request->Req.SetInformation.FileInformationClass = FileInformationClass;
|
Request->Req.SetInformation.FileInformationClass = FileInformationClass;
|
||||||
|
|
||||||
FspFileNodeAcquireExclusive(FileNode, Full);
|
|
||||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||||
|
|
||||||
@ -1352,32 +1506,36 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
|||||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
|
||||||
if (FileRenameInformation != IrpSp->Parameters.SetFile.FileInformationClass ||
|
if (FileRenameInformation != IrpSp->Parameters.SetFile.FileInformationClass ||
|
||||||
!IrpSp->Parameters.SetFile.ReplaceIfExists)
|
0 == FspIopRequestContext(Request, RequestSubjectContextOrAccessToken))
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
SECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
|
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
|
||||||
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
||||||
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
||||||
HANDLE UserModeAccessToken;
|
HANDLE UserModeAccessToken;
|
||||||
PEPROCESS Process;
|
PEPROCESS Process;
|
||||||
|
|
||||||
|
SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken);
|
||||||
|
|
||||||
/* duplicate the subject context access token into an impersonation token */
|
/* duplicate the subject context access token into an impersonation token */
|
||||||
SecurityQualityOfService.Length = sizeof SecurityQualityOfService;
|
SecurityQualityOfService.Length = sizeof SecurityQualityOfService;
|
||||||
SecurityQualityOfService.ImpersonationLevel = SecurityIdentification;
|
SecurityQualityOfService.ImpersonationLevel = SecurityIdentification;
|
||||||
SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
|
||||||
SecurityQualityOfService.EffectiveOnly = FALSE;
|
SecurityQualityOfService.EffectiveOnly = FALSE;
|
||||||
SeCaptureSubjectContext(&SecuritySubjectContext);
|
SeLockSubjectContext(SecuritySubjectContext);
|
||||||
SeLockSubjectContext(&SecuritySubjectContext);
|
Result = SeCreateClientSecurityFromSubjectContext(SecuritySubjectContext,
|
||||||
Result = SeCreateClientSecurityFromSubjectContext(&SecuritySubjectContext,
|
|
||||||
&SecurityQualityOfService, FALSE, &SecurityClientContext);
|
&SecurityQualityOfService, FALSE, &SecurityClientContext);
|
||||||
SeUnlockSubjectContext(&SecuritySubjectContext);
|
SeUnlockSubjectContext(SecuritySubjectContext);
|
||||||
SeReleaseSubjectContext(&SecuritySubjectContext);
|
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken));
|
ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken));
|
||||||
|
|
||||||
|
SeReleaseSubjectContext(SecuritySubjectContext);
|
||||||
|
FspFree(SecuritySubjectContext);
|
||||||
|
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = 0;
|
||||||
|
|
||||||
/* get a user-mode handle to the impersonation token */
|
/* get a user-mode handle to the impersonation token */
|
||||||
Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken,
|
Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken,
|
||||||
0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken);
|
0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken);
|
||||||
@ -1390,7 +1548,7 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
|||||||
ObReferenceObject(Process);
|
ObReferenceObject(Process);
|
||||||
|
|
||||||
/* send the user-mode handle to the user-mode file system */
|
/* send the user-mode handle to the user-mode file system */
|
||||||
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
|
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken;
|
||||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||||
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
|
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
|
||||||
|
|
||||||
@ -1456,7 +1614,7 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
|
|
||||||
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
|
PDEVICE_OBJECT FsvolDeviceObject = Context[RequestDeviceObject];
|
||||||
HANDLE AccessToken = Context[RequestAccessToken];
|
PVOID SubjectContextOrAccessToken = Context[RequestSubjectContextOrAccessToken];
|
||||||
PEPROCESS Process = Context[RequestProcess];
|
PEPROCESS Process = Context[RequestProcess];
|
||||||
|
|
||||||
if (0 != FileNode)
|
if (0 != FileNode)
|
||||||
@ -1465,8 +1623,9 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
if (0 != FsvolDeviceObject)
|
if (0 != FsvolDeviceObject)
|
||||||
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
|
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, Request);
|
||||||
|
|
||||||
if (0 != AccessToken)
|
if (0 != SubjectContextOrAccessToken && 0 != Process)
|
||||||
{
|
{
|
||||||
|
HANDLE AccessToken = SubjectContextOrAccessToken;
|
||||||
KAPC_STATE ApcState;
|
KAPC_STATE ApcState;
|
||||||
BOOLEAN Attach;
|
BOOLEAN Attach;
|
||||||
|
|
||||||
@ -1488,6 +1647,13 @@ static VOID FspFsvolSetInformationRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, P
|
|||||||
|
|
||||||
ObDereferenceObject(Process);
|
ObDereferenceObject(Process);
|
||||||
}
|
}
|
||||||
|
else if (0 != SubjectContextOrAccessToken)
|
||||||
|
{
|
||||||
|
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext = SubjectContextOrAccessToken;
|
||||||
|
|
||||||
|
SeReleaseSubjectContext(SecuritySubjectContext);
|
||||||
|
FspFree(SecuritySubjectContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS FspQueryInformation(
|
NTSTATUS FspQueryInformation(
|
||||||
|
192
src/sys/fsctl.c
@ -25,6 +25,10 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
|||||||
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
BOOLEAN IsWrite);
|
BOOLEAN IsWrite);
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlOplock(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
|
static IO_COMPLETION_ROUTINE FspFsvolFileSystemControlOplockCompletion;
|
||||||
|
static WORKER_THREAD_ROUTINE FspFsvolFileSystemControlOplockCompletionWork;
|
||||||
static NTSTATUS FspFsvolFileSystemControl(
|
static NTSTATUS FspFsvolFileSystemControl(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
||||||
@ -35,6 +39,9 @@ FSP_DRIVER_DISPATCH FspFileSystemControl;
|
|||||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
|
||||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplock)
|
||||||
|
// !#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletion)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletionWork)
|
||||||
#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, FspFsvolFileSystemControlRequestFini)
|
||||||
@ -205,9 +212,7 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
|||||||
TargetFileNameIndex += FsvolDeviceExtension->VolumePrefix.Length;
|
TargetFileNameIndex += FsvolDeviceExtension->VolumePrefix.Length;
|
||||||
|
|
||||||
if (TargetFileNameIndex < ReparseTargetPathLength &&
|
if (TargetFileNameIndex < ReparseTargetPathLength &&
|
||||||
RtlEqualUnicodeString(&FsvolDeviceExtension->VolumePrefix,
|
FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &TargetObjectName))
|
||||||
&TargetObjectName,
|
|
||||||
FSP_VOLUME_PREFIX_CASE_INS))
|
|
||||||
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
|
TargetOnFileSystem = (UINT16)TargetFileNameIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,6 +303,176 @@ static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject;
|
||||||
|
WORK_QUEUE_ITEM WorkItem;
|
||||||
|
} FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT;
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlOplock(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
|
||||||
|
/* is this a valid FileObject? */
|
||||||
|
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||||||
|
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||||
|
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||||
|
ULONG OplockCount;
|
||||||
|
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext;
|
||||||
|
|
||||||
|
if (FileNode->IsDirectory)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As per FastFat:
|
||||||
|
*
|
||||||
|
* We grab the Fcb exclusively for oplock requests, shared for oplock
|
||||||
|
* break acknowledgement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (FsControlCode)
|
||||||
|
{
|
||||||
|
case FSCTL_REQUEST_OPLOCK:
|
||||||
|
if (sizeof(REQUEST_OPLOCK_INPUT_BUFFER) > InputBufferLength ||
|
||||||
|
sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER) > OutputBufferLength)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
if (FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->Flags,
|
||||||
|
REQUEST_OPLOCK_INPUT_FLAG_REQUEST))
|
||||||
|
goto exclusive;
|
||||||
|
if (FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->Flags,
|
||||||
|
REQUEST_OPLOCK_INPUT_FLAG_ACK))
|
||||||
|
goto shared;
|
||||||
|
|
||||||
|
/* one of REQUEST_OPLOCK_INPUT_FLAG_REQUEST or REQUEST_OPLOCK_INPUT_FLAG_ACK required */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
||||||
|
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
||||||
|
case FSCTL_REQUEST_BATCH_OPLOCK:
|
||||||
|
case FSCTL_REQUEST_FILTER_OPLOCK:
|
||||||
|
exclusive:
|
||||||
|
FspFileNodeAcquireExclusive(FileNode, Main);
|
||||||
|
if (!FsRtlOplockIsSharedRequest(Irp))
|
||||||
|
{
|
||||||
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
OplockCount = FileNode->HandleCount;
|
||||||
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OplockCount = FsRtlAreThereCurrentOrInProgressFileLocks(&FileNode->FileLock);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
||||||
|
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
||||||
|
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
||||||
|
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
||||||
|
shared:
|
||||||
|
FspFileNodeAcquireShared(FileNode, Main);
|
||||||
|
OplockCount = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ASSERT(0);
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The FileNode is acquired exclusive or shared.
|
||||||
|
* Make sure to release it before exiting!
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (FSCTL_REQUEST_FILTER_OPLOCK == FsControlCode ||
|
||||||
|
FSCTL_REQUEST_BATCH_OPLOCK == FsControlCode ||
|
||||||
|
(FSCTL_REQUEST_OPLOCK == FsControlCode &&
|
||||||
|
FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->RequestedOplockLevel,
|
||||||
|
OPLOCK_LEVEL_CACHE_HANDLE)))
|
||||||
|
{
|
||||||
|
BOOLEAN DeletePending;
|
||||||
|
|
||||||
|
DeletePending = 0 != FileNode->DeletePending;
|
||||||
|
MemoryBarrier();
|
||||||
|
if (DeletePending)
|
||||||
|
{
|
||||||
|
Result = STATUS_DELETE_PENDING;
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This IRP will be completed by the FSRTL package and therefore
|
||||||
|
* we will have no chance to do our normal IRP completion processing.
|
||||||
|
* Hook the IRP completion and perform the IRP completion processing
|
||||||
|
* there.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CompletionContext = FspAllocNonPaged(sizeof *CompletionContext);
|
||||||
|
if (0 == CompletionContext)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
CompletionContext->FsvolDeviceObject = FsvolDeviceObject;
|
||||||
|
ExInitializeWorkItem(&CompletionContext->WorkItem,
|
||||||
|
FspFsvolFileSystemControlOplockCompletionWork, CompletionContext);
|
||||||
|
|
||||||
|
Result = FspIrpHook(Irp, FspFsvolFileSystemControlOplockCompletion, CompletionContext);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFree(CompletionContext);
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FspOplockFsctrl takes ownership of the IRP under all circumstances.
|
||||||
|
*
|
||||||
|
* We mark the IRP pending so that we can safely return STATUS_PENDING.
|
||||||
|
*/
|
||||||
|
|
||||||
|
IoSetTopLevelIrp(0);
|
||||||
|
|
||||||
|
IoMarkIrpPending(Irp);
|
||||||
|
Result = FspFileNodeOplockFsctl(FileNode, Irp, OplockCount);
|
||||||
|
|
||||||
|
FspFileNodeRelease(FileNode, Main);
|
||||||
|
|
||||||
|
return STATUS_PENDING;
|
||||||
|
|
||||||
|
unlock_exit:
|
||||||
|
FspFileNodeRelease(FileNode, Main);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlOplockCompletion(
|
||||||
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
|
||||||
|
{
|
||||||
|
// !PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext =
|
||||||
|
FspIrpHookContext(Context);
|
||||||
|
ExQueueWorkItem(&CompletionContext->WorkItem, DelayedWorkQueue);
|
||||||
|
|
||||||
|
return FspIrpHookNext(DeviceObject, Irp, Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID FspFsvolFileSystemControlOplockCompletionWork(PVOID Context)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext = Context;
|
||||||
|
FspDeviceDereference(CompletionContext->FsvolDeviceObject);
|
||||||
|
FspFree(CompletionContext);
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolFileSystemControl(
|
static NTSTATUS FspFsvolFileSystemControl(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
@ -320,6 +495,17 @@ static NTSTATUS FspFsvolFileSystemControl(
|
|||||||
case FSCTL_DELETE_REPARSE_POINT:
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
||||||
break;
|
break;
|
||||||
|
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
||||||
|
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
||||||
|
case FSCTL_REQUEST_BATCH_OPLOCK:
|
||||||
|
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
||||||
|
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
||||||
|
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
||||||
|
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
||||||
|
case FSCTL_REQUEST_FILTER_OPLOCK:
|
||||||
|
case FSCTL_REQUEST_OPLOCK:
|
||||||
|
Result = FspFsvolFileSystemControlOplock(FsvolDeviceObject, Irp, IrpSp);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
|
|||||||
//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)
|
||||||
@ -185,7 +185,7 @@ SYM(FSCTL_PIPE_SET_CONNECTION_ATTRIBUTE)
|
|||||||
SYM(FSCTL_PIPE_GET_HANDLE_ATTRIBUTE)
|
SYM(FSCTL_PIPE_GET_HANDLE_ATTRIBUTE)
|
||||||
SYM(FSCTL_PIPE_SET_HANDLE_ATTRIBUTE)
|
SYM(FSCTL_PIPE_SET_HANDLE_ATTRIBUTE)
|
||||||
SYM(FSCTL_PIPE_FLUSH)
|
SYM(FSCTL_PIPE_FLUSH)
|
||||||
SYM(FSCTL_PIPE_SET_CONTAINER_AWARE)
|
//SYM(FSCTL_PIPE_SET_CONTAINER_AWARE)
|
||||||
SYM(FSCTL_PIPE_INTERNAL_READ)
|
SYM(FSCTL_PIPE_INTERNAL_READ)
|
||||||
SYM(FSCTL_PIPE_INTERNAL_WRITE)
|
SYM(FSCTL_PIPE_INTERNAL_WRITE)
|
||||||
SYM(FSCTL_PIPE_INTERNAL_TRANSCEIVE)
|
SYM(FSCTL_PIPE_INTERNAL_TRANSCEIVE)
|
||||||
|
125
src/sys/iop.c
@ -20,6 +20,7 @@
|
|||||||
NTSTATUS FspIopCreateRequestFunnel(
|
NTSTATUS FspIopCreateRequestFunnel(
|
||||||
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_IOP_REQUEST_FINI *RequestFini,
|
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_IOP_REQUEST_FINI *RequestFini,
|
||||||
ULONG Flags, FSP_FSCTL_TRANSACT_REQ **PRequest);
|
ULONG Flags, FSP_FSCTL_TRANSACT_REQ **PRequest);
|
||||||
|
NTSTATUS FspIopCreateRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
VOID FspIopResetRequest(FSP_FSCTL_TRANSACT_REQ *Request, FSP_IOP_REQUEST_FINI *RequestFini);
|
VOID FspIopResetRequest(FSP_FSCTL_TRANSACT_REQ *Request, FSP_IOP_REQUEST_FINI *RequestFini);
|
||||||
NTSTATUS FspIopPostWorkRequestFunnel(PDEVICE_OBJECT DeviceObject,
|
NTSTATUS FspIopPostWorkRequestFunnel(PDEVICE_OBJECT DeviceObject,
|
||||||
@ -29,12 +30,14 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference);
|
|||||||
VOID FspIopCompleteCanceledIrp(PIRP Irp);
|
VOID FspIopCompleteCanceledIrp(PIRP Irp);
|
||||||
BOOLEAN FspIopRetryPrepareIrp(PIRP Irp, NTSTATUS *PResult);
|
BOOLEAN FspIopRetryPrepareIrp(PIRP Irp, NTSTATUS *PResult);
|
||||||
BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, NTSTATUS *PResult);
|
BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, NTSTATUS *PResult);
|
||||||
|
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
|
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp);
|
||||||
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
|
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
|
||||||
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspIopCreateRequestFunnel)
|
#pragma alloc_text(PAGE, FspIopCreateRequestFunnel)
|
||||||
|
#pragma alloc_text(PAGE, FspIopCreateRequestWorkItem)
|
||||||
#pragma alloc_text(PAGE, FspIopDeleteRequest)
|
#pragma alloc_text(PAGE, FspIopDeleteRequest)
|
||||||
#pragma alloc_text(PAGE, FspIopResetRequest)
|
#pragma alloc_text(PAGE, FspIopResetRequest)
|
||||||
#pragma alloc_text(PAGE, FspIopPostWorkRequestFunnel)
|
#pragma alloc_text(PAGE, FspIopPostWorkRequestFunnel)
|
||||||
@ -42,17 +45,18 @@ NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response
|
|||||||
#pragma alloc_text(PAGE, FspIopCompleteCanceledIrp)
|
#pragma alloc_text(PAGE, FspIopCompleteCanceledIrp)
|
||||||
#pragma alloc_text(PAGE, FspIopRetryPrepareIrp)
|
#pragma alloc_text(PAGE, FspIopRetryPrepareIrp)
|
||||||
#pragma alloc_text(PAGE, FspIopRetryCompleteIrp)
|
#pragma alloc_text(PAGE, FspIopRetryCompleteIrp)
|
||||||
|
#pragma alloc_text(PAGE, FspIopSetIrpResponse)
|
||||||
#pragma alloc_text(PAGE, FspIopIrpResponse)
|
#pragma alloc_text(PAGE, FspIopIrpResponse)
|
||||||
#pragma alloc_text(PAGE, FspIopDispatchPrepare)
|
#pragma alloc_text(PAGE, FspIopDispatchPrepare)
|
||||||
#pragma alloc_text(PAGE, FspIopDispatchComplete)
|
#pragma alloc_text(PAGE, FspIopDispatchComplete)
|
||||||
#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 REQ_ALIGN_SIZE <= MEMORY_ALLOCATION_ALIGNMENT
|
#if FSP_FSCTL_TRANSACT_REQ_ALIGNMENT <= MEMORY_ALLOCATION_ALIGNMENT
|
||||||
#define REQ_HEADER_ALIGN_MASK 0
|
#define REQ_HEADER_ALIGN_MASK 0
|
||||||
#define REQ_HEADER_ALIGN_OVERHEAD 0
|
#define REQ_HEADER_ALIGN_OVERHEAD 0
|
||||||
#else
|
#else
|
||||||
#define REQ_HEADER_ALIGN_MASK (REQ_ALIGN_SIZE - 1)
|
#define REQ_HEADER_ALIGN_MASK (FSP_FSCTL_TRANSACT_REQ_ALIGNMENT - 1)
|
||||||
#define REQ_HEADER_ALIGN_OVERHEAD (sizeof(PVOID) + REQ_HEADER_ALIGN_MASK)
|
#define REQ_HEADER_ALIGN_OVERHEAD (sizeof(PVOID) + REQ_HEADER_ALIGN_MASK)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -63,6 +67,7 @@ NTSTATUS FspIopCreateRequestFunnel(
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader;
|
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *RequestWorkItem = 0;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
*PRequest = 0;
|
*PRequest = 0;
|
||||||
@ -73,19 +78,41 @@ NTSTATUS FspIopCreateRequestFunnel(
|
|||||||
if (FSP_FSCTL_TRANSACT_REQ_SIZEMAX < sizeof *Request + ExtraSize)
|
if (FSP_FSCTL_TRANSACT_REQ_SIZEMAX < sizeof *Request + ExtraSize)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
if (FlagOn(Flags, FspIopRequestMustSucceed))
|
if (FlagOn(Flags, FspIopCreateRequestMustSucceedFlag))
|
||||||
|
{
|
||||||
RequestHeader = FspAllocatePoolMustSucceed(
|
RequestHeader = FspAllocatePoolMustSucceed(
|
||||||
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
FlagOn(Flags, FspIopCreateRequestNonPagedFlag) ? NonPagedPool : PagedPool,
|
||||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
||||||
FSP_ALLOC_INTERNAL_TAG);
|
FSP_ALLOC_INTERNAL_TAG);
|
||||||
|
|
||||||
|
if (FlagOn(Flags, FspIopCreateRequestWorkItemFlag))
|
||||||
|
{
|
||||||
|
RequestWorkItem = FspAllocatePoolMustSucceed(
|
||||||
|
NonPagedPool, sizeof *RequestWorkItem, FSP_ALLOC_INTERNAL_TAG);
|
||||||
|
|
||||||
|
RtlZeroMemory(RequestWorkItem, sizeof *RequestWorkItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RequestHeader = ExAllocatePoolWithTag(
|
RequestHeader = ExAllocatePoolWithTag(
|
||||||
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
|
FlagOn(Flags, FspIopCreateRequestNonPagedFlag) ? NonPagedPool : PagedPool,
|
||||||
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
|
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 (FlagOn(Flags, FspIopCreateRequestWorkItemFlag))
|
||||||
|
{
|
||||||
|
RequestWorkItem = FspAllocNonPaged(sizeof *RequestWorkItem);
|
||||||
|
if (0 == RequestWorkItem)
|
||||||
|
{
|
||||||
|
FspFree(RequestHeader);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlZeroMemory(RequestWorkItem, sizeof *RequestWorkItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 != REQ_HEADER_ALIGN_MASK
|
#if 0 != REQ_HEADER_ALIGN_MASK
|
||||||
@ -97,6 +124,7 @@ NTSTATUS FspIopCreateRequestFunnel(
|
|||||||
|
|
||||||
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
|
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
|
||||||
RequestHeader->RequestFini = RequestFini;
|
RequestHeader->RequestFini = RequestFini;
|
||||||
|
RequestHeader->WorkItem = RequestWorkItem;
|
||||||
|
|
||||||
Request = (PVOID)RequestHeader->RequestBuf;
|
Request = (PVOID)RequestHeader->RequestBuf;
|
||||||
Request->Size = (UINT16)(sizeof *Request + ExtraSize);
|
Request->Size = (UINT16)(sizeof *Request + ExtraSize);
|
||||||
@ -110,6 +138,8 @@ NTSTATUS FspIopCreateRequestFunnel(
|
|||||||
Request->FileName.Size = FileName->Length + sizeof(WCHAR);
|
Request->FileName.Size = FileName->Length + sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT(0 == ((UINT_PTR)Request & (FSP_FSCTL_TRANSACT_REQ_ALIGNMENT - 1)));
|
||||||
|
|
||||||
if (0 != Irp)
|
if (0 != Irp)
|
||||||
{
|
{
|
||||||
ASSERT(0 == FspIrpRequest(Irp));
|
ASSERT(0 == FspIrpRequest(Irp));
|
||||||
@ -120,6 +150,26 @@ NTSTATUS FspIopCreateRequestFunnel(
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspIopCreateRequestWorkItem(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *RequestWorkItem;
|
||||||
|
|
||||||
|
if (0 == RequestHeader->WorkItem)
|
||||||
|
{
|
||||||
|
RequestWorkItem = FspAllocNonPaged(sizeof *RequestWorkItem);
|
||||||
|
if (0 == RequestWorkItem)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
RtlZeroMemory(RequestWorkItem, sizeof *RequestWorkItem);
|
||||||
|
RequestHeader->WorkItem = RequestWorkItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
@ -132,6 +182,9 @@ VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
if (0 != RequestHeader->Response)
|
if (0 != RequestHeader->Response)
|
||||||
FspFree(RequestHeader->Response);
|
FspFree(RequestHeader->Response);
|
||||||
|
|
||||||
|
if (0 != RequestHeader->WorkItem)
|
||||||
|
FspFree(RequestHeader->WorkItem);
|
||||||
|
|
||||||
#if 0 != REQ_HEADER_ALIGN_MASK
|
#if 0 != REQ_HEADER_ALIGN_MASK
|
||||||
RequestHeader = ((PVOID *)RequestHeader)[-1];
|
RequestHeader = ((PVOID *)RequestHeader)[-1];
|
||||||
#endif
|
#endif
|
||||||
@ -225,9 +278,55 @@ 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;
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject;
|
||||||
|
|
||||||
if (STATUS_SUCCESS != Result && STATUS_REPARSE != Result && STATUS_BUFFER_OVERFLOW != Result)
|
/*
|
||||||
|
* HACK:
|
||||||
|
*
|
||||||
|
* Turns out that SRV2 sends an undocumented flavor of IRP_MJ_DIRECTORY_CONTROL /
|
||||||
|
* IRP_MN_QUERY_DIRECTORY. These IRP's have a non-NULL Irp->MdlAddress. They expect
|
||||||
|
* the FSD to fill the buffer pointed by Irp->MdlAddress and they cannot handle
|
||||||
|
* completed IRP's with a non-NULL Irp->AssociatedIrp.SystemBuffer. So we have to
|
||||||
|
* provide special support for these IRPs.
|
||||||
|
*
|
||||||
|
* While this processing is IRP_MJ_DIRECTORY_CONTROL specific, we do this here for
|
||||||
|
* these reasons:
|
||||||
|
*
|
||||||
|
* 1. There may be other IRP's that have similar completion requirements under SRV2.
|
||||||
|
* If/when such IRP's are discovered the completion processing can be centralized
|
||||||
|
* here.
|
||||||
|
* 2. IRP_MJ_DIRECTORY_CONTROL has a few different ways that it can complete IRP's.
|
||||||
|
* It is far simpler to do this processing here, even if not academically correct.
|
||||||
|
*
|
||||||
|
* This will have to be revisited if IRP_MJ_DIRECTORY_CONTROL processing changes
|
||||||
|
* substantially (e.g. to no longer use Irp->AssociatedIrp.SystemBuffer).
|
||||||
|
*/
|
||||||
|
if (IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction &&
|
||||||
|
IRP_MN_QUERY_DIRECTORY == IrpSp->MinorFunction &&
|
||||||
|
0 != Irp->MdlAddress && /* SRV2 queries have this set */
|
||||||
|
0 != Irp->AssociatedIrp.SystemBuffer &&
|
||||||
|
FlagOn(Irp->Flags, IRP_BUFFERED_IO))
|
||||||
|
{
|
||||||
|
if (STATUS_SUCCESS == Result)
|
||||||
|
{
|
||||||
|
PVOID Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
||||||
|
if (0 != Address)
|
||||||
|
RtlCopyMemory(Address, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information);
|
||||||
|
else
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFreeExternal(Irp->AssociatedIrp.SystemBuffer);
|
||||||
|
Irp->AssociatedIrp.SystemBuffer = 0;
|
||||||
|
ClearFlag(Irp->Flags, IRP_INPUT_OPERATION | IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STATUS_SUCCESS != Result &&
|
||||||
|
STATUS_REPARSE != Result &&
|
||||||
|
STATUS_OPLOCK_BREAK_IN_PROGRESS != Result &&
|
||||||
|
STATUS_BUFFER_OVERFLOW != Result &&
|
||||||
|
STATUS_SHARING_VIOLATION != 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);
|
||||||
@ -275,6 +374,16 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
|||||||
|
|
||||||
PDEVICE_OBJECT DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
|
PDEVICE_OBJECT DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
|
||||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
||||||
|
|
||||||
|
FspIopSetIrpResponse(Irp, Response);
|
||||||
|
|
||||||
|
return FspIoqRetryCompleteIrp(FsvolDeviceExtension->Ioq, Irp, PResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FspIopSetIrpResponse(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
|
FSP_FSCTL_TRANSACT_REQ_HEADER *RequestHeader = (PVOID)((PUINT8)Request - sizeof *RequestHeader);
|
||||||
|
|
||||||
@ -288,8 +397,6 @@ BOOLEAN FspIopRetryCompleteIrp(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
|||||||
RtlCopyMemory(RequestHeader->Response, Response, Response->Size);
|
RtlCopyMemory(RequestHeader->Response, Response, Response->Size);
|
||||||
Response = RequestHeader->Response;
|
Response = RequestHeader->Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FspIoqRetryCompleteIrp(FsvolDeviceExtension->Ioq, Irp, PResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp)
|
FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp)
|
||||||
|