mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 17:32:57 -05:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
09ab9de32c | |||
75620332c7 | |||
47aa53c70a | |||
c343253718 | |||
6764269a49 | |||
41d69d7186 | |||
f6e6660362 | |||
61027daf6e | |||
9ae9b8ff2c | |||
74bb51ae07 | |||
332ba48203 | |||
0d7f13abeb | |||
e88a7742df | |||
c7b3312cf6 | |||
c0fa5696d7 | |||
43af829d46 | |||
9c1a7fb40b | |||
dd907a44ad | |||
df4c19c113 | |||
deaf475861 | |||
bda0477a79 | |||
4b65871747 | |||
eaa0d7d7d2 | |||
facbc2c1b5 | |||
e5879a9cb0 | |||
0a91292e05 | |||
1a879e3302 | |||
98421fe11b | |||
f6fef97a10 | |||
f0931a0cf2 | |||
9ecb6541cf | |||
d816d607f4 | |||
f3df3f6dd2 | |||
7527155cb8 | |||
868812d248 | |||
20680fa5b5 | |||
00d4aba946 | |||
fadcd84ca9 | |||
966e08e7c1 | |||
8d83d46e7f | |||
cdcd6af81d | |||
9567b94d37 | |||
50a28c4284 | |||
87a1d5468d | |||
fda950b90e | |||
4ccf0d2085 | |||
2c42dc535c | |||
84ab502b98 | |||
0c90a69b27 | |||
2ed46a39fa | |||
cf13cac438 |
2
.github/ISSUE_TEMPLATE/question.md
vendored
2
.github/ISSUE_TEMPLATE/question.md
vendored
@ -5,4 +5,4 @@ about: Questions are better asked in the WinFsp Google Group. However you may as
|
||||
|
||||
## Question
|
||||
|
||||
_Please consider asking questions in the [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp) instead. Before asking a question please also consult the [WinFsp Frequently Asked Questions](https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions)._
|
||||
_Please consider asking questions in the [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp) instead. Before asking a question please also consult the [WinFsp Frequently Asked Questions](https://github.com/winfsp/winfsp/wiki/Frequently-Asked-Questions)._
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
Before submitting this PR please review this checklist. Ideally all checkmarks should be checked upon submitting. (Use an x inside square brackets like so: [x])
|
||||
|
||||
- [ ] **Contributing**: You MUST read and be willing to accept the [CONTRIBUTOR AGREEMENT](https://github.com/billziss-gh/winfsp/blob/master/Contributors.asciidoc). The agreement gives joint copyright interests in your contributions to you and the original WinFsp author. If you have already accepted the [CONTRIBUTOR AGREEMENT](https://github.com/billziss-gh/winfsp/blob/master/Contributors.asciidoc) you do not need to do so again.
|
||||
- [ ] **Contributing**: You MUST read and be willing to accept the [CONTRIBUTOR AGREEMENT](https://github.com/winfsp/winfsp/blob/master/Contributors.asciidoc). The agreement gives joint copyright interests in your contributions to you and the original WinFsp author. If you have already accepted the [CONTRIBUTOR AGREEMENT](https://github.com/winfsp/winfsp/blob/master/Contributors.asciidoc) you do not need to do so again.
|
||||
- [ ] **Topic branch**: Avoid creating the PR off the master branch of your fork. Consider creating a topic branch and request a pull from that. This allows you to add commits to the master branch of your fork without affecting this PR.
|
||||
- [ ] **No tabs**: Consistently use SPACES everywhere. NO TABS, unless the file format requires it (e.g. Makefile).
|
||||
- [ ] **Style**: Follow the same code style as the rest of the project.
|
||||
|
10
.github/workflows/avm.yml
vendored
10
.github/workflows/avm.yml
vendored
@ -11,8 +11,8 @@ jobs:
|
||||
- uses: billziss-gh/avm@v1
|
||||
with:
|
||||
files: |
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.6/winfsp-1.6.20027.msi
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.7/winfsp-1.7.20172.msi
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.8/winfsp-1.8.20304.msi
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.9/winfsp-1.9.21096.msi
|
||||
https://github.com/billziss-gh/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
|
||||
https://github.com/winfsp/winfsp/releases/download/v1.6/winfsp-1.6.20027.msi
|
||||
https://github.com/winfsp/winfsp/releases/download/v1.7/winfsp-1.7.20172.msi
|
||||
https://github.com/winfsp/winfsp/releases/download/v1.8/winfsp-1.8.20304.msi
|
||||
https://github.com/winfsp/winfsp/releases/download/v1.9/winfsp-1.9.21096.msi
|
||||
https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
|
||||
|
72
Changelog.md
72
Changelog.md
@ -1,9 +1,79 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## v1.11B3 (2022+ARM64 Beta3)
|
||||
|
||||
- [NEW] ARM64 support! For details see [WinFsp on ARM64](https://github.com/winfsp/winfsp/wiki/WinFsp-on-ARM64).
|
||||
|
||||
- [NEW] A new file system operation has been added to the FUSE API:
|
||||
|
||||
```C
|
||||
int (*getpath)(const char *path, char *buf, size_t size,
|
||||
struct fuse_file_info *fi);
|
||||
```
|
||||
|
||||
The `getpath` operation allows a case-insensitive file system to report the correct case of a file path. For example, `getpath` can be used to report that the actual path of a file opened as `/PATH/TO/FILE` is really `/Path/To/File`. This capability is important for some Windows file system scenarios and can sometimes result in a performance improvement.
|
||||
|
||||
- [NEW] New `ntptfs` sample file system. This is a production quality pass through file system and should be used instead of the original `passthrough` file system that was developed for education purposes only.
|
||||
|
||||
- [NEW] Many performance improvements:
|
||||
|
||||
- A new `PostDispositionForDirOnly` setting has been added to `FSP_FSCTL_VOLUME_PARAMS`. This allows a file system to declare that it does not want to see `SetInformation/Disposition` requests for files (such requests will still be sent for directories, because a file system is supposed to check if a directory is empty before deletion). This makes file (not directory) deletion faster. This optimization should be safe to enable for most file systems. FUSE file systems get this optimization for free.
|
||||
|
||||
- The FSD now implements "fast I/O" reads and writes. Fast I/O is a technique for doing I/O without using IRP's (I/O Request Packets) and can only work for file systems using the cache manager (`FileInfoTimeout==-1`). This results in significant improvement in read/write scenarios.
|
||||
|
||||
- The FSD now implements "fast I/O" for "transact" messages. Transact messages are used in the communication protocol between the kernel-mode FSD and the user-mode file system. Fast I/O speeds this communication protocol by as much as 10% in some scenarios. (Fast I/O for transact messages is enabled only when using the new `FSP_IOCTL_TRANSACT` control code, but does not require any other special configuration to be enabled.)
|
||||
|
||||
- The FSD per directory cache limit has been increased from 16K to 64K. This should allow for more directory data to be maintained in kernel and reduce round-trips to the user mode file system.
|
||||
|
||||
- The user mode directory buffering mechanism (`FspFileSystemAcquireDirectoryBuffer`) has been improved. The mechanism uses the quick-sort algorithm internally which can exhibit bad performance when sorting already sorted data. The quick-sort algorithm has been improved with the use use of median of three partitioning, which alleviates this problem.
|
||||
|
||||
- [FIX] The WinFsp Network Provider now implements `NPGetUniversalName`. This fixes problems with some apps (e.g. Photos app).
|
||||
|
||||
- [FIX] WinFsp-FUSE now supports Azure AD accounts when specifying the `-o uid=-1` option. In addition a new option `-o uidmap=UID:SID` allows the specification of arbitrary UID<->SID or UID<->UserName mappings.
|
||||
|
||||
- [FIX] All executables (`*.exe,*.dll,*.sys`) in the WinFsp installation `bin` folder are now signed.
|
||||
|
||||
- [FIX] The default value for the registry setting `DistinctPermsForSameOwnerGroup` has been changed from 0 to 1.
|
||||
|
||||
- [BUILD] Product configuration (`MyProductName`, etc.) is done by the file `build.version.props` located in `build\VStudio`. This file was previously named `version.properties`.
|
||||
|
||||
|
||||
## v1.11B2 (2022+ARM64 Beta2)
|
||||
|
||||
- [NEW] ARM64 support! For details see [WinFsp on ARM64](https://github.com/winfsp/winfsp/wiki/WinFsp-on-ARM64).
|
||||
|
||||
- [NEW] A new file system operation has been added to the FUSE API:
|
||||
|
||||
```C
|
||||
int (*getpath)(const char *path, char *buf, size_t size,
|
||||
struct fuse_file_info *fi);
|
||||
```
|
||||
|
||||
The `getpath` operation allows a case-insensitive file system to report the correct case of a file path. For example, `getpath` can be used to report that the actual path of a file opened as `/PATH/TO/FILE` is really `/Path/To/File`. This capability is important for some Windows file system scenarios and can sometimes result in a performance improvement.
|
||||
|
||||
- [NEW] Many performance improvements:
|
||||
|
||||
- A new `PostDispositionForDirOnly` setting has been added to `FSP_FSCTL_VOLUME_PARAMS`. This allows a file system to declare that it does not want to see `SetInformation/Disposition` requests for files (such requests will still be sent for directories, because a file system is supposed to check if a directory is empty before deletion). This makes file (not directory) deletion faster. This optimization should be safe to enable for most file systems. FUSE file systems get this optimization for free.
|
||||
|
||||
- The FSD now implements "fast I/O" reads and writes. Fast I/O is a technique for doing I/O without using IRP's (I/O Request Packets) and can only work for file systems using the cache manager (`FileInfoTimeout==-1`). This results in significant improvement in read/write scenarios.
|
||||
|
||||
- The FSD per directory cache limit has been increased from 16K to 64K. This should allow for more directory data to be maintained in kernel and reduce round-trips to a user mode file system.
|
||||
|
||||
- The user mode directory buffering mechanism (`FspFileSystemAcquireDirectoryBuffer`) has been improved. The mechanism uses the quick-sort algorithm internally which can exhibit bad performance when sorting already sorted data. The quick-sort algorithm has been improved with the use use of median of three partitioning, which alleviates this problem.
|
||||
|
||||
- [NEW] The default value for the registry setting `DistinctPermsForSameOwnerGroup` has been changed from 0 to 1.
|
||||
|
||||
- [NEW] New `ntptfs` sample file system. This is a production quality pass through file system and should be used instead of the original `passthrough` file system that was developed for education purposes only.
|
||||
|
||||
- [FIX] The WinFsp Network Provider now implements `NPGetUniversalName`. This fixes problems with some apps (e.g. Photos app).
|
||||
|
||||
- [BUILD] Product configuration (`MyProductName`, etc.) is done by the file `build.version.props` located in `build\VStudio`. This file was previously named `version.properties`.
|
||||
|
||||
|
||||
## v1.11B1 (2022+ARM64 Beta1)
|
||||
|
||||
- [NEW] ARM64 support! For details see [WinFsp on ARM64](https://github.com/billziss-gh/winfsp/wiki/WinFsp-on-ARM64).
|
||||
- [NEW] ARM64 support! For details see [WinFsp on ARM64](https://github.com/winfsp/winfsp/wiki/WinFsp-on-ARM64).
|
||||
|
||||
- [NEW] New `ntptfs` sample file system. This is a production quality pass through file system and should be used instead of the original `passthrough` file system that was developed for education purposes only.
|
||||
|
||||
|
14
README.md
14
README.md
@ -7,11 +7,11 @@
|
||||
|
||||
<p align="center">
|
||||
<b>Download</b><br>
|
||||
<a href="https://github.com/billziss-gh/winfsp/releases/latest">
|
||||
<img src="https://img.shields.io/github/release/billziss-gh/winfsp.svg?label=stable&style=for-the-badge"/>
|
||||
<a href="https://github.com/winfsp/winfsp/releases/latest">
|
||||
<img src="https://img.shields.io/github/release/winfsp/winfsp.svg?label=stable&style=for-the-badge"/>
|
||||
</a>
|
||||
<a href="https://github.com/billziss-gh/winfsp/releases">
|
||||
<img src="https://img.shields.io/github/release/billziss-gh/winfsp/all.svg?label=latest&colorB=e52e4b&style=for-the-badge"/>
|
||||
<a href="https://github.com/winfsp/winfsp/releases">
|
||||
<img src="https://img.shields.io/github/release/winfsp/winfsp/all.svg?label=latest&colorB=e52e4b&style=for-the-badge"/>
|
||||
</a>
|
||||
<a href="https://chocolatey.org/packages/winfsp">
|
||||
<img src="https://img.shields.io/badge/choco-install%20winfsp-black.svg?style=for-the-badge"/>
|
||||
@ -53,7 +53,7 @@ WinFsp strives for compatibility with NTFS and file system correctness. For the
|
||||
WinFsp has an easy to use but comprehensive API.
|
||||
|
||||
* This simple [Tutorial](doc/WinFsp-Tutorial.asciidoc) explains how to build a file system.
|
||||
* Consult the [API Reference](http://www.secfs.net/winfsp/apiref/) for native development.
|
||||
* Consult the [API Reference](https://winfsp.dev/apiref) for native development.
|
||||
* Includes .NET layer for managed development. See [src/dotnet](src/dotnet).
|
||||
* Includes FUSE 2.8 compatibility layer: [fuse/fuse.h](inc/fuse/fuse.h)
|
||||
* Includes FUSE 3.2 compatibility layer: [fuse3/fuse.h](inc/fuse3/fuse.h)
|
||||
@ -63,7 +63,7 @@ WinFsp has an easy to use but comprehensive API.
|
||||
* Signed drivers provided on every release.
|
||||
* Available under the [GPLv3](License.txt) license with a special exception for Free/Libre and Open Source Software.
|
||||
|
||||
To learn more about WinFsp, please visit its website: http://www.secfs.net/winfsp/
|
||||
To learn more about WinFsp, please visit its website: https://winfsp.dev
|
||||
|
||||
## Project Organization
|
||||
|
||||
@ -125,7 +125,7 @@ I am looking for help in the following areas:
|
||||
|
||||
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
|
||||
* If you are working with a language other than C/C++ (e.g. Delphi, Java, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
|
||||
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
|
||||
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/winfsp/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
|
||||
|
||||
In all cases I can provide ideas and/or support.
|
||||
|
||||
|
10
appveyor.yml
10
appveyor.yml
@ -13,9 +13,9 @@ environment:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
CONFIGURATION: Release
|
||||
TESTING: Func
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
# CONFIGURATION: Release
|
||||
# TESTING: Func
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
CONFIGURATION: Release
|
||||
TESTING: Func
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CONFIGURATION: Release
|
||||
TESTING: Func
|
||||
@ -68,7 +68,9 @@ build_script:
|
||||
|
||||
test_script:
|
||||
- choco install winfsp -s build\VStudio\build\%CONFIGURATION% -y --pre
|
||||
- if %TESTING%==Func appveyor DownloadFile http://www.secfs.net/Test.Filter.Driver.zip && 7z x Test.Filter.Driver.zip
|
||||
- if %TESTING%==Func appveyor DownloadFile https://winfsp.dev/assets/pvt/Test.Filter.Driver.zip.001
|
||||
- if %TESTING%==Func appveyor DownloadFile https://winfsp.dev/assets/pvt/Test.Filter.Driver.zip.002
|
||||
- if %TESTING%==Func 7z x Test.Filter.Driver.zip.001
|
||||
- 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%
|
||||
|
@ -6,7 +6,8 @@
|
||||
|
||||
<!-- git revision -->
|
||||
<MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot>
|
||||
<MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
|
||||
<MyGitHead Condition=" Exists('$(MyGitRoot)/.git/HEAD')">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
|
||||
<MyGitHead Condition="!Exists('$(MyGitRoot)/.git/HEAD')">0000000</MyGitHead>
|
||||
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) And Exists('$(MyGitRoot)/.git/$(MyGitHead.Substring(5))')">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision>
|
||||
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) And !Exists('$(MyGitRoot)/.git/$(MyGitHead.Substring(5))')">$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText($(MyGitRoot)/.git/packed-refs)), '[0-9a-fA-F]{40,}.*$(MyGitHead.Substring(5))').Value.Substring(0, 7))</MyGitRevision>
|
||||
<MyGitRevision Condition="!$(MyGitHead.StartsWith(ref: ))">$(MyGitHead.Substring(0, 7))</MyGitRevision>
|
||||
@ -19,9 +20,12 @@
|
||||
|
||||
<MyCanonicalVersion>1.11</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2022+ARM64 Beta1</MyProductVersion>
|
||||
<MyProductVersion>2022+ARM64 Beta3</MyProductVersion>
|
||||
<MyProductStage>Beta</MyProductStage>
|
||||
|
||||
<MyCrossCert>DigiCert High Assurance EV Root CA.crt</MyCrossCert>
|
||||
<MyCertIssuer>DigiCert</MyCertIssuer>
|
||||
|
||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||
<MyFullVersion>$(MyCanonicalVersion).$(MyBuildNumber).$(MyGitRevision)</MyFullVersion>
|
||||
|
@ -48,6 +48,7 @@
|
||||
<ClInclude Include="..\..\src\shared\um\minimal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\dll\debug.c" />
|
||||
<ClCompile Include="..\..\src\dll\dirbuf.c" />
|
||||
<ClCompile Include="..\..\src\dll\eventlog.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse3\fuse2to3.c" />
|
||||
@ -64,7 +65,7 @@
|
||||
<ClCompile Include="..\..\src\dll\mount.c" />
|
||||
<ClCompile Include="..\..\src\dll\np.c" />
|
||||
<ClCompile Include="..\..\src\dll\security.c" />
|
||||
<ClCompile Include="..\..\src\dll\debug.c" />
|
||||
<ClCompile Include="..\..\src\dll\debuglog.c" />
|
||||
<ClCompile Include="..\..\src\dll\fsctl.c" />
|
||||
<ClCompile Include="..\..\src\dll\fsop.c" />
|
||||
<ClCompile Include="..\..\src\dll\library.c" />
|
||||
|
@ -94,7 +94,7 @@
|
||||
<ClCompile Include="..\..\src\dll\library.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\debug.c">
|
||||
<ClCompile Include="..\..\src\dll\debuglog.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\ntstatus.c">
|
||||
@ -172,6 +172,9 @@
|
||||
<ClCompile Include="..\..\src\dll\ldap.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\debug.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\dll\library.def">
|
||||
|
@ -1,4 +1,3 @@
|
||||
From: https://github.com/billziss-gh/winfsp/blob/master/License.txt
|
||||
From: https://github.com/winfsp/winfsp/blob/master/License.txt
|
||||
|
||||
LICENSE
|
||||
|
||||
|
@ -2,8 +2,8 @@ VERIFICATION
|
||||
Verification is intended to assist the Chocolatey moderators and community
|
||||
in verifying that this package's contents are trustworthy.
|
||||
|
||||
WinFsp GitHub repository: https://github.com/billziss-gh/winfsp
|
||||
WinFsp MSI releases : https://github.com/billziss-gh/winfsp/releases
|
||||
WinFsp GitHub repository: https://github.com/winfsp/winfsp
|
||||
WinFsp MSI releases : https://github.com/winfsp/winfsp/releases
|
||||
|
||||
You may use the Windows certutil utility to confirm the hash of the MSI
|
||||
included in this package against the WinFsp MSI release of the same version.
|
||||
@ -12,4 +12,3 @@ For example, for WinFsp version 1.0.17072 the command line to use is:
|
||||
certutil -hashfile winfsp-1.0.17072.msi SHA256
|
||||
|
||||
The certutil output of the MSI in this package is included below.
|
||||
|
||||
|
@ -3,20 +3,20 @@
|
||||
<metadata>
|
||||
<id>winfsp</id>
|
||||
<version>$version$</version>
|
||||
<packageSourceUrl>https://github.com/billziss-gh/winfsp/tree/master/build/choco</packageSourceUrl>
|
||||
<packageSourceUrl>https://github.com/winfsp/winfsp/tree/master/build/choco</packageSourceUrl>
|
||||
<owners>Bill Zissimopoulos</owners>
|
||||
|
||||
<title>WinFsp</title>
|
||||
<authors>Bill Zissimopoulos</authors>
|
||||
<projectUrl>https://github.com/billziss-gh/winfsp</projectUrl>
|
||||
<iconUrl>https://github.com/billziss-gh/winfsp/raw/master/art/winfsp-solid.png</iconUrl>
|
||||
<projectUrl>https://github.com/winfsp/winfsp</projectUrl>
|
||||
<iconUrl>https://github.com/winfsp/winfsp/raw/master/art/winfsp-solid.png</iconUrl>
|
||||
<copyright>Bill Zissimopoulos</copyright>
|
||||
<licenseUrl>https://github.com/billziss-gh/winfsp/blob/master/License.txt</licenseUrl>
|
||||
<licenseUrl>https://github.com/winfsp/winfsp/blob/master/License.txt</licenseUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<projectSourceUrl>https://github.com/billziss-gh/winfsp</projectSourceUrl>
|
||||
<docsUrl>https://github.com/billziss-gh/winfsp/tree/master/doc</docsUrl>
|
||||
<projectSourceUrl>https://github.com/winfsp/winfsp</projectSourceUrl>
|
||||
<docsUrl>https://github.com/winfsp/winfsp/tree/master/doc</docsUrl>
|
||||
<mailingListUrl>https://groups.google.com/forum/#!forum/winfsp</mailingListUrl>
|
||||
<bugTrackerUrl>https://github.com/billziss-gh/winfsp/issues</bugTrackerUrl>
|
||||
<bugTrackerUrl>https://github.com/winfsp/winfsp/issues</bugTrackerUrl>
|
||||
<tags>driver filesystem fuse gplv3 windows-kernel admin</tags>
|
||||
<summary>Windows File System Proxy - FUSE for Windows</summary>
|
||||
<description>
|
||||
@ -39,7 +39,7 @@ To verify installation:
|
||||
* For Cygwin: `net use m: '\\memfs64\share'`
|
||||
* To delete the drive: `net use m: /delete`
|
||||
</description>
|
||||
<releaseNotes>https://github.com/billziss-gh/winfsp/blob/master/Changelog.asciidoc</releaseNotes>
|
||||
<releaseNotes>https://github.com/winfsp/winfsp/blob/master/Changelog.md</releaseNotes>
|
||||
|
||||
<!--<dependencies>
|
||||
<dependency id="chocolatey-uninstall.extension" />
|
||||
|
@ -5,28 +5,31 @@ This document contains a list of known open-source file systems and file system
|
||||
== File Systems
|
||||
|
||||
- https://github.com/wesley1975/blobfs-win[blobfs-win] - The native porting of the blobfs on the windows platform, blobfs can help you mount the Azure Blob storage as the local disk driver, no matter it is a Linux system or a Windows system.
|
||||
- https://github.com/cryptomator/cryptomator[Cryptomator] - Multi-platform transparent client-side encryption of your files in the cloud
|
||||
- https://github.com/vgough/encfs[EncFS] - an Encrypted Filesystem for FUSE
|
||||
- https://github.com/lowleveldesign/fsmemfs[fsmemfs] - Memory File System written in F#
|
||||
- https://github.com/ihaveamac/fuse-3ds[fuse-3ds] - FUSE Filesystem Python scripts for Nintendo 3DS files
|
||||
- https://github.com/sganis/golddrive[golddrive] - Windows ssh network drive
|
||||
- https://github.com/billziss-gh/hubfs[hubfs] - File system for GitHub
|
||||
- https://github.com/winfsp/hubfs[hubfs] - File system for GitHub
|
||||
- https://github.com/FrKaram/KS2.Drive[KS2.Drive] - Mount a webDAV/AOS server as a local drive
|
||||
- https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows
|
||||
- https://github.com/billziss-gh/objfs[objfs] - Object Storage File System
|
||||
- https://github.com/winfsp/nfs-win[nfs-win] - NFS for Windows
|
||||
- https://github.com/winfsp/objfs[objfs] - Object Storage File System
|
||||
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage
|
||||
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives
|
||||
- https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming
|
||||
- https://github.com/s3fs-fuse/s3fs-fuse[s3fs-fuse] - FUSE-based file system backed by Amazon S3
|
||||
- https://github.com/netheril96/securefs[securefs] - Filesystem in userspace (FUSE) with transparent authenticated encryption
|
||||
- https://github.com/billziss-gh/sshfs-win[sshfs-win] - SSHFS for Windows
|
||||
- https://github.com/winfsp/sshfs-win[sshfs-win] - SSHFS for Windows
|
||||
- https://github.com/printpagestopdf/WordpressDrive[WordpressDrive] - Windows Userspace Filesystem based on WinFsp that presents a Wordpress Site as a Windows Drive
|
||||
- https://github.com/emoose/xbox-winfsp[xbox-winfsp] - Adds native support to Windows for the FATX, STFS & GDFX (aka XGD/XDVDFS) Xbox filesystems.
|
||||
- https://github.com/UtrechtUniversity/YodaDrive[YodaDrive] - Mount a Yoda drive as a local drive
|
||||
|
||||
== File System Libraries
|
||||
|
||||
- https://github.com/billziss-gh/cgofuse[Go: cgofuse] - Cross-platform FUSE library for Go
|
||||
- https://github.com/DuroSoft/fuse-bindings[Nodejs: fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
|
||||
- https://github.com/winfsp/cgofuse[Go: cgofuse] - Cross-platform FUSE library for Go
|
||||
- https://github.com/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR)
|
||||
- https://github.com/jnr-winfsp-team/jnr-winfsp[Java: jnr-winfsp] - A Java binding for WinFsp using Java Native Runtime (JNR)
|
||||
- https://github.com/DuroSoft/fuse-bindings[Nodejs: fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
|
||||
- https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
|
||||
- https://github.com/pleiszenburg/refuse[Python: refuse] - Simple cross-plattform ctypes bindings for libfuse / FUSE for macOS / WinFsp
|
||||
- https://github.com/Scille/winfspy[Python: winfspy] - WinFSP binding for Python
|
||||
|
@ -6,7 +6,7 @@ This document compares the "native" WinFsp API to the FUSE API and provides a ra
|
||||
|
||||
WinFsp provides two different but conceptually similar API's for the same purpose of implementing a user mode file system:
|
||||
|
||||
- The WinFsp API, which is documented in the include file `inc/winfsp/winfsp.h` (and online at http://www.secfs.net/winfsp/apiref/). This API consists of the `FSP_FILE_SYSTEM_INTERFACE` "class" and the `FspFileSystem*` functions.
|
||||
- The WinFsp API, which is documented in the include file `inc/winfsp/winfsp.h` (and online at https://winfsp.dev/apiref). This API consists of the `FSP_FILE_SYSTEM_INTERFACE` "class" and the `FspFileSystem*` functions.
|
||||
- The FUSE (high-level) API, which is the well understood API from the FUSE project originally by Miklos Szeredi.
|
||||
|
||||
Given the similarities between the two API's some questions naturally arise:
|
||||
|
@ -1,6 +1,6 @@
|
||||
= Queued Events - Windows kernel events with IOCP scheduling characteristics
|
||||
|
||||
In this article I am discussing _Queued Events_. _Queued Events_ are a Windows kernel synchronization mechanism that I invented for https://github.com/billziss-gh/winfsp[WinFsp - FUSE for Windows]. _Queued Events_ behave like kernel Synchronization Events (i.e. Win32 auto-reset events), but provide scheduling characteristics similar to those of I/O Completion Ports.
|
||||
In this article I am discussing _Queued Events_. _Queued Events_ are a Windows kernel synchronization mechanism that I invented for https://github.com/winfsp/winfsp[WinFsp - FUSE for Windows]. _Queued Events_ behave like kernel Synchronization Events (i.e. Win32 auto-reset events), but provide scheduling characteristics similar to those of I/O Completion Ports.
|
||||
|
||||
== The Problem
|
||||
|
||||
@ -92,7 +92,7 @@ We now have to consider what happens when we have one EventSet concurrently with
|
||||
|
||||
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.
|
||||
|
||||
The complete implementation of _Queued Events_ within WinFsp can be found here: https://github.com/billziss-gh/winfsp/blob/v1.1/src/sys/driver.h#L655-L795
|
||||
The complete implementation of _Queued Events_ within WinFsp can be found here: https://github.com/winfsp/winfsp/blob/v1.1/src/sys/driver.h#L655-L795
|
||||
|
||||
== Queued Events Scheduling Characteristics
|
||||
|
||||
@ -102,4 +102,3 @@ Queued Events encapsulate KQUEUE's and therefore inherit their scheduling charac
|
||||
- They limit the number of threads that can be satisfied concurrently.
|
||||
|
||||
These characteristics are desirable because they reduce the number of context switches thus speeding up the WinFsp IPC implementation. Performance testing immediately after the incorporation of _Queued Events_ into WinFsp showed significant performance improvements; profiling with xperf showed that context switches among file system threads were now a relatively rare event!
|
||||
|
||||
|
@ -91,7 +91,7 @@ implib=${prefix}/bin/winfsp-${arch}.dll
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE compatible API
|
||||
Version: 2.8
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
URL: https://winfsp.dev
|
||||
Libs: "${implib}"
|
||||
Cflags: -I"${incdir}"
|
||||
----
|
||||
|
@ -15,9 +15,9 @@ 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".
|
||||
All testing was performed using a new performance test suite developed as part of WinFsp, called https://github.com/winfsp/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 is based on the https://github.com/winfsp/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:
|
||||
|
||||
|
@ -15,7 +15,7 @@ NOTE: The file system that we build in this tutorial is suitable for education p
|
||||
|
||||
== Prerequisites
|
||||
|
||||
This tutorial assumes that you have WinFsp and Visual Studio 2015 installed. The WinFsp installer can be downloaded from the WinFsp GitHub repository: https://github.com/billziss-gh/winfsp. The Microsoft Visual Studio Community 2015 can be downloaded for free from Microsoft's web site.
|
||||
This tutorial assumes that you have WinFsp and Visual Studio 2015 installed. The WinFsp installer can be downloaded from the WinFsp GitHub repository: https://github.com/winfsp/winfsp. The Microsoft Visual Studio Community 2015 can be downloaded for free from Microsoft's web site.
|
||||
|
||||
When installing WinFsp make sure to choose "Developer" to ensure that all necessary header and library files are included in the installation.
|
||||
|
||||
|
@ -48,25 +48,51 @@ void tlib_add_test_opt(const char *name, void (*fn)(void))
|
||||
add_test_to_list(name, fn, 1, &test_tail);
|
||||
}
|
||||
|
||||
struct hook
|
||||
{
|
||||
void (*fn)(const char *name, void (*fn)(void), int v);
|
||||
struct hook *next;
|
||||
};
|
||||
static struct hook hook_sentinel = { .next = &hook_sentinel };
|
||||
static struct hook *hook_tail = &hook_sentinel;
|
||||
static void add_hook_to_list(void (*fn)(void), struct hook **tail)
|
||||
{
|
||||
struct hook *hook = calloc(1, sizeof *hook);
|
||||
hook->fn = fn;
|
||||
hook->next = (*tail)->next;
|
||||
(*tail)->next = hook;
|
||||
(*tail) = hook;
|
||||
}
|
||||
void tlib_add_hook(void (*fn)(const char *name, void (*fn)(void), int v))
|
||||
{
|
||||
add_hook_to_list(fn, &hook_tail);
|
||||
}
|
||||
|
||||
static FILE *tlib_out, *tlib_err;
|
||||
static jmp_buf test_jmp_buf, *test_jmp;
|
||||
static char assert_buf[256];
|
||||
static void test_printf(const char *fmt, ...);
|
||||
static double run_test(struct test *test)
|
||||
{
|
||||
double res;
|
||||
for (struct hook *hook = hook_tail->next->next; 0 != hook->fn; hook = hook->next)
|
||||
hook->fn(test->name, test->fn, +1);
|
||||
#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;
|
||||
res = (t1 - t0) / 1000.0;
|
||||
#else
|
||||
time_t t0 = time(0);
|
||||
test->fn();
|
||||
time_t t1 = time(0);
|
||||
return difftime(t1, t0);
|
||||
res = difftime(t1, t0);
|
||||
#endif
|
||||
for (struct hook *hook = hook_tail->next->next; 0 != hook->fn; hook = hook->next)
|
||||
hook->fn(test->name, test->fn, -1);
|
||||
return res;
|
||||
}
|
||||
static void do_test_default(struct test *test, int testno)
|
||||
{
|
||||
|
@ -65,6 +65,23 @@ void tlib_add_test_suite(const char *name, void (*fn)(void));
|
||||
void tlib_add_test(const char *name, void (*fn)(void));
|
||||
void tlib_add_test_opt(const char *name, void (*fn)(void));
|
||||
|
||||
/**
|
||||
* Register a test hook to be run before and after every test.
|
||||
*
|
||||
* Test hooks are functions with prototype
|
||||
* <code>void testhook(const char *name, void (*fn)(void), int v)</code>.
|
||||
* The parameter v specifies that a test is about to be executed (v is +1)
|
||||
* or it was just executed (v is -1).
|
||||
*/
|
||||
#define TESTHOOK(fn)\
|
||||
do\
|
||||
{\
|
||||
void fn(const char *name, void (*fn)(void), int v);\
|
||||
tlib_add_hook(fn);\
|
||||
} while (0)
|
||||
|
||||
void tlib_add_hook(void (*fn)(const char *name, void (*fn)(void), int v));
|
||||
|
||||
/**
|
||||
* Printf function.
|
||||
*
|
||||
|
@ -103,8 +103,10 @@ struct fuse_operations
|
||||
/* _ */ int (*flock)(const char *path, struct fuse_file_info *, int op);
|
||||
/* _ */ int (*fallocate)(const char *path, int mode, fuse_off_t off, fuse_off_t len,
|
||||
struct fuse_file_info *fi);
|
||||
/* WinFsp */
|
||||
/* S */ int (*getpath)(const char *path, char *buf, size_t size,
|
||||
struct fuse_file_info *fi);
|
||||
/* OSXFUSE */
|
||||
/* _ */ int (*reserved00)();
|
||||
/* _ */ int (*reserved01)();
|
||||
/* _ */ int (*reserved02)();
|
||||
/* _ */ int (*statfs_x)(const char *path, struct fuse_statfs *stbuf);
|
||||
|
@ -94,6 +94,9 @@ extern "C" {
|
||||
#define FSP_FUSE_NOTIFY_CHFLAGS 0x0080
|
||||
#define FSP_FUSE_NOTIFY_TRUNCATE 0x0100
|
||||
|
||||
/* getpath extension */
|
||||
#define FSP_FUSE_HAS_GETPATH 1
|
||||
|
||||
struct fuse_file_info
|
||||
{
|
||||
int flags;
|
||||
|
@ -97,8 +97,12 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'L', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_TRANSACT \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'T', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_IOCTL_TRANSACT \
|
||||
CTL_CODE(0x8000 | ('F'<<8) | 'W', 0x800 + 'T', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_TRANSACT_BATCH \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 't', METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||
#define FSP_IOCTL_TRANSACT_BATCH \
|
||||
CTL_CODE(0x8000 | ('F'<<8) | 'W', 0x800 + 't', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_STOP \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_STOP0 \
|
||||
@ -109,6 +113,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
|
||||
/* fsctl internal device codes (usable only in-kernel) */
|
||||
#define FSP_FSCTL_TRANSACT_INTERNAL \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'I', METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||
#define FSP_IOCTL_TRANSACT_INTERNAL \
|
||||
CTL_CODE(0x8000 | ('F'<<8) | 'W', 0x800 + 'I', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
/* fsvol device codes */
|
||||
#define FSP_FSCTL_QUERY_WINFSP \
|
||||
@ -222,7 +228,8 @@ enum
|
||||
UINT32 DirectoryMarkerAsNextOffset:1; /* directory marker is next offset instead of last name */\
|
||||
UINT32 RejectIrpPriorToTransact0:1; /* reject IRP's prior to FspFsctlTransact with 0 buffers */\
|
||||
UINT32 SupportsPosixUnlinkRename:1; /* file system supports POSIX-style unlink and rename */\
|
||||
UINT32 KmReservedFlags:2;\
|
||||
UINT32 PostDispositionWhenNecessaryOnly:1; /* post Disposition for dirs or READONLY attr check */\
|
||||
UINT32 KmReservedFlags:1;\
|
||||
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
|
||||
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
|
||||
|
@ -1750,6 +1750,8 @@ FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
|
||||
/*
|
||||
* Directory buffering
|
||||
*/
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBufferEx(PVOID* PDirBuffer,
|
||||
BOOLEAN Reset, ULONG CapacityHint, PNTSTATUS PResult);
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult);
|
||||
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
@ -1833,6 +1835,7 @@ NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
/*
|
||||
* POSIX Interop
|
||||
*/
|
||||
FSP_API NTSTATUS FspPosixSetUidMap(UINT32 Uid[], PSID Sid[], ULONG Count);
|
||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid);
|
||||
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid);
|
||||
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)());
|
||||
|
@ -4,9 +4,9 @@ RELEASE=10
|
||||
CATEGORY="Utils"
|
||||
SUMMARY="WinFsp FUSE compatibility layer"
|
||||
DESCRIPTION="Enables FUSE file systems to be run on Cygwin."
|
||||
HOMEPAGE="http://www.secfs.net/winfsp/"
|
||||
HOMEPAGE="https://winfsp.dev"
|
||||
|
||||
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/billziss-gh/winfsp/archive/master.tar.gz"}
|
||||
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/winfsp/winfsp/archive/master.tar.gz"}
|
||||
SRC_DIR=${CYGPORT_SRC_DIR:-winfsp-master}
|
||||
|
||||
src_compile()
|
||||
|
@ -4,6 +4,6 @@ incdir=${prefix}/include/fuse
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE compatible API
|
||||
Version: @Version@
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
URL: https://winfsp.dev
|
||||
Libs: -lfuse-@Version@
|
||||
Cflags: -I"${incdir}" -DCYGFUSE
|
||||
|
@ -4,9 +4,9 @@ RELEASE=2
|
||||
CATEGORY="Utils"
|
||||
SUMMARY="WinFsp FUSE3 compatibility layer"
|
||||
DESCRIPTION="Enables FUSE3 file systems to be run on Cygwin."
|
||||
HOMEPAGE="http://www.secfs.net/winfsp/"
|
||||
HOMEPAGE="https://winfsp.dev"
|
||||
|
||||
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/billziss-gh/winfsp/archive/master.tar.gz"}
|
||||
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/winfsp/winfsp/archive/master.tar.gz"}
|
||||
SRC_DIR=${CYGPORT_SRC_DIR:-winfsp-master}
|
||||
|
||||
REQUIRES="fuse"
|
||||
|
@ -4,6 +4,6 @@ incdir=${prefix}/include/fuse3
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE3 compatible API
|
||||
Version: @Version@
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
URL: https://winfsp.dev
|
||||
Libs: -lfuse-@Version@
|
||||
Cflags: -I"${incdir}" -DCYGFUSE
|
||||
|
881
src/dll/debug.c
881
src/dll/debug.c
@ -20,871 +20,22 @@
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
#include <sddl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static HANDLE FspDebugLogHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle)
|
||||
#if !defined(NDEBUG)
|
||||
ULONG DebugRandom(VOID)
|
||||
{
|
||||
FspDebugLogHandle = Handle;
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLog(const char *format, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
/* DbgPrint has a 512 byte limit, but wvsprintf is only safe with a 1024 byte buffer */
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
wvsprintfA(buf, format, ap);
|
||||
va_end(ap);
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
if (INVALID_HANDLE_VALUE != FspDebugLogHandle)
|
||||
{
|
||||
DWORD bytes;
|
||||
WriteFile(FspDebugLogHandle, buf, lstrlenA(buf), &bytes, 0);
|
||||
}
|
||||
else
|
||||
OutputDebugStringA(buf);
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||
{
|
||||
char *Sddl;
|
||||
|
||||
if (0 == SecurityDescriptor)
|
||||
FspDebugLog(format, "null security descriptor");
|
||||
else if (ConvertSecurityDescriptorToStringSecurityDescriptorA(SecurityDescriptor,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0))
|
||||
{
|
||||
FspDebugLog(format, Sddl);
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
else
|
||||
FspDebugLog(format, "invalid security descriptor");
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogSid(const char *format, PSID Sid)
|
||||
{
|
||||
char *S;
|
||||
|
||||
if (0 == Sid)
|
||||
FspDebugLog(format, "null SID");
|
||||
else if (ConvertSidToStringSidA(Sid, &S))
|
||||
{
|
||||
FspDebugLog(format, S);
|
||||
LocalFree(S);
|
||||
}
|
||||
else
|
||||
FspDebugLog(format, "invalid SID");
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime)
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
char buf[32];
|
||||
|
||||
if (FileTimeToSystemTime(FileTime, &SystemTime))
|
||||
{
|
||||
wsprintfA(buf, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03huZ",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds);
|
||||
FspDebugLog(format, buf);
|
||||
}
|
||||
else
|
||||
FspDebugLog(format, "invalid file time");
|
||||
}
|
||||
|
||||
#define MAKE_UINT32_PAIR(v) \
|
||||
((PLARGE_INTEGER)&(v))->HighPart, ((PLARGE_INTEGER)&(v))->LowPart
|
||||
|
||||
static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
|
||||
{
|
||||
switch ((CreateOptions >> 24) & 0xff)
|
||||
{
|
||||
case FILE_CREATE:
|
||||
return "FILE_CREATE";
|
||||
case FILE_OPEN:
|
||||
return "FILE_OPEN";
|
||||
case FILE_OPEN_IF:
|
||||
return "FILE_OPEN_IF";
|
||||
case FILE_OVERWRITE:
|
||||
return "FILE_OVERWRITE";
|
||||
case FILE_SUPERSEDE:
|
||||
return "FILE_SUPERSEDE";
|
||||
case FILE_OVERWRITE_IF:
|
||||
return "FILE_OVERWRITE_IF";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", (PVOID)UserContext, (PVOID)UserContext2);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogFileTimeString(UINT64 FileTime, char *Buf)
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
|
||||
if (0 == FileTime)
|
||||
lstrcpyA(Buf, "0");
|
||||
else if (FileTimeToSystemTime((PFILETIME)&FileTime, &SystemTime))
|
||||
{
|
||||
wsprintfA(Buf, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03huZ",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds);
|
||||
}
|
||||
else
|
||||
lstrcpyA(Buf, "INVALID");
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogFileInfoString(FSP_FSCTL_FILE_INFO *FileInfo, char *Buf)
|
||||
{
|
||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32], ChangeTimeBuf[32];
|
||||
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"FileAttributes=%lx, "
|
||||
"ReparseTag=%lx, "
|
||||
"AllocationSize=%lx:%lx, "
|
||||
"FileSize=%lx:%lx, "
|
||||
"CreationTime=%s, "
|
||||
"LastAccessTime=%s, "
|
||||
"LastWriteTime=%s, "
|
||||
"ChangeTime=%s, "
|
||||
"IndexNumber=%lx:%lx"
|
||||
"}",
|
||||
FileInfo->FileAttributes,
|
||||
FileInfo->ReparseTag,
|
||||
MAKE_UINT32_PAIR(FileInfo->AllocationSize),
|
||||
MAKE_UINT32_PAIR(FileInfo->FileSize),
|
||||
FspDebugLogFileTimeString(FileInfo->CreationTime, CreationTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->LastAccessTime, LastAccessTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->LastWriteTime, LastWriteTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->ChangeTime, ChangeTimeBuf),
|
||||
MAKE_UINT32_PAIR(FileInfo->IndexNumber));
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogVolumeInfoString(FSP_FSCTL_VOLUME_INFO *VolumeInfo, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"TotalSize=%lx:%lx, "
|
||||
"FreeSize=%lx:%lx, "
|
||||
"VolumeLabel=\"%.32S\""
|
||||
"}",
|
||||
MAKE_UINT32_PAIR(VolumeInfo->TotalSize),
|
||||
MAKE_UINT32_PAIR(VolumeInfo->FreeSize),
|
||||
&VolumeInfo->VolumeLabel);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogWideCharBufferString(PVOID WideCharBuf, ULONG Length, char *Buf)
|
||||
{
|
||||
WCHAR TempWideCharBuf[64 + 1];
|
||||
|
||||
if (Length > sizeof TempWideCharBuf - sizeof(WCHAR))
|
||||
Length = sizeof TempWideCharBuf - sizeof(WCHAR);
|
||||
|
||||
memcpy(TempWideCharBuf, WideCharBuf, Length);
|
||||
TempWideCharBuf[Length / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
wsprintfA(Buf, "%.64S", TempWideCharBuf);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
|
||||
{
|
||||
union
|
||||
{
|
||||
PREPARSE_DATA_BUFFER D;
|
||||
PREPARSE_GUID_DATA_BUFFER G;
|
||||
} ReparseData;
|
||||
char SubstituteName[64 + 1], PrintName[64 + 1];
|
||||
|
||||
ReparseData.D = ReparseData0;
|
||||
if (0 == ReparseData.D->ReparseDataLength)
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=%#lx, "
|
||||
"ReparseDataLength=%hu"
|
||||
"}",
|
||||
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
|
||||
else if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData.D->ReparseTag)
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=IO_REPARSE_TAG_MOUNT_POINT, "
|
||||
"SubstituteName=\"%s\", "
|
||||
"PrintName=\"%s\""
|
||||
"}",
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->MountPointReparseBuffer.PathBuffer +
|
||||
ReparseData.D->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->MountPointReparseBuffer.SubstituteNameLength,
|
||||
SubstituteName),
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->MountPointReparseBuffer.PathBuffer +
|
||||
ReparseData.D->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->MountPointReparseBuffer.PrintNameLength,
|
||||
PrintName));
|
||||
else if (IO_REPARSE_TAG_SYMLINK == ReparseData.D->ReparseTag)
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=IO_REPARSE_TAG_SYMLINK, "
|
||||
"SubstituteName=\"%s\", "
|
||||
"PrintName=\"%s\", "
|
||||
"Flags=%u"
|
||||
"}",
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameLength,
|
||||
SubstituteName),
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameLength,
|
||||
PrintName),
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.Flags);
|
||||
else if (IsReparseTagMicrosoft(ReparseData.D->ReparseTag))
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=%#lx, "
|
||||
"ReparseDataLength=%hu"
|
||||
"}",
|
||||
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
|
||||
else
|
||||
#define Guid ReparseData.G->ReparseGuid
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=%#lx, "
|
||||
"ReparseDataLength=%hu, "
|
||||
"ReparseGuid={%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
|
||||
"}",
|
||||
ReparseData.G->ReparseTag, ReparseData.G->ReparseDataLength,
|
||||
Guid.Data1, Guid.Data2, Guid.Data3,
|
||||
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
|
||||
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
|
||||
#undef Guid
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, Name);
|
||||
}
|
||||
|
||||
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint, Name,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information);
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
{
|
||||
char UserContextBuf[40];
|
||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32];
|
||||
char InfoBuf[256];
|
||||
char *Sddl = 0;
|
||||
|
||||
switch (Request->Kind)
|
||||
{
|
||||
case FspFsctlTransactReservedKind:
|
||||
FspDebugLogRequestVoid(Request, "RESERVED");
|
||||
break;
|
||||
case FspFsctlTransactCreateKind:
|
||||
if (0 != Request->Req.Create.SecurityDescriptor.Offset)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
|
||||
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
||||
"AllocationSize=%lx:%lx, "
|
||||
"AccessToken=%p[PID=%lx], DesiredAccess=%lx, GrantedAccess=%lx, "
|
||||
"ShareAccess=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Create.UserMode ? 'U' : 'K',
|
||||
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
|
||||
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
|
||||
Request->Req.Create.HasRestorePrivilege ? 'R' : '-',
|
||||
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
|
||||
Request->Req.Create.CaseSensitive ? 'C' : '-',
|
||||
(PWSTR)Request->Buffer,
|
||||
FspDebugLogDispositionString(Request->Req.Create.CreateOptions),
|
||||
Request->Req.Create.CreateOptions & 0xffffff,
|
||||
Request->Req.Create.FileAttributes,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "",
|
||||
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken),
|
||||
Request->Req.Create.DesiredAccess,
|
||||
Request->Req.Create.GrantedAccess,
|
||||
Request->Req.Create.ShareAccess);
|
||||
LocalFree(Sddl);
|
||||
break;
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
|
||||
"FileAttributes=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Overwrite.UserContext, Request->Req.Overwrite.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Overwrite.FileAttributes);
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Cleanup.Delete ? " [Delete]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Cleanup.UserContext, Request->Req.Cleanup.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Close %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Close.UserContext, Request->Req.Close.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
|
||||
UserContextBuf),
|
||||
(PVOID)Request->Req.Read.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
|
||||
Request->Req.Read.Length,
|
||||
Request->Req.Read.Key);
|
||||
break;
|
||||
case FspFsctlTransactWriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Write.ConstrainedIo ? " [C]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
|
||||
UserContextBuf),
|
||||
(PVOID)Request->Req.Write.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
|
||||
Request->Req.Write.Length,
|
||||
Request->Req.Write.Key);
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryInformation.UserContext, Request->Req.QueryInformation.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
switch (Request->Req.SetInformation.FileInformationClass)
|
||||
{
|
||||
case 4/*FileBasicInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
|
||||
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.Basic.FileAttributes,
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.CreationTime,
|
||||
CreationTimeBuf),
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastAccessTime,
|
||||
LastAccessTimeBuf),
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastWriteTime,
|
||||
LastWriteTimeBuf));
|
||||
break;
|
||||
case 19/*FileAllocationInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
|
||||
"AllocationSize=%lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.Allocation.AllocationSize));
|
||||
break;
|
||||
case 20/*FileEndOfFileInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
|
||||
"FileSize = %lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.EndOfFile.FileSize));
|
||||
break;
|
||||
case 13/*FileDispositionInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%S%s%s, "
|
||||
"%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.Disposition.Delete ? "Delete" : "Undelete");
|
||||
break;
|
||||
case 64/*FileDispositionInformationEx*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [DispositionEx] %s%S%s%s, "
|
||||
"Flags=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.DispositionEx.Flags);
|
||||
break;
|
||||
case 10/*FileRenameInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
|
||||
"NewFileName=\"%S\", AccessToken=%p[PID=%lx]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken));
|
||||
break;
|
||||
case 65/*FileRenameInformationEx*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [RenameEx] %s%S%s%s, "
|
||||
"NewFileName=\"%S\", AccessToken=%p[PID=%lx], Flags=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||
Request->Req.SetInformation.Info.RenameEx.Flags);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryEaKind:
|
||||
FspDebugLogRequestVoid(Request, "QUERYEA");
|
||||
break;
|
||||
case FspFsctlTransactSetEaKind:
|
||||
FspDebugLogRequestVoid(Request, "SETEA");
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FlushBuffers.UserContext, Request->Req.FlushBuffers.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryVolumeInformationKind:
|
||||
FspDebugLogRequestVoid(Request, "QueryVolumeInformation");
|
||||
break;
|
||||
case FspFsctlTransactSetVolumeInformationKind:
|
||||
switch (Request->Req.SetVolumeInformation.FsInformationClass)
|
||||
{
|
||||
case 2/*FileFsLabelInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
|
||||
"Label=\"%S\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
(PWSTR)Request->Buffer);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
|
||||
"Address=%p, Length=%ld, Pattern=%s%S%s, Marker=%s%S%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
|
||||
UserContextBuf),
|
||||
(PVOID)Request->Req.QueryDirectory.Address,
|
||||
Request->Req.QueryDirectory.Length,
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Pattern.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Marker.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Marker.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Marker.Size ? "\"" : "");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
switch (Request->Req.FileSystemControl.FsControlCode)
|
||||
{
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
|
||||
"ReparseData=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
|
||||
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||
UserContextBuf),
|
||||
FspDebugLogReparseDataString(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||
InfoBuf));
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactDeviceControlKind:
|
||||
FspDebugLogRequestVoid(Request, "DEVICECONTROL");
|
||||
break;
|
||||
case FspFsctlTransactShutdownKind:
|
||||
FspDebugLogRequestVoid(Request, "SHUTDOWN");
|
||||
break;
|
||||
case FspFsctlTransactLockControlKind:
|
||||
FspDebugLogRequestVoid(Request, "LOCKCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QuerySecurity.UserContext, Request->Req.QuerySecurity.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetSecurityKind:
|
||||
if (0 != Request->Req.SetSecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Request->Buffer + Request->Req.SetSecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
|
||||
"SecurityInformation=%lx, Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetSecurity.UserContext, Request->Req.SetSecurity.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetSecurity.SecurityInformation,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
break;
|
||||
case FspFsctlTransactQueryStreamInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)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:
|
||||
FspDebugLogRequestVoid(Request, "INVALID");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
if (STATUS_PENDING == Response->IoStatus.Status)
|
||||
return;
|
||||
|
||||
char UserContextBuf[40];
|
||||
char InfoBuf[256];
|
||||
char *Sddl = 0;
|
||||
|
||||
switch (Response->Kind)
|
||||
{
|
||||
case FspFsctlTransactReservedKind:
|
||||
FspDebugLogResponseStatus(Response, "RESERVED");
|
||||
break;
|
||||
case FspFsctlTransactCreateKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Create");
|
||||
else if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||
{
|
||||
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.FileName=\"%s\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogWideCharBufferString(
|
||||
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||
Response->Rsp.Create.Reparse.Buffer.Size,
|
||||
InfoBuf));
|
||||
else if (1/*IO_REMOUNT*/ == Response->IoStatus.Information)
|
||||
FspDebugLogResponseStatus(Response, "Create");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.Data=\"%s\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogReparseDataString(
|
||||
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||
InfoBuf));
|
||||
}
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogUserContextString(
|
||||
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
|
||||
UserContextBuf),
|
||||
Response->Rsp.Create.Opened.GrantedAccess,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Create.Opened.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Overwrite");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLogResponseStatus(Response, "Cleanup");
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLogResponseStatus(Response, "Close");
|
||||
break;
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLogResponseStatus(Response, "Read");
|
||||
break;
|
||||
case FspFsctlTransactWriteKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Write");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QueryInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryEaKind:
|
||||
FspDebugLogResponseStatus(Response, "QUERYEA");
|
||||
break;
|
||||
case FspFsctlTransactSetEaKind:
|
||||
FspDebugLogResponseStatus(Response, "SETEA");
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLogResponseStatus(Response, "FlushBuffers");
|
||||
break;
|
||||
case FspFsctlTransactQueryVolumeInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QueryVolumeInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetVolumeInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetVolumeInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLogResponseStatus(Response, "QueryDirectory");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status) ||
|
||||
0 == Response->Rsp.FileSystemControl.Buffer.Size)
|
||||
FspDebugLogResponseStatus(Response, "FileSystemControl");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
|
||||
"ReparseData=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||
InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactDeviceControlKind:
|
||||
FspDebugLogResponseStatus(Response, "DEVICECONTROL");
|
||||
break;
|
||||
case FspFsctlTransactShutdownKind:
|
||||
FspDebugLogResponseStatus(Response, "SHUTDOWN");
|
||||
break;
|
||||
case FspFsctlTransactLockControlKind:
|
||||
FspDebugLogResponseStatus(Response, "LOCKCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QuerySecurity");
|
||||
else
|
||||
{
|
||||
if (0 != Response->Rsp.QuerySecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Response->Buffer + Response->Rsp.QuerySecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactSetSecurityKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetSecurity");
|
||||
else
|
||||
{
|
||||
if (0 != Response->Rsp.SetSecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Response->Buffer + Response->Rsp.SetSecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryStreamInformationKind:
|
||||
FspDebugLogResponseStatus(Response, "QueryStreamInformation");
|
||||
break;
|
||||
default:
|
||||
FspDebugLogResponseStatus(Response, "INVALID");
|
||||
break;
|
||||
}
|
||||
static SRWLOCK SlimLock = SRWLOCK_INIT;
|
||||
static ULONG Seed = 1;
|
||||
ULONG Result;
|
||||
|
||||
AcquireSRWLockExclusive(&SlimLock);
|
||||
|
||||
/* see ucrt sources */
|
||||
Seed = Seed * 214013 + 2531011;
|
||||
Result = (Seed >> 16) & 0x7fff;
|
||||
|
||||
ReleaseSRWLockExclusive(&SlimLock);
|
||||
|
||||
return Result;
|
||||
}
|
||||
#endif
|
||||
|
890
src/dll/debuglog.c
Normal file
890
src/dll/debuglog.c
Normal file
@ -0,0 +1,890 @@
|
||||
/**
|
||||
* @file dll/debuglog.c
|
||||
*
|
||||
* @copyright 2015-2022 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this software
|
||||
* in accordance with the commercial license agreement provided in
|
||||
* conjunction with the software. The terms and conditions of any such
|
||||
* commercial license agreement shall govern, supersede, and render
|
||||
* ineffective any application of the GPLv3 license to this software,
|
||||
* notwithstanding of any reference thereto in the software or
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
#include <sddl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static HANDLE FspDebugLogHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
FSP_API VOID FspDebugLogSetHandle(HANDLE Handle)
|
||||
{
|
||||
FspDebugLogHandle = Handle;
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLog(const char *format, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
/* DbgPrint has a 512 byte limit, but wvsprintf is only safe with a 1024 byte buffer */
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
wvsprintfA(buf, format, ap);
|
||||
va_end(ap);
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
if (INVALID_HANDLE_VALUE != FspDebugLogHandle)
|
||||
{
|
||||
DWORD bytes;
|
||||
WriteFile(FspDebugLogHandle, buf, lstrlenA(buf), &bytes, 0);
|
||||
}
|
||||
else
|
||||
OutputDebugStringA(buf);
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||
{
|
||||
char *Sddl;
|
||||
|
||||
if (0 == SecurityDescriptor)
|
||||
FspDebugLog(format, "null security descriptor");
|
||||
else if (ConvertSecurityDescriptorToStringSecurityDescriptorA(SecurityDescriptor,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0))
|
||||
{
|
||||
FspDebugLog(format, Sddl);
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
else
|
||||
FspDebugLog(format, "invalid security descriptor");
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogSid(const char *format, PSID Sid)
|
||||
{
|
||||
char *S;
|
||||
|
||||
if (0 == Sid)
|
||||
FspDebugLog(format, "null SID");
|
||||
else if (ConvertSidToStringSidA(Sid, &S))
|
||||
{
|
||||
FspDebugLog(format, S);
|
||||
LocalFree(S);
|
||||
}
|
||||
else
|
||||
FspDebugLog(format, "invalid SID");
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime)
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
char buf[32];
|
||||
|
||||
if (FileTimeToSystemTime(FileTime, &SystemTime))
|
||||
{
|
||||
wsprintfA(buf, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03huZ",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds);
|
||||
FspDebugLog(format, buf);
|
||||
}
|
||||
else
|
||||
FspDebugLog(format, "invalid file time");
|
||||
}
|
||||
|
||||
#define MAKE_UINT32_PAIR(v) \
|
||||
((PLARGE_INTEGER)&(v))->HighPart, ((PLARGE_INTEGER)&(v))->LowPart
|
||||
|
||||
static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
|
||||
{
|
||||
switch ((CreateOptions >> 24) & 0xff)
|
||||
{
|
||||
case FILE_CREATE:
|
||||
return "FILE_CREATE";
|
||||
case FILE_OPEN:
|
||||
return "FILE_OPEN";
|
||||
case FILE_OPEN_IF:
|
||||
return "FILE_OPEN_IF";
|
||||
case FILE_OVERWRITE:
|
||||
return "FILE_OVERWRITE";
|
||||
case FILE_SUPERSEDE:
|
||||
return "FILE_SUPERSEDE";
|
||||
case FILE_OVERWRITE_IF:
|
||||
return "FILE_OVERWRITE_IF";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", (PVOID)UserContext, (PVOID)UserContext2);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogFileTimeString(UINT64 FileTime, char *Buf)
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
|
||||
if (0 == FileTime)
|
||||
lstrcpyA(Buf, "0");
|
||||
else if (FileTimeToSystemTime((PFILETIME)&FileTime, &SystemTime))
|
||||
{
|
||||
wsprintfA(Buf, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03huZ",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds);
|
||||
}
|
||||
else
|
||||
lstrcpyA(Buf, "INVALID");
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogFileInfoString(FSP_FSCTL_FILE_INFO *FileInfo, char *Buf)
|
||||
{
|
||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32], ChangeTimeBuf[32];
|
||||
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"FileAttributes=%lx, "
|
||||
"ReparseTag=%lx, "
|
||||
"AllocationSize=%lx:%lx, "
|
||||
"FileSize=%lx:%lx, "
|
||||
"CreationTime=%s, "
|
||||
"LastAccessTime=%s, "
|
||||
"LastWriteTime=%s, "
|
||||
"ChangeTime=%s, "
|
||||
"IndexNumber=%lx:%lx"
|
||||
"}",
|
||||
FileInfo->FileAttributes,
|
||||
FileInfo->ReparseTag,
|
||||
MAKE_UINT32_PAIR(FileInfo->AllocationSize),
|
||||
MAKE_UINT32_PAIR(FileInfo->FileSize),
|
||||
FspDebugLogFileTimeString(FileInfo->CreationTime, CreationTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->LastAccessTime, LastAccessTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->LastWriteTime, LastWriteTimeBuf),
|
||||
FspDebugLogFileTimeString(FileInfo->ChangeTime, ChangeTimeBuf),
|
||||
MAKE_UINT32_PAIR(FileInfo->IndexNumber));
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogVolumeInfoString(FSP_FSCTL_VOLUME_INFO *VolumeInfo, char *Buf)
|
||||
{
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"TotalSize=%lx:%lx, "
|
||||
"FreeSize=%lx:%lx, "
|
||||
"VolumeLabel=\"%.32S\""
|
||||
"}",
|
||||
MAKE_UINT32_PAIR(VolumeInfo->TotalSize),
|
||||
MAKE_UINT32_PAIR(VolumeInfo->FreeSize),
|
||||
&VolumeInfo->VolumeLabel);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogWideCharBufferString(PVOID WideCharBuf, ULONG Length, char *Buf)
|
||||
{
|
||||
WCHAR TempWideCharBuf[64 + 1];
|
||||
|
||||
if (Length > sizeof TempWideCharBuf - sizeof(WCHAR))
|
||||
Length = sizeof TempWideCharBuf - sizeof(WCHAR);
|
||||
|
||||
memcpy(TempWideCharBuf, WideCharBuf, Length);
|
||||
TempWideCharBuf[Length / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
wsprintfA(Buf, "%.64S", TempWideCharBuf);
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
|
||||
{
|
||||
union
|
||||
{
|
||||
PREPARSE_DATA_BUFFER D;
|
||||
PREPARSE_GUID_DATA_BUFFER G;
|
||||
} ReparseData;
|
||||
char SubstituteName[64 + 1], PrintName[64 + 1];
|
||||
|
||||
ReparseData.D = ReparseData0;
|
||||
if (0 == ReparseData.D->ReparseDataLength)
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=%#lx, "
|
||||
"ReparseDataLength=%hu"
|
||||
"}",
|
||||
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
|
||||
else if (IO_REPARSE_TAG_MOUNT_POINT == ReparseData.D->ReparseTag)
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=IO_REPARSE_TAG_MOUNT_POINT, "
|
||||
"SubstituteName=\"%s\", "
|
||||
"PrintName=\"%s\""
|
||||
"}",
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->MountPointReparseBuffer.PathBuffer +
|
||||
ReparseData.D->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->MountPointReparseBuffer.SubstituteNameLength,
|
||||
SubstituteName),
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->MountPointReparseBuffer.PathBuffer +
|
||||
ReparseData.D->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->MountPointReparseBuffer.PrintNameLength,
|
||||
PrintName));
|
||||
else if (IO_REPARSE_TAG_SYMLINK == ReparseData.D->ReparseTag)
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=IO_REPARSE_TAG_SYMLINK, "
|
||||
"SubstituteName=\"%s\", "
|
||||
"PrintName=\"%s\", "
|
||||
"Flags=%u"
|
||||
"}",
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.SubstituteNameLength,
|
||||
SubstituteName),
|
||||
FspDebugLogWideCharBufferString(
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR),
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.PrintNameLength,
|
||||
PrintName),
|
||||
ReparseData.D->SymbolicLinkReparseBuffer.Flags);
|
||||
else if (IsReparseTagMicrosoft(ReparseData.D->ReparseTag))
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=%#lx, "
|
||||
"ReparseDataLength=%hu"
|
||||
"}",
|
||||
ReparseData.D->ReparseTag, ReparseData.D->ReparseDataLength);
|
||||
else
|
||||
#define Guid ReparseData.G->ReparseGuid
|
||||
wsprintfA(Buf,
|
||||
"{"
|
||||
"ReparseTag=%#lx, "
|
||||
"ReparseDataLength=%hu, "
|
||||
"ReparseGuid={%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
|
||||
"}",
|
||||
ReparseData.G->ReparseTag, ReparseData.G->ReparseDataLength,
|
||||
Guid.Data1, Guid.Data2, Guid.Data3,
|
||||
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
|
||||
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
|
||||
#undef Guid
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
||||
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, Name);
|
||||
}
|
||||
|
||||
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
|
||||
{
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint, Name,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information);
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
||||
{
|
||||
char UserContextBuf[40];
|
||||
char CreationTimeBuf[32], LastAccessTimeBuf[32], LastWriteTimeBuf[32];
|
||||
char InfoBuf[256];
|
||||
char *Sddl = 0;
|
||||
|
||||
switch (Request->Kind)
|
||||
{
|
||||
case FspFsctlTransactReservedKind:
|
||||
FspDebugLogRequestVoid(Request, "RESERVED");
|
||||
break;
|
||||
case FspFsctlTransactCreateKind:
|
||||
if (0 != Request->Req.Create.SecurityDescriptor.Offset)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
|
||||
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
||||
"AllocationSize=%lx:%lx, "
|
||||
"AccessToken=%p[PID=%lx], DesiredAccess=%lx, GrantedAccess=%lx, "
|
||||
"ShareAccess=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Create.UserMode ? 'U' : 'K',
|
||||
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
|
||||
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
|
||||
Request->Req.Create.HasRestorePrivilege ? 'R' : '-',
|
||||
Request->Req.Create.OpenTargetDirectory ? 'D' : '-',
|
||||
Request->Req.Create.CaseSensitive ? 'C' : '-',
|
||||
(PWSTR)Request->Buffer,
|
||||
FspDebugLogDispositionString(Request->Req.Create.CreateOptions),
|
||||
Request->Req.Create.CreateOptions & 0xffffff,
|
||||
Request->Req.Create.FileAttributes,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "",
|
||||
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken),
|
||||
Request->Req.Create.DesiredAccess,
|
||||
Request->Req.Create.GrantedAccess,
|
||||
Request->Req.Create.ShareAccess);
|
||||
LocalFree(Sddl);
|
||||
break;
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
|
||||
"FileAttributes=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Overwrite.UserContext, Request->Req.Overwrite.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.Overwrite.FileAttributes);
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Cleanup.Delete ? " [Delete]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Cleanup.UserContext, Request->Req.Cleanup.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Close %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Close.UserContext, Request->Req.Close.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
|
||||
UserContextBuf),
|
||||
(PVOID)Request->Req.Read.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
|
||||
Request->Req.Read.Length,
|
||||
Request->Req.Read.Key);
|
||||
break;
|
||||
case FspFsctlTransactWriteKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
|
||||
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->Req.Write.ConstrainedIo ? " [C]" : "",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
|
||||
UserContextBuf),
|
||||
(PVOID)Request->Req.Write.Address,
|
||||
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
|
||||
Request->Req.Write.Length,
|
||||
Request->Req.Write.Key);
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryInformation.UserContext, Request->Req.QueryInformation.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
switch (Request->Req.SetInformation.FileInformationClass)
|
||||
{
|
||||
case 4/*FileBasicInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
|
||||
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.Basic.FileAttributes,
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.CreationTime,
|
||||
CreationTimeBuf),
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastAccessTime,
|
||||
LastAccessTimeBuf),
|
||||
FspDebugLogFileTimeString(Request->Req.SetInformation.Info.Basic.LastWriteTime,
|
||||
LastWriteTimeBuf));
|
||||
break;
|
||||
case 19/*FileAllocationInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
|
||||
"AllocationSize=%lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.Allocation.AllocationSize));
|
||||
break;
|
||||
case 20/*FileEndOfFileInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
|
||||
"FileSize = %lx:%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
MAKE_UINT32_PAIR(Request->Req.SetInformation.Info.EndOfFile.FileSize));
|
||||
break;
|
||||
case 13/*FileDispositionInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%S%s%s, "
|
||||
"%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.Disposition.Delete ? "Delete" : "Undelete");
|
||||
break;
|
||||
case 64/*FileDispositionInformationEx*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [DispositionEx] %s%S%s%s, "
|
||||
"Flags=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetInformation.Info.DispositionEx.Flags);
|
||||
break;
|
||||
case 10/*FileRenameInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
|
||||
"NewFileName=\"%S\", AccessToken=%p[PID=%lx]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken));
|
||||
break;
|
||||
case 65/*FileRenameInformationEx*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [RenameEx] %s%S%s%s, "
|
||||
"NewFileName=\"%S\", AccessToken=%p[PID=%lx], Flags=%lx\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf),
|
||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||
Request->Req.SetInformation.Info.RenameEx.Flags);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryEaKind:
|
||||
FspDebugLogRequestVoid(Request, "QUERYEA");
|
||||
break;
|
||||
case FspFsctlTransactSetEaKind:
|
||||
FspDebugLogRequestVoid(Request, "SETEA");
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FlushBuffers.UserContext, Request->Req.FlushBuffers.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryVolumeInformationKind:
|
||||
FspDebugLogRequestVoid(Request, "QueryVolumeInformation");
|
||||
break;
|
||||
case FspFsctlTransactSetVolumeInformationKind:
|
||||
switch (Request->Req.SetVolumeInformation.FsInformationClass)
|
||||
{
|
||||
case 2/*FileFsLabelInformation*/:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
|
||||
"Label=\"%S\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
(PWSTR)Request->Buffer);
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
|
||||
"Address=%p, Length=%ld, Pattern=%s%S%s, Marker=%s%S%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
|
||||
UserContextBuf),
|
||||
(PVOID)Request->Req.QueryDirectory.Address,
|
||||
Request->Req.QueryDirectory.Length,
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Pattern.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Marker.Size ? "\"" : "",
|
||||
Request->Req.QueryDirectory.Marker.Size ?
|
||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : L"NULL",
|
||||
Request->Req.QueryDirectory.Marker.Size ? "\"" : "");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
switch (Request->Req.FileSystemControl.FsControlCode)
|
||||
{
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
|
||||
"ReparseData=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
|
||||
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||
UserContextBuf),
|
||||
FspDebugLogReparseDataString(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||
InfoBuf));
|
||||
break;
|
||||
default:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.FileSystemControl.UserContext, Request->Req.FileSystemControl.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactDeviceControlKind:
|
||||
FspDebugLogRequestVoid(Request, "DEVICECONTROL");
|
||||
break;
|
||||
case FspFsctlTransactShutdownKind:
|
||||
FspDebugLogRequestVoid(Request, "SHUTDOWN");
|
||||
break;
|
||||
case FspFsctlTransactLockControlKind:
|
||||
FspDebugLogRequestVoid(Request, "LOCKCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.QuerySecurity.UserContext, Request->Req.QuerySecurity.UserContext2,
|
||||
UserContextBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetSecurityKind:
|
||||
if (0 != Request->Req.SetSecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Request->Buffer + Request->Req.SetSecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
|
||||
"SecurityInformation=%lx, Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||
Request->FileName.Size ? "\"" : "",
|
||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||
Request->FileName.Size ? "\", " : "",
|
||||
FspDebugLogUserContextString(
|
||||
Request->Req.SetSecurity.UserContext, Request->Req.SetSecurity.UserContext2,
|
||||
UserContextBuf),
|
||||
Request->Req.SetSecurity.SecurityInformation,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
break;
|
||||
case FspFsctlTransactQueryStreamInformationKind:
|
||||
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %s%S%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)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:
|
||||
FspDebugLogRequestVoid(Request, "INVALID");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
if (STATUS_PENDING == Response->IoStatus.Status)
|
||||
return;
|
||||
|
||||
char UserContextBuf[40];
|
||||
char InfoBuf[256];
|
||||
char *Sddl = 0;
|
||||
|
||||
switch (Response->Kind)
|
||||
{
|
||||
case FspFsctlTransactReservedKind:
|
||||
FspDebugLogResponseStatus(Response, "RESERVED");
|
||||
break;
|
||||
case FspFsctlTransactCreateKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Create");
|
||||
else if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||
{
|
||||
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.FileName=\"%s\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogWideCharBufferString(
|
||||
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||
Response->Rsp.Create.Reparse.Buffer.Size,
|
||||
InfoBuf));
|
||||
else if (1/*IO_REMOUNT*/ == Response->IoStatus.Information)
|
||||
FspDebugLogResponseStatus(Response, "Create");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"Reparse.Data=\"%s\"\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogReparseDataString(
|
||||
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
|
||||
InfoBuf));
|
||||
}
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
|
||||
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogUserContextString(
|
||||
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
|
||||
UserContextBuf),
|
||||
Response->Rsp.Create.Opened.GrantedAccess,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Create.Opened.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactOverwriteKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Overwrite");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactCleanupKind:
|
||||
FspDebugLogResponseStatus(Response, "Cleanup");
|
||||
break;
|
||||
case FspFsctlTransactCloseKind:
|
||||
FspDebugLogResponseStatus(Response, "Close");
|
||||
break;
|
||||
case FspFsctlTransactReadKind:
|
||||
FspDebugLogResponseStatus(Response, "Read");
|
||||
break;
|
||||
case FspFsctlTransactWriteKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "Write");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QueryInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
|
||||
"FileInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryEaKind:
|
||||
FspDebugLogResponseStatus(Response, "QUERYEA");
|
||||
break;
|
||||
case FspFsctlTransactSetEaKind:
|
||||
FspDebugLogResponseStatus(Response, "SETEA");
|
||||
break;
|
||||
case FspFsctlTransactFlushBuffersKind:
|
||||
FspDebugLogResponseStatus(Response, "FlushBuffers");
|
||||
break;
|
||||
case FspFsctlTransactQueryVolumeInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QueryVolumeInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactSetVolumeInformationKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetVolumeInformation");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
|
||||
"VolumeInfo=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactQueryDirectoryKind:
|
||||
FspDebugLogResponseStatus(Response, "QueryDirectory");
|
||||
break;
|
||||
case FspFsctlTransactFileSystemControlKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status) ||
|
||||
0 == Response->Rsp.FileSystemControl.Buffer.Size)
|
||||
FspDebugLogResponseStatus(Response, "FileSystemControl");
|
||||
else
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
|
||||
"ReparseData=%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||
InfoBuf));
|
||||
break;
|
||||
case FspFsctlTransactDeviceControlKind:
|
||||
FspDebugLogResponseStatus(Response, "DEVICECONTROL");
|
||||
break;
|
||||
case FspFsctlTransactShutdownKind:
|
||||
FspDebugLogResponseStatus(Response, "SHUTDOWN");
|
||||
break;
|
||||
case FspFsctlTransactLockControlKind:
|
||||
FspDebugLogResponseStatus(Response, "LOCKCONTROL");
|
||||
break;
|
||||
case FspFsctlTransactQuerySecurityKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "QuerySecurity");
|
||||
else
|
||||
{
|
||||
if (0 != Response->Rsp.QuerySecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Response->Buffer + Response->Rsp.QuerySecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactSetSecurityKind:
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
FspDebugLogResponseStatus(Response, "SetSecurity");
|
||||
else
|
||||
{
|
||||
if (0 != Response->Rsp.SetSecurity.SecurityDescriptor.Size)
|
||||
ConvertSecurityDescriptorToStringSecurityDescriptorA(
|
||||
Response->Buffer + Response->Rsp.SetSecurity.SecurityDescriptor.Offset,
|
||||
SDDL_REVISION_1,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
|
||||
&Sddl, 0);
|
||||
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
|
||||
"Security=%s%s%s\n",
|
||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
|
||||
Response->IoStatus.Status, Response->IoStatus.Information,
|
||||
Sddl ? "\"" : "",
|
||||
Sddl ? Sddl : "NULL",
|
||||
Sddl ? "\"" : "");
|
||||
LocalFree(Sddl);
|
||||
}
|
||||
break;
|
||||
case FspFsctlTransactQueryStreamInformationKind:
|
||||
FspDebugLogResponseStatus(Response, "QueryStreamInformation");
|
||||
break;
|
||||
default:
|
||||
FspDebugLogResponseStatus(Response, "INVALID");
|
||||
break;
|
||||
}
|
||||
}
|
@ -21,6 +21,11 @@
|
||||
|
||||
#include <dll/library.h>
|
||||
|
||||
#define FspFileSystemDirectoryBufferLoBound (256)
|
||||
#define FspFileSystemDirectoryBufferHiBound (1024 * 1024)
|
||||
#define FspFileSystemDirectoryBufferLoFactor (4)
|
||||
#define FspFileSystemDirectoryBufferHiFactor (2)
|
||||
|
||||
#define RETURN(R, B) \
|
||||
do \
|
||||
{ \
|
||||
@ -32,7 +37,7 @@
|
||||
typedef struct
|
||||
{
|
||||
SRWLOCK Lock;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
ULONG InitialCapacity, Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
|
||||
|
||||
@ -179,12 +184,15 @@ static VOID FspFileSystemQSortDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l
|
||||
{
|
||||
while (r > l)
|
||||
{
|
||||
#if 0
|
||||
#if 1
|
||||
exch(Index[(l + r) / 2], Index[r - 1]);
|
||||
compexch(Index[l], Index[r - 1]);
|
||||
compexch(Index[l], Index[r]);
|
||||
compexch(Index[r - 1], Index[r]);
|
||||
|
||||
if (r - 1 <= l + 1)
|
||||
break;
|
||||
|
||||
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l + 1, r - 1);
|
||||
#else
|
||||
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l, r);
|
||||
@ -224,8 +232,8 @@ static inline VOID FspFileSystemSortDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BU
|
||||
FspFileSystemQSortDirectoryBuffer(Buffer, Index, 0, Count - 1);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult)
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBufferEx(PVOID* PDirBuffer,
|
||||
BOOLEAN Reset, ULONG CapacityHint, PNTSTATUS PResult)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = FspInterlockedLoadPointer(PDirBuffer);
|
||||
|
||||
@ -234,10 +242,20 @@ FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
static SRWLOCK CreateLock = SRWLOCK_INIT;
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *NewDirBuffer;
|
||||
|
||||
/* compute next (or equal) power of 2; ensure fits within bounds */
|
||||
ULONG bitidx;
|
||||
if (_BitScanReverse(&bitidx, CapacityHint - 1))
|
||||
CapacityHint = (1 << (1 + bitidx));
|
||||
CapacityHint = FspFileSystemDirectoryBufferLoBound > CapacityHint ?
|
||||
FspFileSystemDirectoryBufferLoBound : CapacityHint;
|
||||
CapacityHint = FspFileSystemDirectoryBufferHiBound < CapacityHint ?
|
||||
FspFileSystemDirectoryBufferHiBound : CapacityHint;
|
||||
|
||||
NewDirBuffer = MemAlloc(sizeof *NewDirBuffer);
|
||||
if (0 == NewDirBuffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
memset(NewDirBuffer, 0, sizeof *NewDirBuffer);
|
||||
NewDirBuffer->InitialCapacity = CapacityHint;
|
||||
InitializeSRWLock(&NewDirBuffer->Lock);
|
||||
AcquireSRWLockExclusive(&NewDirBuffer->Lock);
|
||||
|
||||
@ -267,6 +285,12 @@ FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
RETURN(STATUS_SUCCESS, FALSE);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult)
|
||||
{
|
||||
return FspFileSystemAcquireDirectoryBufferEx(PDirBuffer, Reset, 0, PResult);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult)
|
||||
{
|
||||
@ -301,7 +325,7 @@ FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
|
||||
if (0 == Buffer)
|
||||
{
|
||||
Buffer = MemAlloc(Capacity = 512);
|
||||
Buffer = MemAlloc(Capacity = DirBuffer->InitialCapacity);
|
||||
if (0 == Buffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
|
||||
@ -309,7 +333,9 @@ FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer = MemRealloc(Buffer, Capacity = DirBuffer->Capacity * 2);
|
||||
ULONG Factor = FspFileSystemDirectoryBufferHiBound > DirBuffer->Capacity ?
|
||||
FspFileSystemDirectoryBufferLoFactor : FspFileSystemDirectoryBufferHiFactor;
|
||||
Buffer = MemRealloc(Buffer, Capacity = DirBuffer->Capacity * Factor);
|
||||
if (0 == Buffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
|
||||
|
@ -26,6 +26,12 @@
|
||||
#define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX
|
||||
#define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR))
|
||||
|
||||
static INIT_ONCE FspFsctlServiceVersionInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static ULONG FspFsctlServiceVersionValue;
|
||||
static DWORD FspFsctlTransactCode = FSP_FSCTL_TRANSACT;
|
||||
static DWORD FspFsctlTransactBatchCode = FSP_FSCTL_TRANSACT_BATCH;
|
||||
|
||||
static VOID FspFsctlServiceVersion(PUINT32 PVersion);
|
||||
static NTSTATUS FspFsctlStartService(VOID);
|
||||
|
||||
FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
|
||||
@ -76,6 +82,9 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
/* initialize FspFsctlTransactCode */
|
||||
FspFsctlServiceVersion(0);
|
||||
|
||||
VolumeHandle = CreateFileW(DevicePathBuf,
|
||||
0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
if (INVALID_HANDLE_VALUE == VolumeHandle)
|
||||
@ -127,6 +136,7 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
|
||||
BOOLEAN Batch)
|
||||
{
|
||||
NTSTATUS Result = STATUS_SUCCESS;
|
||||
DWORD ControlCode;
|
||||
DWORD Bytes = 0;
|
||||
|
||||
if (0 != PRequestBufSize)
|
||||
@ -135,8 +145,18 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
|
||||
*PRequestBufSize = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* During file system volume creation FspFsctlCreateVolume called FspFsctlServiceVersion
|
||||
* which examined the version of the driver in use and initialized the variables
|
||||
* FspFsctlTransactCode and FspFsctlTransactBatchCode with either the new
|
||||
* FSP_IOCTL_TRANSACT* codes or the old FSP_FSCTL_TRANSACT* codes.
|
||||
*/
|
||||
ControlCode = Batch ?
|
||||
(DEBUGTEST(50) ? FspFsctlTransactBatchCode : FSP_FSCTL_TRANSACT_BATCH) :
|
||||
(DEBUGTEST(50) ? FspFsctlTransactCode : FSP_FSCTL_TRANSACT);
|
||||
|
||||
if (!DeviceIoControl(VolumeHandle,
|
||||
Batch ? FSP_FSCTL_TRANSACT_BATCH : FSP_FSCTL_TRANSACT,
|
||||
ControlCode,
|
||||
ResponseBuf, (DWORD)ResponseBufSize, RequestBuf, Bytes,
|
||||
&Bytes, 0))
|
||||
{
|
||||
@ -262,6 +282,79 @@ FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath)
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static BOOL WINAPI FspFsctlServiceVersionInitialize(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
|
||||
PWSTR ModuleFileName;
|
||||
SC_HANDLE ScmHandle = 0;
|
||||
SC_HANDLE SvcHandle = 0;
|
||||
QUERY_SERVICE_CONFIGW *ServiceConfig = 0;
|
||||
DWORD Size;
|
||||
|
||||
ScmHandle = OpenSCManagerW(0, 0, 0);
|
||||
if (0 == ScmHandle)
|
||||
goto exit;
|
||||
|
||||
SvcHandle = OpenServiceW(ScmHandle, DriverName, SERVICE_QUERY_CONFIG);
|
||||
if (0 == SvcHandle)
|
||||
goto exit;
|
||||
|
||||
if (QueryServiceConfig(SvcHandle, 0, 0, &Size) ||
|
||||
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
goto exit;
|
||||
|
||||
ServiceConfig = MemAlloc(Size);
|
||||
if (0 == ServiceConfig)
|
||||
goto exit;
|
||||
|
||||
if (!QueryServiceConfig(SvcHandle, ServiceConfig, Size, &Size))
|
||||
goto exit;
|
||||
|
||||
ModuleFileName = ServiceConfig->lpBinaryPathName;
|
||||
if (L'\\' == ModuleFileName[0] &&
|
||||
L'?' == ModuleFileName[1] &&
|
||||
L'?' == ModuleFileName[2] &&
|
||||
L'\\' == ModuleFileName[3])
|
||||
{
|
||||
if (L'U' == ModuleFileName[4] &&
|
||||
L'N' == ModuleFileName[5] &&
|
||||
L'C' == ModuleFileName[6] &&
|
||||
L'\\' == ModuleFileName[7])
|
||||
{
|
||||
ModuleFileName[6] = L'\\';
|
||||
ModuleFileName = ModuleFileName + 6;
|
||||
}
|
||||
else
|
||||
ModuleFileName = ModuleFileName + 4;
|
||||
}
|
||||
|
||||
FspGetModuleVersion(ModuleFileName, &FspFsctlServiceVersionValue);
|
||||
|
||||
if (0x0001000b /*v1.11*/ <= FspFsctlServiceVersionValue)
|
||||
{
|
||||
FspFsctlTransactCode = FSP_IOCTL_TRANSACT;
|
||||
FspFsctlTransactBatchCode = FSP_IOCTL_TRANSACT_BATCH;
|
||||
}
|
||||
|
||||
exit:
|
||||
MemFree(ServiceConfig);
|
||||
if (0 != SvcHandle)
|
||||
CloseServiceHandle(SvcHandle);
|
||||
if (0 != ScmHandle)
|
||||
CloseServiceHandle(ScmHandle);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static VOID FspFsctlServiceVersion(PUINT32 PVersion)
|
||||
{
|
||||
InitOnceExecuteOnce(&FspFsctlServiceVersionInitOnce, FspFsctlServiceVersionInitialize, 0, 0);
|
||||
|
||||
if (0 != PVersion)
|
||||
*PVersion = FspFsctlServiceVersionValue;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsctlStartService(VOID)
|
||||
{
|
||||
static SRWLOCK Lock = SRWLOCK_INIT;
|
||||
@ -429,7 +522,7 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
|
||||
* required rights are not there if GetEffectiveRightsFromAclW fails; the worst
|
||||
* that can happen is that the rights get added twice (which is benign).
|
||||
*
|
||||
* See https://github.com/billziss-gh/winfsp/issues/62
|
||||
* See https://github.com/winfsp/winfsp/issues/62
|
||||
*/
|
||||
AccessRights = 0;
|
||||
}
|
||||
|
@ -1142,7 +1142,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
|
||||
break;
|
||||
case 13/*FileDispositionInformation*/:
|
||||
case 64/*FileDispositionInformationEx*/:
|
||||
if (0 == (0x10/*IGNORE_READONLY_ATTRIBUTE*/ & Request->Req.SetInformation.Info.DispositionEx.Flags) &&
|
||||
if (1/*DELETE*/ == (0x11/*DELETE|IGNORE_READONLY_ATTRIBUTE*/ &
|
||||
Request->Req.SetInformation.Info.DispositionEx.Flags) &&
|
||||
0 != FileSystem->Interface->GetFileInfo)
|
||||
{
|
||||
Result = FileSystem->Interface->GetFileInfo(FileSystem,
|
||||
|
@ -82,6 +82,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
||||
FUSE_OPT_KEY("fstypename=", 'F'),
|
||||
FUSE_OPT_KEY("volname=", 'v'),
|
||||
|
||||
FUSE_OPT_KEY("uidmap=", 'm'),
|
||||
|
||||
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
||||
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
||||
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
||||
@ -293,43 +295,241 @@ static int fsp_fuse_sddl_to_security(const char *Sddl, PUINT8 Security, PULONG P
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsp_fuse_username_to_uid(const char *username, int *puid)
|
||||
static int fsp_fuse_tokenuser_to_sid(HANDLE Token, PSID Sid, PULONG PSidSize)
|
||||
{
|
||||
union
|
||||
{
|
||||
TOKEN_USER V;
|
||||
UINT8 B[128];
|
||||
} InfoBuf;
|
||||
PTOKEN_USER InfoPtr = &InfoBuf.V;
|
||||
DWORD Size;
|
||||
int res = -1;
|
||||
|
||||
if (!GetTokenInformation(Token, TokenUser, InfoPtr, sizeof InfoBuf, &Size))
|
||||
{
|
||||
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
goto exit;
|
||||
|
||||
InfoPtr = MemAlloc(Size);
|
||||
if (0 == InfoPtr)
|
||||
goto exit;
|
||||
|
||||
if (!GetTokenInformation(Token, TokenUser, InfoPtr, Size, &Size))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Size = GetLengthSid(InfoPtr->User.Sid);
|
||||
if (*PSidSize >= Size)
|
||||
{
|
||||
memcpy(Sid, InfoPtr->User.Sid, Size);
|
||||
*PSidSize = Size;
|
||||
|
||||
res = 0;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (InfoPtr != &InfoBuf.V)
|
||||
MemFree(InfoPtr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsp_fuse_tokenuser_is_azuread(HANDLE Token)
|
||||
{
|
||||
union
|
||||
{
|
||||
SID V;
|
||||
UINT8 B[SECURITY_MAX_SID_SIZE];
|
||||
} SidBuf;
|
||||
ULONG Size;
|
||||
PSID Sid = &SidBuf.V;
|
||||
BYTE Count, Authority;
|
||||
UINT32 SubAuthority0;
|
||||
|
||||
Size = sizeof SidBuf;
|
||||
if (-1 == fsp_fuse_tokenuser_to_sid(Token, &SidBuf.V, &Size))
|
||||
return 0;
|
||||
|
||||
Count = *GetSidSubAuthorityCount(Sid);
|
||||
Authority = GetSidIdentifierAuthority(Sid)->Value[5];
|
||||
SubAuthority0 = 2 <= Count ? *GetSidSubAuthority(Sid, 0) : 0;
|
||||
|
||||
return 12 == Authority && 1 == SubAuthority0;
|
||||
}
|
||||
|
||||
static int fsp_fuse_username_to_sid(const char *UserName, PSID Sid, PULONG PSidSize)
|
||||
{
|
||||
union
|
||||
{
|
||||
SID V;
|
||||
UINT8 B[SECURITY_MAX_SID_SIZE];
|
||||
} SidBuf;
|
||||
PSID SidPtr = &SidBuf.V;
|
||||
char Name[256], Domn[256];
|
||||
DWORD SidSize, NameSize, DomnSize;
|
||||
DWORD Size, NameSize, DomnSize;
|
||||
SID_NAME_USE Use;
|
||||
UINT32 Uid;
|
||||
NTSTATUS Result;
|
||||
int res = -1;
|
||||
|
||||
*puid = 0;
|
||||
|
||||
NameSize = lstrlenA(username) + 1;
|
||||
if ('S' == UserName[0] && '-' == UserName[1] && '1' == UserName[2] && '-' == UserName[3])
|
||||
{
|
||||
if (!ConvertStringSidToSidA(UserName, &SidPtr))
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
NameSize = lstrlenA(UserName) + 1;
|
||||
if (sizeof Name / sizeof Name[0] < NameSize)
|
||||
return -1;
|
||||
memcpy(Name, username, NameSize);
|
||||
goto exit;
|
||||
memcpy(Name, UserName, NameSize);
|
||||
for (PSTR P = Name, EndP = P + NameSize; EndP > P; P++)
|
||||
if ('+' == *P)
|
||||
*P = '\\';
|
||||
|
||||
SidSize = sizeof SidBuf;
|
||||
Size = sizeof SidBuf;
|
||||
DomnSize = sizeof Domn / sizeof Domn[0];
|
||||
if (!LookupAccountNameA(0, Name, &SidBuf, &SidSize, Domn, &DomnSize, &Use))
|
||||
if (!LookupAccountNameA(0, Name, SidPtr, &Size, Domn, &DomnSize, &Use))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Size = GetLengthSid(SidPtr);
|
||||
if (*PSidSize >= Size)
|
||||
{
|
||||
memcpy(Sid, SidPtr, Size);
|
||||
*PSidSize = Size;
|
||||
|
||||
res = 0;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (SidPtr != &SidBuf.V)
|
||||
LocalFree(SidPtr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsp_fuse_username_to_uid(const char *UserName, int *PUid)
|
||||
{
|
||||
union
|
||||
{
|
||||
SID V;
|
||||
UINT8 B[SECURITY_MAX_SID_SIZE];
|
||||
} SidBuf;
|
||||
ULONG SidSize;
|
||||
UINT32 Uid;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PUid = 0;
|
||||
|
||||
SidSize = sizeof SidBuf;
|
||||
if (-1 == fsp_fuse_username_to_sid(UserName, &SidBuf.V, &SidSize))
|
||||
return -1;
|
||||
|
||||
Result = FspPosixMapSidToUid(&SidBuf, &Uid);
|
||||
Result = FspPosixMapSidToUid(&SidBuf.V, &Uid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return -1;
|
||||
|
||||
*puid = Uid;
|
||||
*PUid = Uid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsp_fuse_set_uidmap(const char *Spec)
|
||||
{
|
||||
char Buf[1024], *P = Buf, *UidP, *UserP, C;
|
||||
int Len;
|
||||
UINT32 Uid[8];
|
||||
PSID Sid[8];
|
||||
union
|
||||
{
|
||||
SID V;
|
||||
UINT8 B[SECURITY_MAX_SID_SIZE];
|
||||
} SidBuf[8];
|
||||
ULONG SidSize;
|
||||
ULONG Count;
|
||||
NTSTATUS Result;
|
||||
int res = -1;
|
||||
|
||||
Len = lstrlenA(Spec);
|
||||
if (sizeof Buf <= Len)
|
||||
return -1;
|
||||
memcpy(Buf, Spec, Len + 1);
|
||||
|
||||
Count = 0;
|
||||
for (;;)
|
||||
{
|
||||
if (sizeof Uid / sizeof Uid[0] <= Count)
|
||||
{
|
||||
/* out of space */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
UidP = P;
|
||||
for (; '\0' != (C = *P) && ';' != C && ':' != C; P++)
|
||||
;
|
||||
*P = '\0';
|
||||
|
||||
if (UidP == P)
|
||||
break;
|
||||
|
||||
Uid[Count] = strtouint(UidP, 0, 10, 0);
|
||||
if (0 == Uid[Count])
|
||||
{
|
||||
/* invalid uid */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
UserP = 0;
|
||||
if (':' == C)
|
||||
{
|
||||
UserP = ++P;
|
||||
for (; '\0' != (C = *P) && ';' != C; P++)
|
||||
;
|
||||
*P = '\0';
|
||||
}
|
||||
|
||||
if (0 != UserP && '\0' != *UserP)
|
||||
{
|
||||
SidSize = sizeof SidBuf[Count];
|
||||
if (-1 == fsp_fuse_username_to_sid(UserP, &SidBuf[Count].V, &SidSize))
|
||||
{
|
||||
/* invalid SID */
|
||||
goto exit;
|
||||
}
|
||||
Sid[Count] = &SidBuf[Count].V;
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE Token;
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
|
||||
{
|
||||
SidSize = sizeof SidBuf[Count];
|
||||
if (-1 == fsp_fuse_tokenuser_to_sid(Token, &SidBuf[Count].V, &SidSize))
|
||||
{
|
||||
/* invalid SID */
|
||||
CloseHandle(Token);
|
||||
goto exit;
|
||||
}
|
||||
CloseHandle(Token);
|
||||
Sid[Count] = &SidBuf[Count].V;
|
||||
}
|
||||
}
|
||||
|
||||
Count++;
|
||||
|
||||
if ('\0' == C)
|
||||
break;
|
||||
|
||||
P++;
|
||||
}
|
||||
|
||||
Result = FspPosixSetUidMap(Uid, Sid, Count);
|
||||
res = NT_SUCCESS(Result) ? 0 : -1;
|
||||
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsp_fuse_utf8towcs_trunc(
|
||||
const char *Str, int StrLen,
|
||||
PWSTR Wcs, int WcsLen)
|
||||
@ -424,6 +624,7 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
" -o KeepFileCache do not discard cache when files are closed\n"
|
||||
" -o LegacyUnlinkRename do not support new POSIX unlink/rename\n"
|
||||
" -o ThreadCount number of file system dispatcher threads\n"
|
||||
" -o uidmap=UID:SID[;...] explicit UID <-> SID map (max 8 entries)\n"
|
||||
);
|
||||
opt_data->help = 1;
|
||||
return 1;
|
||||
@ -531,6 +732,14 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
if (0 == opt_data->VolumeLabelLength)
|
||||
return -1;
|
||||
return 0;
|
||||
case 'm':
|
||||
arg += sizeof "uidmap=" - 1;
|
||||
if (-1 == fsp_fuse_set_uidmap(arg))
|
||||
{
|
||||
opt_data->set_uidmap = -1;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,6 +788,11 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
ErrorMessage = L": invalid user or group name.";
|
||||
goto fail;
|
||||
}
|
||||
else if (-1 == opt_data.set_uidmap)
|
||||
{
|
||||
ErrorMessage = L": invalid uidmap.";
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (opt_data.help)
|
||||
@ -601,6 +815,10 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
|
||||
{
|
||||
/* if an AzureAD user and no uidmap specified, set a default uidmap that matches Cygwin */
|
||||
if (!opt_data.set_uidmap && fsp_fuse_tokenuser_is_azuread(Token))
|
||||
fsp_fuse_set_uidmap("4096:");
|
||||
|
||||
fsp_fuse_get_token_uidgid(Token, TokenUser,
|
||||
opt_data.set_uid && -1 == opt_data.uid ? &opt_data.uid : 0,
|
||||
opt_data.set_gid && -1 == opt_data.gid ? &opt_data.gid : 0);
|
||||
|
@ -5,6 +5,6 @@ implib=${prefix}/bin/winfsp-${arch}.dll
|
||||
Name: fuse
|
||||
Description: WinFsp FUSE compatible API
|
||||
Version: 2.8
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
URL: https://winfsp.dev
|
||||
Libs: "${implib}"
|
||||
Cflags: -I"${incdir}"
|
||||
|
@ -850,6 +850,29 @@ exit:
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID fsp_fuse_intf_GetOpenFileInfoPath(
|
||||
struct fuse *f,
|
||||
const char *PosixPath,
|
||||
struct fuse_file_info *fi,
|
||||
FSP_FSCTL_OPEN_FILE_INFO *OpenFileInfo)
|
||||
{
|
||||
char PosixNormalizedName[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||
PWSTR NormalizedName;
|
||||
ULONG NormalizedNameSize;
|
||||
|
||||
if (0 == f->ops.getpath(PosixPath, PosixNormalizedName, sizeof PosixNormalizedName, fi) &&
|
||||
NT_SUCCESS(FspPosixMapPosixToWindowsPath(PosixNormalizedName, &NormalizedName)))
|
||||
{
|
||||
NormalizedNameSize = lstrlenW(NormalizedName) * sizeof(WCHAR);
|
||||
if (OpenFileInfo->NormalizedNameSize >= NormalizedNameSize)
|
||||
{
|
||||
OpenFileInfo->NormalizedNameSize = (UINT16)NormalizedNameSize;
|
||||
memcpy(OpenFileInfo->NormalizedName, NormalizedName, NormalizedNameSize);
|
||||
}
|
||||
FspPosixDeletePath(NormalizedName);
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
||||
@ -1005,7 +1028,7 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
Result = FspFileSystemEnumerateEa(FileSystem,
|
||||
fsp_fuse_intf_SetEaEntry, contexthdr->PosixPath, ExtraBuffer, ExtraLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
@ -1015,13 +1038,6 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
|
||||
* NOTE: Originally WinFsp dit not support disabling the cache manager
|
||||
* for an individual file. This is now possible and we should revisit.
|
||||
*
|
||||
* Ignore fuse_file_info::nonseekable.
|
||||
*/
|
||||
|
||||
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, contexthdr->PosixPath,
|
||||
FUSE_FILE_INFO(CreateOptions & FILE_DIRECTORY_FILE, &fi),
|
||||
@ -1029,6 +1045,14 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
|
||||
* NOTE: Originally WinFsp did not support disabling the cache manager
|
||||
* for an individual file. This is now possible and we should revisit.
|
||||
*
|
||||
* Ignore fuse_file_info::nonseekable.
|
||||
*/
|
||||
|
||||
*PFileDesc = filedesc;
|
||||
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf);
|
||||
|
||||
@ -1040,6 +1064,10 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
filedesc->DirBuffer = 0;
|
||||
contexthdr->PosixPath = 0;
|
||||
|
||||
if (!f->VolumeParams.CaseSensitiveSearch && 0 != f->ops.getpath)
|
||||
fsp_fuse_intf_GetOpenFileInfoPath(f, filedesc->PosixPath, -1 != fi.fh ? &fi : 0,
|
||||
FspFileSystemGetOpenFileInfo(FileInfo));
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
@ -1163,10 +1191,9 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache
|
||||
* WinFsp does not currently support disabling the cache manager
|
||||
* for an individual file although it should not be hard to add
|
||||
* if required.
|
||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
|
||||
* NOTE: Originally WinFsp did not support disabling the cache manager
|
||||
* for an individual file. This is now possible and we should revisit.
|
||||
*
|
||||
* Ignore fuse_file_info::nonseekable.
|
||||
*/
|
||||
@ -1182,6 +1209,10 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
filedesc->DirBuffer = 0;
|
||||
contexthdr->PosixPath = 0;
|
||||
|
||||
if (!f->VolumeParams.CaseSensitiveSearch && 0 != f->ops.getpath)
|
||||
fsp_fuse_intf_GetOpenFileInfoPath(f, filedesc->PosixPath, -1 != fi.fh ? &fi : 0,
|
||||
FspFileSystemGetOpenFileInfo(FileInfo));
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
@ -1225,7 +1256,7 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
Result = FspFileSystemEnumerateEa(FileSystem,
|
||||
fsp_fuse_intf_SetEaEntry, filedesc->PosixPath, Ea, EaLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
|
||||
return Result;
|
||||
}
|
||||
|
||||
@ -2112,6 +2143,10 @@ static NTSTATUS fsp_fuse_intf_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
|
||||
char PosixPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||
int ParentLength, FSlashLength, PosixNameLength;
|
||||
UINT32 Uid, Gid, Mode;
|
||||
char PosixNormalizedName[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||
PWSTR NormalizedName, NormalizedNameSuffix;
|
||||
ULONG NormalizedNameSize;
|
||||
BOOLEAN Normalized = FALSE;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (!filedesc->IsDirectory || filedesc->IsReparsePoint)
|
||||
@ -2145,13 +2180,33 @@ static NTSTATUS fsp_fuse_intf_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* FUSE does not do FileName normalization; so just return the FileName as given to us!
|
||||
*/
|
||||
|
||||
//memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
|
||||
|
||||
if (!f->VolumeParams.CaseSensitiveSearch && 0 != f->ops.getpath)
|
||||
{
|
||||
if (0 == f->ops.getpath(PosixPath, PosixNormalizedName, sizeof PosixNormalizedName, 0) &&
|
||||
NT_SUCCESS(FspPosixMapPosixToWindowsPath(PosixNormalizedName, &NormalizedName)))
|
||||
{
|
||||
NormalizedNameSuffix = NormalizedName;
|
||||
for (PWSTR P = NormalizedNameSuffix; *P; P++)
|
||||
if (L'\\' == *P)
|
||||
NormalizedNameSuffix = P + 1;
|
||||
NormalizedNameSize = lstrlenW(NormalizedNameSuffix) * sizeof(WCHAR);
|
||||
if (f->VolumeParams.MaxComponentLength * sizeof(WCHAR) >= NormalizedNameSize)
|
||||
{
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + NormalizedNameSize);
|
||||
memcpy(DirInfo->FileNameBuf, NormalizedNameSuffix, NormalizedNameSize);
|
||||
Normalized = TRUE;
|
||||
}
|
||||
FspPosixDeletePath(NormalizedName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Normalized)
|
||||
{
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + lstrlenW(FileName) * sizeof(WCHAR));
|
||||
memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO));
|
||||
}
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
|
@ -95,9 +95,9 @@ static NTSTATUS fsp_fuse_loop_start(struct fuse *f)
|
||||
context->private_data = f->data = f->ops.init(&conn);
|
||||
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
|
||||
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
|
||||
if (!f->VolumeParams.CaseSensitiveSearch)
|
||||
if (!f->VolumeParams.CaseSensitiveSearch && 0 == f->ops.getpath)
|
||||
/*
|
||||
* Disable GetDirInfoByName when file system is case-insensitive.
|
||||
* Disable GetDirInfoByName when file system is case-insensitive and getpath == 0.
|
||||
* The reason is that Windows always sends us queries with uppercase
|
||||
* file names in GetDirInfoByName and we have no way in FUSE to normalize
|
||||
* those file names when embedding them in FSP_FSCTL_DIR_INFO.
|
||||
@ -184,9 +184,19 @@ static NTSTATUS fsp_fuse_loop_start(struct fuse *f)
|
||||
f->has_slashdot = 0 == err && 0040000 == (stbuf.st_mode & 0170000);
|
||||
}
|
||||
}
|
||||
if (0 == (f->conn_want & FSP_FUSE_CAP_DELETE_ACCESS) || 0 == f->ops.access)
|
||||
f->VolumeParams.PostDispositionWhenNecessaryOnly = 1;
|
||||
if (0 != f->ops.listxattr && 0 != f->ops.getxattr &&
|
||||
0 != f->ops.setxattr && 0 != f->ops.removexattr)
|
||||
f->VolumeParams.ExtendedAttributes = 1;
|
||||
{
|
||||
char buf[1024];
|
||||
int err;
|
||||
|
||||
/* if this fails with ENOSYS, then no EA support */
|
||||
err = f->ops.getxattr("/",
|
||||
"non-existant-a11ec902d22f4ec49003af15282d3b00", buf, sizeof buf);
|
||||
f->VolumeParams.ExtendedAttributes = -ENOSYS_(f->env) != err;
|
||||
}
|
||||
|
||||
/* the FSD does not currently limit these VolumeParams fields; do so here! */
|
||||
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
|
||||
@ -194,7 +204,7 @@ static NTSTATUS fsp_fuse_loop_start(struct fuse *f)
|
||||
f->VolumeParams.SectorSize = FSP_FUSE_SECTORSIZE_MAX;
|
||||
if (f->VolumeParams.SectorsPerAllocationUnit == 0)
|
||||
f->VolumeParams.SectorsPerAllocationUnit = 1;
|
||||
if (f->VolumeParams.MaxComponentLength > 255)
|
||||
if (f->VolumeParams.MaxComponentLength == 0 || f->VolumeParams.MaxComponentLength > 255)
|
||||
f->VolumeParams.MaxComponentLength = 255;
|
||||
|
||||
if (0 == f->VolumeParams.VolumeCreationTime)
|
||||
|
@ -147,6 +147,7 @@ struct fsp_fuse_core_opt_data
|
||||
set_create_dir_umask, create_dir_umask,
|
||||
set_uid, uid, username_to_uid_result,
|
||||
set_gid, gid,
|
||||
set_uidmap,
|
||||
set_attr_timeout, attr_timeout,
|
||||
rellinks,
|
||||
dothidden;
|
||||
|
@ -5,6 +5,6 @@ implib=${prefix}/bin/winfsp-${arch}.dll
|
||||
Name: fuse3
|
||||
Description: WinFsp FUSE3 compatible API
|
||||
Version: 3.2
|
||||
URL: http://www.secfs.net/winfsp/
|
||||
URL: https://winfsp.dev
|
||||
Libs: "${implib}"
|
||||
Cflags: -I"${incdir}"
|
||||
|
@ -9,3 +9,4 @@ EXPORTS
|
||||
NPOpenEnum PRIVATE
|
||||
NPEnumResource PRIVATE
|
||||
NPCloseEnum PRIVATE
|
||||
NPGetUniversalName PRIVATE
|
||||
|
@ -46,6 +46,15 @@
|
||||
#define DEBUGLOGSID(fmt, Sid) ((void)0)
|
||||
#endif
|
||||
|
||||
/* DEBUGTEST */
|
||||
#if !defined(NDEBUG)
|
||||
ULONG DebugRandom(VOID);
|
||||
#define DEBUGTEST(Percent) \
|
||||
(DebugRandom() <= (Percent) * 0x7fff / 100)
|
||||
#else
|
||||
#define DEBUGTEST(Percent) (TRUE)
|
||||
#endif
|
||||
|
||||
VOID FspWksidFinalize(BOOLEAN Dynamic);
|
||||
VOID FspPosixFinalize(BOOLEAN Dynamic);
|
||||
VOID FspEventLogFinalize(BOOLEAN Dynamic);
|
||||
@ -72,6 +81,7 @@ ULONG FspLdapGetDefaultNamingContext(PVOID Ldap, PWSTR *PValue);
|
||||
ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue);
|
||||
|
||||
PWSTR FspDiagIdent(VOID);
|
||||
NTSTATUS FspGetModuleVersion(PWSTR ModuleFileName, PUINT32 PVersion);
|
||||
|
||||
#define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1)
|
||||
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
#include <dbt.h>
|
||||
|
||||
static INIT_ONCE FspMountInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
||||
@ -28,21 +29,30 @@ static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
|
||||
HANDLE Handle);
|
||||
static NTSTATUS (NTAPI *FspNtClose)(
|
||||
HANDLE Handle);
|
||||
static BOOLEAN FspMountDoNotUseLauncher;
|
||||
static BOOLEAN FspMountDoNotUseLauncherValue;
|
||||
static BOOLEAN FspMountBroadcastDriveChangeValue;
|
||||
|
||||
static VOID FspMountInitializeFromRegistry(VOID)
|
||||
{
|
||||
DWORD MountDoNotUseLauncher;
|
||||
DWORD Value;
|
||||
DWORD Size;
|
||||
LONG Result;
|
||||
|
||||
MountDoNotUseLauncher = 0;
|
||||
Size = sizeof MountDoNotUseLauncher;
|
||||
Value = 0;
|
||||
Size = sizeof Value;
|
||||
Result = RegGetValueW(HKEY_LOCAL_MACHINE, L"" FSP_FSCTL_PRODUCT_FULL_REGKEY,
|
||||
L"MountDoNotUseLauncher",
|
||||
RRF_RT_REG_DWORD, 0, &MountDoNotUseLauncher, &Size);
|
||||
RRF_RT_REG_DWORD, 0, &Value, &Size);
|
||||
if (ERROR_SUCCESS == Result)
|
||||
FspMountDoNotUseLauncher = !!MountDoNotUseLauncher;
|
||||
FspMountDoNotUseLauncherValue = !!Value;
|
||||
|
||||
Value = 0;
|
||||
Size = sizeof Value;
|
||||
Result = RegGetValueW(HKEY_LOCAL_MACHINE, L"" FSP_FSCTL_PRODUCT_FULL_REGKEY,
|
||||
L"MountBroadcastDriveChange",
|
||||
RRF_RT_REG_DWORD, 0, &Value, &Size);
|
||||
if (ERROR_SUCCESS == Result)
|
||||
FspMountBroadcastDriveChangeValue = !!Value;
|
||||
}
|
||||
|
||||
static BOOL WINAPI FspMountInitialize(
|
||||
@ -375,6 +385,48 @@ static NTSTATUS FspLauncherDefineDosDevice(
|
||||
return !NT_SUCCESS(Result) ? Result : FspNtStatusFromWin32(ErrorCode);
|
||||
}
|
||||
|
||||
static VOID FspMountBroadcastDriveChange(PWSTR MountPoint, WPARAM WParam)
|
||||
{
|
||||
/*
|
||||
* DefineDosDeviceW (either directly or via the CSRSS) broadcasts a WM_DEVICECHANGE message
|
||||
* when a drive is added/removed. Unfortunately on some systems this broadcast fails. The
|
||||
* result is that Explorer does not receive the WM_DEVICECHANGE notification and does not
|
||||
* become aware of the drive change. This results in only minor UI issues for local drives,
|
||||
* but more seriously it makes network drives inaccessible from some Explorer windows.
|
||||
*
|
||||
* The problem is that BroadcastSystemMessage can hang indefinitely when supplied the flags
|
||||
* NOHANG | FORCEIFHUNG | NOTIMEOUTIFNOTHUNG. The NOTIMEOUTIFNOTHUNG flag instructs the BSM
|
||||
* API to not timeout an app that is not considered hung; however an app that is not hung may
|
||||
* still fail to respond to a broadcasted message indefinitely. This can result in the BSM
|
||||
* API never returning ("hanging").
|
||||
*
|
||||
* To resolve this we simply call BroadcastSystemMessage with BSF_POSTMESSAGE. (It would work
|
||||
* with BSF_NOHANG | BSF_FORCEIFHUNG and without NOTIMEOUTIFNOTHUNG, but BSF_POSTMESSAGE is
|
||||
* faster).
|
||||
*/
|
||||
|
||||
BOOLEAN IsLocalSystem;
|
||||
DEV_BROADCAST_VOLUME DriveChange;
|
||||
DWORD Flags, Recipients;
|
||||
|
||||
FspServiceContextCheck(0, &IsLocalSystem);
|
||||
|
||||
memset(&DriveChange, 0, sizeof DriveChange);
|
||||
DriveChange.dbcv_size = sizeof DriveChange;
|
||||
DriveChange.dbcv_devicetype = DBT_DEVTYP_VOLUME;
|
||||
DriveChange.dbcv_flags = DBTF_NET;
|
||||
DriveChange.dbcv_unitmask = 1 << (MountPoint[0] - 'a');
|
||||
|
||||
Flags = BSF_POSTMESSAGE;
|
||||
Recipients = BSM_APPLICATIONS | (IsLocalSystem ? BSM_ALLDESKTOPS : 0);
|
||||
BroadcastSystemMessageW(
|
||||
Flags,
|
||||
&Recipients,
|
||||
WM_DEVICECHANGE,
|
||||
WParam,
|
||||
(LPARAM)&DriveChange);
|
||||
}
|
||||
|
||||
static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PMountHandle)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
@ -384,7 +436,7 @@ static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PM
|
||||
|
||||
Result = FspServiceContextCheck(0, &IsLocalSystem);
|
||||
IsServiceContext = NT_SUCCESS(Result) && !IsLocalSystem;
|
||||
if (IsServiceContext && !FspMountDoNotUseLauncher)
|
||||
if (IsServiceContext && !FspMountDoNotUseLauncherValue)
|
||||
{
|
||||
/*
|
||||
* If the current process is in the service context but not LocalSystem,
|
||||
@ -402,6 +454,13 @@ static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PM
|
||||
{
|
||||
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
/*
|
||||
* On some systems DefineDosDeviceW fails to properly broadcast the WM_DEVICECHANGE
|
||||
* notification. So use a workaround. See comments in FspMountBroadcastDriveChange.
|
||||
*/
|
||||
if (FspMountBroadcastDriveChangeValue)
|
||||
FspMountBroadcastDriveChange(MountPoint, DBT_DEVICEARRIVAL);
|
||||
}
|
||||
|
||||
if (0 != FspNtOpenSymbolicLinkObject)
|
||||
@ -457,9 +516,18 @@ static NTSTATUS FspMountRemove_Drive(PWSTR VolumeName, PWSTR MountPoint, HANDLE
|
||||
*/
|
||||
Result = FspLauncherDefineDosDevice(L'-', MountPoint, VolumeName);
|
||||
else
|
||||
{
|
||||
Result = DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
|
||||
MountPoint, VolumeName) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
/*
|
||||
* On some systems DefineDosDeviceW fails to properly broadcast the WM_DEVICECHANGE
|
||||
* notification. So use a workaround. See comments in FspMountBroadcastDriveChange.
|
||||
*/
|
||||
if (FspMountBroadcastDriveChangeValue)
|
||||
FspMountBroadcastDriveChange(MountPoint, DBT_DEVICEREMOVECOMPLETE);
|
||||
}
|
||||
|
||||
if (0 != MountHandle)
|
||||
FspNtClose(MountHandle);
|
||||
|
||||
|
93
src/dll/np.c
93
src/dll/np.c
@ -863,6 +863,99 @@ DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
DWORD APIENTRY NPGetUniversalName(
|
||||
LPCWSTR lpLocalPath,
|
||||
DWORD dwInfoLevel,
|
||||
LPVOID lpBuffer,
|
||||
LPDWORD lpBufferSize)
|
||||
{
|
||||
DWORD NpResult;
|
||||
WCHAR LocalNameBuf[3];
|
||||
PCWSTR RemainLocalPath;
|
||||
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
||||
DWORD RemoteNameSize, RemainLocalPathSize, RequiredBufferSize;
|
||||
|
||||
if (UNIVERSAL_NAME_INFO_LEVEL != dwInfoLevel &&
|
||||
REMOTE_NAME_INFO_LEVEL != dwInfoLevel)
|
||||
return WN_BAD_LEVEL;
|
||||
|
||||
if (0 == lpLocalPath ||
|
||||
L'\0' == lpLocalPath[0] ||
|
||||
L':' != lpLocalPath[1] ||
|
||||
(L'\0' != lpLocalPath[2] && L'\\' != lpLocalPath[2]))
|
||||
return WN_BAD_LOCALNAME;
|
||||
|
||||
LocalNameBuf[0] = lpLocalPath[0];
|
||||
LocalNameBuf[1] = L':';
|
||||
LocalNameBuf[2] = L'\0';
|
||||
RemainLocalPath = lpLocalPath + 2;
|
||||
|
||||
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
|
||||
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
|
||||
if (WN_SUCCESS != NpResult)
|
||||
return NpResult;
|
||||
|
||||
RemoteNameSize = lstrlenW(RemoteNameBuf) * sizeof(WCHAR);
|
||||
RemainLocalPathSize = lstrlenW(RemainLocalPath) * sizeof(WCHAR) + sizeof(WCHAR)/* term-0 */;
|
||||
|
||||
if (UNIVERSAL_NAME_INFO_LEVEL == dwInfoLevel)
|
||||
{
|
||||
RequiredBufferSize = sizeof(UNIVERSAL_NAME_INFOW) +
|
||||
/* UniversalName */ RemoteNameSize + RemainLocalPathSize;
|
||||
|
||||
if (RequiredBufferSize > *lpBufferSize)
|
||||
{
|
||||
*lpBufferSize = RequiredBufferSize;
|
||||
NpResult = WN_MORE_DATA;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
LPUNIVERSAL_NAME_INFOW Info = lpBuffer;
|
||||
memset(Info, 0, sizeof *Info);
|
||||
Info->lpUniversalName = (PVOID)(Info + 1);
|
||||
memcpy(Info->lpUniversalName, RemoteNameBuf, RemoteNameSize);
|
||||
memcpy((PUINT8)Info->lpUniversalName + RemoteNameSize, RemainLocalPath,
|
||||
RemainLocalPathSize);
|
||||
|
||||
NpResult = WN_SUCCESS;
|
||||
}
|
||||
else if (REMOTE_NAME_INFO_LEVEL == dwInfoLevel)
|
||||
{
|
||||
RequiredBufferSize = sizeof(REMOTE_NAME_INFOW) +
|
||||
/* UniversalName */ RemoteNameSize + RemainLocalPathSize +
|
||||
/* ConnectionName */RemoteNameSize + sizeof(WCHAR) +
|
||||
/* RemainingPath */ RemainLocalPathSize;
|
||||
|
||||
if (RequiredBufferSize > *lpBufferSize)
|
||||
{
|
||||
*lpBufferSize = RequiredBufferSize;
|
||||
NpResult = WN_MORE_DATA;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
LPREMOTE_NAME_INFOW Info = lpBuffer;
|
||||
memset(Info, 0, sizeof *Info);
|
||||
Info->lpUniversalName = (PVOID)(Info + 1);
|
||||
Info->lpConnectionName = (PVOID)((PUINT8)Info->lpUniversalName +
|
||||
RemoteNameSize + RemainLocalPathSize);
|
||||
Info->lpRemainingPath = (PVOID)((PUINT8)Info->lpConnectionName +
|
||||
RemoteNameSize + sizeof(WCHAR));
|
||||
memcpy(Info->lpUniversalName, RemoteNameBuf, RemoteNameSize);
|
||||
memcpy((PUINT8)Info->lpUniversalName + RemoteNameSize, RemainLocalPath,
|
||||
RemainLocalPathSize);
|
||||
memcpy(Info->lpConnectionName, RemoteNameBuf, RemoteNameSize + sizeof(WCHAR));
|
||||
memcpy(Info->lpRemainingPath, RemainLocalPath, RemainLocalPathSize);
|
||||
|
||||
NpResult = WN_SUCCESS;
|
||||
}
|
||||
else
|
||||
/* should not happen! */
|
||||
NpResult = WN_BAD_LEVEL;
|
||||
|
||||
exit:
|
||||
return NpResult;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD Signature; /* cheap and cheerful! */
|
||||
|
@ -215,3 +215,36 @@ FSP_API NTSTATUS FspVersion(PUINT32 PVersion)
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS FspGetModuleVersion(PWSTR ModuleFileName, PUINT32 PVersion)
|
||||
{
|
||||
/* internal only: get version of any module */
|
||||
|
||||
PVOID VersionInfo;
|
||||
DWORD Size;
|
||||
VS_FIXEDFILEINFO *FixedFileInfo = 0;
|
||||
UINT32 Version;
|
||||
|
||||
*PVersion = 0;
|
||||
|
||||
Size = GetFileVersionInfoSizeW(ModuleFileName, &Size/*dummy*/);
|
||||
if (0 < Size)
|
||||
{
|
||||
VersionInfo = MemAlloc(Size);
|
||||
if (0 != VersionInfo &&
|
||||
GetFileVersionInfoW(ModuleFileName, 0, Size, VersionInfo) &&
|
||||
VerQueryValueW(VersionInfo, L"\\", &FixedFileInfo, &Size))
|
||||
{
|
||||
Version = FixedFileInfo->dwFileVersionMS;
|
||||
}
|
||||
|
||||
MemFree(VersionInfo);
|
||||
}
|
||||
|
||||
if (0 == FixedFileInfo)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
*PVersion = Version;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -277,6 +277,11 @@ namespace Fsp
|
||||
get { return 0 != (_VolumeParams.Flags & VolumeParams.PostCleanupWhenModifiedOnly); }
|
||||
set { _VolumeParams.Flags |= (value ? VolumeParams.PostCleanupWhenModifiedOnly : 0); }
|
||||
}
|
||||
public Boolean PostDispositionWhenNecessaryOnly
|
||||
{
|
||||
get { return 0 != (_VolumeParams.Flags & VolumeParams.PostDispositionWhenNecessaryOnly); }
|
||||
set { _VolumeParams.Flags |= (value ? VolumeParams.PostDispositionWhenNecessaryOnly : 0); }
|
||||
}
|
||||
public Boolean PassQueryDirectoryPattern
|
||||
{
|
||||
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryPattern); }
|
||||
|
@ -56,6 +56,7 @@ namespace Fsp.Interop
|
||||
internal const UInt32 WslFeatures = 0x04000000;
|
||||
internal const UInt32 RejectIrpPriorToTransact0 = 0x10000000;
|
||||
internal const UInt32 SupportsPosixUnlinkRename = 0x20000000;
|
||||
internal const UInt32 PostDispositionWhenNecessaryOnly = 0x40000000;
|
||||
internal const int PrefixSize = 192;
|
||||
internal const int FileSystemNameSize = 16;
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include <shared/ku/library.h>
|
||||
|
||||
FSP_API NTSTATUS FspPosixSetUidMap(UINT32 Uid[], PSID Sid[], ULONG Count);
|
||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid);
|
||||
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid);
|
||||
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
|
||||
@ -58,6 +59,7 @@ FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
|
||||
|
||||
#if defined(_KERNEL_MODE)
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspPosixSetUidMap)
|
||||
#pragma alloc_text(PAGE, FspPosixMapUidToSid)
|
||||
#pragma alloc_text(PAGE, FspPosixMapSidToUid)
|
||||
#pragma alloc_text(PAGE, FspPosixCreateSid)
|
||||
@ -345,6 +347,8 @@ VOID FspPosixFinalize(BOOLEAN Dynamic)
|
||||
|
||||
if (Dynamic)
|
||||
{
|
||||
FspPosixSetUidMap(0, 0, 0);
|
||||
|
||||
MemFree(FspTrustedDomains);
|
||||
MemFree(FspAccountDomainSid);
|
||||
MemFree(FspPrimaryDomainSid);
|
||||
@ -425,6 +429,52 @@ static inline BOOLEAN FspPosixIsRelativeSid(PISID Sid1, PISID Sid2)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static UINT32 FspPosixUidMap_Uid[8];
|
||||
static PSID FspPosixUidMap_Sid[8];
|
||||
static ULONG FspPosixUidMap_Cnt = 0;
|
||||
|
||||
FSP_API NTSTATUS FspPosixSetUidMap(UINT32 Uid[], PSID Sid[], ULONG Count)
|
||||
{
|
||||
FSP_KU_CODE;
|
||||
|
||||
NTSTATUS Result;
|
||||
|
||||
if (sizeof FspPosixUidMap_Uid / sizeof FspPosixUidMap_Uid[0] < Count)
|
||||
Count = sizeof FspPosixUidMap_Uid / sizeof FspPosixUidMap_Uid[0];
|
||||
|
||||
for (ULONG I = 0; FspPosixUidMap_Cnt > I; I++)
|
||||
{
|
||||
MemFree(FspPosixUidMap_Sid[I]);
|
||||
FspPosixUidMap_Uid[I] = 0;
|
||||
FspPosixUidMap_Sid[I] = 0;
|
||||
}
|
||||
|
||||
FspPosixUidMap_Cnt = 0;
|
||||
for (ULONG I = 0; Count > I; I++)
|
||||
{
|
||||
ULONG L = GetLengthSid(Sid[I]);
|
||||
PSID S = MemAlloc(L);
|
||||
if (0 == S)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
FspPosixUidMap_Uid[I] = Uid[I];
|
||||
FspPosixUidMap_Sid[I] = S;
|
||||
memcpy(S, Sid[I], L);
|
||||
FspPosixUidMap_Cnt = I + 1;
|
||||
}
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result))
|
||||
FspPosixSetUidMap(0, 0, 0);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
||||
{
|
||||
FSP_KU_CODE;
|
||||
@ -433,6 +483,20 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
||||
|
||||
*PSid = 0;
|
||||
|
||||
/*
|
||||
* UidMap overrides default UID <-> SID mapping.
|
||||
*/
|
||||
for (ULONG I = 0; FspPosixUidMap_Cnt > I; I++)
|
||||
if (FspPosixUidMap_Uid[I] == Uid)
|
||||
{
|
||||
ULONG L = GetLengthSid(FspPosixUidMap_Sid[I]);
|
||||
PSID S = MemAlloc(L);
|
||||
if (0 != S)
|
||||
memcpy(S, FspPosixUidMap_Sid[I], L);
|
||||
*PSid = S;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* UID namespace partitioning (from [IDMAP] rules):
|
||||
*
|
||||
@ -556,6 +620,7 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
|
||||
else if (FspUnmappedUid != Uid && 0x1000 <= Uid && Uid < 0x100000)
|
||||
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
|
||||
|
||||
exit:
|
||||
if (0 == *PSid)
|
||||
*PSid = FspUnmappedSid;
|
||||
|
||||
@ -577,6 +642,16 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
||||
if (!IsValidSid(Sid) || 0 == (Count = *GetSidSubAuthorityCount(Sid)))
|
||||
return STATUS_INVALID_SID;
|
||||
|
||||
/*
|
||||
* UidMap overrides default UID <-> SID mapping.
|
||||
*/
|
||||
for (ULONG I = 0; FspPosixUidMap_Cnt > I; I++)
|
||||
if (EqualSid(FspPosixUidMap_Sid[I], Sid))
|
||||
{
|
||||
*PUid = FspPosixUidMap_Uid[I];
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Authority = GetSidIdentifierAuthority(Sid)->Value[5];
|
||||
SubAuthority0 = 2 <= Count ? *GetSidSubAuthority(Sid, 0) : 0;
|
||||
Rid = *GetSidSubAuthority(Sid, Count - 1);
|
||||
@ -671,6 +746,7 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
|
||||
*PUid = 0x10000 + 0x100 * Authority + Rid;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (-1 == *PUid)
|
||||
*PUid = FspUnmappedUid;
|
||||
|
||||
|
@ -66,11 +66,17 @@ BOOLEAN FspFastIoCheckIfPossible(
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
#if 1
|
||||
ASSERT(FALSE);
|
||||
return FALSE;
|
||||
|
||||
#else
|
||||
FSP_ENTER_BOOL(PAGED_CODE());
|
||||
|
||||
Result = FALSE;
|
||||
|
||||
FSP_LEAVE_BOOL("FileObject=%p", FileObject);
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID FspAcquireFileForNtCreateSection(
|
||||
@ -299,9 +305,16 @@ VOID FspPropagateTopFlags(PIRP Irp, PIRP TopLevelIrp)
|
||||
|
||||
if ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG >= TopLevelIrp)
|
||||
{
|
||||
/*
|
||||
* FAST I/O only acquires the Main lock.
|
||||
* Other (non-IRP) top levels acquire the Full lock.
|
||||
*/
|
||||
DEBUGBREAK_EX(iorecu);
|
||||
|
||||
FspIrpSetTopFlags(Irp, FspFileNodeAcquireFull);
|
||||
FspIrpSetTopFlags(Irp,
|
||||
(PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP == TopLevelIrp ?
|
||||
FspFileNodeAcquireMain :
|
||||
FspFileNodeAcquireFull);
|
||||
}
|
||||
else if ((PIRP)MM_SYSTEM_RANGE_START <= TopLevelIrp && IO_TYPE_IRP == TopLevelIrp->Type)
|
||||
{
|
||||
|
@ -21,6 +21,9 @@
|
||||
|
||||
#include <sys/driver.h>
|
||||
|
||||
FAST_IO_DEVICE_CONTROL FspFastIoDeviceControl;
|
||||
static NTSTATUS FspFsctlDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspFsvrtDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static BOOLEAN FspFsvrtDeviceControlStorageQuery(
|
||||
@ -33,6 +36,8 @@ static FSP_IOP_REQUEST_FINI FspFsvolDeviceControlRequestFini;
|
||||
FSP_DRIVER_DISPATCH FspDeviceControl;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspFastIoDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspFsctlDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspFsvrtDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspFsvrtDeviceControlStorageQuery)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControl)
|
||||
@ -46,6 +51,81 @@ enum
|
||||
RequestFileNode = 0,
|
||||
};
|
||||
|
||||
BOOLEAN FspFastIoDeviceControl(
|
||||
PFILE_OBJECT FileObject,
|
||||
BOOLEAN CanWait,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength,
|
||||
ULONG IoControlCode,
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
FSP_ENTER_BOOL(PAGED_CODE());
|
||||
/* cannot use FSP_ENTER_FIO() because it only supports fsvol devices */
|
||||
|
||||
Result = DEBUGTEST(50) &&
|
||||
CanWait &&
|
||||
FSP_IOCTL_TRANSACT == IoControlCode &&
|
||||
FspFsctlDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind;
|
||||
if (!Result)
|
||||
FSP_RETURN();
|
||||
|
||||
#if 0
|
||||
PDEVICE_OBJECT FsctlDeviceObject = DeviceObject;
|
||||
if (!FspDeviceReference(FsctlDeviceObject))
|
||||
{
|
||||
IoStatus->Status = STATUS_CANCELLED;
|
||||
IoStatus->Information = 0;
|
||||
FSP_RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(0 == IoGetTopLevelIrp());
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
|
||||
|
||||
IoStatus->Status = FspVolumeFastTransact(
|
||||
FileObject->FsContext2,
|
||||
IoControlCode,
|
||||
InputBuffer,
|
||||
InputBufferLength,
|
||||
OutputBuffer,
|
||||
OutputBufferLength,
|
||||
IoStatus,
|
||||
(PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
|
||||
|
||||
IoSetTopLevelIrp(0);
|
||||
|
||||
#if 0
|
||||
FspDeviceDereference(FsctlDeviceObject);
|
||||
#endif
|
||||
|
||||
FSP_LEAVE_BOOL(
|
||||
"%s, FileObject=%p",
|
||||
IoctlCodeSym(IoControlCode),
|
||||
FileObject);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsctlDeviceControl(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
||||
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
||||
{
|
||||
case FSP_IOCTL_TRANSACT:
|
||||
case FSP_IOCTL_TRANSACT_BATCH:
|
||||
case FSP_IOCTL_TRANSACT_INTERNAL:
|
||||
if (0 != IrpSp->FileObject->FsContext2)
|
||||
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvrtDeviceControl(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
@ -258,6 +338,8 @@ NTSTATUS FspDeviceControl(
|
||||
FSP_RETURN(Result = FspFsvolDeviceControl(DeviceObject, Irp, IrpSp));
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
FSP_RETURN(Result = FspFsvrtDeviceControl(DeviceObject, Irp, IrpSp));
|
||||
case FspFsctlDeviceExtensionKind:
|
||||
FSP_RETURN(Result = FspFsctlDeviceControl(DeviceObject, Irp, IrpSp));
|
||||
default:
|
||||
FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
|
||||
}
|
||||
|
@ -865,6 +865,8 @@ NTSTATUS FspFsvolDirectoryControlPrepare(
|
||||
PVOID Address;
|
||||
PEPROCESS Process;
|
||||
|
||||
ASSERT(FspProcessBufferSizeMax >= Request->Req.QueryDirectory.Length);
|
||||
|
||||
Result = FspProcessBufferAcquire(Request->Req.QueryDirectory.Length, &Cookie, &Address);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
@ -89,15 +89,15 @@ NTSTATUS DriverEntry(
|
||||
/* setup fast I/O and resource acquisition */
|
||||
FspFastIoDispatch.SizeOfFastIoDispatch = sizeof FspFastIoDispatch;
|
||||
FspFastIoDispatch.FastIoCheckIfPossible = FspFastIoCheckIfPossible;
|
||||
//FspFastIoDispatch.FastIoRead = 0;
|
||||
//FspFastIoDispatch.FastIoWrite = 0;
|
||||
FspFastIoDispatch.FastIoRead = FspFastIoRead;
|
||||
FspFastIoDispatch.FastIoWrite = FspFastIoWrite;
|
||||
FspFastIoDispatch.FastIoQueryBasicInfo = FspFastIoQueryBasicInfo;
|
||||
FspFastIoDispatch.FastIoQueryStandardInfo = FspFastIoQueryStandardInfo;
|
||||
//FspFastIoDispatch.FastIoLock = 0;
|
||||
//FspFastIoDispatch.FastIoUnlockSingle = 0;
|
||||
//FspFastIoDispatch.FastIoUnlockAll = 0;
|
||||
//FspFastIoDispatch.FastIoUnlockAllByKey = 0;
|
||||
//FspFastIoDispatch.FastIoDeviceControl = 0;
|
||||
FspFastIoDispatch.FastIoDeviceControl = FspFastIoDeviceControl;
|
||||
FspFastIoDispatch.AcquireFileForNtCreateSection = FspAcquireFileForNtCreateSection;
|
||||
FspFastIoDispatch.ReleaseFileForNtCreateSection = FspReleaseFileForNtCreateSection;
|
||||
//FspFastIoDispatch.FastIoDetachDevice = 0;
|
||||
|
@ -304,6 +304,48 @@ VOID FspTraceNtStatus(const char *file, int line, const char *func, NTSTATUS Sta
|
||||
} \
|
||||
); \
|
||||
return Result
|
||||
#define FSP_ENTER_FIO(...) \
|
||||
PDEVICE_OBJECT FsvolDeviceObject; \
|
||||
switch (FspDeviceExtension(DeviceObject)->Kind)\
|
||||
{ \
|
||||
case FspFsmupDeviceExtensionKind: \
|
||||
FsvolDeviceObject = FspMupGetFsvolDeviceObject(FileObject);\
|
||||
if (0 == FsvolDeviceObject) \
|
||||
{ \
|
||||
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;\
|
||||
IoStatus->Information = 0; \
|
||||
return TRUE; \
|
||||
} \
|
||||
break; \
|
||||
case FspFsvolDeviceExtensionKind: \
|
||||
FsvolDeviceObject = DeviceObject;\
|
||||
break; \
|
||||
default: \
|
||||
return FALSE; \
|
||||
} \
|
||||
BOOLEAN Result = TRUE; \
|
||||
BOOLEAN fsp_device_deref = FALSE; \
|
||||
FSP_ENTER_(ioentr, __VA_ARGS__); \
|
||||
do \
|
||||
{ \
|
||||
ASSERT(0 == IoGetTopLevelIrp()); \
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP); \
|
||||
if (!FspDeviceReference(FsvolDeviceObject))\
|
||||
{ \
|
||||
IoStatus->Status = STATUS_CANCELLED;\
|
||||
IoStatus->Information = 0; \
|
||||
goto fsp_leave_label; \
|
||||
} \
|
||||
fsp_device_deref = TRUE; \
|
||||
} while (0,0)
|
||||
#define FSP_LEAVE_FIO(fmt, ...) \
|
||||
FSP_LEAVE_( \
|
||||
FSP_DEBUGLOG_(fmt, " = %s", __VA_ARGS__, Result ? "TRUE" : "FALSE");\
|
||||
if (fsp_device_deref) \
|
||||
FspDeviceDereference(FsvolDeviceObject);\
|
||||
IoSetTopLevelIrp(0); \
|
||||
); \
|
||||
return Result
|
||||
#define FSP_ENTER_BOOL(...) \
|
||||
BOOLEAN Result = TRUE; FSP_ENTER_(iocall, __VA_ARGS__)
|
||||
#define FSP_LEAVE_BOOL(fmt, ...) \
|
||||
@ -383,6 +425,9 @@ FSP_IOPREP_DISPATCH FspFsvolWritePrepare;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolWriteComplete;
|
||||
|
||||
/* fast I/O and resource acquisition callbacks */
|
||||
FAST_IO_DEVICE_CONTROL FspFastIoDeviceControl;
|
||||
FAST_IO_READ FspFastIoRead;
|
||||
FAST_IO_WRITE FspFastIoWrite;
|
||||
FAST_IO_QUERY_BASIC_INFO FspFastIoQueryBasicInfo;
|
||||
FAST_IO_QUERY_STANDARD_INFO FspFastIoQueryStandardInfo;
|
||||
FAST_IO_QUERY_NETWORK_OPEN_INFO FspFastIoQueryNetworkOpenInfo;
|
||||
@ -643,6 +688,8 @@ NTSTATUS FspOplockFsctrl(
|
||||
FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0)
|
||||
#define FSP_NEXT_EA(Ea, EaEnd) \
|
||||
(0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd))
|
||||
#define FSP_FUNCTION_FROM_CTL_CODE(ControlCode)\
|
||||
(((ControlCode) >> 2) & 0xfff)
|
||||
|
||||
/* utility: synchronous work queue */
|
||||
typedef struct
|
||||
@ -882,7 +929,7 @@ retry:
|
||||
{
|
||||
if (PsIsThreadTerminating(PsGetCurrentThread()))
|
||||
return STATUS_THREAD_IS_TERMINATING;
|
||||
if (0 != Irp && Irp->Cancel)
|
||||
if (0 != Irp && ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG >= Irp || Irp->Cancel))
|
||||
return STATUS_CANCELLED;
|
||||
if (0 != ExpirationTime)
|
||||
{
|
||||
@ -1088,7 +1135,7 @@ enum
|
||||
FspFsvolDeviceSecurityCacheCapacity = 100,
|
||||
FspFsvolDeviceSecurityCacheItemSizeMax = 4096,
|
||||
FspFsvolDeviceDirInfoCacheCapacity = 100,
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(FspProcessBufferSizeMax, PAGE_SIZE),
|
||||
FspFsvolDeviceStreamInfoCacheCapacity = 100,
|
||||
FspFsvolDeviceStreamInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE),
|
||||
FspFsvolDeviceEaCacheCapacity = 100,
|
||||
@ -1360,6 +1407,8 @@ NTSTATUS FspMupRegister(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
|
||||
VOID FspMupUnregister(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
|
||||
PDEVICE_OBJECT FspMupGetFsvolDeviceObject(
|
||||
PFILE_OBJECT FileObject);
|
||||
NTSTATUS FspMupHandleIrp(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp);
|
||||
|
||||
@ -1378,6 +1427,15 @@ NTSTATUS FspVolumeGetNameList(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeTransact(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeFastTransact(
|
||||
PDEVICE_OBJECT FsvolDeviceObject,
|
||||
ULONG ControlCode,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength,
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PIRP Irp);
|
||||
NTSTATUS FspVolumeTransactFsext(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeStop(
|
||||
@ -1388,6 +1446,7 @@ NTSTATUS FspVolumeWork(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
|
||||
/* file objects */
|
||||
//#define FSP_FILE_NODE_NO_PGIO
|
||||
#define FspFileNodeKind(FileNode) \
|
||||
(((FSP_FILE_NODE *)FileNode)->Header.NodeTypeCode)
|
||||
#define FspFileNodeIsValid(FileNode) \
|
||||
|
@ -342,7 +342,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
|
||||
RtlZeroMemory(FileNode, sizeof *FileNode + ExtraSize);
|
||||
FileNode->Header.NodeTypeCode = FspFileNodeFileKind;
|
||||
FileNode->Header.NodeByteSize = sizeof *FileNode;
|
||||
FileNode->Header.IsFastIoPossible = FastIoIsNotPossible;
|
||||
FileNode->Header.IsFastIoPossible = FastIoIsQuestionable;
|
||||
FileNode->Header.Resource = &NonPaged->Resource;
|
||||
FileNode->Header.PagingIoResource = &NonPaged->PagingIoResource;
|
||||
FileNode->Header.ValidDataLength.QuadPart = MAXLONGLONG;
|
||||
@ -407,8 +407,10 @@ VOID FspFileNodeAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
||||
if (Flags & FspFileNodeAcquireMain)
|
||||
ExAcquireResourceSharedLite(FileNode->Header.Resource, TRUE);
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
ExAcquireResourceSharedLite(FileNode->Header.PagingIoResource, TRUE);
|
||||
#endif
|
||||
|
||||
FSP_FILE_NODE_SET_FLAGS();
|
||||
}
|
||||
@ -432,6 +434,7 @@ BOOLEAN FspFileNodeTryAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags, BOOLE
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
{
|
||||
Result = ExAcquireResourceSharedLite(FileNode->Header.PagingIoResource, Wait);
|
||||
@ -442,6 +445,7 @@ BOOLEAN FspFileNodeTryAcquireSharedF(FSP_FILE_NODE *FileNode, ULONG Flags, BOOLE
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Result)
|
||||
FSP_FILE_NODE_SET_FLAGS();
|
||||
@ -462,8 +466,10 @@ VOID FspFileNodeAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
||||
if (Flags & FspFileNodeAcquireMain)
|
||||
ExAcquireResourceExclusiveLite(FileNode->Header.Resource, TRUE);
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
ExAcquireResourceExclusiveLite(FileNode->Header.PagingIoResource, TRUE);
|
||||
#endif
|
||||
|
||||
FSP_FILE_NODE_SET_FLAGS();
|
||||
}
|
||||
@ -487,6 +493,7 @@ BOOLEAN FspFileNodeTryAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags, BO
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
{
|
||||
Result = ExAcquireResourceExclusiveLite(FileNode->Header.PagingIoResource, Wait);
|
||||
@ -497,6 +504,7 @@ BOOLEAN FspFileNodeTryAcquireExclusiveF(FSP_FILE_NODE *FileNode, ULONG Flags, BO
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Result)
|
||||
FSP_FILE_NODE_SET_FLAGS();
|
||||
@ -513,8 +521,10 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
||||
|
||||
FSP_FILE_NODE_GET_FLAGS();
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
ExConvertExclusiveToSharedLite(FileNode->Header.PagingIoResource);
|
||||
#endif
|
||||
|
||||
if (Flags & FspFileNodeAcquireMain)
|
||||
ExConvertExclusiveToSharedLite(FileNode->Header.Resource);
|
||||
@ -534,8 +544,10 @@ VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
||||
if (Flags & FspFileNodeAcquireMain)
|
||||
ExSetResourceOwnerPointer(FileNode->Header.Resource, Owner);
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
ExSetResourceOwnerPointer(FileNode->Header.PagingIoResource, Owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
||||
@ -548,8 +560,10 @@ VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags)
|
||||
FSP_FILE_NODE_GET_FLAGS();
|
||||
FSP_FILE_NODE_ASSERT_FLAGS_SET();
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
ExReleaseResourceLite(FileNode->Header.PagingIoResource);
|
||||
#endif
|
||||
|
||||
if (Flags & FspFileNodeAcquireMain)
|
||||
ExReleaseResourceLite(FileNode->Header.Resource);
|
||||
@ -569,6 +583,7 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
||||
|
||||
Owner = (PVOID)((UINT_PTR)Owner | 3);
|
||||
|
||||
#if !defined(FSP_FILE_NODE_NO_PGIO)
|
||||
if (Flags & FspFileNodeAcquirePgio)
|
||||
{
|
||||
if (ExIsResourceAcquiredLite(FileNode->Header.PagingIoResource))
|
||||
@ -576,6 +591,7 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
||||
else
|
||||
ExReleaseResourceForThreadLite(FileNode->Header.PagingIoResource, (ERESOURCE_THREAD)Owner);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Flags & FspFileNodeAcquireMain)
|
||||
{
|
||||
|
@ -1435,12 +1435,30 @@ static NTSTATUS FspFsvolSetPositionInformation(PFILE_OBJECT FileObject,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static inline FspFsvolSetDispositionInformationFlags(
|
||||
PFILE_OBJECT FileObject,
|
||||
FSP_FILE_NODE *FileNode,
|
||||
FSP_FILE_DESC *FileDesc,
|
||||
UINT32 DispositionFlags)
|
||||
{
|
||||
BOOLEAN Delete = BooleanFlagOn(DispositionFlags, FILE_DISPOSITION_DELETE);
|
||||
|
||||
FspFileNodeSetDeletePending(FileNode, Delete);
|
||||
FileObject->DeletePending = Delete;
|
||||
|
||||
if (!Delete)
|
||||
FileDesc->PosixDelete = FALSE;
|
||||
else if (FlagOn(DispositionFlags, FILE_DISPOSITION_POSIX_SEMANTICS))
|
||||
FileDesc->PosixDelete = TRUE;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolSetDispositionInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
|
||||
UINT32 DispositionFlags;
|
||||
@ -1465,7 +1483,7 @@ static NTSTATUS FspFsvolSetDispositionInformation(
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.SupportsPosixUnlinkRename)
|
||||
if (!FsvolDeviceExtension->VolumeParams.SupportsPosixUnlinkRename)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (sizeof(FILE_DISPOSITION_INFORMATION_EX) > Length)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@ -1589,6 +1607,28 @@ retry:
|
||||
}
|
||||
FileDesc->DispositionStatus = STATUS_SUCCESS;
|
||||
|
||||
if (!FileNode->IsDirectory && FsvolDeviceExtension->VolumeParams.PostDispositionWhenNecessaryOnly)
|
||||
{
|
||||
if (FILE_DISPOSITION_DELETE ==
|
||||
(DispositionFlags & (FILE_DISPOSITION_DELETE | FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE)))
|
||||
{
|
||||
FSP_FSCTL_FILE_INFO FileInfoBuf;
|
||||
if (!FspFileNodeTryGetFileInfo(FileNode, &FileInfoBuf))
|
||||
goto slow;
|
||||
if (0 != (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
Result = STATUS_CANNOT_DELETE;
|
||||
goto unlock_exit;
|
||||
}
|
||||
}
|
||||
|
||||
FspFsvolSetDispositionInformationFlags(FileObject, FileNode, FileDesc, DispositionFlags);
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
goto unlock_exit;
|
||||
slow:;
|
||||
}
|
||||
|
||||
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, 0,
|
||||
FspFsvolSetInformationRequestFini, &Request);
|
||||
if (!NT_SUCCESS(Result))
|
||||
@ -1622,19 +1662,12 @@ static NTSTATUS FspFsvolSetDispositionInformationSuccess(
|
||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
UINT32 DispositionFlags = Request->Req.SetInformation.Info.DispositionEx.Flags;
|
||||
BOOLEAN Delete = BooleanFlagOn(DispositionFlags, FILE_DISPOSITION_DELETE);
|
||||
|
||||
FspFileNodeSetDeletePending(FileNode, Delete);
|
||||
FileObject->DeletePending = Delete;
|
||||
|
||||
if (!Delete)
|
||||
FileDesc->PosixDelete = FALSE;
|
||||
else if (FlagOn(DispositionFlags, FILE_DISPOSITION_POSIX_SEMANTICS))
|
||||
FileDesc->PosixDelete = TRUE;
|
||||
FspFsvolSetDispositionInformationFlags(FileObject, FileNode, FileDesc, DispositionFlags);
|
||||
|
||||
/* fastfat does this, although it seems unnecessary */
|
||||
#if 1
|
||||
if (FileNode->IsDirectory && Delete)
|
||||
if (FileNode->IsDirectory && FlagOn(DispositionFlags, FILE_DISPOSITION_DELETE))
|
||||
{
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||
FspFsvolDeviceExtension(IrpSp->DeviceObject);
|
||||
|
@ -152,6 +152,7 @@
|
||||
#define FspIoqEventSet(E) KeSetEvent(E, 1, FALSE)
|
||||
#define FspIoqEventCancellableWait(E,T,I) FsRtlCancellableWaitForSingleObject(E,T,I)
|
||||
#define FspIoqEventClear(E) KeClearEvent(E)
|
||||
#error FsRtlCancellableWaitForSingleObject needs to support FSRTL_FAST_IO_TOP_LEVEL_IRP cancellation
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -43,6 +43,8 @@ NTSTATUS FspMupRegister(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
|
||||
VOID FspMupUnregister(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
|
||||
PDEVICE_OBJECT FspMupGetFsvolDeviceObject(
|
||||
PFILE_OBJECT FileObject);
|
||||
NTSTATUS FspMupHandleIrp(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp);
|
||||
static NTSTATUS FspMupRedirQueryPathEx(
|
||||
@ -52,6 +54,7 @@ static NTSTATUS FspMupRedirQueryPathEx(
|
||||
#pragma alloc_text(PAGE, FspMupGetClassName)
|
||||
#pragma alloc_text(PAGE, FspMupRegister)
|
||||
#pragma alloc_text(PAGE, FspMupUnregister)
|
||||
#pragma alloc_text(PAGE, FspMupGetFsvolDeviceObject)
|
||||
#pragma alloc_text(PAGE, FspMupHandleIrp)
|
||||
#pragma alloc_text(PAGE, FspMupRedirQueryPathEx)
|
||||
#endif
|
||||
@ -191,6 +194,27 @@ VOID FspMupUnregister(
|
||||
ExReleaseResourceLite(&FsmupDeviceExtension->PrefixTableResource);
|
||||
}
|
||||
|
||||
PDEVICE_OBJECT FspMupGetFsvolDeviceObject(
|
||||
PFILE_OBJECT FileObject)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
PDEVICE_OBJECT FsvolDeviceObject = 0;
|
||||
|
||||
ASSERT(0 != FileObject);
|
||||
|
||||
if (FspFileNodeIsValid(FileObject->FsContext))
|
||||
FsvolDeviceObject = ((FSP_FILE_NODE*)FileObject->FsContext)->FsvolDeviceObject;
|
||||
else if (0 != FileObject->FsContext2 &&
|
||||
#pragma prefast(disable:28175, "We are a filesystem: ok to access DeviceObject->Type")
|
||||
IO_TYPE_DEVICE == ((PDEVICE_OBJECT)FileObject->FsContext2)->Type &&
|
||||
0 != ((PDEVICE_OBJECT)FileObject->FsContext2)->DeviceExtension &&
|
||||
FspFsvolDeviceExtensionKind == FspDeviceExtension((PDEVICE_OBJECT)FileObject->FsContext2)->Kind)
|
||||
FsvolDeviceObject = (PDEVICE_OBJECT)FileObject->FsContext2;
|
||||
|
||||
return FsvolDeviceObject;
|
||||
}
|
||||
|
||||
NTSTATUS FspMupHandleIrp(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp)
|
||||
{
|
||||
@ -276,7 +300,7 @@ NTSTATUS FspMupHandleIrp(
|
||||
FsvolDeviceObject = ((FSP_FILE_NODE *)FileObject->FsContext)->FsvolDeviceObject;
|
||||
else if (0 != FileObject->FsContext2 &&
|
||||
#pragma prefast(disable:28175, "We are a filesystem: ok to access DeviceObject->Type")
|
||||
3 == ((PDEVICE_OBJECT)FileObject->FsContext2)->Type &&
|
||||
IO_TYPE_DEVICE == ((PDEVICE_OBJECT)FileObject->FsContext2)->Type &&
|
||||
0 != ((PDEVICE_OBJECT)FileObject->FsContext2)->DeviceExtension &&
|
||||
FspFsvolDeviceExtensionKind == FspDeviceExtension((PDEVICE_OBJECT)FileObject->FsContext2)->Kind)
|
||||
FsvolDeviceObject = (PDEVICE_OBJECT)FileObject->FsContext2;
|
||||
|
103
src/sys/read.c
103
src/sys/read.c
@ -21,6 +21,7 @@
|
||||
|
||||
#include <sys/driver.h>
|
||||
|
||||
FAST_IO_READ FspFastIoRead;
|
||||
static NTSTATUS FspFsvolRead(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspFsvolReadCached(
|
||||
@ -35,6 +36,7 @@ static FSP_IOP_REQUEST_FINI FspFsvolReadNonCachedRequestFini;
|
||||
FSP_DRIVER_DISPATCH FspRead;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspFastIoRead)
|
||||
#pragma alloc_text(PAGE, FspFsvolRead)
|
||||
#pragma alloc_text(PAGE, FspFsvolReadCached)
|
||||
#pragma alloc_text(PAGE, FspFsvolReadNonCached)
|
||||
@ -55,6 +57,107 @@ enum
|
||||
};
|
||||
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestSafeMdl, "");
|
||||
|
||||
BOOLEAN FspFastIoRead(
|
||||
PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER ByteOffset,
|
||||
ULONG Length,
|
||||
BOOLEAN CanWait,
|
||||
ULONG Key,
|
||||
PVOID UserBuffer,
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
FSP_ENTER_FIO(PAGED_CODE());
|
||||
|
||||
IoStatus->Status = STATUS_SUCCESS;
|
||||
IoStatus->Information = 0;
|
||||
|
||||
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||
{
|
||||
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
FSP_RETURN(Result = TRUE);
|
||||
}
|
||||
|
||||
FSP_FILE_NODE* FileNode = FileObject->FsContext;
|
||||
LARGE_INTEGER ReadOffset = *ByteOffset;
|
||||
ULONG ReadLength = Length;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
|
||||
/* only regular files can be read */
|
||||
if (FileNode->IsDirectory)
|
||||
{
|
||||
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
||||
FSP_RETURN(Result = TRUE);
|
||||
}
|
||||
|
||||
/* do we have anything to read? */
|
||||
if (0 == ReadLength)
|
||||
FSP_RETURN(Result = TRUE);
|
||||
|
||||
/* does the file support caching? */
|
||||
if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
/* try to acquire the FileNode Main shared */
|
||||
Result = DEBUGTEST(90) &&
|
||||
FspFileNodeTryAcquireSharedF(FileNode, FspFileNodeAcquireMain, CanWait);
|
||||
if (!Result)
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
/* is the file actually cached? */
|
||||
if (0 == FileObject->PrivateCacheMap)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = FALSE);
|
||||
}
|
||||
|
||||
/* does the file have oplocks or file locks? */
|
||||
Result =
|
||||
FsRtlOplockIsFastIoPossible(FspFileNodeAddrOfOplock(FileNode)) &&
|
||||
!FsRtlAreThereCurrentFileLocks(&FileNode->FileLock);
|
||||
if (!Result)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = FALSE);
|
||||
}
|
||||
|
||||
/* trim ReadLength; the cache manager does not tolerate reads beyond file size */
|
||||
ASSERT(FspTimeoutInfinity32 ==
|
||||
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
|
||||
FspFileNodeGetFileInfo(FileNode, &FileInfo);
|
||||
if ((UINT64)ReadOffset.QuadPart >= FileInfo.FileSize)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
IoStatus->Status = STATUS_END_OF_FILE;
|
||||
FSP_RETURN(Result = TRUE);
|
||||
}
|
||||
if ((UINT64)ReadLength > FileInfo.FileSize - ReadOffset.QuadPart)
|
||||
ReadLength = (ULONG)(FileInfo.FileSize - ReadOffset.QuadPart);
|
||||
|
||||
NTSTATUS Result0 =
|
||||
FspCcCopyRead(FileObject, &ReadOffset, ReadLength, CanWait, UserBuffer, IoStatus);
|
||||
if (!NT_SUCCESS(Result0))
|
||||
{
|
||||
IoStatus->Status = Result0;
|
||||
IoStatus->Information = 0;
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = TRUE);
|
||||
}
|
||||
Result = STATUS_SUCCESS == Result0;
|
||||
|
||||
SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
|
||||
if (Result)
|
||||
FileObject->CurrentByteOffset.QuadPart = ReadOffset.QuadPart + ReadLength;
|
||||
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
|
||||
FSP_LEAVE_FIO(
|
||||
"FileObject=%p, UserBuffer=%p, CanWait=%d, "
|
||||
"Key=%#lx, ByteOffset=%#lx:%#lx, Length=%ld",
|
||||
FileObject, UserBuffer, CanWait,
|
||||
Key, ByteOffset->HighPart, ByteOffset->LowPart, Length);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolRead(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
|
@ -46,6 +46,15 @@ static NTSTATUS FspVolumeGetNameListNoLock(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeTransact(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeFastTransact(
|
||||
PDEVICE_OBJECT FsvolDeviceObject,
|
||||
ULONG ControlCode,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength,
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PIRP Irp);
|
||||
NTSTATUS FspVolumeTransactFsext(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeStop(
|
||||
@ -71,6 +80,7 @@ NTSTATUS FspVolumeWork(
|
||||
#pragma alloc_text(PAGE, FspVolumeGetNameList)
|
||||
#pragma alloc_text(PAGE, FspVolumeGetNameListNoLock)
|
||||
#pragma alloc_text(PAGE, FspVolumeTransact)
|
||||
#pragma alloc_text(PAGE, FspVolumeFastTransact)
|
||||
#pragma alloc_text(PAGE, FspVolumeTransactFsext)
|
||||
#pragma alloc_text(PAGE, FspVolumeStop)
|
||||
#pragma alloc_text(PAGE, FspVolumeNotify)
|
||||
@ -764,22 +774,35 @@ NTSTATUS FspVolumeTransact(
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
|
||||
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
|
||||
ASSERT(
|
||||
(
|
||||
IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction &&
|
||||
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction &&
|
||||
(
|
||||
FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode ||
|
||||
FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode ||
|
||||
FSP_FSCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode);
|
||||
FSP_FSCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode
|
||||
)
|
||||
) ||
|
||||
(
|
||||
IRP_MJ_DEVICE_CONTROL == IrpSp->MajorFunction &&
|
||||
(
|
||||
FSP_IOCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode ||
|
||||
FSP_IOCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode ||
|
||||
FSP_IOCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode
|
||||
)
|
||||
));
|
||||
ASSERT(0 != IrpSp->FileObject->FsContext2);
|
||||
|
||||
/* check parameters */
|
||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
|
||||
ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||||
ULONG ControlFunction = FSP_FUNCTION_FROM_CTL_CODE(ControlCode);
|
||||
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
PVOID InputBuffer = 0;
|
||||
PVOID OutputBuffer = 0;
|
||||
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
|
||||
if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction)
|
||||
{
|
||||
InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
||||
if (KernelMode != Irp->RequestorMode)
|
||||
@ -796,13 +819,36 @@ NTSTATUS FspVolumeTransact(
|
||||
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (0 != OutputBufferLength &&
|
||||
((FSP_FSCTL_TRANSACT == ControlCode &&
|
||||
((FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT) == ControlFunction &&
|
||||
FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) ||
|
||||
(FSP_FSCTL_TRANSACT_BATCH == ControlCode &&
|
||||
(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_BATCH) == ControlFunction &&
|
||||
FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength)))
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
return FspVolumeFastTransact(
|
||||
FsvolDeviceObject,
|
||||
ControlCode,
|
||||
InputBuffer,
|
||||
InputBufferLength,
|
||||
OutputBuffer,
|
||||
OutputBufferLength,
|
||||
&Irp->IoStatus,
|
||||
Irp);
|
||||
}
|
||||
|
||||
NTSTATUS FspVolumeFastTransact(
|
||||
PDEVICE_OBJECT FsvolDeviceObject,
|
||||
ULONG ControlCode,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength,
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (!FspDeviceReference(FsvolDeviceObject))
|
||||
return STATUS_CANCELLED;
|
||||
|
||||
@ -813,6 +859,7 @@ NTSTATUS FspVolumeTransact(
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
ULONG ControlFunction = FSP_FUNCTION_FROM_CTL_CODE(ControlCode);
|
||||
PUINT8 BufferEnd;
|
||||
FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest;
|
||||
@ -882,6 +929,8 @@ NTSTATUS FspVolumeTransact(
|
||||
}
|
||||
}
|
||||
|
||||
if ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG < Irp)
|
||||
{
|
||||
/* were we sent an output buffer? */
|
||||
switch (ControlCode & 3)
|
||||
{
|
||||
@ -900,9 +949,10 @@ NTSTATUS FspVolumeTransact(
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (0 == OutputBuffer)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoStatus->Information = 0;
|
||||
Result = STATUS_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
@ -923,7 +973,7 @@ NTSTATUS FspVolumeTransact(
|
||||
}
|
||||
if (FspIoqTimeout == PendingIrp || FspIoqCancelled == PendingIrp)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoStatus->Information = 0;
|
||||
Result = FspIoqTimeout == PendingIrp ? STATUS_SUCCESS : STATUS_CANCELLED;
|
||||
goto exit;
|
||||
}
|
||||
@ -932,7 +982,7 @@ NTSTATUS FspVolumeTransact(
|
||||
RepostedIrp = 0;
|
||||
Request = OutputBuffer;
|
||||
BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength;
|
||||
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ?
|
||||
ASSERT(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction ?
|
||||
TRUE :
|
||||
FspFsctlTransactCanProduceRequest(Request, BufferEnd));
|
||||
LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq);
|
||||
@ -955,7 +1005,7 @@ NTSTATUS FspVolumeTransact(
|
||||
FspIopCompleteIrp(PendingIrp, Result);
|
||||
else
|
||||
{
|
||||
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
|
||||
if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction)
|
||||
{
|
||||
InternalBuffer = FspAllocatePoolMustSucceed(
|
||||
PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG);
|
||||
@ -979,7 +1029,7 @@ NTSTATUS FspVolumeTransact(
|
||||
ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
|
||||
if (0 != InternalBuffer)
|
||||
{
|
||||
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode);
|
||||
ASSERT(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction);
|
||||
*(PVOID *)OutputBuffer = 0;
|
||||
FspFree(InternalBuffer);
|
||||
}
|
||||
@ -989,14 +1039,14 @@ NTSTATUS FspVolumeTransact(
|
||||
}
|
||||
|
||||
/* are we doing single request or batch mode? */
|
||||
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
|
||||
if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction)
|
||||
{
|
||||
Irp->IoStatus.Information = sizeof(PVOID);
|
||||
IoStatus->Information = sizeof(PVOID);
|
||||
Result = STATUS_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
if (FSP_FSCTL_TRANSACT == ControlCode)
|
||||
if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT) == ControlFunction)
|
||||
break;
|
||||
|
||||
/* check that we have enough space before pulling the next pending IRP off the queue */
|
||||
@ -1013,7 +1063,7 @@ NTSTATUS FspVolumeTransact(
|
||||
break;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)OutputBuffer;
|
||||
IoStatus->Information = (PUINT8)Request - (PUINT8)OutputBuffer;
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
|
125
src/sys/write.c
125
src/sys/write.c
@ -21,6 +21,7 @@
|
||||
|
||||
#include <sys/driver.h>
|
||||
|
||||
FAST_IO_WRITE FspFastIoWrite;
|
||||
static NTSTATUS FspFsvolWrite(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspFsvolWriteCached(
|
||||
@ -36,6 +37,7 @@ static FSP_IOP_REQUEST_FINI FspFsvolWriteNonCachedRequestFini;
|
||||
FSP_DRIVER_DISPATCH FspWrite;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspFastIoWrite)
|
||||
#pragma alloc_text(PAGE, FspFsvolWrite)
|
||||
#pragma alloc_text(PAGE, FspFsvolWriteCached)
|
||||
#pragma alloc_text(PAGE, FspFsvolWriteNonCached)
|
||||
@ -56,6 +58,129 @@ enum
|
||||
};
|
||||
FSP_FSCTL_STATIC_ASSERT(RequestCookie == RequestSafeMdl, "");
|
||||
|
||||
BOOLEAN FspFastIoWrite(
|
||||
PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER ByteOffset,
|
||||
ULONG Length,
|
||||
BOOLEAN CanWait,
|
||||
ULONG Key,
|
||||
PVOID UserBuffer,
|
||||
PIO_STATUS_BLOCK IoStatus,
|
||||
PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
FSP_ENTER_FIO(PAGED_CODE());
|
||||
|
||||
IoStatus->Status = STATUS_SUCCESS;
|
||||
IoStatus->Information = 0;
|
||||
|
||||
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||
{
|
||||
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
FSP_RETURN(Result = TRUE);
|
||||
}
|
||||
|
||||
FSP_FILE_NODE* FileNode = FileObject->FsContext;
|
||||
LARGE_INTEGER WriteOffset = *ByteOffset;
|
||||
ULONG WriteLength = Length;
|
||||
BOOLEAN WriteToEndOfFile =
|
||||
FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
UINT64 WriteEndOffset;
|
||||
BOOLEAN ExtendingFile;
|
||||
|
||||
/* only regular files can be written */
|
||||
if (FileNode->IsDirectory)
|
||||
{
|
||||
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
||||
FSP_RETURN(Result = TRUE);
|
||||
}
|
||||
|
||||
/* do we have anything to write? */
|
||||
if (0 == WriteLength)
|
||||
FSP_RETURN(Result = TRUE);
|
||||
|
||||
/* WinFsp cannot do Fast I/O when extending file */
|
||||
if (WriteToEndOfFile)
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
/* does the file support caching? is it write-through? */
|
||||
if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) ||
|
||||
FlagOn(FileObject->Flags, FO_WRITE_THROUGH))
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
/* can we write without flushing? */
|
||||
Result = DEBUGTEST(90) &&
|
||||
CcCanIWrite(FileObject, WriteLength, CanWait, FALSE) &&
|
||||
CcCopyWriteWontFlush(FileObject, &WriteOffset, WriteLength);
|
||||
if (!Result)
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
/* try to acquire the FileNode Main exclusive */
|
||||
Result = DEBUGTEST(90) &&
|
||||
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireMain, CanWait);
|
||||
if (!Result)
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
/* is the file actually cached? */
|
||||
if (0 == FileObject->PrivateCacheMap)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = FALSE);
|
||||
}
|
||||
|
||||
/* does the file have oplocks or file locks? */
|
||||
Result =
|
||||
FsRtlOplockIsFastIoPossible(FspFileNodeAddrOfOplock(FileNode)) &&
|
||||
!FsRtlAreThereCurrentFileLocks(&FileNode->FileLock);
|
||||
if (!Result)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = FALSE);
|
||||
}
|
||||
|
||||
/* compute new file size */
|
||||
ASSERT(FspTimeoutInfinity32 ==
|
||||
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
|
||||
FspFileNodeGetFileInfo(FileNode, &FileInfo);
|
||||
if (WriteToEndOfFile)
|
||||
WriteOffset.QuadPart = FileInfo.FileSize;
|
||||
WriteEndOffset = WriteOffset.QuadPart + WriteLength;
|
||||
ExtendingFile = FileInfo.FileSize < WriteEndOffset;
|
||||
|
||||
/* WinFsp cannot do Fast I/O when extending file */
|
||||
if (ExtendingFile)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = FALSE);
|
||||
}
|
||||
|
||||
NTSTATUS Result0 =
|
||||
FspCcCopyWrite(FileObject, &WriteOffset, WriteLength, CanWait, UserBuffer);
|
||||
if (!NT_SUCCESS(Result0))
|
||||
{
|
||||
IoStatus->Status = Result0;
|
||||
IoStatus->Information = 0;
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FSP_RETURN(Result = FALSE);
|
||||
}
|
||||
Result = STATUS_SUCCESS == Result0;
|
||||
|
||||
if (Result)
|
||||
{
|
||||
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||
FileObject->CurrentByteOffset.QuadPart = WriteEndOffset;
|
||||
IoStatus->Information = WriteLength;
|
||||
}
|
||||
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
|
||||
FSP_LEAVE_FIO(
|
||||
"FileObject=%p, UserBuffer=%p, CanWait=%d, "
|
||||
"Key=%#lx, ByteOffset=%#lx:%#lx, Length=%ld",
|
||||
FileObject, UserBuffer, CanWait,
|
||||
Key, ByteOffset->HighPart, ByteOffset->LowPart, Length);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolWrite(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
|
@ -1,128 +0,0 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
call "%~dp0myinfo.bat"
|
||||
|
||||
set MsiName="%MyProductName% - %MyDescription%"
|
||||
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
|
||||
set Issuer="DigiCert"
|
||||
set Subject="%MyCompanyName%"
|
||||
|
||||
set Configuration=Release
|
||||
set SignedPackage=
|
||||
|
||||
if not X%1==X set Configuration=%1
|
||||
if not X%2==X set SignedPackage=%2
|
||||
|
||||
echo Configuration=%Configuration%
|
||||
echo:
|
||||
|
||||
if X%~nx0==Xbuild-choco.bat (
|
||||
cd %~dp0..\build\VStudio
|
||||
goto :choco
|
||||
)
|
||||
|
||||
call "%~dp0vcvarsall.bat" x64
|
||||
|
||||
if not X%SignedPackage%==X (
|
||||
if not exist "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi" (echo previous build not found >&2 & exit /b 1)
|
||||
if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
|
||||
del "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi"
|
||||
if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg"
|
||||
for /R "%SignedPackage%" %%f in (*.sys) do (
|
||||
copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
|
||||
)
|
||||
)
|
||||
|
||||
cd %~dp0..\build\VStudio
|
||||
set signfail=0
|
||||
|
||||
if X%SignedPackage%==X (
|
||||
if exist build\ for /R build\ %%d in (%Configuration%) do (
|
||||
if exist "%%d" rmdir /s/q "%%d"
|
||||
)
|
||||
|
||||
devenv winfsp.sln /build "%Configuration%|x64"
|
||||
if errorlevel 1 goto fail
|
||||
devenv winfsp.sln /build "%Configuration%|x86"
|
||||
if errorlevel 1 goto fail
|
||||
|
||||
for %%f in (build\%Configuration%\%MyProductFileName%-x64.sys build\%Configuration%\%MyProductFileName%-x86.sys) do (
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
|
||||
pushd build\%Configuration%
|
||||
echo .OPTION EXPLICIT >driver.ddf
|
||||
echo .Set CabinetFileCountThreshold=0 >>driver.ddf
|
||||
echo .Set FolderFileCountThreshold=0 >>driver.ddf
|
||||
echo .Set FolderSizeThreshold=0 >>driver.ddf
|
||||
echo .Set MaxCabinetSize=0 >>driver.ddf
|
||||
echo .Set MaxDiskFileCount=0 >>driver.ddf
|
||||
echo .Set MaxDiskSize=0 >>driver.ddf
|
||||
echo .Set CompressionType=MSZIP >>driver.ddf
|
||||
echo .Set Cabinet=on >>driver.ddf
|
||||
echo .Set Compress=on >>driver.ddf
|
||||
echo .Set CabinetNameTemplate=driver.cab >>driver.ddf
|
||||
echo .Set DiskDirectory1=. >>driver.ddf
|
||||
echo .Set DestinationDir=x64 >>driver.ddf
|
||||
echo driver-x64.inf >>driver.ddf
|
||||
echo %MyProductFileName%-x64.sys >>driver.ddf
|
||||
echo .Set DestinationDir=x86 >>driver.ddf
|
||||
echo driver-x86.inf >>driver.ddf
|
||||
echo %MyProductFileName%-x86.sys >>driver.ddf
|
||||
makecab /F driver.ddf
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /t http://timestamp.digicert.com driver.cab
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
popd
|
||||
)
|
||||
|
||||
devenv winfsp.sln /build "Installer.%Configuration%|x86"
|
||||
if errorlevel 1 goto fail
|
||||
|
||||
for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do (
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com /d %MsiName% %%f
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
REM signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
|
||||
REM if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
|
||||
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
|
||||
|
||||
set Version=
|
||||
for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do set Version=%%~nf
|
||||
set Version=!Version:%MyProductFileName%-=!
|
||||
if X%SignedPackage%==X (
|
||||
pushd build\%Configuration%
|
||||
powershell -command "Compress-Archive -Path winfsp-tests-*.exe,..\..\..\..\License.txt,..\..\..\..\tst\winfsp-tests\README.md -DestinationPath winfsp-tests-!Version!.zip"
|
||||
if errorlevel 1 goto fail
|
||||
popd
|
||||
)
|
||||
|
||||
:choco
|
||||
if not exist "build\%Configuration%\%MyProductFileName%-*.msi" (echo installer msi not found >&2 & exit /b 1)
|
||||
if not X!MyProductName!==XWinFsp (echo skipping choco build for !MyProductName! >&2 & exit /b 0)
|
||||
set Version=
|
||||
for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do set Version=%%~nf
|
||||
set Version=!Version:%MyProductFileName%-=!
|
||||
set PackageVersion=!Version!
|
||||
if not X!MyProductStage!==XGold (
|
||||
set PackageVersion=!Version!-pre
|
||||
)
|
||||
where /q choco.exe
|
||||
if %ERRORLEVEL% equ 0 (
|
||||
copy ..\choco\* build\%Configuration%
|
||||
copy ..\choco\LICENSE.TXT /B + ..\..\License.txt /B build\%Configuration%\LICENSE.txt /B
|
||||
certutil -hashfile build\%Configuration%\%MyProductFileName%-!Version!.msi SHA256 >>build\%Configuration%\VERIFICATION.txt
|
||||
choco pack build\%Configuration%\winfsp.nuspec --version=!PackageVersion! --outputdirectory=build\%Configuration% MsiVersion=!Version!
|
||||
if errorlevel 1 goto fail
|
||||
)
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
1
tools/build-choco.bat
Symbolic link
1
tools/build-choco.bat
Symbolic link
@ -0,0 +1 @@
|
||||
build.bat
|
@ -6,8 +6,8 @@ setlocal EnableDelayedExpansion
|
||||
call "%~dp0myinfo.bat"
|
||||
|
||||
set MsiName="%MyProductName% - %MyDescription%"
|
||||
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
|
||||
set Issuer="DigiCert"
|
||||
set CrossCert="%~dp0%MyCrossCert%"
|
||||
set Issuer="%MyCertIssuer%"
|
||||
set Subject="%MyCompanyName%"
|
||||
|
||||
set Configuration=Release
|
||||
@ -70,12 +70,19 @@ if X%SignedPackage%==X (
|
||||
if errorlevel 1 goto fail
|
||||
)
|
||||
|
||||
for %%f in (build\%Configuration%\%MyProductFileName%-a64.sys build\%Configuration%\%MyProductFileName%-x64.sys build\%Configuration%\%MyProductFileName%-x86.sys) do (
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com %%f
|
||||
pushd build\%Configuration%
|
||||
set signfiles=^
|
||||
%MyProductFileName%-a64.sys %MyProductFileName%-x64.sys %MyProductFileName%-x86.sys^
|
||||
%MyProductFileName%-a64.dll %MyProductFileName%-x64.dll %MyProductFileName%-x86.dll %MyProductFileName%-msil.dll^
|
||||
launcher-a64.exe launcher-x64.exe launcher-x86.exe^
|
||||
launchctl-a64.exe launchctl-x64.exe launchctl-x86.exe^
|
||||
fsptool-a64.exe fsptool-x64.exe fsptool-x86.exe^
|
||||
memfs-a64.exe memfs-x64.exe memfs-x86.exe memfs-dotnet-msil.exe
|
||||
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com !signfiles!
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 %%f
|
||||
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 !signfiles!
|
||||
if errorlevel 1 set /a signfail=signfail+1
|
||||
)
|
||||
popd
|
||||
|
||||
pushd build\%Configuration%
|
||||
echo .OPTION EXPLICIT >driver.ddf
|
||||
|
@ -1,7 +1,7 @@
|
||||
@echo off
|
||||
|
||||
REM This script is used to fix GitHub issue #162:
|
||||
REM https://github.com/billziss-gh/winfsp/issues/162
|
||||
REM https://github.com/winfsp/winfsp/issues/162
|
||||
REM
|
||||
REM It works as follows:
|
||||
REM
|
||||
|
@ -14,6 +14,10 @@ for /F "tokens=2,3,4 delims=<>" %%a in (%~dp0..\build\VStudio\build.version.prop
|
||||
set MyProductVersion=%%b
|
||||
) else if "%%a"=="MyProductStage" (
|
||||
set MyProductStage=%%b
|
||||
) else if "%%a"=="MyCrossCert" (
|
||||
set MyCrossCert=%%b
|
||||
) else if "%%a"=="MyCertIssuer" (
|
||||
set MyCertIssuer=%%b
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -24,3 +28,5 @@ echo MyDescription=%MyDescription%
|
||||
echo MyCompanyName=%MyCompanyName%
|
||||
echo MyProductVersion=%MyProductVersion%
|
||||
echo MyProductStage=%MyProductStage%
|
||||
echo MyCrossCert=%MyCrossCert%
|
||||
echo MyCertIssuer=%MyCertIssuer%
|
||||
|
63
tools/run-all-perf-tests.bat
Normal file
63
tools/run-all-perf-tests.bat
Normal file
@ -0,0 +1,63 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
REM see https://stackoverflow.com/a/11995662
|
||||
net session >nul 2>&1
|
||||
if !ERRORLEVEL! neq 0 echo must be run as Administrator >&2 & goto fail
|
||||
|
||||
set Count=3
|
||||
if not X%1==X set Count=%1
|
||||
|
||||
set outdir=%cd%
|
||||
pushd %~dp0..
|
||||
set ProjRoot=%cd%
|
||||
popd
|
||||
|
||||
set perftests="%ProjRoot%\tools\run-perf-tests.bat"
|
||||
set memfs="%ProjRoot%\build\VStudio\build\Release\memfs-x64.exe"
|
||||
set ntptfs="%ProjRoot%\tst\ntptfs\build\Release\ntptfs-x64.exe"
|
||||
if not exist %memfs% echo cannot find memfs >&2 & goto fail
|
||||
if not exist %ntptfs% echo cannot find ntptfs >&2 & goto fail
|
||||
|
||||
mkdir C:\t
|
||||
pushd C:\t
|
||||
for /l %%i in (1,1,%Count%) do (
|
||||
echo ntfs-%%i
|
||||
call %perftests% Release > %outdir%\ntfs-%%i.csv
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
popd
|
||||
rmdir C:\t
|
||||
|
||||
start "" /b %memfs% -t -1 -n 1000000 -i -m X:
|
||||
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
|
||||
pushd X:\
|
||||
for /l %%i in (1,1,%Count%) do (
|
||||
echo memfs-%%i
|
||||
call %perftests% Release > %outdir%\memfs-%%i.csv
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
popd
|
||||
taskkill /f /im memfs-x64.exe
|
||||
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Add-MpPreference -ExclusionProcess '%ntptfs%'"
|
||||
mkdir C:\t
|
||||
start "" /b %ntptfs% -t -1 -p C:\t -m X:
|
||||
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
|
||||
pushd X:\
|
||||
for /l %%i in (1,1,%Count%) do (
|
||||
echo ntptfs-%%i
|
||||
call %perftests% Release > %outdir%\ntptfs-%%i.csv
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
popd
|
||||
taskkill /f /im ntptfs-x64.exe
|
||||
rmdir C:\t
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Remove-MpPreference -ExclusionProcess '%ntptfs%'"
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
@ -30,25 +30,25 @@ pushd fsbench
|
||||
set OptFiles=1000 2000 3000 4000 5000
|
||||
if X%2==Xbaseline set OptFiles=10000
|
||||
for %%a in (%OptFiles%) do (
|
||||
call :csv %%a "%fsbench% --files=%%a file_*"
|
||||
call :csv %%a "%fsbench% --empty-cache --files=%%a file_*"
|
||||
)
|
||||
|
||||
set OptRdwrCc=100 200 300 400 500
|
||||
if X%2==Xbaseline set OptRdwrCc=1000
|
||||
for %%a in (%OptRdwrCc%) do (
|
||||
call :csv %%a "%fsbench% --rdwr-cc=%%a rdwr_cc_*"
|
||||
call :csv %%a "%fsbench% --empty-cache --rdwr-cc=%%a rdwr_cc_*"
|
||||
)
|
||||
|
||||
set OptRdwrNc=100 200 300 400 500
|
||||
if X%2==Xbaseline set OptRdwrNc=100
|
||||
for %%a in (%OptRdwrNc%) do (
|
||||
call :csv %%a "%fsbench% --rdwr-nc=%%a rdwr_nc_*"
|
||||
call :csv %%a "%fsbench% --empty-cache --rdwr-nc=%%a rdwr_nc_*"
|
||||
)
|
||||
|
||||
set OptMmap=100 200 300 400 500
|
||||
if X%2==Xbaseline set OptMmap=1000
|
||||
for %%a in (%OptMmap%) do (
|
||||
call :csv %%a "%fsbench% --mmap=%%a mmap_*"
|
||||
call :csv %%a "%fsbench% --empty-cache --mmap=%%a mmap_*"
|
||||
)
|
||||
|
||||
popd
|
||||
|
@ -762,6 +762,9 @@ rem difference.
|
||||
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
|
||||
call :__ifstest %1 /g ReparsePoints -t SetPointEASNotSupportedTest -t EnumReparsePointsTest -t ChangeNotificationReparseTest /c
|
||||
if !ERRORLEVEL! neq 0 set IfsTestNtptfsExit=1
|
||||
) else if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
|
||||
call :__ifstest %1 /g ReparsePoints -t SetPointEASNotSupportedTest -t EnumReparsePointsTest -t ChangeNotificationReparseTest -t SetPointIoReparseDataInvalidTest -t SetPointIoReparseTagMismatchTest -t SetPointAttributeConflictTest /c
|
||||
if !ERRORLEVEL! neq 0 set IfsTestNtptfsExit=1
|
||||
) else (
|
||||
call :__ifstest %1 /g ReparsePoints -t SetPointEASNotSupportedTest -t EnumReparsePointsTest -t ChangeNotificationReparseTest -t SetPointIoReparseDataInvalidTest /c
|
||||
if !ERRORLEVEL! neq 0 set IfsTestNtptfsExit=1
|
||||
@ -845,17 +848,45 @@ if not X!IfsTestFound!==XYES set IfsTestExit=1
|
||||
exit /b !IfsTestExit!
|
||||
|
||||
:sample-ntptfs-x64
|
||||
call :__run_sample_ntptfs_test ntptfs x64 ntptfs-x64 ^
|
||||
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
|
||||
rem need POSIX delete for rename_mmap_test
|
||||
call :__run_sample_ntptfs_test ntptfs x64 ntptfs-x64 ^
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" ^
|
||||
"--external --resilient +* -rename_flipflop_test -rename_mmap_test -exec_rename_dir_test -stream_rename_flipflop_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
) else if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
|
||||
rem need POSIX delete for rename_mmap_test
|
||||
call :__run_sample_ntptfs_test ntptfs x64 ntptfs-x64 ^
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" ^
|
||||
"--external --resilient +* -rename_flipflop_test -rename_mmap_test -exec_rename_dir_test -stream_rename_flipflop_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
) else (
|
||||
call :__run_sample_ntptfs_test ntptfs x64 ntptfs-x64 ^
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" ^
|
||||
"--external --resilient +* -rename_flipflop_test -exec_rename_dir_test -stream_rename_flipflop_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
:sample-ntptfs-x86
|
||||
call :__run_sample_ntptfs_test ntptfs x86 ntptfs-x86 ^
|
||||
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
|
||||
rem need POSIX delete for rename_mmap_test
|
||||
call :__run_sample_ntptfs_test ntptfs x86 ntptfs-x86 ^
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" ^
|
||||
"--external --resilient +* -rename_flipflop_test -rename_mmap_test -exec_rename_dir_test -stream_rename_flipflop_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
) else if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
|
||||
rem need POSIX delete for rename_mmap_test
|
||||
call :__run_sample_ntptfs_test ntptfs x86 ntptfs-x86 ^
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" ^
|
||||
"--external --resilient +* -rename_flipflop_test -rename_mmap_test -exec_rename_dir_test -stream_rename_flipflop_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
) else (
|
||||
call :__run_sample_ntptfs_test ntptfs x86 ntptfs-x86 ^
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" ^
|
||||
"--external --resilient +* -rename_flipflop_test -exec_rename_dir_test -stream_rename_flipflop_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
:sample-ntptfs-x64-fsx
|
||||
|
@ -1,16 +1,24 @@
|
||||
@echo off
|
||||
|
||||
set vcvarsall="%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
|
||||
set vcvarsall=""
|
||||
|
||||
set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
if exist %vswhere% (
|
||||
for /f "usebackq tokens=*" %%i in (`%vswhere% -latest -find VC\**\vcvarsall.bat`) do (
|
||||
if exist "%%i" (
|
||||
for /f "usebackq tokens=*" %%i in (`%vswhere% -version [15.0^,17.0^) -find VC\**\vcvarsall.bat`) do (
|
||||
set vcvarsall="%%i"
|
||||
) else (
|
||||
for /f "usebackq tokens=*" %%i in (`%vswhere% -latest -property installationPath`) do (
|
||||
)
|
||||
)
|
||||
|
||||
if not exist %vcvarsall% (
|
||||
if exist %vswhere% (
|
||||
for /f "usebackq tokens=*" %%i in (`%vswhere% -version [15.0^,17.0^) -property installationPath`) do (
|
||||
set vcvarsall="%%i\VC\Auxiliary\Build\vcvarsall.bat"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if not exist %vcvarsall% (
|
||||
set vcvarsall="%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat"
|
||||
)
|
||||
|
||||
call %vcvarsall% %*
|
||||
|
60
tools/winfsp-winpe.bat
Normal file
60
tools/winfsp-winpe.bat
Normal file
@ -0,0 +1,60 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
if NOT [%1]==[] set Arch=%1
|
||||
if NOT [%2]==[] set Mount=%2
|
||||
if NOT [%3]==[] set Image=%3
|
||||
if [!Mount!]==[] (echo usage: winfsp-winpe Arch Mount [Image] >&2 & goto fail)
|
||||
|
||||
set SkipDism=0
|
||||
if [!Image!]==[] set SkipDism=1
|
||||
|
||||
set RegKey="HKLM\SOFTWARE\WinFsp"
|
||||
set RegVal="InstallDir"
|
||||
reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1
|
||||
if !ERRORLEVEL! equ 0 (
|
||||
for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do (
|
||||
set InstallDir=%%j
|
||||
)
|
||||
)
|
||||
if not exist "!InstallDir!" (echo cannot find WinFsp installation >&2 & goto fail)
|
||||
|
||||
if not exist !Mount! (echo cannot find mount directory !Mount! >&2 & goto fail)
|
||||
if !SkipDism! equ 0 (
|
||||
if not exist !Image! (echo cannot find image file !Image! >&2 & goto fail)
|
||||
)
|
||||
|
||||
if !SkipDism! equ 0 (
|
||||
echo Dism /Mount-Image /ImageFile:!Image! /Index:1 /MountDir:!Mount!
|
||||
Dism /Mount-Image /ImageFile:!Image! /Index:1 /MountDir:!Mount!
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
|
||||
echo copy "!InstallDir!"\bin\winfsp-!Arch!.dll !Mount!\Windows\System32
|
||||
copy "!InstallDir!"\bin\winfsp-!Arch!.dll !Mount!\Windows\System32 >nul
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
|
||||
echo copy "!InstallDir!"\bin\winfsp-!Arch!.sys !Mount!\Windows\System32
|
||||
copy "!InstallDir!"\bin\winfsp-!Arch!.sys !Mount!\Windows\System32 >nul
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
|
||||
rem echo copy "!InstallDir!"\bin\memfs-!Arch!.exe !Mount!\Windows\System32
|
||||
rem copy "!InstallDir!"\bin\memfs-!Arch!.exe !Mount!\Windows\System32 >nul
|
||||
rem if !ERRORLEVEL! neq 0 goto fail
|
||||
|
||||
echo Creating !Mount!\Windows\System32\startnet.cmd
|
||||
echo regsvr32 /s winfsp-x64.dll > !Mount!\Windows\System32\startnet.cmd
|
||||
echo wpeinit >> !Mount!\Windows\System32\startnet.cmd
|
||||
|
||||
if !SkipDism! equ 0 (
|
||||
echo Dism /Unmount-Image /MountDir:!Mount! /Commit
|
||||
Dism /Unmount-Image /MountDir:!Mount! /Commit
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
)
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
38
tools/wpr-test.bat
Normal file
38
tools/wpr-test.bat
Normal file
@ -0,0 +1,38 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
if not X%1==X set File=%1
|
||||
if X%File%==X (echo usage: wpr-test file.etl fsbench-args... >&2 & goto fail)
|
||||
|
||||
REM see https://stackoverflow.com/a/45969239/429091
|
||||
set Args=%*
|
||||
call set Args=%%args:*%1=%%
|
||||
|
||||
REM see https://stackoverflow.com/a/11995662
|
||||
net session >nul 2>&1
|
||||
if %ERRORLEVEL% neq 0 echo must be run as Administrator >&2 & goto fail
|
||||
|
||||
set outdir=%cd%
|
||||
pushd %~dp0..
|
||||
set ProjRoot=%cd%
|
||||
popd
|
||||
|
||||
set fsbench="%ProjRoot%\build\VStudio\build\Release\fsbench-x64.exe"
|
||||
if not exist %fsbench% echo cannot find fsbench >&2 & goto fail
|
||||
|
||||
wpr -start CPU -start FileIO
|
||||
|
||||
mkdir fsbench
|
||||
pushd fsbench
|
||||
%fsbench% %Args%
|
||||
popd
|
||||
rmdir fsbench
|
||||
|
||||
wpr -stop %File% %File% -skipPdbGen
|
||||
|
||||
exit /b 0
|
||||
|
||||
:fail
|
||||
exit /b 1
|
@ -23,6 +23,7 @@
|
||||
#include <strsafe.h>
|
||||
#include <tlib/testsuite.h>
|
||||
|
||||
static BOOLEAN OptEmptyCache = FALSE;
|
||||
static ULONG OptFileCount = 1000;
|
||||
static ULONG OptListCount = 100;
|
||||
static ULONG OptRdwrFileSize = 4096 * 1024;
|
||||
@ -398,6 +399,64 @@ static void mmap_tests(void)
|
||||
TEST(mmap_read_test);
|
||||
}
|
||||
|
||||
static void EmptyCache(const char *name, void (*fn)(void), int v)
|
||||
{
|
||||
NTSYSCALLAPI NTSTATUS NTAPI
|
||||
NtSetSystemInformation(
|
||||
ULONG SystemInformationClass,
|
||||
PVOID SystemInformation,
|
||||
ULONG SystemInformationLength);
|
||||
|
||||
if (+1 == v) /* setup */
|
||||
{
|
||||
/* flush the file system cache (requires SE_INCREASE_QUOTA_NAME) */
|
||||
ASSERT(SetSystemFileCacheSize((SIZE_T)-1, (SIZE_T)-1, 0));
|
||||
|
||||
/* flush/purge the standby list (requires SE_PROF_SINGLE_PROCESS_NAME) */
|
||||
ULONG Command;
|
||||
Command = 3 /*MemoryFlushModifiedList*/;
|
||||
ASSERT(0 == NtSetSystemInformation(80 /*SystemMemoryListInformation*/, &Command, sizeof Command));
|
||||
Command = 4 /*MemoryPurgeStandbyList*/;
|
||||
ASSERT(0 == NtSetSystemInformation(80 /*SystemMemoryListInformation*/, &Command, sizeof Command));
|
||||
}
|
||||
else
|
||||
if (-1 == v) /* teardown */
|
||||
{
|
||||
}
|
||||
}
|
||||
static DWORD EnablePrivilegesForEmptyCache(VOID)
|
||||
{
|
||||
union
|
||||
{
|
||||
TOKEN_PRIVILEGES P;
|
||||
UINT8 B[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
|
||||
} Privileges;
|
||||
HANDLE Token;
|
||||
|
||||
Privileges.P.PrivilegeCount = 2;
|
||||
Privileges.P.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
Privileges.P.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!LookupPrivilegeValueW(0, SE_PROF_SINGLE_PROCESS_NAME, &Privileges.P.Privileges[0].Luid) ||
|
||||
!LookupPrivilegeValueW(0, SE_INCREASE_QUOTA_NAME, &Privileges.P.Privileges[1].Luid))
|
||||
return GetLastError();
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token))
|
||||
return GetLastError();
|
||||
|
||||
if (!AdjustTokenPrivileges(Token, FALSE, &Privileges.P, 0, 0, 0) ||
|
||||
ERROR_NOT_ALL_ASSIGNED == GetLastError())
|
||||
{
|
||||
CloseHandle(Token);
|
||||
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
CloseHandle(Token);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
#define rmarg(argv, argc, argi) \
|
||||
argc--, \
|
||||
memmove(argv + argi, argv + argi + 1, (argc - argi) * sizeof(char *)),\
|
||||
@ -414,7 +473,12 @@ int main(int argc, char *argv[])
|
||||
const char *a = argv[argi];
|
||||
if ('-' == a[0])
|
||||
{
|
||||
if (0 == strncmp("--files=", a, sizeof "--files=" - 1))
|
||||
if (0 == strcmp("--empty-cache", a))
|
||||
{
|
||||
OptEmptyCache = TRUE;
|
||||
rmarg(argv, argc, argi);
|
||||
}
|
||||
else if (0 == strncmp("--files=", a, sizeof "--files=" - 1))
|
||||
{
|
||||
OptFileCount = strtoul(a + sizeof "--files=" - 1, 0, 10);
|
||||
rmarg(argv, argc, argi);
|
||||
@ -442,6 +506,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (OptEmptyCache)
|
||||
{
|
||||
if (0 != EnablePrivilegesForEmptyCache())
|
||||
{
|
||||
tlib_printf("ABORT: cannot enable privileges required for empty cache\n");
|
||||
abort();
|
||||
}
|
||||
TESTHOOK(EmptyCache);
|
||||
}
|
||||
|
||||
tlib_run_tests(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
@ -282,6 +282,7 @@ namespace memfs
|
||||
Host.ReparsePointsAccessCheck = false;
|
||||
Host.NamedStreams = true;
|
||||
Host.PostCleanupWhenModifiedOnly = true;
|
||||
Host.PostDispositionWhenNecessaryOnly = true;
|
||||
Host.PassQueryDirectoryFileName = true;
|
||||
Host.ExtendedAttributes = true;
|
||||
Host.WslFeatures = true;
|
||||
|
@ -182,6 +182,51 @@ UINT64 MemfsGetSystemTime(VOID)
|
||||
return ((PLARGE_INTEGER)&FileTime)->QuadPart;
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned MemfsUpperChar(unsigned c)
|
||||
{
|
||||
/*
|
||||
* Bit-twiddling upper case char:
|
||||
*
|
||||
* - Let signbit(x) = x & 0x100 (treat bit 0x100 as "signbit").
|
||||
* - 'A' <= c && c <= 'Z' <=> s = signbit(c - 'A') ^ signbit(c - ('Z' + 1)) == 1
|
||||
* - c >= 'A' <=> c - 'A' >= 0 <=> signbit(c - 'A') = 0
|
||||
* - c <= 'Z' <=> c - ('Z' + 1) < 0 <=> signbit(c - ('Z' + 1)) = 1
|
||||
* - Bit 0x20 = 0x100 >> 3 toggles uppercase to lowercase and vice-versa.
|
||||
*
|
||||
* This is actually faster than `(c - 'a' <= 'z' - 'a') ? (c & ~0x20) : c`, even
|
||||
* when compiled using cmov conditional moves at least on this system (i7-1065G7).
|
||||
*
|
||||
* See https://godbolt.org/z/ebv131Wrh
|
||||
*/
|
||||
unsigned s = ((c - 'a') ^ (c - ('z' + 1))) & 0x100;
|
||||
return c & ~(s >> 3);
|
||||
}
|
||||
|
||||
static inline
|
||||
int MemfsWcsnicmp(const wchar_t *s0, const wchar_t *t0, int n)
|
||||
{
|
||||
/* Use fast loop for ASCII and fall back to CompareStringW for general case. */
|
||||
const wchar_t *s = s0;
|
||||
const wchar_t *t = t0;
|
||||
int v = 0;
|
||||
for (const void *e = t + n; e > (const void *)t; ++s, ++t)
|
||||
{
|
||||
unsigned sc = *s, tc = *t;
|
||||
if (0xffffff80 & (sc | tc))
|
||||
{
|
||||
v = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, s0, n, t0, n);
|
||||
if (0 != v)
|
||||
return v - 2;
|
||||
else
|
||||
return _wcsnicmp(s, t, n);
|
||||
}
|
||||
if (0 != (v = MemfsUpperChar(sc) - MemfsUpperChar(tc)) || !tc)
|
||||
break;
|
||||
}
|
||||
return v;/*(0 < v) - (0 > v);*/
|
||||
}
|
||||
|
||||
static inline
|
||||
int MemfsFileNameCompare(PWSTR a, int alen, PWSTR b, int blen, BOOLEAN CaseInsensitive)
|
||||
{
|
||||
@ -226,13 +271,7 @@ int MemfsFileNameCompare(PWSTR a, int alen, PWSTR b, int blen, BOOLEAN CaseInsen
|
||||
len = plen < qlen ? plen : qlen;
|
||||
|
||||
if (CaseInsensitive)
|
||||
{
|
||||
res = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, partp, plen, partq, qlen);
|
||||
if (0 != res)
|
||||
res -= 2;
|
||||
else
|
||||
res = _wcsnicmp(partp, partq, len);
|
||||
}
|
||||
res = MemfsWcsnicmp(partp, partq, len);
|
||||
else
|
||||
res = wcsncmp(partp, partq, len);
|
||||
|
||||
@ -2386,6 +2425,7 @@ NTSTATUS MemfsCreateFunnel(
|
||||
VolumeParams.NamedStreams = 1;
|
||||
#endif
|
||||
VolumeParams.PostCleanupWhenModifiedOnly = 1;
|
||||
VolumeParams.PostDispositionWhenNecessaryOnly = 1;
|
||||
#if defined(MEMFS_DIRINFO_BY_NAME)
|
||||
VolumeParams.PassQueryDirectoryFileName = 1;
|
||||
#endif
|
||||
|
@ -24,12 +24,14 @@
|
||||
#define FileSystemContext ((PTFS *)(FileSystem)->UserContext)
|
||||
#define FileContextHandle (((FILE_CONTEXT *)(FileContext))->Handle)
|
||||
#define FileContextIsDirectory (((FILE_CONTEXT *)(FileContext))->IsDirectory)
|
||||
#define FileContextDirFileSize (((FILE_CONTEXT *)(FileContext))->DirFileSize)
|
||||
#define FileContextDirBuffer (&((FILE_CONTEXT *)(FileContext))->DirBuffer)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE Handle;
|
||||
BOOLEAN IsDirectory;
|
||||
ULONG DirFileSize;
|
||||
PVOID DirBuffer;
|
||||
} FILE_CONTEXT;
|
||||
|
||||
@ -241,6 +243,7 @@ static NTSTATUS CreateEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
memset(FileContext, 0, sizeof *FileContext);
|
||||
FileContext->Handle = Handle;
|
||||
FileContext->IsDirectory = IsDirectory;
|
||||
FileContext->DirFileSize = (ULONG)FileInfo->FileSize;
|
||||
*PFileContext = FileContext;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
@ -331,6 +334,7 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
memset(FileContext, 0, sizeof *FileContext);
|
||||
FileContext->Handle = Handle;
|
||||
FileContext->IsDirectory = IsDirectory;
|
||||
FileContext->DirFileSize = (ULONG)FileInfo->FileSize;
|
||||
*PFileContext = FileContext;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
@ -787,6 +791,18 @@ static NTSTATUS BufferedReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
PTFS *Ptfs = FileSystemContext;
|
||||
HANDLE Handle = FileContextHandle;
|
||||
ULONG CapacityHint = FileContextDirFileSize;
|
||||
/*
|
||||
* An analysis of the relationship between the required buffer capacity and the
|
||||
* NTFS directory size (as reported by FileStandardInformation) showed the ratio
|
||||
* between the two to be between 0.5 and 1 with some outliers outside those bounds.
|
||||
* (For this analysis file names of average length of 4 or 24 were used and NTFS
|
||||
* had 8.3 file names disabled.)
|
||||
*
|
||||
* We use the NTFS directory size as our capacity hint (i.e. ratio of 1), which
|
||||
* means that we may overestimate the required buffer capacity in most cases.
|
||||
* This is ok since our goal is to improve performance.
|
||||
*/
|
||||
PVOID PDirBuffer = FileContextDirBuffer;
|
||||
BOOLEAN RestartScan;
|
||||
ULONG BytesTransferred;
|
||||
@ -801,7 +817,7 @@ static NTSTATUS BufferedReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS Result, DirBufferResult;
|
||||
|
||||
DirBufferResult = STATUS_SUCCESS;
|
||||
if (FspFileSystemAcquireDirectoryBuffer(PDirBuffer, 0 == Marker, &DirBufferResult))
|
||||
if (FspFileSystemAcquireDirectoryBufferEx(PDirBuffer, 0 == Marker, CapacityHint, &DirBufferResult))
|
||||
{
|
||||
for (RestartScan = TRUE;; RestartScan = FALSE)
|
||||
{
|
||||
@ -1263,6 +1279,7 @@ NTSTATUS PtfsCreate(
|
||||
/*FILE_SUPPORTS_POSIX_UNLINK_RENAME*/);
|
||||
VolumeParams.ReadOnlyVolume = !!(FsAttrInfo.V.FileSystemAttributes & FILE_READ_ONLY_VOLUME);
|
||||
VolumeParams.PostCleanupWhenModifiedOnly = 1;
|
||||
VolumeParams.PostDispositionWhenNecessaryOnly = 1;
|
||||
VolumeParams.PassQueryDirectoryPattern = 1;
|
||||
VolumeParams.FlushAndPurgeOnCleanup = !!(FsAttributeMask & PtfsFlushAndPurgeOnCleanup);
|
||||
VolumeParams.WslFeatures = !!(FsAttributeMask & PtfsWslFeatures);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
@ -59,6 +60,7 @@
|
||||
typedef struct
|
||||
{
|
||||
const char *rootdir;
|
||||
size_t rootlen;
|
||||
} PTFS;
|
||||
|
||||
static int ptfs_getattr(const char *path, struct fuse_stat *stbuf)
|
||||
@ -293,6 +295,43 @@ static int ptfs_utimens(const char *path, const struct fuse_timespec tv[2])
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
static int ptfs_getpath(const char *path, char *buf, size_t size,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
if (0 == fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
if (-1 == getpath(path, buf, size))
|
||||
return errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
if (-1 == fgetpath(fd, buf, size))
|
||||
return errno;
|
||||
}
|
||||
|
||||
PTFS *ptfs = fuse_get_context()->private_data;
|
||||
size = strlen(buf);
|
||||
if (size > ptfs->rootlen)
|
||||
{
|
||||
size -= ptfs->rootlen;
|
||||
memmove(buf, buf + ptfs->rootlen, size);
|
||||
buf[size] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = '/';
|
||||
buf[1] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
static int ptfs_setcrtime(const char *path, const struct fuse_timespec *tv)
|
||||
{
|
||||
@ -344,6 +383,9 @@ static struct fuse_operations ptfs_ops =
|
||||
#if defined(PTFS_UTIMENS)
|
||||
.utimens = ptfs_utimens,
|
||||
#endif
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
.getpath = ptfs_getpath,
|
||||
#endif
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
.setcrtime = ptfs_setcrtime,
|
||||
#endif
|
||||
@ -360,6 +402,10 @@ static void usage(void)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
WinFspLoad();
|
||||
#endif
|
||||
|
||||
PTFS ptfs = { 0 };
|
||||
|
||||
if (3 <= argc && '-' != argv[argc - 2][0] && '-' != argv[argc - 1][0])
|
||||
@ -413,5 +459,17 @@ int main(int argc, char *argv[])
|
||||
if (0 == ptfs.rootdir)
|
||||
usage();
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
if (-1 != getpath(ptfs.rootdir, buf, sizeof buf))
|
||||
{
|
||||
ptfs.rootlen = strlen(buf);
|
||||
if (1 == ptfs.rootlen)
|
||||
ptfs.rootlen = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return fuse_main(argc, argv, &ptfs_ops, &ptfs);
|
||||
}
|
||||
|
@ -212,6 +212,26 @@ int open(const char *path, int oflag, ...)
|
||||
return (int)(intptr_t)h;
|
||||
}
|
||||
|
||||
int fgetpath(int fd, char *buf, size_t size)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
WCHAR FileName[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||
DWORD FileNameLength;
|
||||
|
||||
FileNameLength = GetFinalPathNameByHandleW(h, FileName, sizeof FileName / sizeof(WCHAR),
|
||||
VOLUME_NAME_NONE | FILE_NAME_NORMALIZED);
|
||||
if (0 == FileNameLength)
|
||||
return error();
|
||||
|
||||
FspPosixEncodeWindowsPath(FileName, FileNameLength);
|
||||
size = WideCharToMultiByte(CP_UTF8, 0, FileName, FileNameLength, buf, (int)(size - 1), 0, 0);
|
||||
if (0 == size)
|
||||
return error();
|
||||
buf[size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fstat(int fd, struct fuse_stat *stbuf)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
@ -303,6 +323,22 @@ int close(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getpath(const char *path, char *buf, size_t size)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
int res = fgetpath((int)(intptr_t)h, buf, size);
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int lstat(const char *path, struct fuse_stat *stbuf)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
|
@ -46,6 +46,7 @@ char *realpath(const char *path, char *resolved);
|
||||
int statvfs(const char *path, struct fuse_statvfs *stbuf);
|
||||
|
||||
int open(const char *path, int oflag, ...);
|
||||
int fgetpath(int fd, char *buf, size_t size);
|
||||
int fstat(int fd, struct fuse_stat *stbuf);
|
||||
int ftruncate(int fd, fuse_off_t size);
|
||||
int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset);
|
||||
@ -53,6 +54,7 @@ int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset);
|
||||
int fsync(int fd);
|
||||
int close(int fd);
|
||||
|
||||
int getpath(const char *path, char *buf, size_t size);
|
||||
int lstat(const char *path, struct fuse_stat *stbuf);
|
||||
int chmod(const char *path, fuse_mode_t mode);
|
||||
int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid);
|
||||
@ -79,8 +81,5 @@ struct dirent *readdir(DIR *dirp);
|
||||
int closedir(DIR *dirp);
|
||||
|
||||
long WinFspLoad(void);
|
||||
#undef fuse_main
|
||||
#define fuse_main(argc, argv, ops, data)\
|
||||
(WinFspLoad(), fuse_main_real(argc, argv, ops, sizeof *(ops), data))
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <tlib/testsuite.h>
|
||||
#include <strsafe.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "winfsp-tests.h"
|
||||
@ -145,7 +146,7 @@ static void dirbuf_dots_test(void)
|
||||
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
|
||||
}
|
||||
|
||||
static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
|
||||
static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount, BOOLEAN Presort)
|
||||
{
|
||||
PVOID DirBuffer = 0;
|
||||
NTSTATUS Result;
|
||||
@ -162,6 +163,7 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
|
||||
ULONG DotIndex = Count / 3, DotDotIndex = Count / 3 * 2;
|
||||
WCHAR Marker[MAX_PATH];
|
||||
ULONG N, MarkerIndex, MarkerLength;
|
||||
UINT64 PresortIndex = 0;
|
||||
|
||||
srand(seed);
|
||||
|
||||
@ -189,12 +191,18 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
|
||||
DirInfo->FileNameBuf[0] = L'.';
|
||||
DirInfo->FileNameBuf[1] = L'.';
|
||||
}
|
||||
else
|
||||
else if (!Presort)
|
||||
{
|
||||
N = 24 + rand() % (32 - 24);
|
||||
for (ULONG J = 0; N > J; J++)
|
||||
DirInfo->FileNameBuf[J] = 'A' + rand() % 26;
|
||||
}
|
||||
else
|
||||
{
|
||||
N = 24;
|
||||
StringCbPrintfW(DirInfo->FileNameBuf, 64, L"FILEFILE%016llx", PresortIndex);
|
||||
PresortIndex++;
|
||||
}
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + N * sizeof(WCHAR));
|
||||
|
||||
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
|
||||
@ -212,7 +220,7 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
|
||||
typedef struct
|
||||
{
|
||||
SRWLOCK Lock;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
ULONG InitialCapacity, Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *PeekDirBuffer = DirBuffer;
|
||||
@ -348,31 +356,60 @@ static void dirbuf_fill_test(void)
|
||||
{
|
||||
unsigned seed = (unsigned)time(0);
|
||||
|
||||
dirbuf_fill_dotest(1485473509, 10, 0);
|
||||
dirbuf_fill_dotest(1485473509, 10, 3);
|
||||
dirbuf_fill_dotest(1485473509, 10, 0, FALSE);
|
||||
dirbuf_fill_dotest(1485473509, 10, 3, FALSE);
|
||||
|
||||
for (ULONG I = 0; 10000 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 10, 0);
|
||||
dirbuf_fill_dotest(seed + I, 10, 3);
|
||||
dirbuf_fill_dotest(seed + I, 10, 0, FALSE);
|
||||
dirbuf_fill_dotest(seed + I, 10, 3, FALSE);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 1000 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 100, 0);
|
||||
dirbuf_fill_dotest(seed + I, 100, 30);
|
||||
dirbuf_fill_dotest(seed + I, 100, 0, FALSE);
|
||||
dirbuf_fill_dotest(seed + I, 100, 30, FALSE);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 100 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 1000, 0);
|
||||
dirbuf_fill_dotest(seed + I, 1000, 300);
|
||||
dirbuf_fill_dotest(seed + I, 1000, 0, FALSE);
|
||||
dirbuf_fill_dotest(seed + I, 1000, 300, FALSE);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 10 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 10000, 0);
|
||||
dirbuf_fill_dotest(seed + I, 10000, 3000);
|
||||
dirbuf_fill_dotest(seed + I, 10000, 0, FALSE);
|
||||
dirbuf_fill_dotest(seed + I, 10000, 3000, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void dirbuf_presort_fill_test(void)
|
||||
{
|
||||
unsigned seed = (unsigned)time(0);
|
||||
|
||||
for (ULONG I = 0; 10000 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 10, 0, TRUE);
|
||||
dirbuf_fill_dotest(seed + I, 10, 3, TRUE);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 1000 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 100, 0, TRUE);
|
||||
dirbuf_fill_dotest(seed + I, 100, 30, TRUE);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 100 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 1000, 0, TRUE);
|
||||
dirbuf_fill_dotest(seed + I, 1000, 300, TRUE);
|
||||
}
|
||||
|
||||
for (ULONG I = 0; 10 > I; I++)
|
||||
{
|
||||
dirbuf_fill_dotest(seed + I, 10000, 0, FALSE);
|
||||
dirbuf_fill_dotest(seed + I, 10000, 3000, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,5 +509,6 @@ void dirbuf_tests(void)
|
||||
TEST(dirbuf_empty_test);
|
||||
TEST(dirbuf_dots_test);
|
||||
TEST(dirbuf_fill_test);
|
||||
TEST(dirbuf_presort_fill_test);
|
||||
TEST(dirbuf_boundary_test);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, UL
|
||||
ASSERT(Success);
|
||||
}
|
||||
|
||||
for (int j = 1; 100 >= j; j++)
|
||||
for (int j = 1; 400 >= j; j++)
|
||||
{
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\fileABCDEFGHIJKLMNOPQRSTUVXWYZfile%d",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), j);
|
||||
@ -90,7 +90,7 @@ static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, UL
|
||||
} while (FindNextFileW(Handle, &FindData));
|
||||
ASSERT(ERROR_NO_MORE_FILES == GetLastError());
|
||||
|
||||
ASSERT(110 == FileCount);
|
||||
ASSERT(410 == FileCount);
|
||||
|
||||
Success = FindClose(Handle);
|
||||
ASSERT(Success);
|
||||
@ -194,8 +194,8 @@ static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, UL
|
||||
} while (FindNextFileW(Handle, &FindData));
|
||||
ASSERT(ERROR_NO_MORE_FILES == GetLastError());
|
||||
|
||||
ASSERT(100 == FileCount);
|
||||
ASSERT(101 * 100 / 2 == FileTotal);
|
||||
ASSERT(400 == FileCount);
|
||||
ASSERT(401 * 400 / 2 == FileTotal);
|
||||
|
||||
Success = FindClose(Handle);
|
||||
ASSERT(Success);
|
||||
@ -224,7 +224,7 @@ static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, UL
|
||||
ASSERT(Success);
|
||||
}
|
||||
|
||||
for (int j = 1; 100 >= j; j++)
|
||||
for (int j = 1; 400 >= j; j++)
|
||||
{
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\fileABCDEFGHIJKLMNOPQRSTUVXWYZfile%d",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), j);
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
static void posix_map_sid_test(void)
|
||||
{
|
||||
#define TEST_UIDMAP_UID 1000042
|
||||
#define TEST_UIDMAP_SID L"S-1-12-1-1111-2222-3333-4444"
|
||||
struct
|
||||
{
|
||||
PWSTR SidStr;
|
||||
@ -100,6 +102,7 @@ static void posix_map_sid_test(void)
|
||||
{ L"S-1-16-16384", 0x64000 },
|
||||
{ L"S-1-16-20480", 0x65000 },
|
||||
{ L"S-1-16-28672", 0x67000 },
|
||||
{ TEST_UIDMAP_SID, TEST_UIDMAP_UID },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
@ -112,6 +115,14 @@ static void posix_map_sid_test(void)
|
||||
PSID Sid0, Sid1;
|
||||
UINT32 Uid;
|
||||
|
||||
UINT32 UidMap_Uid[1] = { TEST_UIDMAP_UID };
|
||||
PSID UidMap_Sid[1];
|
||||
Success = ConvertStringSidToSidW(TEST_UIDMAP_SID, &UidMap_Sid[0]);
|
||||
ASSERT(Success);
|
||||
Result = FspPosixSetUidMap(UidMap_Uid, UidMap_Sid, 1);
|
||||
ASSERT(NT_SUCCESS(Result));
|
||||
LocalFree(UidMap_Sid[0]);
|
||||
|
||||
Success = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
|
||||
ASSERT(Success);
|
||||
|
||||
@ -169,6 +180,12 @@ static void posix_map_sid_test(void)
|
||||
|
||||
LocalFree(map[sizeof map / sizeof map[0] - 2].SidStr);
|
||||
LocalFree(map[sizeof map / sizeof map[0] - 1].SidStr);
|
||||
|
||||
Result = FspPosixSetUidMap(0, 0, 0);
|
||||
ASSERT(NT_SUCCESS(Result));
|
||||
|
||||
#undef TEST_UIDMAP_UID
|
||||
#undef TEST_UIDMAP_SID
|
||||
}
|
||||
|
||||
static void posix_map_sd_test(void)
|
||||
|
Reference in New Issue
Block a user