Compare commits

..

30 Commits

Author SHA1 Message Date
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
60 changed files with 1097 additions and 149 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,41 @@
# Changelog
## 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 Beta2</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

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

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

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

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

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

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

@ -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,
@ -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:
@ -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,6 +184,8 @@ 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;

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

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

@ -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;
@ -1436,8 +1437,8 @@ namespace Fsp.Interop
String RegPath, DllName, DllPath;
SYSTEM_INFO SystemInfo;
GetSystemInfo(out SystemInfo);
switch ((UInt32)SystemInfo.wProcessorArchitecture)
{
switch ((UInt32)SystemInfo.wProcessorArchitecture)
{
case SYSTEM_INFO.PROCESSOR_ARCHITECTURE_ARM64:
RegPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\" + ProductName;
DllName = ProductFileName + "-a64.dll";
@ -1451,7 +1452,7 @@ namespace Fsp.Interop
RegPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\" + ProductName;
DllName = ProductFileName + "-x86.dll";
break;
}
}
IntPtr Module;
Module = LoadLibraryW(DllName);
if (IntPtr.Zero == Module)

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

@ -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,8 +89,8 @@ 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;

View File

@ -304,6 +304,43 @@ VOID FspTraceNtStatus(const char *file, int line, const char *func, NTSTATUS Sta
} \
); \
return Result
#define FSP_ENTER_FIO(...) \
PDEVICE_OBJECT FsvolDeviceObject; \
if (FspFsmupDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind)\
{ \
FsvolDeviceObject = FspMupGetFsvolDeviceObject(FileObject);\
if (0 == FsvolDeviceObject) \
{ \
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;\
IoStatus->Information = 0; \
return TRUE; \
} \
} \
else \
FsvolDeviceObject = DeviceObject;\
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 +420,8 @@ FSP_IOPREP_DISPATCH FspFsvolWritePrepare;
FSP_IOCMPL_DISPATCH FspFsvolWriteComplete;
/* fast I/O and resource acquisition callbacks */
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;
@ -1088,7 +1127,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 +1399,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);

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;

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

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

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

@ -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
@ -24,6 +24,19 @@ if X%~nx0==Xbuild-choco.bat (
goto :choco
)
set BuildArm64=yes
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
set BuildArm64=no
)
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
set BuildArm64=no
)
if X%BuildArm64%==Xno (
echo WARNING: APPVEYOR BUILD ON UNSUPPORTED VERSION OF VISUAL STUDIO.
echo WARNING: ARM64 BUILD PRODUCTS ARE COPIES OF X64 BUILD PRODUCTS.
echo:
)
call "%~dp0vcvarsall.bat" x64
if not X%SignedPackage%==X (
@ -44,12 +57,20 @@ if X%SignedPackage%==X (
if exist "%%d" rmdir /s/q "%%d"
)
if X%BuildArm64%==Xyes (
devenv winfsp.sln /build "%Configuration%|ARM64"
if errorlevel 1 goto fail
)
devenv winfsp.sln /build "%Configuration%|x64"
if errorlevel 1 goto fail
devenv winfsp.sln /build "%Configuration%|x86"
if errorlevel 1 goto fail
if X%BuildArm64%==Xno (
copy build\%Configuration%\*-x64.* build\%Configuration%\*-a64.* >nul
if errorlevel 1 goto fail
)
for %%f in (build\%Configuration%\%MyProductFileName%-x64.sys build\%Configuration%\%MyProductFileName%-x86.sys) do (
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
@ -69,6 +90,9 @@ if X%SignedPackage%==X (
echo .Set Compress=on >>driver.ddf
echo .Set CabinetNameTemplate=driver.cab >>driver.ddf
echo .Set DiskDirectory1=. >>driver.ddf
echo .Set DestinationDir=a64 >>driver.ddf
echo driver-a64.inf >>driver.ddf
echo %MyProductFileName%-a64.sys >>driver.ddf
echo .Set DestinationDir=x64 >>driver.ddf
echo driver-x64.inf >>driver.ddf
echo %MyProductFileName%-x64.sys >>driver.ddf
@ -76,7 +100,7 @@ if X%SignedPackage%==X (
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
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 driver.cab
if errorlevel 1 set /a signfail=signfail+1
popd
)

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

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

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

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

@ -2386,6 +2386,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);