Compare commits

...

51 Commits

Author SHA1 Message Date
09ab9de32c tst: memfs: MemfsUpperChar
Bit-twiddling upper case char
2022-05-30 17:08:36 +01:00
75620332c7 tst: memfs: MemfsFileNameCompare
Use fast loop for ASCII and fall back to
CompareStringW for general case.
2022-05-30 14:13:53 +01:00
47aa53c70a dll: FspFsctlServiceVersion
During file system volume creation FspFsctlCreateVolume calls FspFsctlServiceVersion
which examines the version of the driver in use and initializes the variables
FspFsctlTransactCode and FspFsctlTransactBatchCode with either the new
FSP_IOCTL_TRANSACT* codes or the old FSP_FSCTL_TRANSACT* codes.
2022-05-27 18:31:36 +01:00
c343253718 inc: fuse: FSP_FUSE_HAS_GETPATH 2022-05-25 21:11:28 +01:00
6764269a49 dll: MountBroadcastDriveChange registry setting: BSF_POSTMESSAGE 2022-05-25 20:52:54 +01:00
41d69d7186 dll: MountBroadcastDriveChange registry setting 2022-05-25 16:55:54 +01:00
f6e6660362 dll: fuse: gracefully handle ENOSYS from xattr calls 2022-05-23 22:07:37 +01:00
61027daf6e update changelog 2022-05-23 21:38:53 +01:00
9ae9b8ff2c dll: fuse: uidmap option and AzureAD support 2022-05-23 17:53:39 +01:00
74bb51ae07 shared: posix: FspPosixSetUidMap 2022-05-19 00:50:38 +01:00
332ba48203 changelog: update for 2022+ARM64 Beta3 2022-05-18 14:01:43 +01:00
0d7f13abeb changelog: update for 2022+ARM64 Beta3 2022-05-18 13:59:16 +01:00
e88a7742df build: version: bump to 2022+ARM64 Beta3 2022-05-18 13:56:00 +01:00
c7b3312cf6 sys: disable FSP_FILE_NODE_NO_PGIO 2022-05-17 23:44:16 +01:00
c0fa5696d7 sys: FspVolumeFastTransact 2022-05-17 17:25:18 +01:00
43af829d46 sys,dll,inc: FSP_IOCTL_TRANSACT 2022-05-16 21:40:01 +01:00
9c1a7fb40b build: sign all artifacts destined for installation 2022-05-16 12:24:25 +01:00
dd907a44ad dll: fuse: ensure MaxComponentLength is initialized 2022-04-25 17:41:42 +01:00
df4c19c113 sys: FSP_FILE_NODE_NO_PGIO 2022-04-19 15:21:54 +01:00
deaf475861 sys: FSP_ENTER_FIO: handle bogus fast I/O to fsctl device 2022-04-19 14:29:29 +01:00
bda0477a79 tst: fsbench: --empty-cache option 2022-04-19 10:21:31 +01:00
4b65871747 changelog: update for 2022+ARM64 Beta2 2022-04-13 16:57:36 +01:00
eaa0d7d7d2 tst: passthrough-fuse: ensure WinFsp DLL loaded 2022-04-12 23:26:18 +01:00
facbc2c1b5 tst: passthrough-fuse: getpath: GetFinalPathNameByHandle 2022-04-12 18:21:19 +01:00
e5879a9cb0 dll: fuse: getpath 2022-04-12 15:44:54 +01:00
0a91292e05 tst: ntptfs: PostDispositionWhenNecessaryOnly 2022-04-02 18:11:54 +01:00
1a879e3302 inc, src: PostDispositionWhenNecessaryOnly
- Rename PostDispositionForDirOnly to PostDispositionWhenNecessaryOnly

- Implement PostDispositionWhenNecessaryOnly across the board
2022-04-02 12:48:35 +01:00
98421fe11b inc,sys,tst: fsctl: PostDispositionForDirOnly 2022-04-01 20:54:54 +01:00
f6fef97a10 changelog: update for 2022+ARM64 Beta2 2022-03-30 18:22:54 +01:00
f0931a0cf2 tools: wpr-test.bat 2022-03-30 18:06:59 +01:00
9ecb6541cf tools: vsvarsall.bat: cleanup and restrict to VS2019 2022-03-25 20:40:19 +00:00
d816d607f4 sys: FspFsvolDeviceDirInfoCacheItemSizeMax: increase to 64K 2022-03-24 18:10:04 +00:00
f3df3f6dd2 build: version: bump to 2022+ARM64 Beta2 2022-03-22 19:12:55 +00:00
7527155cb8 dll: dirbuf:
- FspFileSystemAcquireDirectoryBufferEx takes hint for initial capacity.
- Buffer allocation strategy has been improved to minimize reallocation.
- Quick sort of directory entries now implements median of three partitioning. This improves performance of sorting already sorted data.
2022-03-22 16:47:40 +00:00
868812d248 tools: run-all-perf-tests.bat 2022-03-21 16:11:02 +00:00
20680fa5b5 sys: FastIo: read/write implementation 2022-03-20 20:31:54 +00:00
00d4aba946 github: winfsp org 2022-03-02 18:01:21 +00:00
fadcd84ca9 winfsp.dev website 2022-03-02 17:36:14 +00:00
966e08e7c1 appveyor: winfsp.dev 2022-03-02 16:38:37 +00:00
8d83d46e7f build.version.props: MyCrossCert, MyCertIssuer 2022-02-24 13:20:21 +00:00
cdcd6af81d tools: run-tests: ntptfs: accommodate OS version differences 2022-02-11 11:12:59 +00:00
9567b94d37 tools: run-tests: ntptfs: accommodate OS version differences 2022-02-10 14:08:17 +00:00
50a28c4284 tools: run-tests: ntptfs: accommodate OS version differences 2022-02-10 10:30:31 +00:00
87a1d5468d tools: run-tests: ntptfs: enable rename_mmap_test 2022-02-09 17:42:37 +00:00
fda950b90e appveyor: enable VS2017 build 2022-02-09 17:02:16 +00:00
4ccf0d2085 build: allow builds outside git 2022-02-09 17:01:32 +00:00
2c42dc535c tools: winfsp-winpe.bat 2022-02-07 17:57:50 +00:00
84ab502b98 doc: update known file systems 2022-02-03 16:42:19 +00:00
0c90a69b27 dotnet: Interop.cs: fix newlines 2022-02-03 16:15:24 +00:00
2ed46a39fa tools: build-choco.bat: copy from build.bat 2022-02-03 16:08:54 +00:00
cf13cac438 dll: np: NPGetUniversalName implementation 2022-02-03 15:32:35 +00:00
79 changed files with 2966 additions and 1222 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
int res = -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)
goto exit;
memcpy(Name, UserName, NameSize);
for (PSTR P = Name, EndP = P + NameSize; EndP > P; P++)
if ('+' == *P)
*P = '\\';
Size = sizeof SidBuf;
DomnSize = sizeof Domn / sizeof Domn[0];
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;
NameSize = lstrlenA(username) + 1;
if (sizeof Name / sizeof Name[0] < NameSize)
return -1;
memcpy(Name, username, NameSize);
for (PSTR P = Name, EndP = P + NameSize; EndP > P; P++)
if ('+' == *P)
*P = '\\';
*PUid = 0;
SidSize = sizeof SidBuf;
DomnSize = sizeof Domn / sizeof Domn[0];
if (!LookupAccountNameA(0, Name, &SidBuf, &SidSize, Domn, &DomnSize, &Use))
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);

View File

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

View File

@ -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);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + lstrlenW(FileName) * sizeof(WCHAR));
memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO));
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;

View File

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

View File

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

View File

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

View File

@ -9,3 +9,4 @@ EXPORTS
NPOpenEnum PRIVATE
NPEnumResource PRIVATE
NPCloseEnum PRIVATE
NPGetUniversalName PRIVATE

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(
FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode ||
FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode ||
FSP_FSCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode);
(
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
)
) ||
(
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,27 +929,30 @@ NTSTATUS FspVolumeTransact(
}
}
/* were we sent an output buffer? */
switch (ControlCode & 3)
if ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG < Irp)
{
case METHOD_NEITHER:
OutputBuffer = Irp->UserBuffer;
break;
case METHOD_OUT_DIRECT:
if (0 != Irp->MdlAddress)
OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
break;
case METHOD_BUFFERED:
if (0 != OutputBufferLength)
OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
break;
default:
ASSERT(0);
break;
/* were we sent an output buffer? */
switch (ControlCode & 3)
{
case METHOD_NEITHER:
OutputBuffer = Irp->UserBuffer;
break;
case METHOD_OUT_DIRECT:
if (0 != Irp->MdlAddress)
OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
break;
case METHOD_BUFFERED:
if (0 != OutputBufferLength)
OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
break;
default:
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:

View File

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

View File

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

@ -0,0 +1 @@
build.bat

View File

@ -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
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%
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 !signfiles!
if errorlevel 1 set /a signfail=signfail+1
popd
pushd build\%Configuration%
echo .OPTION EXPLICIT >driver.ddf

View File

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

View File

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

View 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

View File

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

View File

@ -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 ^
"%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 "%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
) 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 ^
"%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 "%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
) 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

View File

@ -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" (
set vcvarsall="%%i"
) else (
for /f "usebackq tokens=*" %%i in (`%vswhere% -latest -property installationPath`) do (
set vcvarsall="%%i\VC\Auxiliary\Build\vcvarsall.bat"
)
for /f "usebackq tokens=*" %%i in (`%vswhere% -version [15.0^,17.0^) -find VC\**\vcvarsall.bat`) do (
set vcvarsall="%%i"
)
)
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
View 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
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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