Compare commits

...

111 Commits

Author SHA1 Message Date
847eab3da4 tst: memfs-fuse3: #if0 ioctl 2019-10-21 20:21:36 -07:00
5131ed5c01 Merge branch 'bdutro-o_append-fix' 2019-10-21 20:14:02 -07:00
b513128cfe In Windows, Go clears any write-related flags when O_APPEND is
specified. This causes WinFSP to think that any O_APPEND requests are
actually read-only. This adds an additional check for the
FILE_APPEND_DATA flag so that we can ensure the request is sent with at
least O_WRONLY and O_APPEND set.
2019-10-21 18:04:26 -05:00
3fe69f2208 installer: add fsext development files 2019-10-18 16:23:27 -07:00
29fd9bf779 sys: fsext: allow multiple providers (up to 4) 2019-10-18 16:00:31 -07:00
3c391ca711 build: bump version to 2019.3 B3 2019-10-16 12:18:24 -07:00
82a8545d8f tst: memfs-fuse3: fix narrow conversion on x86 builds 2019-10-09 14:42:39 -07:00
79be3e445a tst: memfs-fuse3: accurately compute current time 2019-10-09 11:39:41 -07:00
b04266e0fe tools: run-tests: add memfs-fuse3 testing 2019-10-08 04:35:28 +01:00
25adfaec00 update Changelog 2019-10-08 04:30:30 +01:00
ce20747534 tst: memfs-fuse3: testing 2019-10-07 18:32:25 -07:00
d3d75bf977 tst: add memfs-fuse3 file system 2019-10-07 14:24:18 -07:00
6f1f1cda71 update Changelog 2019-10-07 22:17:07 +01:00
21dfeca124 update Changelog 2019-10-07 22:15:29 +01:00
6f585ce63e Merge pull request #251 from johntyner/feature/remove-fuse-prefix
Remove "FUSE-" prefix from file system name when using FUSE API
2019-10-07 14:05:18 -07:00
8f90305726 add support for setting file system name without 'FUSE-' prefix 2019-10-07 07:05:01 -07:00
490d0577bb Revert "Remove 'FUSE-' prefix from file system name when using fuse interface"
This reverts commit 7d2ff3afeb.
2019-10-07 06:47:02 -07:00
c9d3cb74c7 add John Tyner to contributors 2019-09-25 16:20:50 -07:00
7d2ff3afeb Remove 'FUSE-' prefix from file system name when using fuse interface 2019-09-24 20:04:29 -07:00
c415c87195 dll: FspMountSet, FspMountRemove 2019-09-24 15:34:01 -07:00
d161ca59a7 update Changelog 2019-09-12 05:36:19 +01:00
bc03af3b2a doc: update FAQ, Known File Systems 2019-09-12 04:54:40 +01:00
ed1543665c Merge pull request #248 from JohnOberschelp/master
Airfs cleanup after persistence review
2019-09-10 22:32:58 -07:00
a99fa512d4 Fixed issues noted at the PR review 2019-09-10 16:00:34 -07:00
a6800dd73d Fixed issues noted at the PR review 2019-09-10 15:59:48 -07:00
aa9354773b Fixed issues noted at the PR review 2019-09-10 15:58:35 -07:00
05b37c744b sys,dll: only user mode sends MountManager IOCTL's
(except for cleanup in FspMountdevFini)
2019-09-08 17:45:00 -07:00
1d15c9546b Merge branch 'pvt-sqlfix2' 2019-09-08 11:05:17 -07:00
51b33f02aa Merge pull request #241 from JohnOberschelp/master
Add persistence to Airfs
2019-09-07 17:40:42 -07:00
97ffa741b2 tst: volpath-test: fix silly mistake 2019-09-07 11:56:34 -07:00
073645db3b tst: fix tests broken by new mountmgr func 2019-09-07 11:39:06 -07:00
fd9ac1c9e0 appveyor: WDK 1903 hackfix 2019-09-06 20:56:37 -07:00
62b08c3d1e appveyor: WDK 1903 hackfix 2019-09-07 04:54:39 +01:00
9436fd8402 sys: implement SectorSize queries
- IRP_MJ_QUERY_VOLUME_INFORMATION/FileFsSectorSizeInformation
- IOCTL_STORAGE_QUERY_PROPERTY/StorageAccessAlignmentProperty
2019-09-06 20:52:15 -07:00
de75454d50 sys: FspFsvolDeviceControl: disable mountdev handling on fsvol devices 2019-09-06 15:43:20 -07:00
430d7a5650 sys: FspMountdevMake: use non-repeatable (i.e. non UUIDv5) GUID when non-persistent mountdev 2019-09-06 14:34:33 -07:00
4655926d03 sys, dll: mount manager support 2019-09-06 14:24:00 -07:00
565caebe4c sys,dll: FspFileSystemSetMountPoint: mount manager support 2019-09-05 19:58:14 -07:00
a47f853beb sys: mountdev: mount manager support 2019-09-05 09:54:36 -07:00
89ec3e6733 ku: UUID v5 generation 2019-09-04 13:45:53 -07:00
dbdfaeee1f tst: winfsp-tests: GetVolumePathName testing 2019-08-23 16:00:35 +01:00
2c64d59001 Add common.h & persistence.cpp for Airfs to Product.wxs 2019-08-09 15:58:12 -07:00
af8c74378e appveyor: hack to make WDK 1903 work on VS2015 2019-08-07 22:53:21 -07:00
19c320350f Add persistence.cpp and common.h 2019-08-03 17:55:29 -07:00
d60b1de430 Add persistence.cpp and common.h 2019-08-03 17:54:26 -07:00
6a7b6c77c6 Create common.h 2019-08-03 12:22:57 -07:00
16b1b2b349 Create persistence.cpp
Create persistence.cpp to supply functionality needed for volume persistence within a memory-mapped file:
    memory management
    sorted sets
    offsets that don’t use a pointer
2019-08-03 12:19:56 -07:00
f181593f49 Add persistence to Airfs
Adds persistence to Airfs; stores the volume in a file.
The interface has changed slightly. Pass...
-N VolumeName ( for example C:\Users\foo\Desktop\test.air )
-n MapName    ( for example Local\Airfs )
... in place of the no longer used...
-n MaxFileNodes
2019-08-03 11:52:47 -07:00
d2f42f4918 update Changelog 2019-07-11 03:17:33 -07:00
a73f1b9559 launcher: path transform language 2019-07-09 13:26:07 -07:00
fb6893968a dll: fuse: add --UserName and --GroupName 2019-07-08 15:12:26 -07:00
c97f2cb660 dotnet: add MountEx and fine-grained timeouts 2019-07-07 12:12:04 -07:00
3a12d928e5 dll: fuse: avoid calling fgetattr on directories 2019-07-01 00:00:37 -07:00
8fa337ae54 sys: fix issues found by static analyzer 2019-06-28 16:19:58 -07:00
7f084787e3 sys: fix issues found by static analyzer 2019-06-28 15:21:36 -07:00
369c0256f3 build: version.properties: update company name 2019-06-25 17:11:01 -07:00
f25983853b tools: build.bat: update cert subject 2019-06-25 17:09:34 -07:00
757e23ded6 ku: kernel-mode testing and fixes 2019-06-24 16:14:03 -07:00
ebb9b8b799 sys: FspVolumeTransact: remove erroneous ASSERT 2019-06-23 11:07:01 -07:00
804bcc3354 sys: FspVolumeTransactFsext:
- only allow ControlCodes with 0xC00 bits set in Function
2019-06-22 15:40:48 -07:00
f5fde4c0bb sys: FspVolumeTransactFsext 2019-06-22 15:18:16 -07:00
dcf7e4c5a6 sys: fsext: FsextProvider testing 2019-06-22 14:30:23 -07:00
adc759447e sys: FspVolumeCreate: fix missing return 2019-06-21 16:37:07 -07:00
f0d7e5b322 Merge pull request #237 from dworkin/feature/async-dotnet
Async I/O for dotnet
2019-06-21 14:48:30 -07:00
bfd8dca62d Delay unmounting until all Slowio tasks are done.
Preventing a crash when unmounting a filesystem with pending Slowio.
2019-06-20 15:49:02 +02:00
79b2f38d87 update README 2019-06-18 21:52:19 -07:00
4ae03629f7 sys: FspFsextProvider: load provider driver 2019-06-18 20:28:59 -07:00
f4496786e5 src: ku: posix.c
- src/ku directory contains shared kernel/user mode code
2019-06-18 16:49:20 -07:00
b637a72ec8 sys: FspFsextProvider 2019-06-18 16:11:38 -07:00
2cd1bddafb sys: FspFsextProvider 2019-06-14 21:22:01 -07:00
6b83748d89 sys: fsext: WIP 2019-06-14 20:53:09 -07:00
ed31a187ac opt/fsext: kernel mode winfsp extension 2019-06-14 18:34:19 -07:00
781deff06f sys: default TransactTimeout changes 2019-06-11 17:53:34 -07:00
3902874ac9 dll: FspFileSystemStartDispatcher
Change default number of threads when ThreadCount==0 is passed.
New min DEFAULT number of threads is 4 and new max DEFAULT number of threads is 16.
The absolute minimum number of threads that any file system dispatcher has remains 2.
2019-06-11 11:51:20 -07:00
8ad77fe62f shared: minimal.h: fix memmove issue in VS 2019 2019-06-06 15:10:25 -07:00
f78b3464ce sys: meta: fix rare memory leak 2019-06-05 20:43:12 -07:00
02fd6906c2 Revert making SeekableReadDirectory virtual.
This would be an API-breaking change that is actually pointless.
Override ReadDirectory instead, as intended.
2019-06-05 09:24:27 +02:00
ce436fc29a Attempt to add a slowio test for memfs-dotnet. 2019-06-04 17:10:33 +02:00
879fa2464f Add asynchronous I/O testing to memfs-dotnet.
Make SeekableReadDirectory virtual, so that it can be overridden.
2019-06-04 15:58:54 +02:00
af7e5432a7 Let the Status argument be a signed integer.
The constants are defined as negative numbers, which would have required
a cast to unsigned for each call.
2019-05-15 14:09:08 +02:00
1d619e0874 Use pointers instead of references.
To avoid copying structs needlessly.
2019-05-14 11:38:55 +02:00
290896b010 Add asyncronous support for dotnet. 2019-05-13 09:47:59 +02:00
c01402443d wslinux support: ATOMIC_CREATE_ECP_CONTEXT 2019-04-27 15:30:57 -07:00
195f3bf92d build: VS2015 - VS2019 round-tripping: LatestTargetPlatformVersion 2019-04-26 09:44:30 -07:00
ae86aeb633 README: WinFsp now builds with VS2015 - VS2019 2019-04-25 17:43:14 -07:00
369da895d3 build: VS2015 - VS2019 round-tripping 2019-04-25 16:43:53 -07:00
17adae481c sys: FspFileNodeOplockCheckAsyncEx: fix stupid mistake in DEBUGTEST code 2019-04-18 23:47:27 -07:00
db34b8c913 update changelog 2019-04-18 20:45:56 -07:00
f6212be687 README: minor fix 2019-04-18 20:38:35 -07:00
7af36d8f78 Merge branch 'master' of https://github.com/billziss-gh/winfsp 2019-04-18 17:46:51 -07:00
f6e49a11c8 .gitignore: add .vs rule 2019-04-18 17:45:11 -07:00
01ca9cef35 README: add info on VS2015 + latest WDK problem 2019-04-18 17:34:02 -07:00
7cb29a4db3 sys: remove unused variables 2019-04-18 17:22:58 -07:00
5523320348 build: fix stampinf cmdline for latest WDK 2019-04-18 17:21:06 -07:00
969651f5f6 sys: improve support for FileStatLxInformation 2019-04-18 15:57:22 -07:00
a08fdccb17 sys: FspSendQueryEaIrp: fix EA related BSOD 2019-04-17 16:04:44 -07:00
859d4250c3 tst: winfsp-tests: wsl: fix WOW64 failure 2019-04-17 15:04:53 -07:00
c6b7b7586e sys: ea: buffers from user mode fs can have zero length 2019-04-17 14:40:06 -07:00
6406246ce2 tools: deploy: fix driver path 2019-04-17 14:39:16 -07:00
9d8ff57be7 Merge branch 'master' into pvt-wsl 2019-04-17 11:28:06 -07:00
2b0d204ff1 sys: FileStatInformation is missing on old WDK's 2019-04-16 21:28:09 -07:00
851d0758d9 sys: define FSP_FILE_STAT*_INFORMATION that are missing on some WDK's 2019-04-16 15:55:13 -07:00
4f444b412e dll: fuse: create_file_mask, create_dir_mask options 2019-04-16 15:16:54 -07:00
e9578b48ce update Changelog 2019-04-16 12:15:32 -07:00
3c3163c41b dll; fuse: rename dot_hidden option to dothidden 2019-04-16 12:11:43 -07:00
8beb534340 dll: fuse: dot_hidden option adds hidden file attribute on dot files 2019-04-15 16:30:00 -07:00
9dcc04f882 tools: update deploy/debug scripts 2019-04-15 15:34:35 -07:00
ce83619728 sys: FileStatLxInformation and friends 2019-04-15 15:04:31 -07:00
04b3675f12 update .gitignore files 2019-04-03 22:39:25 -07:00
6a23f28249 build: bump version number 2019-04-03 22:39:03 -07:00
351b4f5294 sys: fileinfo: fix unnecessary STATUS_BUFFER_TOO_SMALL 2019-04-03 09:52:00 -07:00
105 changed files with 7171 additions and 1611 deletions

View File

@ -1,6 +1,65 @@
= Changelog = Changelog
v1.5B3 (2019.3 B3)::
Changes since v1.4:
* [GEN] WinFsp file systems can now be used by WSLinux. Use the command `sudo mount -t drvfs x: /mnt/x` to mount.
* [GEN] Extended attribute support has been added for all WinFsp API's: native, .NET, FUSE2 and FUSE3.
* [GEN] Mount Manager support has been added and it works for current and new file systems:
** If the file system mountpoint is in the syntax `\\.\X:` then the Mount Manager is used.
** If the file system mountpoint is in the syntax `X:` then `DefineDosDeviceW` is used (i.e. same as today).
** If the file system mountpoint is in the syntax `X:\DIR` then a reparse point is used and the file system is mounted as a directory (i.e. same as today).
** Caveats:
*** It requires Administrator access. This is because opening the `\\.\MountPointManager` device requires Administrator access.
*** It currently works with drives (`\\.\X:`) but not directories (`\\.\X:\DIR`).
*** Mount Manager drives created by WinFsp are transient. WinFsp takes various steps to ensure that this is the case.
*** Mount Manager drives are global and are visible across Terminal Services sessions (they go into the `\GLOBAL??` portion of the NT namespace).
* [FSD] Support for kernel-mode file systems on top of WinFsp has been added. See `FspFsextProvider`. This is in preparation for WinFuse - FUSE for Windows and WSLinux.
* [FSD] FastIO support has been added. FastIO operations are enabled on cache-enabled file systems with the notable exception of `FastIoQueryOpen`, which allows opening files in kernel mode; this operation requires the file system to specify the `FSP_FSCTL_VOLUME_PARAMS::AllowOpenInKernelMode` flag.
* [FSD] Support for `FileFsSectorSizeInformation` and `IOCTL_STORAGE_QUERY_PROPERTY / StorageAccessAlignmentProperty` has been added.
* [DLL] The `FspFileSystemStartDispatcher` default number of threads (`ThreadCount==0`) has been changed. See commit 3902874ac93fe40685d9761f46a96358ba24f24c for more.
* [FUSE] FUSE has new `-o UserName=DOMAIN+USERNAME` and `-o GroupName=DOMAIN+GROUPNAME` options. These function like the `-o uid=UID` and `-o gid=GID` options, but accept Windows user and groups names.
* [FUSE] FUSE has new `-o dothidden` option that is used to add the Windows hidden file attribute to files that start with a dot.
* [FUSE] FUSE has new `-o create_file_umask=nnn` and `-o create_dir_umask=nnn` options that allow for more control than the `-o create_umask=nnn` option.
* [FUSE] FUSE has new `--ExactFileSystemName=FSNAME` option that removes the "FUSE-" prefix from the file system name. (Use with caution: see discussion in PR #251.) (Thanks @johntyner.)
* [.NET] The .NET API now supports asynchronous handling of `Read`, `Write` and `ReadDirectory`. (Thanks @dworkin.)
* [.NET] The .NET API now supports fine-grained timeouts (`VolumeInfoTimeout`, `DirInfoTimeout`, etc).
* [.NET] The .NET API has new method `FileSystemHost.MountEx` that adds a `ThreadCount` parameter.
* [LAUNCH] The Launcher can now rewrite path arguments passed to file systems during launching using "Path Transformation Language". See commit a73f1b95592617ac7484e16c2e642573a4d65644 for more.
* [MEMFS] A new memfs FUSE3 file system written in C++ has been added. See `tst/memfs-fuse3`.
* [AIRFS] John Oberschelp has done some fantastic work adding persistence to the airfs file system. (Thanks @JohnOberschelp.)
* [FIX] Fixes for very large (> 4GiB) files. (Thanks @dworkin.)
* [FIX] A fix for how FUSE handles the return value from `opendir`. (GitHub issue billziss-gh/sshfs-win#54)
* [FIX] A fix for an invalid UID to SID mapping on domains with a lot of users. (Thanks @sganis.)
* [FIX] A fix on the C++ layer. (Thanks @colatkinson.)
* Other fixes and improvements.
v1.5B2 (2019.3 B2)::
Changes since v1.4:
* [GEN] WinFsp file systems can now be used by WSLinux. Use the command `sudo mount -t drvfs x: /mnt/x` to mount.
* [GEN] Extended attribute support has been added for all WinFsp API's: native, .NET, FUSE2 and FUSE3.
* [FSD] Support for kernel-mode file systems on top of WinFsp has been added. See `FspFsextProvider`. This is in preparation for WinFuse - FUSE for Windows and WSLinux.
* [FSD] FastIO support has been added. FastIO operations are enabled on cache-enabled file systems with the notable exception of `FastIoQueryOpen`, which allows opening files in kernel mode; this operation requires the file system to specify the `FSP_FSCTL_VOLUME_PARAMS::AllowOpenInKernelMode` flag.
* [DLL] The `FspFileSystemStartDispatcher` default number of threads (`ThreadCount==0`) has been changed. See commit 3902874ac93fe40685d9761f46a96358ba24f24c for more.
* [FUSE] FUSE has new `-o UserName=DOMAIN\USERNAME` and `-o GroupName=DOMAIN\GROUPNAME` options. These function like the `-o uid=UID` and `-o gid=GID` options, but accept Windows user and groups names.
* [FUSE] FUSE has new `-o dothidden` option that is used to add the Windows hidden file attribute to files that start with a dot.
* [FUSE] FUSE has new `-o create_file_umask=nnn` and `-o create_dir_umask=nnn` options that allow for more control than the `-o create_umask=nnn` option.
* [.NET] The .NET API now supports asynchronous handling of `Read`, `Write` and `ReadDirectory`. (Thanks @dworkin.)
* [.NET] The .NET API now supports fine-grained timeouts (`VolumeInfoTimeout`, `DirInfoTimeout`, etc).
* [.NET] The .NET API has new method `FileSystemHost.MountEx` that adds a `ThreadCount` parameter.
* [LAUNCH] The Launcher can now rewrite path arguments passed to file systems during launching using "Path Transformation Language". See commit a73f1b95592617ac7484e16c2e642573a4d65644 for more.
* [FIX] Fixes for very large (> 4GiB) files. (Thanks @dworkin.)
* [FIX] A fix for how FUSE handles the return value from `opendir`. (GitHub issue billziss-gh/sshfs-win#54)
* [FIX] A fix for an invalid UID to SID mapping on domains with a lot of users. (Thanks @sganis.)
* [FIX] A fix on the C++ layer. (Thanks @colatkinson.)
* Other fixes and improvements.
v1.5B1 (2019.3 B1):: v1.5B1 (2019.3 B1)::
Changes since v1.4: Changes since v1.4:
@ -11,6 +70,7 @@ Changes since v1.4:
* A fix for an invalid UID to SID mapping on domains with a lot of users. (Thanks @sganis.) * A fix for an invalid UID to SID mapping on domains with a lot of users. (Thanks @sganis.)
* A fix on the C++ layer. (Thanks @colatkinson.) * A fix on the C++ layer. (Thanks @colatkinson.)
v1.4.19049 (2019.2):: v1.4.19049 (2019.2)::
Changes since v1.3: Changes since v1.3:

View File

@ -56,11 +56,13 @@ CONTRIBUTOR LIST
|=== |===
|Ben Rubson |ben.rubson at gmail.com |Ben Rubson |ben.rubson at gmail.com
|Bill Zissimopoulos |billziss at navimatics.com |Bill Zissimopoulos |billziss at navimatics.com
|Brett Dutro |brett.dutro at gmail.com
|Colin Atkinson (Atakama, https://atakama.com) |colin at atakama.com |Colin Atkinson (Atakama, https://atakama.com) |colin at atakama.com
|Felix Croes |felix at dworkin.nl |Felix Croes |felix at dworkin.nl
|Francois Karam (KS2, http://www.ks2.fr) |francois.karam at ks2.fr |Francois Karam (KS2, http://www.ks2.fr) |francois.karam at ks2.fr
|Fritz Elfert |fritz-github at fritz-elfert.de |Fritz Elfert |fritz-github at fritz-elfert.de
|John Oberschelp |john at oberschelp.net |John Oberschelp |john at oberschelp.net
|John Tyner |jtyner at gmail.com
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com |Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|Santiago Ganis |sganis at gmail.com |Santiago Ganis |sganis at gmail.com
|Tobias Urlaub |saibotu at outlook.de |Tobias Urlaub |saibotu at outlook.de

View File

@ -96,6 +96,7 @@ The project source code is organized as follows:
* :file_folder: [src/dll/fuse3](src/dll/fuse3): Source code to the FUSE3 compatibility layer. * :file_folder: [src/dll/fuse3](src/dll/fuse3): Source code to the FUSE3 compatibility layer.
* :file_folder: [src/dotnet](src/dotnet): Source code to the .NET layer. * :file_folder: [src/dotnet](src/dotnet): Source code to the .NET layer.
* :file_folder: [src/fsptool](src/fsptool): Source code to fsptool command line utility. * :file_folder: [src/fsptool](src/fsptool): Source code to fsptool command line utility.
* :file_folder: [src/ku](src/ku): Source code that can be used from kernel or user mode.
* :file_folder: [src/launcher](src/launcher): Source code to the launcher service and the launchctl utility. * :file_folder: [src/launcher](src/launcher): Source code to the launcher service and the launchctl utility.
* :file_folder: [src/sys](src/sys): Source code to the WinFsp FSD. * :file_folder: [src/sys](src/sys): Source code to the WinFsp FSD.
* :file_folder: [opt/cygfuse](opt/cygfuse): Source code to the FUSE for Cygwin package. * :file_folder: [opt/cygfuse](opt/cygfuse): Source code to the FUSE for Cygwin package.
@ -107,8 +108,12 @@ The project source code is organized as follows:
In order to build WinFsp you will need the following: In order to build WinFsp you will need the following:
* Visual Studio 2015 * Visual Studio 2015 - 2019
* Windows Driver Kit (WDK) 10 * Windows Driver Kit (WDK) 10
- **NOTE**: When using the latest WDK (Windows 10.0.18362.1) with Visual Studio 2015 you may get an error about a missing task `ValidateNTTargetVersion`. The fix is to edit the file `\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets` and modify the `UsingTask` line for `ValidateNTTargetVersion` as follows:
```
<UsingTask TaskName="ValidateNTTargetVersion" AssemblyFile="$(WDKContentRoot)build\bin\Microsoft.DriverKit.Build.Tasks.16.0.dll"/>
```
* [Wix toolset](http://wixtoolset.org) * [Wix toolset](http://wixtoolset.org)
To fully build WinFsp (including the installer) you must use `tools\build.bat`. By default it builds a Release build, but you can choose either the Debug or Release configuration by using the syntax: To fully build WinFsp (including the installer) you must use `tools\build.bat`. By default it builds a Release build, but you can choose either the Debug or Release configuration by using the syntax:

View File

@ -15,6 +15,13 @@ init:
#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) #- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install: install:
- ps: |
# Hack to make WDK 1903 work on VS2015.
# See https://github.com/appveyor-tests/WDK-10.0.14393.0/blob/31cf12217fe0c92b218c70d7027dfe145be4f4cb/appveyor.yml#L7
[xml]$targets = get-content "C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets"
$usingTask = $targets.ChildNodes[1].UsingTask | ? {$_.TaskName -eq "ValidateNTTargetVersion"}
$usingTask.AssemblyFile = '$(WDKContentRoot)build\bin\Microsoft.DriverKit.Build.Tasks.16.0.dll'
$targets.Save("C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets")
- git submodule update --init --recursive - git submodule update --init --recursive
- appveyor AddMessage "Change boot configuration and reboot" -Category Information - appveyor AddMessage "Change boot configuration and reboot" -Category Information
- bcdedit /set testsigning on - bcdedit /set testsigning on

View File

@ -4,3 +4,6 @@ build
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.csproj.user *.csproj.user
*.VC.db
*.VC.opendb
.vs

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\version.properties" />
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@ -14,18 +15,18 @@
<ProjectGuid>{95C223E6-B5F1-4FD0-9376-41CDBC824445}</ProjectGuid> <ProjectGuid>{95C223E6-B5F1-4FD0-9376-41CDBC824445}</ProjectGuid>
<RootNamespace>CustomActions</RootNamespace> <RootNamespace>CustomActions</RootNamespace>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@ -68,7 +69,6 @@
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile> <ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
@ -92,7 +92,6 @@
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(WIX)sdk\VS2015\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile> <ModuleDefinitionFile>CustomActions.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>

View File

@ -369,6 +369,23 @@
<File Name="uninstall.sh" KeyPath="yes" /> <File Name="uninstall.sh" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="OPTDIR.fsext" Name="fsext" FileSource="..\..\..\opt\fsext">
<Directory Id="OPTDIR.fsext.inc" Name="inc">
<Directory Id="OPTDIR.fsext.inc.winfsp" Name="winfsp">
<Component Id="C.fsext.h">
<File Name="fsext.h" KeyPath="yes" />
</Component>
</Directory>
</Directory>
<Directory Id="OPTDIR.fsext.lib" Name="lib">
<Component Id="C.fsext.winfsp_x64.lib">
<File Id="FILE.fsext.winfsp_x64.lib" Name="winfsp-x64.lib" KeyPath="yes" />
</Component>
<Component Id="C.fsext.winfsp_x86.lib">
<File Id="FILE.fsext.winfsp_x86.lib" Name="winfsp-x86.lib" KeyPath="yes" />
</Component>
</Directory>
</Directory>
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst"> <DirectoryRef Id="SMPDIR" FileSource="..\..\..\tst">
<Directory Id="SMPDIR.memfs" Name="memfs"> <Directory Id="SMPDIR.memfs" Name="memfs">
@ -382,6 +399,29 @@
<File Name="memfs-main.c" KeyPath="yes" /> <File Name="memfs-main.c" KeyPath="yes" />
</Component> </Component>
</Directory> </Directory>
<Directory Id="SMPDIR.memfs_fuse3" Name="memfs-fuse3">
<Component Id="C.memfs_fuse3.cpp">
<File Name="memfs-fuse3.cpp" KeyPath="yes" />
</Component>
<Component Id="C.memfs_fuse3.compat.h">
<File Id="F.memfs_fuse3.compat.h" Name="compat.h" KeyPath="yes" />
</Component>
<Component Id="C.memfs_fuse3.sln">
<File Name="memfs-fuse3.sln" KeyPath="yes" />
</Component>
<Component Id="C.memfs_fuse3.vcxproj">
<File Name="memfs-fuse3.vcxproj" KeyPath="yes" />
</Component>
<Component Id="C.memfs_fuse3.vcxproj.filters">
<File Name="memfs-fuse3.vcxproj.filters" KeyPath="yes" />
</Component>
<Component Id="C.memfs_fuse3.Makefile">
<File Id="F.memfs_fuse3.Makefile" Name="Makefile" KeyPath="yes" />
</Component>
<Component Id="C.memfs_fuse3.README.md">
<File Id="F.memfsx_fuse3.README.md" Name="README.md" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.memfs_dotnet" Name="memfs-dotnet"> <Directory Id="SMPDIR.memfs_dotnet" Name="memfs-dotnet">
<Component Id="C.memfs_dotnet.Program.cs"> <Component Id="C.memfs_dotnet.Program.cs">
<File Id="FILE.memfs_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" /> <File Id="FILE.memfs_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
@ -391,6 +431,12 @@
<Component Id="C.airfs.cpp"> <Component Id="C.airfs.cpp">
<File Name="airfs.cpp" KeyPath="yes" /> <File Name="airfs.cpp" KeyPath="yes" />
</Component> </Component>
<Component Id="C.persistence.cpp">
<File Name="persistence.cpp" KeyPath="yes" />
</Component>
<Component Id="C.common.h">
<File Name="common.h" KeyPath="yes" />
</Component>
<Component Id="C.airfs.sln"> <Component Id="C.airfs.sln">
<File Name="airfs.sln" KeyPath="yes" /> <File Name="airfs.sln" KeyPath="yes" />
</Component> </Component>
@ -580,13 +626,27 @@
<ComponentRef Id="C.fuse.install.sh" /> <ComponentRef Id="C.fuse.install.sh" />
<ComponentRef Id="C.fuse.uninstall.sh" /> <ComponentRef Id="C.fuse.uninstall.sh" />
</ComponentGroup> </ComponentGroup>
<ComponentGroup Id="C.WinFsp.opt.fsext">
<ComponentRef Id="C.fsext.h" />
<ComponentRef Id="C.fsext.winfsp_x64.lib" />
<ComponentRef Id="C.fsext.winfsp_x86.lib" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.smp"> <ComponentGroup Id="C.WinFsp.smp">
<ComponentRef Id="C.memfs_x64.exe" /> <ComponentRef Id="C.memfs_x64.exe" />
<ComponentRef Id="C.memfs_x86.exe" /> <ComponentRef Id="C.memfs_x86.exe" />
<ComponentRef Id="C.memfs.h" /> <ComponentRef Id="C.memfs.h" />
<ComponentRef Id="C.memfs.cpp" /> <ComponentRef Id="C.memfs.cpp" />
<ComponentRef Id="C.memfs_main.c" /> <ComponentRef Id="C.memfs_main.c" />
<ComponentRef Id="C.memfs_fuse3.cpp" />
<ComponentRef Id="C.memfs_fuse3.compat.h" />
<ComponentRef Id="C.memfs_fuse3.sln" />
<ComponentRef Id="C.memfs_fuse3.vcxproj" />
<ComponentRef Id="C.memfs_fuse3.vcxproj.filters" />
<ComponentRef Id="C.memfs_fuse3.Makefile" />
<ComponentRef Id="C.memfs_fuse3.README.md" />
<ComponentRef Id="C.airfs.cpp" /> <ComponentRef Id="C.airfs.cpp" />
<ComponentRef Id="C.persistence.cpp" />
<ComponentRef Id="C.common.h" />
<ComponentRef Id="C.airfs.sln" /> <ComponentRef Id="C.airfs.sln" />
<ComponentRef Id="C.airfs.vcxproj" /> <ComponentRef Id="C.airfs.vcxproj" />
<ComponentRef Id="C.airfs.vcxproj.filters" /> <ComponentRef Id="C.airfs.vcxproj.filters" />
@ -694,6 +754,16 @@
<ComponentGroupRef Id="C.WinFsp.smp.net" /> <ComponentGroupRef Id="C.WinFsp.smp.net" />
<ComponentGroupRef Id="C.WinFsp.sym" /> <ComponentGroupRef Id="C.WinFsp.sym" />
</Feature> </Feature>
<Feature
Id="F.KernelDeveloper"
Level="1000"
Title="Kernel Developer"
Description="Additional files needed for in-kernel development."
AllowAdvertise="no"
InstallDefault="local"
Absent="allow">
<ComponentGroupRef Id="C.WinFsp.opt.fsext" />
</Feature>
<Feature <Feature
Id="F.Cygfuse" Id="F.Cygfuse"
Level="1000" Level="1000"

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@ -22,32 +23,32 @@
<ProjectGuid>{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}</ProjectGuid> <ProjectGuid>{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>fsbench</RootNamespace> <RootNamespace>fsbench</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -106,7 +107,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -122,7 +122,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -142,7 +141,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -162,7 +160,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@ -22,32 +23,32 @@
<ProjectGuid>{10757011-749D-4954-873B-AE38D8145472}</ProjectGuid> <ProjectGuid>{10757011-749D-4954-873B-AE38D8145472}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>fscrash</RootNamespace> <RootNamespace>fscrash</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -106,7 +107,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -122,7 +122,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -142,7 +141,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -162,7 +160,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@ -22,33 +23,33 @@
<ProjectGuid>{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}</ProjectGuid> <ProjectGuid>{AA7190E8-877F-4827-8CDD-E0D85F83C8C1}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>memfs</RootNamespace> <RootNamespace>memfs</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
<ProjectName>memfs</ProjectName> <ProjectName>memfs</ProjectName>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -107,7 +108,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -124,7 +124,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -143,7 +142,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
@ -164,7 +162,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\version.properties" />
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@ -22,32 +23,32 @@
<ProjectGuid>{262DF8CC-E7A8-4460-A22C-683CBA322C32}</ProjectGuid> <ProjectGuid>{262DF8CC-E7A8-4460-A22C-683CBA322C32}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>winfsptests</RootNamespace> <RootNamespace>winfsptests</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -106,7 +107,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -123,7 +123,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -142,7 +141,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@ -163,7 +161,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@ -194,6 +191,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\launch-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\launch-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\launcher-ptrans-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />
@ -206,8 +204,11 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\uuid5-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\volpath-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\wsl-test.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h" /> <ClInclude Include="..\..\..\ext\tlib\testsuite.h" />

View File

@ -97,6 +97,18 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\ea-test.c"> <ClCompile Include="..\..\..\tst\winfsp-tests\ea-test.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\wsl-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\launcher-ptrans-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\volpath-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\uuid5-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h"> <ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -23,32 +23,32 @@
<ProjectGuid>{1E997BEC-1642-4A5C-B252-852DA094E11E}</ProjectGuid> <ProjectGuid>{1E997BEC-1642-4A5C-B252-852DA094E11E}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>fsptool</RootNamespace> <RootNamespace>fsptool</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -108,7 +108,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
@ -127,7 +126,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
@ -149,7 +147,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
@ -171,7 +168,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>

View File

@ -23,32 +23,32 @@
<ProjectGuid>{264A5D09-126F-4760-A3F1-4B3B95C925AA}</ProjectGuid> <ProjectGuid>{264A5D09-126F-4760-A3F1-4B3B95C925AA}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>launchctl</RootNamespace> <RootNamespace>launchctl</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -110,7 +110,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
@ -131,7 +130,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
@ -155,7 +153,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>
@ -179,7 +176,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
</Link> </Link>

View File

@ -23,32 +23,32 @@
<ProjectGuid>{6CDF9411-B852-4EAC-822D-8F930675F17B}</ProjectGuid> <ProjectGuid>{6CDF9411-B852-4EAC-822D-8F930675F17B}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>launcher</RootNamespace> <RootNamespace>launcher</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -110,7 +110,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
@ -132,7 +131,6 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
@ -157,7 +155,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
@ -182,7 +179,6 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;userenv.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
@ -190,6 +186,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\src\launcher\launcher.c" /> <ClCompile Include="..\..\..\src\launcher\launcher.c" />
<ClCompile Include="..\..\..\src\launcher\ptrans.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\winfsp_dll.vcxproj"> <ProjectReference Include="..\winfsp_dll.vcxproj">

View File

@ -16,6 +16,9 @@
<ClCompile Include="..\..\..\src\launcher\launcher.c"> <ClCompile Include="..\..\..\src\launcher\launcher.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\launcher\ptrans.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\src\shared\minimal.h"> <ClInclude Include="..\..\..\src\shared\minimal.h">

View File

@ -13,12 +13,12 @@
<MyProductName>WinFsp</MyProductName> <MyProductName>WinFsp</MyProductName>
<MyDescription>Windows File System Proxy</MyDescription> <MyDescription>Windows File System Proxy</MyDescription>
<MyCompanyName>Navimatics Corporation</MyCompanyName> <MyCompanyName>Navimatics LLC</MyCompanyName>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright> <MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<MyCanonicalVersion>1.5</MyCanonicalVersion> <MyCanonicalVersion>1.5</MyCanonicalVersion>
<MyProductVersion>2019.3 B1</MyProductVersion> <MyProductVersion>2019.3 B3</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Beta</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
@ -37,4 +37,17 @@
<PreprocessorDefinitions>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion)</PreprocessorDefinitions> <PreprocessorDefinitions>MyProductName=$(MyProductName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion)</PreprocessorDefinitions>
</ResourceCompile> </ResourceCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(DefaultPlatformToolset)'=='v140'">
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(DefaultPlatformToolset)'!='v140'">
<Link>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<PropertyGroup>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
</Project> </Project>

View File

@ -35,6 +35,7 @@
<ClInclude Include="..\..\src\dll\fuse3\library.h" /> <ClInclude Include="..\..\src\dll\fuse3\library.h" />
<ClInclude Include="..\..\src\dll\fuse\library.h" /> <ClInclude Include="..\..\src\dll\fuse\library.h" />
<ClInclude Include="..\..\src\dll\library.h" /> <ClInclude Include="..\..\src\dll\library.h" />
<ClInclude Include="..\..\src\ku\library.h" />
<ClInclude Include="..\..\src\shared\minimal.h" /> <ClInclude Include="..\..\src\shared\minimal.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -50,8 +51,8 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" /> <ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
<ClCompile Include="..\..\src\dll\launch.c" /> <ClCompile Include="..\..\src\dll\launch.c" />
<ClCompile Include="..\..\src\dll\mount.c" />
<ClCompile Include="..\..\src\dll\np.c" /> <ClCompile Include="..\..\src\dll\np.c" />
<ClCompile Include="..\..\src\dll\posix.c" />
<ClCompile Include="..\..\src\dll\security.c" /> <ClCompile Include="..\..\src\dll\security.c" />
<ClCompile Include="..\..\src\dll\debug.c" /> <ClCompile Include="..\..\src\dll\debug.c" />
<ClCompile Include="..\..\src\dll\fsctl.c" /> <ClCompile Include="..\..\src\dll\fsctl.c" />
@ -63,6 +64,7 @@
<ClCompile Include="..\..\src\dll\service.c" /> <ClCompile Include="..\..\src\dll\service.c" />
<ClCompile Include="..\..\src\dll\util.c" /> <ClCompile Include="..\..\src\dll\util.c" />
<ClCompile Include="..\..\src\dll\wksid.c" /> <ClCompile Include="..\..\src\dll\wksid.c" />
<ClCompile Include="..\..\src\ku\posix.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in"> <CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
@ -126,33 +128,33 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<ProjectGuid>{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}</ProjectGuid> <ProjectGuid>{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>winfspdll</RootNamespace> <RootNamespace>winfspdll</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
<ProjectName>winfsp.dll</ProjectName> <ProjectName>winfsp.dll</ProjectName>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -216,7 +218,6 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
@ -244,7 +245,6 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
@ -273,7 +273,6 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
@ -304,7 +303,6 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>

View File

@ -27,6 +27,9 @@
<Filter Include="Source\fuse3"> <Filter Include="Source\fuse3">
<UniqueIdentifier>{96091a7b-3923-4a74-9491-3ee230c688f9}</UniqueIdentifier> <UniqueIdentifier>{96091a7b-3923-4a74-9491-3ee230c688f9}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source\ku">
<UniqueIdentifier>{613cce77-2428-4f9a-9187-f37e009253c1}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\inc\winfsp\fsctl.h"> <ClInclude Include="..\..\inc\winfsp\fsctl.h">
@ -77,6 +80,9 @@
<ClInclude Include="..\..\src\dll\fuse3\library.h"> <ClInclude Include="..\..\src\dll\fuse3\library.h">
<Filter>Source\fuse3</Filter> <Filter>Source\fuse3</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ku\library.h">
<Filter>Source\ku</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\dll\library.c"> <ClCompile Include="..\..\src\dll\library.c">
@ -124,9 +130,6 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c"> <ClCompile Include="..\..\src\dll\fuse\fuse_main.c">
<Filter>Source\fuse</Filter> <Filter>Source\fuse</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\dll\posix.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c"> <ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
<Filter>Source\fuse</Filter> <Filter>Source\fuse</Filter>
</ClCompile> </ClCompile>
@ -154,6 +157,12 @@
<ClCompile Include="..\..\src\dll\fuse3\fuse3_compat.c"> <ClCompile Include="..\..\src\dll\fuse3\fuse3_compat.c">
<Filter>Source\fuse3</Filter> <Filter>Source\fuse3</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ku\posix.c">
<Filter>Source\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\mount.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\..\src\dll\library.def"> <None Include="..\..\src\dll\library.def">

View File

@ -101,11 +101,11 @@
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>..\..\src;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\src;..\..\opt\fsext\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions> _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions> _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
@ -114,11 +114,11 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>..\..\src;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\src;..\..\opt\fsext\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions> _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions> _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
@ -127,11 +127,11 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>..\..\src;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\src;..\..\opt\fsext\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions> _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions> _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
@ -140,11 +140,11 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>..\..\src;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\src;..\..\opt\fsext\inc;..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions> _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions> _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
@ -155,6 +155,8 @@
<FilesToPackage Include="$(TargetPath)" /> <FilesToPackage Include="$(TargetPath)" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\ku\posix.c" />
<ClCompile Include="..\..\src\ku\uuid5.c" />
<ClCompile Include="..\..\src\sys\cleanup.c" /> <ClCompile Include="..\..\src\sys\cleanup.c" />
<ClCompile Include="..\..\src\sys\close.c" /> <ClCompile Include="..\..\src\sys\close.c" />
<ClCompile Include="..\..\src\sys\create.c" /> <ClCompile Include="..\..\src\sys\create.c" />
@ -169,10 +171,12 @@
<ClCompile Include="..\..\src\sys\fileinfo.c" /> <ClCompile Include="..\..\src\sys\fileinfo.c" />
<ClCompile Include="..\..\src\sys\flush.c" /> <ClCompile Include="..\..\src\sys\flush.c" />
<ClCompile Include="..\..\src\sys\fsctl.c" /> <ClCompile Include="..\..\src\sys\fsctl.c" />
<ClCompile Include="..\..\src\sys\fsext.c" />
<ClCompile Include="..\..\src\sys\iop.c" /> <ClCompile Include="..\..\src\sys\iop.c" />
<ClCompile Include="..\..\src\sys\ioq.c" /> <ClCompile Include="..\..\src\sys\ioq.c" />
<ClCompile Include="..\..\src\sys\lockctl.c" /> <ClCompile Include="..\..\src\sys\lockctl.c" />
<ClCompile Include="..\..\src\sys\meta.c" /> <ClCompile Include="..\..\src\sys\meta.c" />
<ClCompile Include="..\..\src\sys\mountdev.c" />
<ClCompile Include="..\..\src\sys\mup.c" /> <ClCompile Include="..\..\src\sys\mup.c" />
<ClCompile Include="..\..\src\sys\name.c" /> <ClCompile Include="..\..\src\sys\name.c" />
<ClCompile Include="..\..\src\sys\psbuffer.c" /> <ClCompile Include="..\..\src\sys\psbuffer.c" />
@ -188,6 +192,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\inc\winfsp\fsctl.h" /> <ClInclude Include="..\..\inc\winfsp\fsctl.h" />
<ClInclude Include="..\..\opt\fsext\inc\winfsp\fsext.h" />
<ClInclude Include="..\..\src\ku\library.h" />
<ClInclude Include="..\..\src\sys\driver.h" /> <ClInclude Include="..\..\src\sys\driver.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -212,7 +218,7 @@ for /f "delims=" %%l in (%(FullPath)) do (
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
) )
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command> stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkObjects> <LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">set DriverFile=$(TargetFileName) <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)" set Provider="$(MyCompanyName)"
@ -225,7 +231,7 @@ for /f "delims=" %%l in (%(FullPath)) do (
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
) )
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command> stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkObjects> <LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">set DriverFile=$(TargetFileName) <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)" set Provider="$(MyCompanyName)"
@ -238,7 +244,7 @@ for /f "delims=" %%l in (%(FullPath)) do (
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
) )
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command> stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkObjects> <LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkObjects>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">set DriverFile=$(TargetFileName) <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)" set Provider="$(MyCompanyName)"
@ -251,7 +257,7 @@ for /f "delims=" %%l in (%(FullPath)) do (
echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf echo !line! &gt;&gt;$(OutDir)driver-$(PlatformTarget).inf
) )
stampinf -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command> stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(PlatformTarget).inf</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkObjects> <LinkObjects Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkObjects>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Writing driver-$(PlatformTarget).inf</Message> <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Writing driver-$(PlatformTarget).inf</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)driver-$(PlatformTarget).inf</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)driver-$(PlatformTarget).inf</Outputs>

View File

@ -12,6 +12,9 @@
<Filter Include="Include\winfsp"> <Filter Include="Include\winfsp">
<UniqueIdentifier>{904f0df1-2fb8-4f84-aa46-fa929488c39a}</UniqueIdentifier> <UniqueIdentifier>{904f0df1-2fb8-4f84-aa46-fa929488c39a}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source\ku">
<UniqueIdentifier>{235076b8-290c-4dec-b005-71d9b8e8cba7}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\sys\driver.c"> <ClCompile Include="..\..\src\sys\driver.c">
@ -104,6 +107,18 @@
<ClCompile Include="..\..\src\sys\mup.c"> <ClCompile Include="..\..\src\sys\mup.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\sys\fsext.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ku\posix.c">
<Filter>Source\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ku\uuid5.c">
<Filter>Source\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sys\mountdev.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h"> <ClInclude Include="..\..\src\sys\driver.h">
@ -112,6 +127,12 @@
<ClInclude Include="..\..\inc\winfsp\fsctl.h"> <ClInclude Include="..\..\inc\winfsp\fsctl.h">
<Filter>Include\winfsp</Filter> <Filter>Include\winfsp</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\opt\fsext\inc\winfsp\fsext.h">
<Filter>Include\winfsp</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ku\library.h">
<Filter>Source\ku</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="..\..\src\sys\version.rc"> <ResourceCompile Include="..\..\src\sys\version.rc">

View File

@ -18,10 +18,6 @@ Disconnecting (unmapping) a network drive does not work.::
Case-sensitive file systems do not work properly when mounted as a directory.:: Case-sensitive file systems do not work properly when mounted as a directory.::
This is fixed as of WinFsp 2018.2 B3. This is fixed as of WinFsp 2018.2 B3.
+
Windows and WinFsp support case-sensitive file systems. These file systems work properly when mounted as a drive. Unfortunately when a file system is mounted as a directory over NTFS, Windows expects it to be case-insensitive and will UPPERCASE many of the file names sent to the file system.
+
This is an unfortunate but well understood Windows limitation. Case-sensitive file systems should only be mounted as drives.
Why is the DLL not installed in the Windows system directories?:: Why is the DLL not installed in the Windows system directories?::
@ -68,5 +64,10 @@ With this in mind here are the reasons for the current WinFsp-FUSE behavior:
WinFsp-FUSE does not have the ability to support multiple file systems from within the same process. Why?:: WinFsp-FUSE does not have the ability to support multiple file systems from within the same process. Why?::
This is supported as of WinFsp 2018.2 B2. This is supported as of WinFsp 2018.2 B2.
I have problems getting permissions to work properly in a WinFsp-FUSE file system. Can you help?::
The WinFsp-FUSE layer includes a built-in command line option that can help: `-o uid=-1`. This instructs the WinFsp-FUSE layer to present all file system files as if they are owned by the user that launched the file system.
+ +
The core WinFsp layer always supported multiple file systems in the same process either simultaneously or one after another. However this was not the case with WinFsp-FUSE (i.e. the FUSE layer of WinFsp) prior to version 2018.2 B2. This limitation has been rectified as of WinFsp 2018.2 B2. Alternatives include `-o uid=-1,gid=-1`, which presents files as owned by the user *and* group that launched the file system and `-o uid=-1,gid=11`, which presents files as owned by the user that launched the file system and the group "Authenticated Users". (The `fsptool` utility in the `bin` subdirectory of the WinFsp installation directory can be used to convert Windows accounts/SID's to UID's and vice versa.)

View File

@ -5,6 +5,7 @@ This document contains a list of known file systems and file system libraries th
== File Systems == File Systems
- https://github.com/vgough/encfs[EncFS] - an Encrypted Filesystem for FUSE - 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/ihaveamac/fuse-3ds[fuse-3ds] - FUSE Filesystem Python scripts for Nintendo 3DS files
- https://github.com/FrKaram/KS2.Drive[KS2.Drive] - Mount a webDAV/AOS server as a local drive - 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/nfs-win[nfs-win] - NFS for Windows
@ -13,6 +14,7 @@ This document contains a list of known file systems and file system libraries th
- https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming - https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming
- https://github.com/netheril96/securefs[securefs] - Filesystem in userspace (FUSE) with transparent authenticated encryption - 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/billziss-gh/sshfs-win[sshfs-win] - SSHFS for Windows
- https://github.com/UtrechtUniversity/YodaDrive[YodaDrive] - Mount a Yoda drive as a local drive
== File System Libraries == File System Libraries
@ -20,3 +22,4 @@ This document contains a list of known file systems and file system libraries th
- 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/DuroSoft/fuse-bindings[Nodejs: fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
- https://github.com/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR) - https://github.com/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR)
- https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE - https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
- https://github.com/Scille/winfspy[Python: winfspy] - WinFSP binding for Python

View File

@ -54,6 +54,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_DECLSPEC_ALIGN __declspec(align(FSP_FSCTL_DEFAULT_ALIGNMENT)) #define FSP_FSCTL_DECLSPEC_ALIGN __declspec(align(FSP_FSCTL_DEFAULT_ALIGNMENT))
/* fsctl device codes */ /* fsctl device codes */
#define FSP_FSCTL_MOUNTDEV \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'M', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_VOLUME_NAME \ #define FSP_FSCTL_VOLUME_NAME \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, FILE_ANY_ACCESS) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_VOLUME_LIST \ #define FSP_FSCTL_VOLUME_LIST \
@ -65,6 +67,10 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_STOP \ #define FSP_FSCTL_STOP \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
/* 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_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams=" #define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR)) #define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
@ -83,7 +89,7 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024) #define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX #define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((T) & 0xffffffff)) #define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((UINT_PTR)((T) & 0xffffffff)))
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff)) #define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff))
#define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */ #define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */
@ -121,7 +127,7 @@ enum
{ {
FspFsctlTransactTimeoutMinimum = 1000, FspFsctlTransactTimeoutMinimum = 1000,
FspFsctlTransactTimeoutMaximum = 10000, FspFsctlTransactTimeoutMaximum = 10000,
FspFsctlTransactTimeoutDefault = 1000, FspFsctlTransactTimeoutDefault = 1000, /* DEPRECATED: default is unspecified */
FspFsctlIrpTimeoutMinimum = 60000, FspFsctlIrpTimeoutMinimum = 60000,
FspFsctlIrpTimeoutMaximum = 600000, FspFsctlIrpTimeoutMaximum = 600000,
FspFsctlIrpTimeoutDefault = 300000, FspFsctlIrpTimeoutDefault = 300000,
@ -139,7 +145,7 @@ enum
UINT64 VolumeCreationTime;\ UINT64 VolumeCreationTime;\
UINT32 VolumeSerialNumber;\ UINT32 VolumeSerialNumber;\
/* I/O timeouts, capacity, etc. */\ /* I/O timeouts, capacity, etc. */\
UINT32 TransactTimeout; /* FSP_FSCTL_TRANSACT timeout (millis; 1 sec - 10 sec) */\ UINT32 TransactTimeout; /* DEPRECATED: (millis; 1 sec - 10 sec) */\
UINT32 IrpTimeout; /* pending IRP timeout (millis; 1 min - 10 min) */\ UINT32 IrpTimeout; /* pending IRP timeout (millis; 1 min - 10 min) */\
UINT32 IrpCapacity; /* maximum number of pending IRP's (100 - 1000)*/\ UINT32 IrpCapacity; /* maximum number of pending IRP's (100 - 1000)*/\
UINT32 FileInfoTimeout; /* FileInfo/Security/VolumeInfo timeout (millis) */\ UINT32 FileInfoTimeout; /* FileInfo/Security/VolumeInfo timeout (millis) */\
@ -168,7 +174,8 @@ enum
/* additional kernel-mode flags */\ /* additional kernel-mode flags */\
UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\ UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\
UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\ UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\
UINT32 KmReservedFlags:6;\ UINT32 WslFeatures:1; /* support features required for WSLinux */\
UINT32 KmReservedFlags:5;\
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\ WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)]; WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\ #define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
@ -184,7 +191,8 @@ enum
UINT32 SecurityTimeout; /* security info timeout (millis); overrides FileInfoTimeout */\ UINT32 SecurityTimeout; /* security info timeout (millis); overrides FileInfoTimeout */\
UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\ UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\
UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */\ UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */\
UINT32 Reserved32[2];\ UINT32 FsextControlCode;\
UINT32 Reserved32[1];\
UINT64 Reserved64[2]; UINT64 Reserved64[2];
typedef struct typedef struct
{ {
@ -277,7 +285,7 @@ typedef struct
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */ UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
FSP_FSCTL_TRANSACT_BUF Ea; /* extended attributes buffer */ FSP_FSCTL_TRANSACT_BUF Ea; /* extended attributes or reparse point buffer */
UINT32 UserMode:1; /* request originated in user mode */ UINT32 UserMode:1; /* request originated in user mode */
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */ UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */ UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */
@ -286,6 +294,7 @@ typedef struct
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */ UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */ UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */
UINT32 AcceptsSecurityDescriptor:1; UINT32 AcceptsSecurityDescriptor:1;
UINT32 EaIsReparsePoint:1; /* Ea buffer is reparse point */
UINT32 ReservedFlags:24; UINT32 ReservedFlags:24;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */ UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create; } Create;
@ -586,11 +595,13 @@ static inline FSP_FSCTL_TRANSACT_RSP *FspFsctlTransactConsumeResponse(
return NextResponse <= ResponseBufEnd ? (FSP_FSCTL_TRANSACT_RSP *)NextResponse : 0; return NextResponse <= ResponseBufEnd ? (FSP_FSCTL_TRANSACT_RSP *)NextResponse : 0;
} }
#if !defined(WINFSP_SYS_INTERNAL) #if !defined(_KERNEL_MODE)
FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize, PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
PHANDLE PVolumeHandle); PHANDLE PVolumeHandle);
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle,
BOOLEAN Persistent, GUID *UniqueId);
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
PVOID ResponseBuf, SIZE_T ResponseBufSize, PVOID ResponseBuf, SIZE_T ResponseBufSize,
PVOID RequestBuf, SIZE_T *PRequestBufSize, PVOID RequestBuf, SIZE_T *PRequestBufSize,
@ -599,6 +610,20 @@ FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle);
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath, FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize); PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath); FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
typedef struct
{
/* in */
HANDLE VolumeHandle; /* volume handle returned by FspFsctlCreateVolume */
PWSTR VolumeName; /* volume name returned by FspFsctlCreateVolume */
PSECURITY_DESCRIPTOR Security; /* optional: security descriptor for directories */
UINT64 Reserved; /* reserved for future use */
/* in/out */
PWSTR MountPoint; /* FspMountSet sets drive in buffer when passed "*:" */
HANDLE MountHandle; /* FspMountSet sets, FspMountRemove uses */
} FSP_MOUNT_DESC;
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc);
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -912,7 +912,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
/** /**
* Create new file or directory. * Create new file or directory.
* *
* This function works like Create, except that it also accepts EA (extended attributes). * This function works like Create, except that it also accepts an extra buffer that
* may contain extended attributes or a reparse point.
* *
* NOTE: If both Create and CreateEx are defined, CreateEx takes precedence. * NOTE: If both Create and CreateEx are defined, CreateEx takes precedence.
* *
@ -941,10 +942,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* Windows GetSecurityDescriptorLength API. Will be NULL for named streams. * Windows GetSecurityDescriptorLength API. Will be NULL for named streams.
* @param AllocationSize * @param AllocationSize
* Allocation size for the newly created file. * Allocation size for the newly created file.
* @param Ea * @param ExtraBuffer
* Extended attributes buffer. * Extended attributes or reparse point buffer.
* @param EaLength * @param ExtraLength
* Extended attributes buffer length. * Extended attributes or reparse point buffer length.
* @param ExtraBufferIsReparsePoint
* FALSE: extra buffer is extended attributes; TRUE: extra buffer is reparse point.
* @param PFileContext [out] * @param PFileContext [out]
* Pointer that will receive the file context on successful return from this call. * Pointer that will receive the file context on successful return from this call.
* @param FileInfo [out] * @param FileInfo [out]
@ -956,7 +959,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*CreateEx)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*CreateEx)(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PVOID ExtraBuffer, ULONG ExtraLength, BOOLEAN ExtraBufferIsReparsePoint,
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo); PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo);
/** /**
* Overwrite a file. * Overwrite a file.

View File

@ -0,0 +1,93 @@
/**
* @file winfsp/fsext.h
*
* @copyright 2015-2019 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.
*/
#ifndef WINFSP_FSEXT_H_INCLUDED
#define WINFSP_FSEXT_H_INCLUDED
#if !defined(_KERNEL_MODE)
#error This file can only be included when compiling for kernel mode.
#endif
#include <winfsp/fsctl.h>
#if defined(WINFSP_SYS_INTERNAL)
#define FSP_DDI __declspec(dllexport)
#else
#define FSP_DDI __declspec(dllimport)
#endif
#if !defined(FSP_DDI_DEF)
#define FSP_DDI_DEF(RetType, Name, ...) FSP_DDI RetType NTAPI Name ( __VA_ARGS__ );
#endif
typedef struct
{
UINT32 Version;
/* in */
UINT32 DeviceTransactCode;
UINT32 DeviceExtensionSize;
NTSTATUS (*DeviceInit)(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_PARAMS *VolumeParams);
VOID (*DeviceFini)(PDEVICE_OBJECT DeviceObject);
VOID (*DeviceExpirationRoutine)(PDEVICE_OBJECT DeviceObject, UINT64 ExpirationTime);
NTSTATUS (*DeviceTransact)(PDEVICE_OBJECT DeviceObject, PIRP Irp);
/* out */
UINT32 DeviceExtensionOffset;
} FSP_FSEXT_PROVIDER;
FSP_DDI_DEF(NTSTATUS, FspFsextProviderRegister,
FSP_FSEXT_PROVIDER *Provider)
FSP_DDI_DEF(NTSTATUS, FspPosixMapUidToSid,
UINT32 Uid,
PSID *PSid)
FSP_DDI_DEF(NTSTATUS, FspPosixMapSidToUid,
PSID Sid,
PUINT32 PUid)
FSP_DDI_DEF(VOID, FspDeleteSid,
PSID Sid,
NTSTATUS (*CreateFunc)())
FSP_DDI_DEF(NTSTATUS, FspPosixMapPermissionsToSecurityDescriptor,
UINT32 Uid,
UINT32 Gid,
UINT32 Mode,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
FSP_DDI_DEF(NTSTATUS, FspPosixMapSecurityDescriptorToPermissions,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PUINT32 PUid,
PUINT32 PGid,
PUINT32 PMode)
FSP_DDI_DEF(NTSTATUS, FspPosixMapWindowsToPosixPathEx,
PWSTR WindowsPath,
char **PPosixPath,
BOOLEAN Translate)
FSP_DDI_DEF(NTSTATUS, FspPosixMapPosixToWindowsPathEx,
const char *PosixPath,
PWSTR *PWindowsPath,
BOOLEAN Translate)
FSP_DDI_DEF(VOID, FspPosixDeletePath,
void *Path)
FSP_DDI_DEF(VOID, FspPosixEncodeWindowsPath,
PWSTR WindowsPath,
ULONG Size)
FSP_DDI_DEF(VOID, FspPosixDecodeWindowsPath,
PWSTR WindowsPath,
ULONG Size)
#endif

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
// tools\impdef.bat lib\winfsp.impdef lib\winfsp-x64.lib
// tools\impdef.bat lib\winfsp.impdef lib\winfsp-x86.lib
#define FSP_DDI_DEF(RetType, Name, ...) __declspec(dllexport) RetType NTAPI Name ( __VA_ARGS__ ) {}
#include <ntifs.h>
#include <winfsp/fsext.h>

View File

@ -24,41 +24,19 @@
enum enum
{ {
FspFileSystemDispatcherThreadCountMin = 2, FspFileSystemDispatcherThreadCountMin = 2,
FspFileSystemDispatcherDefaultThreadCountMin = 4,
FspFileSystemDispatcherDefaultThreadCountMax = 16,
}; };
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface; static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT; static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
static DWORD FspFileSystemTlsKey = TLS_OUT_OF_INDEXES; static DWORD FspFileSystemTlsKey = TLS_OUT_OF_INDEXES;
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
HANDLE Handle);
static NTSTATUS (NTAPI *FspNtClose)(
HANDLE Handle);
static BOOL WINAPI FspFileSystemInitialize( static BOOL WINAPI FspFileSystemInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{ {
HANDLE Handle;
FspFileSystemTlsKey = TlsAlloc(); FspFileSystemTlsKey = TlsAlloc();
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
{
FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject");
FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose)
{
FspNtOpenSymbolicLinkObject = 0;
FspNtMakeTemporaryObject = 0;
FspNtClose = 0;
}
}
return TRUE; return TRUE;
} }
@ -91,7 +69,9 @@ FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
else else
{ {
if (FspPathIsDrive(MountPoint)) if (FspPathIsMountmgrMountPoint(MountPoint))
Result = STATUS_SUCCESS; /* cannot check with the mount manager, assume success */
else if (FspPathIsDrive(MountPoint))
Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ? Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ?
STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS; STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS;
else else
@ -194,205 +174,6 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
MemFree(FileSystem); MemFree(FileSystem);
} }
static NTSTATUS FspFileSystemLauncherDefineDosDevice(
WCHAR Sign, PWSTR MountPoint, PWSTR VolumeName)
{
if (2 != lstrlenW(MountPoint) ||
FSP_FSCTL_VOLUME_NAME_SIZEMAX / sizeof(WCHAR) <= lstrlenW(VolumeName))
return STATUS_INVALID_PARAMETER;
WCHAR Argv0[4];
PWSTR Argv[2];
NTSTATUS Result;
ULONG ErrorCode;
Argv0[0] = Sign;
Argv0[1] = MountPoint[0];
Argv0[2] = MountPoint[1];
Argv0[3] = L'\0';
Argv[0] = Argv0;
Argv[1] = VolumeName;
Result = FspLaunchCallLauncherPipe(FspLaunchCmdDefineDosDevice, 2, Argv, 0, 0, 0, &ErrorCode);
return !NT_SUCCESS(Result) ? Result : FspNtStatusFromWin32(ErrorCode);
}
static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName,
PHANDLE PMountHandle)
{
NTSTATUS Result;
BOOLEAN IsLocalSystem, IsServiceContext;
*PMountHandle = 0;
Result = FspServiceContextCheck(0, &IsLocalSystem);
IsServiceContext = NT_SUCCESS(Result) && !IsLocalSystem;
if (IsServiceContext)
{
/*
* If the current process is in the service context but not LocalSystem,
* ask the launcher to DefineDosDevice for us. This is because the launcher
* runs in the LocalSystem context and can create global drives.
*
* In this case the launcher will also add DELETE access to the drive symlink
* for us, so that we can make it temporary below.
*/
Result = FspFileSystemLauncherDefineDosDevice(L'+', MountPoint, VolumeName);
if (!NT_SUCCESS(Result))
return Result;
}
else
{
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
return FspNtStatusFromWin32(GetLastError());
}
if (0 != FspNtOpenSymbolicLinkObject)
{
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(PMountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(*PMountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(*PMountHandle);
*PMountHandle = 0;
}
}
}
/* HACK:
*
* Handles do not use the low 2 bits (unless they are console handles).
* Abuse this fact to remember that we are running in the service context.
*/
*PMountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)*PMountHandle | IsServiceContext);
return STATUS_SUCCESS;
}
static NTSTATUS FspFileSystemSetMountPoint_Directory(PWSTR MountPoint, PWSTR VolumeName,
PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle)
{
NTSTATUS Result;
SECURITY_ATTRIBUTES SecurityAttributes;
HANDLE MountHandle = INVALID_HANDLE_VALUE;
DWORD Backslashes, Bytes;
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR P, PathBuffer;
*PMountHandle = 0;
/*
* Windows does not allow mount points (junctions) to point to network file systems.
*
* Count how many backslashes our VolumeName has. If it is 3 or more this is a network
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
*/
for (P = VolumeName, Backslashes = 0; *P; P++)
if (L'\\' == *P)
if (3 == ++Backslashes)
{
Result = STATUS_NETWORK_ACCESS_DENIED;
goto exit;
}
memset(&SecurityAttributes, 0, sizeof SecurityAttributes);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
MountHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&SecurityAttributes,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
VolumeNameLength *= sizeof(WCHAR);
BackslashLength *= sizeof(WCHAR);
ReparseDataLength = (USHORT)(
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer)) +
2 * (VolumeNameLength + BackslashLength + sizeof(WCHAR));
ReparseData = MemAlloc(REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength);
if (0 == ReparseData)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
ReparseData->ReparseDataLength = ReparseDataLength;
ReparseData->Reserved = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameOffset = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameLength =
VolumeNameLength + BackslashLength;
ReparseData->MountPointReparseBuffer.PrintNameOffset =
ReparseData->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
ReparseData->MountPointReparseBuffer.PrintNameLength =
VolumeNameLength + BackslashLength;
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer;
memcpy(PathBuffer, VolumeName, VolumeNameLength);
if (BackslashLength)
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer +
(ReparseData->MountPointReparseBuffer.PrintNameOffset) / sizeof(WCHAR);
memcpy(PathBuffer, VolumeName, VolumeNameLength);
if (BackslashLength)
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0,
&Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
*PMountHandle = MountHandle;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
CloseHandle(MountHandle);
MemFree(ReparseData);
return Result;
}
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint) FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
{ {
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0); return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
@ -404,105 +185,55 @@ FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR
if (0 != FileSystem->MountPoint) if (0 != FileSystem->MountPoint)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
FSP_MOUNT_DESC Desc;
int Size;
NTSTATUS Result; NTSTATUS Result;
HANDLE MountHandle = 0;
memset(&Desc, 0, sizeof Desc);
Desc.VolumeHandle = FileSystem->VolumeHandle;
Desc.VolumeName = FileSystem->VolumeName;
Desc.Security = SecurityDescriptor;
if (0 == MountPoint) if (0 == MountPoint)
MountPoint = L"*:";
Size = (lstrlenW(MountPoint) + 1) * sizeof(WCHAR);
Desc.MountPoint = MemAlloc(Size);
if (0 == Desc.MountPoint)
{ {
DWORD Drives; Result = STATUS_INSUFFICIENT_RESOURCES;
WCHAR Drive; goto exit;
MountPoint = MemAlloc(3 * sizeof(WCHAR));
if (0 == MountPoint)
return STATUS_INSUFFICIENT_RESOURCES;
MountPoint[1] = L':';
MountPoint[2] = L'\0';
Drives = GetLogicalDrives();
if (0 != Drives)
{
for (Drive = 'Z'; 'D' <= Drive; Drive--)
if (0 == (Drives & (1 << (Drive - 'A'))))
{
MountPoint[0] = Drive;
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
&MountHandle);
if (NT_SUCCESS(Result))
goto exit;
}
Result = STATUS_NO_SUCH_DEVICE;
}
else
Result = FspNtStatusFromWin32(GetLastError());
} }
else memcpy(Desc.MountPoint, MountPoint, Size);
{
PWSTR P;
ULONG L;
L = (ULONG)((lstrlenW(MountPoint) + 1) * sizeof(WCHAR)); Result = FspMountSet(&Desc);
P = MemAlloc(L);
if (0 == P)
return STATUS_INSUFFICIENT_RESOURCES;
memcpy(P, MountPoint, L);
MountPoint = P;
if (FspPathIsDrive(MountPoint))
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
&MountHandle);
else
Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
SecurityDescriptor, &MountHandle);
}
exit: exit:
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
FileSystem->MountPoint = MountPoint; FileSystem->MountPoint = Desc.MountPoint;
FileSystem->MountHandle = MountHandle; FileSystem->MountHandle = Desc.MountHandle;
} }
else else
MemFree(MountPoint); MemFree(Desc.MountPoint);
return Result; return Result;
} }
static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle)
{
BOOLEAN IsServiceContext = 0 != ((DWORD)(UINT_PTR)MountHandle & 1);
MountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)MountHandle & ~1);
if (IsServiceContext)
/*
* If the current process is in the service context but not LocalSystem,
* ask the launcher to DefineDosDevice for us. This is because the launcher
* runs in the LocalSystem context and can remove global drives.
*/
FspFileSystemLauncherDefineDosDevice(L'-', MountPoint, VolumeName);
else
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
MountPoint, VolumeName);
if (0 != MountHandle)
FspNtClose(MountHandle);
}
static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle)
{
/* directory is marked DELETE_ON_CLOSE */
CloseHandle(MountHandle);
}
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem) FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
{ {
if (0 == FileSystem->MountPoint) if (0 == FileSystem->MountPoint)
return; return;
if (FspPathIsDrive(FileSystem->MountPoint)) FSP_MOUNT_DESC Desc;
FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
FileSystem->MountHandle); memset(&Desc, 0, sizeof Desc);
else Desc.VolumeHandle = FileSystem->VolumeHandle;
FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle); Desc.VolumeName = FileSystem->VolumeName;
Desc.MountPoint = FileSystem->MountPoint;
Desc.MountHandle = FileSystem->MountHandle;
FspMountRemove(&Desc);
MemFree(FileSystem->MountPoint); MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0; FileSystem->MountPoint = 0;
@ -636,6 +367,11 @@ FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG
for (ThreadCount = 0; 0 != ProcessMask; ProcessMask >>= 1) for (ThreadCount = 0; 0 != ProcessMask; ProcessMask >>= 1)
ThreadCount += ProcessMask & 1; ThreadCount += ProcessMask & 1;
if (ThreadCount < FspFileSystemDispatcherDefaultThreadCountMin)
ThreadCount = FspFileSystemDispatcherDefaultThreadCountMin;
else if (ThreadCount > FspFileSystemDispatcherDefaultThreadCountMax)
ThreadCount = FspFileSystemDispatcherDefaultThreadCountMax;
} }
if (ThreadCount < FspFileSystemDispatcherThreadCountMin) if (ThreadCount < FspFileSystemDispatcherThreadCountMin)

View File

@ -107,6 +107,20 @@ exit:
return Result; return Result;
} }
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle,
BOOLEAN Persistent, GUID *UniqueId)
{
DWORD Bytes;
if (!DeviceIoControl(VolumeHandle,
FSP_FSCTL_MOUNTDEV,
&Persistent, sizeof Persistent, UniqueId, sizeof *UniqueId,
&Bytes, 0))
return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS;
}
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
PVOID ResponseBuf, SIZE_T ResponseBufSize, PVOID ResponseBuf, SIZE_T ResponseBufSize,
PVOID RequestBuf, SIZE_T *PRequestBufSize, PVOID RequestBuf, SIZE_T *PRequestBufSize,

View File

@ -443,6 +443,7 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
0 != Request->Req.Create.Ea.Size ? 0 != Request->Req.Create.Ea.Size ?
(PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0, (PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0,
Request->Req.Create.Ea.Size, Request->Req.Create.Ea.Size,
Request->Req.Create.EaIsReparsePoint,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo); AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
else else
Result = FileSystem->Interface->Create(FileSystem, Result = FileSystem->Interface->Create(FileSystem,
@ -590,6 +591,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
0 != Request->Req.Create.Ea.Size ? 0 != Request->Req.Create.Ea.Size ?
(PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0, (PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0,
Request->Req.Create.Ea.Size, Request->Req.Create.Ea.Size,
Request->Req.Create.EaIsReparsePoint,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo); AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
else else
Result = FileSystem->Interface->Create(FileSystem, Result = FileSystem->Interface->Create(FileSystem,
@ -724,6 +726,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
0 != Request->Req.Create.Ea.Size ? 0 != Request->Req.Create.Ea.Size ?
(PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0, (PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0,
Request->Req.Create.Ea.Size, Request->Req.Create.Ea.Size,
Request->Req.Create.EaIsReparsePoint,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo); AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
else else
Result = FileSystem->Interface->Create(FileSystem, Result = FileSystem->Interface->Create(FileSystem,

View File

@ -54,6 +54,10 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("umask=%o", umask, 0), FSP_FUSE_CORE_OPT("umask=%o", umask, 0),
FSP_FUSE_CORE_OPT("create_umask=", set_create_umask, 1), FSP_FUSE_CORE_OPT("create_umask=", set_create_umask, 1),
FSP_FUSE_CORE_OPT("create_umask=%o", create_umask, 0), FSP_FUSE_CORE_OPT("create_umask=%o", create_umask, 0),
FSP_FUSE_CORE_OPT("create_file_umask=", set_create_file_umask, 1),
FSP_FUSE_CORE_OPT("create_file_umask=%o", create_file_umask, 0),
FSP_FUSE_CORE_OPT("create_dir_umask=", set_create_dir_umask, 1),
FSP_FUSE_CORE_OPT("create_dir_umask=%o", create_dir_umask, 0),
FSP_FUSE_CORE_OPT("uid=", set_uid, 1), FSP_FUSE_CORE_OPT("uid=", set_uid, 1),
FSP_FUSE_CORE_OPT("uid=%d", uid, 0), FSP_FUSE_CORE_OPT("uid=%d", uid, 0),
FSP_FUSE_CORE_OPT("gid=", set_gid, 1), FSP_FUSE_CORE_OPT("gid=", set_gid, 1),
@ -71,6 +75,9 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("rellinks", rellinks, 1), FSP_FUSE_CORE_OPT("rellinks", rellinks, 1),
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0), FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
FSP_FUSE_CORE_OPT("dothidden", dothidden, 1),
FSP_FUSE_CORE_OPT("nodothidden", dothidden, 0),
FUSE_OPT_KEY("fstypename=", 'F'), FUSE_OPT_KEY("fstypename=", 'F'),
FUSE_OPT_KEY("volname=", 'v'), FUSE_OPT_KEY("volname=", 'v'),
@ -95,6 +102,17 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FUSE_OPT_KEY("--VolumePrefix=", 'U'), FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("FileSystemName=", 'F'), FUSE_OPT_KEY("FileSystemName=", 'F'),
FUSE_OPT_KEY("--FileSystemName=", 'F'), FUSE_OPT_KEY("--FileSystemName=", 'F'),
FUSE_OPT_KEY("ExactFileSystemName=", 'E'),
FUSE_OPT_KEY("--ExactFileSystemName=", 'E'),
FSP_FUSE_CORE_OPT("UserName=", set_uid, 1),
FUSE_OPT_KEY("UserName=", 'u'),
FSP_FUSE_CORE_OPT("--UserName=", set_uid, 1),
FUSE_OPT_KEY("--UserName=", 'u'),
FSP_FUSE_CORE_OPT("GroupName=", set_gid, 1),
FUSE_OPT_KEY("GroupName=", 'g'),
FSP_FUSE_CORE_OPT("--GroupName=", set_gid, 1),
FUSE_OPT_KEY("--GroupName=", 'g'),
FUSE_OPT_END, FUSE_OPT_END,
}; };
@ -226,6 +244,43 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
return fsp_fuse_opt_match(env, fsp_fuse_core_opts, opt); return fsp_fuse_opt_match(env, fsp_fuse_core_opts, opt);
} }
static int fsp_fuse_username_to_uid(const char *username, int *puid)
{
union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} SidBuf;
char Name[256], Domn[256];
DWORD SidSize, NameSize, DomnSize;
SID_NAME_USE Use;
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 = '\\';
SidSize = sizeof SidBuf;
DomnSize = sizeof Domn / sizeof Domn[0];
if (!LookupAccountNameA(0, Name, &SidBuf, &SidSize, Domn, &DomnSize, &Use))
return -1;
Result = FspPosixMapSidToUid(&SidBuf, &Uid);
if (!NT_SUCCESS(Result))
return -1;
*puid = Uid;
return 0;
}
static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key, static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
struct fuse_args *outargs) struct fuse_args *outargs)
{ {
@ -241,9 +296,12 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
FSP_FUSE_LIBRARY_NAME " options:\n" FSP_FUSE_LIBRARY_NAME " options:\n"
" -o umask=MASK set file permissions (octal)\n" " -o umask=MASK set file permissions (octal)\n"
" -o create_umask=MASK set newly created file permissions (octal)\n" " -o create_umask=MASK set newly created file permissions (octal)\n"
" -o create_file_umask=MASK for files only\n"
" -o create_dir_umask=MASK for directories only\n"
" -o uid=N set file owner (-1 for mounting user id)\n" " -o uid=N set file owner (-1 for mounting user id)\n"
" -o gid=N set file group (-1 for mounting user group)\n" " -o gid=N set file group (-1 for mounting user group)\n"
" -o rellinks interpret absolute symlinks as volume relative\n" " -o rellinks interpret absolute symlinks as volume relative\n"
" -o dothidden dot files have the Windows hidden file attrib\n"
" -o volname=NAME set volume label\n" " -o volname=NAME set volume label\n"
" -o VolumePrefix=UNC set UNC prefix (/Server/Share)\n" " -o VolumePrefix=UNC set UNC prefix (/Server/Share)\n"
" --VolumePrefix=UNC set UNC prefix (\\Server\\Share)\n" " --VolumePrefix=UNC set UNC prefix (\\Server\\Share)\n"
@ -311,6 +369,40 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0'; [sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR)); memcpy(opt_data->VolumeParams.FileSystemName, L"FUSE-", 5 * sizeof(WCHAR));
return 0; return 0;
case 'E':
if ('E' == arg[0])
arg += sizeof "ExactFileSystemName=" - 1;
else if ('E' == arg[2])
arg += sizeof "--ExactFileSystemName=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.FileSystemName,
sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR)))
return -1;
opt_data->VolumeParams.FileSystemName
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
return 0;
case 'u':
if ('U' == arg[0])
arg += sizeof "UserName=" - 1;
else if ('U' == arg[2])
arg += sizeof "--UserName=" - 1;
if (-1 == fsp_fuse_username_to_uid(arg, &opt_data->uid))
{
opt_data->username_to_uid_result = -1;
return -1;
}
return 0;
case 'g':
if ('G' == arg[0])
arg += sizeof "GroupName=" - 1;
else if ('G' == arg[2])
arg += sizeof "--GroupName=" - 1;
if (-1 == fsp_fuse_username_to_uid(arg, &opt_data->gid))
{
opt_data->username_to_uid_result = -1;
return -1;
}
return 0;
case 'v': case 'v':
arg += sizeof "volname=" - 1; arg += sizeof "volname=" - 1;
opt_data->VolumeLabelLength = (UINT16)(sizeof(WCHAR) * opt_data->VolumeLabelLength = (UINT16)(sizeof(WCHAR) *
@ -355,7 +447,14 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
opt_data.VolumeParams.FlushAndPurgeOnCleanup = TRUE; opt_data.VolumeParams.FlushAndPurgeOnCleanup = TRUE;
if (-1 == fsp_fuse_core_opt_parse(env, args, &opt_data, /*help=*/1)) if (-1 == fsp_fuse_core_opt_parse(env, args, &opt_data, /*help=*/1))
{
if (-1 == opt_data.username_to_uid_result)
{
ErrorMessage = L": invalid user or group name.";
goto fail;
}
return 0; return 0;
}
if (opt_data.help) if (opt_data.help)
return 0; return 0;
@ -422,9 +521,12 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
f->env = env; f->env = env;
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask; f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
f->set_create_umask = opt_data.set_create_umask; f->create_umask = opt_data.create_umask; f->set_create_umask = opt_data.set_create_umask; f->create_umask = opt_data.create_umask;
f->set_create_file_umask = opt_data.set_create_file_umask; f->create_file_umask = opt_data.create_file_umask;
f->set_create_dir_umask = opt_data.set_create_dir_umask; f->create_dir_umask = opt_data.create_dir_umask;
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid; f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid; f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
f->rellinks = opt_data.rellinks; f->rellinks = opt_data.rellinks;
f->dothidden = opt_data.dothidden;
f->ThreadCount = opt_data.ThreadCount; f->ThreadCount = opt_data.ThreadCount;
memcpy(&f->ops, ops, opsize); memcpy(&f->ops, ops, opsize);
f->data = data; f->data = data;

View File

@ -354,6 +354,7 @@ static inline UINT32 fsp_fuse_intf_MapFlagsToFileAttributes(uint32_t flags)
return FileAttributes; return FileAttributes;
} }
#define FUSE_FILE_INFO(IsDirectory, fi) ((IsDirectory) ? 0 : (fi))
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\ #define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo) fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
@ -429,6 +430,15 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
} }
if (StatEx) if (StatEx)
FileInfo->FileAttributes |= fsp_fuse_intf_MapFlagsToFileAttributes(stbuf.st_flags); FileInfo->FileAttributes |= fsp_fuse_intf_MapFlagsToFileAttributes(stbuf.st_flags);
if (f->dothidden)
{
const char *basename = PosixPath;
for (const char *p = PosixPath; '\0' != *p; p++)
if ('/' == *p)
basename = p + 1;
if ('.' == basename[0])
FileInfo->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
}
FileInfo->FileSize = stbuf.st_size; FileInfo->FileSize = stbuf.st_size;
FileInfo->AllocationSize = FileInfo->AllocationSize =
(FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; (FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
@ -743,7 +753,7 @@ exit:
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PVOID ExtraBuffer, ULONG ExtraLength, BOOLEAN ExtraBufferIsReparsePoint,
PVOID *PFileDesc, FSP_FSCTL_FILE_INFO *FileInfo) PVOID *PFileDesc, FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
@ -757,12 +767,21 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
int err; int err;
NTSTATUS Result; NTSTATUS Result;
if (0 != Ea) if (0 != ExtraBuffer)
{ {
if (0 == f->ops.listxattr || 0 == f->ops.getxattr || if (!ExtraBufferIsReparsePoint)
0 == f->ops.setxattr || 0 == f->ops.removexattr)
{ {
Result = STATUS_EAS_NOT_SUPPORTED; if (0 == f->ops.listxattr || 0 == f->ops.getxattr ||
0 == f->ops.setxattr || 0 == f->ops.removexattr)
{
Result = STATUS_EAS_NOT_SUPPORTED;
goto exit;
}
}
else
{
/* !!!: revisit */
Result = STATUS_INVALID_PARAMETER;
goto exit; goto exit;
} }
} }
@ -785,8 +804,22 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
goto exit; goto exit;
} }
Mode &= ~context->umask; Mode &= ~context->umask;
if (f->set_create_umask) if (CreateOptions & FILE_DIRECTORY_FILE)
Mode = 0777 & ~f->create_umask; {
if (f->set_create_dir_umask)
Mode = 0777 & ~f->create_dir_umask;
else
if (f->set_create_umask)
Mode = 0777 & ~f->create_umask;
}
else
{
if (f->set_create_file_umask)
Mode = 0777 & ~f->create_file_umask;
else
if (f->set_create_umask)
Mode = 0777 & ~f->create_umask;
}
memset(&fi, 0, sizeof fi); memset(&fi, 0, sizeof fi);
if ('C' == f->env->environment) /* Cygwin */ if ('C' == f->env->environment) /* Cygwin */
@ -866,12 +899,21 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
goto exit; goto exit;
} }
if (0 != Ea) if (0 != ExtraBuffer)
{ {
Result = FspFileSystemEnumerateEa(FileSystem, if (!ExtraBufferIsReparsePoint)
fsp_fuse_intf_SetEaEntry, contexthdr->PosixPath, Ea, EaLength); {
if (!NT_SUCCESS(Result)) Result = FspFileSystemEnumerateEa(FileSystem,
fsp_fuse_intf_SetEaEntry, contexthdr->PosixPath, ExtraBuffer, ExtraLength);
if (!NT_SUCCESS(Result))
goto exit;
}
else
{
/* !!!: revisit: WslFeatures, GetFileInfoFunnel, GetReparsePointEx, SetReparsePoint */
Result = STATUS_INVALID_PARAMETER;
goto exit; goto exit;
}
} }
/* /*
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache. * Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
@ -881,7 +923,8 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
* Ignore fuse_file_info::nonseekable. * Ignore fuse_file_info::nonseekable.
*/ */
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, contexthdr->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, contexthdr->PosixPath,
FUSE_FILE_INFO(CreateOptions & FILE_DIRECTORY_FILE, &fi),
&Uid, &Gid, &Mode, &FileInfoBuf); &Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
@ -983,6 +1026,20 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
} }
else else
{ {
/*
* Some Windows applications (notably Go programs) specify FILE_APPEND_DATA without
* FILE_WRITE_DATA when opening files for appending. This caused the WinFsp-FUSE layer
* to erroneously pass O_RDONLY to the FUSE file system in such cases. We add a test
* for FILE_APPEND_DATA to ensure that either O_WRONLY or O_RDWR is specified and that
* the O_APPEND flag is set.
*/
if (GrantedAccess & FILE_APPEND_DATA)
{
if (fi.flags == 0)
fi.flags = 1; /* need O_WRONLY as a bare minimum in order to append */
fi.flags |= 8/*O_APPEND*/;
}
if (0 != f->ops.open) if (0 != f->ops.open)
{ {
err = f->ops.open(contexthdr->PosixPath, &fi); err = f->ops.open(contexthdr->PosixPath, &fi);
@ -1096,7 +1153,8 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
return Result; return Result;
} }
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, FileInfo); &Uid, &Gid, &Mode, FileInfo);
} }
@ -1227,7 +1285,8 @@ static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, &FileInfoBuf); &Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -1307,7 +1366,8 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, &FileInfoBuf); &Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -1330,7 +1390,8 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, FileInfo); &Uid, &Gid, &Mode, FileInfo);
} }
@ -1368,7 +1429,8 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
{ {
if (0 == LastAccessTime || 0 == LastWriteTime) if (0 == LastAccessTime || 0 == LastWriteTime)
{ {
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, &FileInfoBuf); &Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -1415,7 +1477,8 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
return Result; return Result;
} }
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, FileInfo); &Uid, &Gid, &Mode, FileInfo);
} }
@ -1442,7 +1505,8 @@ static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, &FileInfoBuf); &Uid, &Gid, &Mode, &FileInfoBuf);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -1589,7 +1653,8 @@ static NTSTATUS fsp_fuse_intf_GetSecurity(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
return fsp_fuse_intf_GetSecurityEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetSecurityEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&FileAttributes, SecurityDescriptorBuf, PSecurityDescriptorSize); &FileAttributes, SecurityDescriptorBuf, PSecurityDescriptorSize);
} }
@ -1613,8 +1678,9 @@ static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, &Uid, &Gid, &Mode, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
&FileInfo); FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, &FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
@ -1712,7 +1778,7 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
UINT32 Uid, Gid, Mode; UINT32 Uid, Gid, Mode;
NTSTATUS Result0; NTSTATUS Result0;
Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, 0, 0, stbuf, Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, name, 0, stbuf,
&Uid, &Gid, &Mode, 0, &DirInfo->FileInfo); &Uid, &Gid, &Mode, 0, &DirInfo->FileInfo);
if (NT_SUCCESS(Result0)) if (NT_SUCCESS(Result0))
DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */ DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */
@ -1972,7 +2038,9 @@ static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
return fsp_fuse_intf_GetReparsePointEx(FileSystem, filedesc->PosixPath, &fi, Buffer, PSize); return fsp_fuse_intf_GetReparsePointEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
Buffer, PSize);
} }
static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
@ -2043,7 +2111,8 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, &FileInfo); &Uid, &Gid, &Mode, &FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -2316,7 +2385,8 @@ static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem,
fi.flags = filedesc->OpenFlags; fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle; fi.fh = filedesc->FileHandle;
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath,
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
&Uid, &Gid, &Mode, FileInfo); &Uid, &Gid, &Mode, FileInfo);
} }

View File

@ -216,11 +216,13 @@ static int fsp_fuse_opt_call_proc(struct fsp_fuse_env *env,
goto exit; goto exit;
} }
result = 0;
exit: exit:
if (0 != fullarg) if (0 != fullarg)
env->memfree(fullarg); env->memfree(fullarg);
return 0; return result;
} }
static int fsp_fuse_opt_process_arg(struct fsp_fuse_env *env, static int fsp_fuse_opt_process_arg(struct fsp_fuse_env *env,

View File

@ -50,9 +50,12 @@ struct fuse
struct fsp_fuse_env *env; struct fsp_fuse_env *env;
int set_umask, umask; int set_umask, umask;
int set_create_umask, create_umask; int set_create_umask, create_umask;
int set_create_file_umask, create_file_umask;
int set_create_dir_umask, create_dir_umask;
int set_uid, uid; int set_uid, uid;
int set_gid, gid; int set_gid, gid;
int rellinks; int rellinks;
int dothidden;
unsigned ThreadCount; unsigned ThreadCount;
struct fuse_operations ops; struct fuse_operations ops;
void *data; void *data;
@ -137,10 +140,13 @@ struct fsp_fuse_core_opt_data
HANDLE DebugLogHandle; HANDLE DebugLogHandle;
int set_umask, umask, int set_umask, umask,
set_create_umask, create_umask, set_create_umask, create_umask,
set_uid, uid, set_create_file_umask, create_file_umask,
set_create_dir_umask, create_dir_umask,
set_uid, uid, username_to_uid_result,
set_gid, gid, set_gid, gid,
set_attr_timeout, attr_timeout, set_attr_timeout, attr_timeout,
rellinks; rellinks,
dothidden;
int set_FileInfoTimeout, int set_FileInfoTimeout,
set_DirInfoTimeout, set_DirInfoTimeout,
set_EaTimeout, set_EaTimeout,

View File

@ -91,6 +91,21 @@ static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
) && ) &&
L':' == FileName[1] && L'\0' == FileName[2]; L':' == FileName[1] && L'\0' == FileName[2];
} }
static inline BOOLEAN FspPathIsMountmgrMountPoint(PWSTR FileName)
{
return
(
L'\\' == FileName[0] &&
L'\\' == FileName[1] &&
(L'?' == FileName[2] || L'.' == FileName[2]) &&
L'\\' == FileName[3]
) &&
(
(L'A' <= FileName[4] && FileName[4] <= L'Z') ||
(L'a' <= FileName[4] && FileName[4] <= L'z')
) &&
L':' == FileName[5];
}
#define FSP_NEXT_EA(Ea, EaEnd) \ #define FSP_NEXT_EA(Ea, EaEnd) \
(0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd)) (0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd))

612
src/dll/mount.c Normal file
View File

@ -0,0 +1,612 @@
/**
* @file dll/mount.c
*
* @copyright 2015-2019 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>
static INIT_ONCE FspMountInitOnce = INIT_ONCE_STATIC_INIT;
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
HANDLE Handle);
static NTSTATUS (NTAPI *FspNtClose)(
HANDLE Handle);
static BOOL WINAPI FspMountInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
HANDLE Handle;
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
{
FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject");
FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose)
{
FspNtOpenSymbolicLinkObject = 0;
FspNtMakeTemporaryObject = 0;
FspNtClose = 0;
}
}
return TRUE;
}
static NTSTATUS FspMountmgrControl(ULONG IoControlCode,
PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, PULONG POutputBufferLength)
{
HANDLE MgrHandle = INVALID_HANDLE_VALUE;
DWORD Bytes = 0;
NTSTATUS Result;
if (0 == POutputBufferLength)
POutputBufferLength = &Bytes;
MgrHandle = CreateFileW(L"\\\\.\\MountPointManager",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
0);
if (INVALID_HANDLE_VALUE == MgrHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!DeviceIoControl(MgrHandle,
IoControlCode,
InputBuffer, InputBufferLength, OutputBuffer, *POutputBufferLength,
&Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
*POutputBufferLength = Bytes;
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != MgrHandle)
CloseHandle(MgrHandle);
return Result;
}
static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint)
{
/* only support drives for now! (format: \\.\X:) */
if (L'\0' != MountPoint[6])
return STATUS_INVALID_PARAMETER;
/* mountmgr.h */
typedef enum
{
Disabled = 0,
Enabled,
} MOUNTMGR_AUTO_MOUNT_STATE;
typedef struct
{
MOUNTMGR_AUTO_MOUNT_STATE CurrentState;
} MOUNTMGR_QUERY_AUTO_MOUNT;
typedef struct
{
MOUNTMGR_AUTO_MOUNT_STATE NewState;
} MOUNTMGR_SET_AUTO_MOUNT;
typedef struct
{
USHORT DeviceNameLength;
WCHAR DeviceName[1];
} MOUNTMGR_TARGET_NAME;
typedef struct
{
USHORT SymbolicLinkNameOffset;
USHORT SymbolicLinkNameLength;
USHORT DeviceNameOffset;
USHORT DeviceNameLength;
} MOUNTMGR_CREATE_POINT_INPUT;
GUID UniqueId;
MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount;
MOUNTMGR_SET_AUTO_MOUNT SetAutoMount;
MOUNTMGR_TARGET_NAME *TargetName = 0;
MOUNTMGR_CREATE_POINT_INPUT *CreatePointInput = 0;
ULONG VolumeNameSize, QueryAutoMountSize, TargetNameSize, CreatePointInputSize;
HKEY RegKey;
LONG RegResult;
WCHAR RegValueName[MAX_PATH];
UINT8 RegValueData[sizeof UniqueId];
DWORD RegValueNameSize, RegValueDataSize;
DWORD RegType;
NTSTATUS Result;
/* transform our volume into one that can be used by the MountManager */
Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId);
if (!NT_SUCCESS(Result))
goto exit;
VolumeNameSize = lstrlenW(VolumeName) * sizeof(WCHAR);
QueryAutoMountSize = sizeof QueryAutoMount;
TargetNameSize = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + VolumeNameSize;
CreatePointInputSize = sizeof *CreatePointInput +
sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeNameSize;
TargetName = MemAlloc(TargetNameSize);
if (0 == TargetName)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
CreatePointInput = MemAlloc(CreatePointInputSize);
if (0 == CreatePointInput)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
/* query the current AutoMount value and save it */
Result = FspMountmgrControl(
CTL_CODE('m', 15, METHOD_BUFFERED, FILE_ANY_ACCESS),
/* IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT */
0, 0, &QueryAutoMount, &QueryAutoMountSize);
if (!NT_SUCCESS(Result))
goto exit;
/* disable AutoMount */
SetAutoMount.NewState = 0;
Result = FspMountmgrControl(
CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
/* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */
&SetAutoMount, sizeof SetAutoMount, 0, 0);
if (!NT_SUCCESS(Result))
goto exit;
/* announce volume arrival */
memset(TargetName, 0, sizeof *TargetName);
TargetName->DeviceNameLength = (USHORT)VolumeNameSize;
memcpy(TargetName->DeviceName,
VolumeName, TargetName->DeviceNameLength);
Result = FspMountmgrControl(
CTL_CODE('m', 11, METHOD_BUFFERED, FILE_READ_ACCESS),
/* IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION */
TargetName, TargetNameSize, 0, 0);
if (!NT_SUCCESS(Result))
goto exit;
/* reset the AutoMount value to the saved one */
SetAutoMount.NewState = QueryAutoMount.CurrentState;
FspMountmgrControl(
CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
/* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */
&SetAutoMount, sizeof SetAutoMount, 0, 0);
#if 0
if (!NT_SUCCESS(Result))
goto exit;
#endif
/* create mount point */
memset(CreatePointInput, 0, sizeof *CreatePointInput);
CreatePointInput->SymbolicLinkNameOffset = sizeof *CreatePointInput;
CreatePointInput->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
CreatePointInput->DeviceNameOffset =
CreatePointInput->SymbolicLinkNameOffset + CreatePointInput->SymbolicLinkNameLength;
CreatePointInput->DeviceNameLength = (USHORT)VolumeNameSize;
memcpy((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset,
L"\\DosDevices\\X:", CreatePointInput->SymbolicLinkNameLength);
((PWCHAR)((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset))[12] =
MountPoint[4] & ~0x20;
/* convert to uppercase */
memcpy((PUINT8)CreatePointInput + CreatePointInput->DeviceNameOffset,
VolumeName, CreatePointInput->DeviceNameLength);
Result = FspMountmgrControl(
CTL_CODE('m', 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
/* IOCTL_MOUNTMGR_CREATE_POINT */
CreatePointInput, CreatePointInputSize, 0, 0);
if (!NT_SUCCESS(Result))
goto exit;
/* HACK: delete the MountManager registry entries */
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\MountedDevices",
0, KEY_READ | KEY_WRITE, &RegKey);
if (ERROR_SUCCESS == RegResult)
{
for (DWORD I = 0;; I++)
{
RegValueNameSize = MAX_PATH;
RegValueDataSize = sizeof RegValueData;
RegResult = RegEnumValueW(RegKey,
I, RegValueName, &RegValueNameSize, 0, &RegType, RegValueData, &RegValueDataSize);
if (ERROR_NO_MORE_ITEMS == RegResult)
break;
else if (ERROR_SUCCESS != RegResult)
continue;
if (REG_BINARY == RegType &&
sizeof RegValueData == RegValueDataSize &&
InlineIsEqualGUID((GUID *)&RegValueData, &UniqueId))
{
RegResult = RegDeleteValueW(RegKey, RegValueName);
if (ERROR_SUCCESS == RegResult)
/* reset index after modifying key; only safe way to use RegEnumValueW with modifications */
I = -1;
}
}
RegCloseKey(RegKey);
}
Result = STATUS_SUCCESS;
exit:
MemFree(CreatePointInput);
MemFree(TargetName);
return Result;
}
static NTSTATUS FspMountRemove_Mountmgr(PWSTR MountPoint)
{
/* mountmgr.h */
typedef struct
{
ULONG SymbolicLinkNameOffset;
USHORT SymbolicLinkNameLength;
USHORT Reserved1;
ULONG UniqueIdOffset;
USHORT UniqueIdLength;
USHORT Reserved2;
ULONG DeviceNameOffset;
USHORT DeviceNameLength;
USHORT Reserved3;
} MOUNTMGR_MOUNT_POINT;
typedef struct
{
ULONG Size;
ULONG NumberOfMountPoints;
MOUNTMGR_MOUNT_POINT MountPoints[1];
} MOUNTMGR_MOUNT_POINTS;
MOUNTMGR_MOUNT_POINT *Input = 0;
MOUNTMGR_MOUNT_POINTS *Output = 0;
ULONG InputSize, OutputSize;
NTSTATUS Result;
InputSize = sizeof *Input + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
OutputSize = 4096;
Input = MemAlloc(InputSize);
if (0 == Input)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Output = MemAlloc(OutputSize);
if (0 == Output)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memset(Input, 0, sizeof *Input);
Input->SymbolicLinkNameOffset = sizeof *Input;
Input->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
memcpy((PUINT8)Input + Input->SymbolicLinkNameOffset,
L"\\DosDevices\\X:", Input->SymbolicLinkNameLength);
((PWCHAR)((PUINT8)Input + Input->SymbolicLinkNameOffset))[12] = MountPoint[4] & ~0x20;
/* convert to uppercase */
Result = FspMountmgrControl(
CTL_CODE('m', 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
/* IOCTL_MOUNTMGR_DELETE_POINTS */
Input, InputSize, Output, &OutputSize);
if (!NT_SUCCESS(Result))
goto exit;
Result = STATUS_SUCCESS;
exit:
MemFree(Output);
MemFree(Input);
return Result;
}
static NTSTATUS FspLauncherDefineDosDevice(
WCHAR Sign, PWSTR MountPoint, PWSTR VolumeName)
{
if (2 != lstrlenW(MountPoint) ||
FSP_FSCTL_VOLUME_NAME_SIZEMAX / sizeof(WCHAR) <= lstrlenW(VolumeName))
return STATUS_INVALID_PARAMETER;
WCHAR Argv0[4];
PWSTR Argv[2];
NTSTATUS Result;
ULONG ErrorCode;
Argv0[0] = Sign;
Argv0[1] = MountPoint[0];
Argv0[2] = MountPoint[1];
Argv0[3] = L'\0';
Argv[0] = Argv0;
Argv[1] = VolumeName;
Result = FspLaunchCallLauncherPipe(FspLaunchCmdDefineDosDevice, 2, Argv, 0, 0, 0, &ErrorCode);
return !NT_SUCCESS(Result) ? Result : FspNtStatusFromWin32(ErrorCode);
}
static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PMountHandle)
{
NTSTATUS Result;
BOOLEAN IsLocalSystem, IsServiceContext;
*PMountHandle = 0;
Result = FspServiceContextCheck(0, &IsLocalSystem);
IsServiceContext = NT_SUCCESS(Result) && !IsLocalSystem;
if (IsServiceContext)
{
/*
* If the current process is in the service context but not LocalSystem,
* ask the launcher to DefineDosDevice for us. This is because the launcher
* runs in the LocalSystem context and can create global drives.
*
* In this case the launcher will also add DELETE access to the drive symlink
* for us, so that we can make it temporary below.
*/
Result = FspLauncherDefineDosDevice(L'+', MountPoint, VolumeName);
if (!NT_SUCCESS(Result))
return Result;
}
else
{
if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName))
return FspNtStatusFromWin32(GetLastError());
}
if (0 != FspNtOpenSymbolicLinkObject)
{
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(PMountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(*PMountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(*PMountHandle);
*PMountHandle = 0;
}
}
}
/* HACK:
*
* Handles do not use the low 2 bits (unless they are console handles).
* Abuse this fact to remember that we are running in the service context.
*/
*PMountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)*PMountHandle | IsServiceContext);
return STATUS_SUCCESS;
}
static NTSTATUS FspMountRemove_Drive(PWSTR VolumeName, PWSTR MountPoint, HANDLE MountHandle)
{
NTSTATUS Result;
BOOLEAN IsServiceContext;
IsServiceContext = 0 != ((DWORD)(UINT_PTR)MountHandle & 1);
MountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)MountHandle & ~1);
if (IsServiceContext)
/*
* If the current process is in the service context but not LocalSystem,
* ask the launcher to DefineDosDevice for us. This is because the launcher
* runs in the LocalSystem context and can remove global drives.
*/
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());
if (0 != MountHandle)
FspNtClose(MountHandle);
return Result;
}
static NTSTATUS FspMountSet_Directory(PWSTR VolumeName, PWSTR MountPoint,
PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle)
{
NTSTATUS Result;
SECURITY_ATTRIBUTES SecurityAttributes;
HANDLE MountHandle = INVALID_HANDLE_VALUE;
DWORD Backslashes, Bytes;
USHORT VolumeNameLength, BackslashLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR P, PathBuffer;
*PMountHandle = 0;
/*
* Windows does not allow mount points (junctions) to point to network file systems.
*
* Count how many backslashes our VolumeName has. If it is 3 or more this is a network
* file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED.
*/
for (P = VolumeName, Backslashes = 0; *P; P++)
if (L'\\' == *P)
if (3 == ++Backslashes)
{
Result = STATUS_NETWORK_ACCESS_DENIED;
goto exit;
}
memset(&SecurityAttributes, 0, sizeof SecurityAttributes);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
MountHandle = CreateFileW(MountPoint,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&SecurityAttributes,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE,
0);
if (INVALID_HANDLE_VALUE == MountHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
VolumeNameLength = (USHORT)lstrlenW(VolumeName);
BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1];
VolumeNameLength *= sizeof(WCHAR);
BackslashLength *= sizeof(WCHAR);
ReparseDataLength = (USHORT)(
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer)) +
2 * (VolumeNameLength + BackslashLength + sizeof(WCHAR));
ReparseData = MemAlloc(REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength);
if (0 == ReparseData)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
ReparseData->ReparseDataLength = ReparseDataLength;
ReparseData->Reserved = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameOffset = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameLength =
VolumeNameLength + BackslashLength;
ReparseData->MountPointReparseBuffer.PrintNameOffset =
ReparseData->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
ReparseData->MountPointReparseBuffer.PrintNameLength =
VolumeNameLength + BackslashLength;
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer;
memcpy(PathBuffer, VolumeName, VolumeNameLength);
if (BackslashLength)
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer +
(ReparseData->MountPointReparseBuffer.PrintNameOffset) / sizeof(WCHAR);
memcpy(PathBuffer, VolumeName, VolumeNameLength);
if (BackslashLength)
PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\';
PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0';
if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0,
&Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
*PMountHandle = MountHandle;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle)
CloseHandle(MountHandle);
MemFree(ReparseData);
return Result;
}
static NTSTATUS FspMountRemove_Directory(HANDLE MountHandle)
{
/* directory is marked DELETE_ON_CLOSE */
return CloseHandle(MountHandle) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
}
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
{
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
Desc->MountHandle = 0;
if (L'*' == Desc->MountPoint[0] && ':' == Desc->MountPoint[1] && L'\0' == Desc->MountPoint[2])
{
NTSTATUS Result;
DWORD Drives;
WCHAR Drive;
Drives = GetLogicalDrives();
if (0 == Drives)
return FspNtStatusFromWin32(GetLastError());
for (Drive = 'Z'; 'D' <= Drive; Drive--)
if (0 == (Drives & (1 << (Drive - 'A'))))
{
Desc->MountPoint[0] = Drive;
Result = FspMountSet_Drive(Desc->VolumeName, Desc->MountPoint,
&Desc->MountHandle);
if (NT_SUCCESS(Result))
return Result;
}
Desc->MountPoint[0] = L'*';
return STATUS_NO_SUCH_DEVICE;
}
else if (FspPathIsMountmgrMountPoint(Desc->MountPoint))
return FspMountSet_Mountmgr(Desc->VolumeHandle, Desc->VolumeName, Desc->MountPoint);
else if (FspPathIsDrive(Desc->MountPoint))
return FspMountSet_Drive(Desc->VolumeName, Desc->MountPoint,
&Desc->MountHandle);
else
return FspMountSet_Directory(Desc->VolumeName, Desc->MountPoint, Desc->Security,
&Desc->MountHandle);
}
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
{
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
if (FspPathIsMountmgrMountPoint(Desc->MountPoint))
return FspMountRemove_Mountmgr(Desc->MountPoint);
else if (FspPathIsDrive(Desc->MountPoint))
return FspMountRemove_Drive(Desc->VolumeName, Desc->MountPoint, Desc->MountHandle);
else
return FspMountRemove_Directory(Desc->MountHandle);
}

View File

@ -1085,8 +1085,9 @@ namespace Fsp
UInt32 FileAttributes, UInt32 FileAttributes,
Byte[] SecurityDescriptor, Byte[] SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
out Object FileNode, out Object FileNode,
out Object FileDesc, out Object FileDesc,
out FileInfo FileInfo, out FileInfo FileInfo,
@ -1391,6 +1392,16 @@ namespace Fsp
} }
} }
/// <summary> /// <summary>
/// Makes a byte array that contains a reparse point.
/// </summary>
/// <returns>The reparse point byte array.</returns>
public static Byte[] MakeReparsePoint(
IntPtr Buffer,
UInt32 Size)
{
return Api.MakeReparsePoint(Buffer, (UIntPtr)Size);
}
/// <summary>
/// Gets the reparse tag from reparse data. /// Gets the reparse tag from reparse data.
/// </summary> /// </summary>
/// <param name="ReparseData"> /// <param name="ReparseData">

View File

@ -40,6 +40,7 @@ namespace Fsp
/// <param name="FileSystem">The file system to host.</param> /// <param name="FileSystem">The file system to host.</param>
public FileSystemHost(FileSystemBase FileSystem) public FileSystemHost(FileSystemBase FileSystem)
{ {
_VolumeParams.Version = (UInt16)Marshal.SizeOf(_VolumeParams);
_VolumeParams.Flags = VolumeParams.UmFileContextIsFullContext; _VolumeParams.Flags = VolumeParams.UmFileContextIsFullContext;
_FileSystem = FileSystem; _FileSystem = FileSystem;
} }
@ -126,6 +127,86 @@ namespace Fsp
set { _VolumeParams.FileInfoTimeout = value; } set { _VolumeParams.FileInfoTimeout = value; }
} }
/// <summary> /// <summary>
/// Gets or sets the volume information timeout.
/// </summary>
public UInt32 VolumeInfoTimeout
{
get
{
return 0 != (_VolumeParams.AdditionalFlags & VolumeParams.VolumeInfoTimeoutValid) ?
_VolumeParams.VolumeInfoTimeout : _VolumeParams.FileInfoTimeout;
}
set
{
_VolumeParams.AdditionalFlags |= VolumeParams.VolumeInfoTimeoutValid;
_VolumeParams.VolumeInfoTimeout = value;
}
}
/// <summary>
/// Gets or sets the directory information timeout.
/// </summary>
public UInt32 DirInfoTimeout
{
get
{
return 0 != (_VolumeParams.AdditionalFlags & VolumeParams.DirInfoTimeoutValid) ?
_VolumeParams.DirInfoTimeout : _VolumeParams.FileInfoTimeout;
}
set
{
_VolumeParams.AdditionalFlags |= VolumeParams.DirInfoTimeoutValid;
_VolumeParams.DirInfoTimeout = value;
}
}
/// <summary>
/// Gets or sets the security information timeout.
/// </summary>
public UInt32 SecurityTimeout
{
get
{
return 0 != (_VolumeParams.AdditionalFlags & VolumeParams.SecurityTimeoutValid) ?
_VolumeParams.SecurityTimeout : _VolumeParams.FileInfoTimeout;
}
set
{
_VolumeParams.AdditionalFlags |= VolumeParams.SecurityTimeoutValid;
_VolumeParams.SecurityTimeout = value;
}
}
/// <summary>
/// Gets or sets the stream information timeout.
/// </summary>
public UInt32 StreamInfoTimeout
{
get
{
return 0 != (_VolumeParams.AdditionalFlags & VolumeParams.StreamInfoTimeoutValid) ?
_VolumeParams.StreamInfoTimeout : _VolumeParams.FileInfoTimeout;
}
set
{
_VolumeParams.AdditionalFlags |= VolumeParams.StreamInfoTimeoutValid;
_VolumeParams.StreamInfoTimeout = value;
}
}
/// <summary>
/// Gets or sets the EA information timeout.
/// </summary>
public UInt32 EaTimeout
{
get
{
return 0 != (_VolumeParams.AdditionalFlags & VolumeParams.EaTimeoutValid) ?
_VolumeParams.EaTimeout : _VolumeParams.FileInfoTimeout;
}
set
{
_VolumeParams.AdditionalFlags |= VolumeParams.EaTimeoutValid;
_VolumeParams.EaTimeout = value;
}
}
/// <summary>
/// Gets or sets a value that determines whether the file system is case sensitive. /// Gets or sets a value that determines whether the file system is case sensitive.
/// </summary> /// </summary>
public Boolean CaseSensitiveSearch public Boolean CaseSensitiveSearch
@ -221,6 +302,11 @@ namespace Fsp
get { return 0 != (_VolumeParams.Flags & VolumeParams.AllowOpenInKernelMode); } get { return 0 != (_VolumeParams.Flags & VolumeParams.AllowOpenInKernelMode); }
set { _VolumeParams.Flags |= (value ? VolumeParams.AllowOpenInKernelMode : 0); } set { _VolumeParams.Flags |= (value ? VolumeParams.AllowOpenInKernelMode : 0); }
} }
public Boolean WslFeatures
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.WslFeatures); }
set { _VolumeParams.Flags |= (value ? VolumeParams.WslFeatures : 0); }
}
/// <summary> /// <summary>
/// Gets or sets the prefix for a network file system. /// Gets or sets the prefix for a network file system.
/// </summary> /// </summary>
@ -274,11 +360,44 @@ namespace Fsp
/// A value of 0 disables all debug logging. /// A value of 0 disables all debug logging.
/// A value of -1 enables all debug logging. /// A value of -1 enables all debug logging.
/// </param> /// </param>
/// <returns></returns> /// <returns>STATUS_SUCCESS or error code.</returns>
public Int32 Mount(String MountPoint, public Int32 Mount(String MountPoint,
Byte[] SecurityDescriptor = null, Byte[] SecurityDescriptor = null,
Boolean Synchronized = false, Boolean Synchronized = false,
UInt32 DebugLog = 0) UInt32 DebugLog = 0)
{
return MountEx(MountPoint, 0, SecurityDescriptor, Synchronized, DebugLog);
}
/// <summary>
/// Mounts a file system.
/// </summary>
/// <param name="MountPoint">
/// The mount point for the new file system. A value of null means that
/// the file system should use the next available drive letter counting
/// downwards from Z: as its mount point.
/// </param>
/// <param name="ThreadCount">
/// Number of threads to use to service file system requests. A value
/// of 0 means that the default number of threads should be used.
/// </param>
/// <param name="SecurityDescriptor">
/// Security descriptor to use if mounting on (newly created) directory.
/// A value of null means the directory should be created with default
/// security.
/// </param>
/// <param name="Synchronized">
/// If true file system operations are synchronized using an exclusive lock.
/// </param>
/// <param name="DebugLog">
/// A value of 0 disables all debug logging.
/// A value of -1 enables all debug logging.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public Int32 MountEx(String MountPoint,
UInt32 ThreadCount,
Byte[] SecurityDescriptor = null,
Boolean Synchronized = false,
UInt32 DebugLog = 0)
{ {
Int32 Result; Int32 Result;
try try
@ -315,7 +434,7 @@ namespace Fsp
} }
if (0 <= Result) if (0 <= Result)
{ {
Result = Api.FspFileSystemStartDispatcher(_FileSystemPtr, 0); Result = Api.FspFileSystemStartDispatcher(_FileSystemPtr, ThreadCount);
if (0 > Result) if (0 > Result)
try try
{ {
@ -381,6 +500,83 @@ namespace Fsp
{ {
return Api.GetVersion(); return Api.GetVersion();
} }
/// <summary>
/// Returns a RequestHint to reference the current operation asynchronously.
/// </summary>
public UInt64 GetOperationRequestHint()
{
return Api.FspFileSystemGetOperationRequestHint();
}
/// <summary>
/// Asynchronously complete a Read operation.
/// </summary>
/// <param name="RequestHint">
/// A reference to the operation to complete.
/// </param>
/// <param name="Status">
/// STATUS_SUCCESS or error code.
/// </param>
/// <param name="BytesTransferred">
/// Number of bytes read.
/// </param>
public void SendReadResponse(UInt64 RequestHint, Int32 Status, UInt32 BytesTransferred)
{
FspFsctlTransactRsp Response = default(FspFsctlTransactRsp);
Response.Size = 128;
Response.Kind = (UInt32)FspFsctlTransact.ReadKind;
Response.Hint = RequestHint;
Response.IoStatus.Information = BytesTransferred;
Response.IoStatus.Status = (UInt32)Status;
Api.FspFileSystemSendResponse(_FileSystemPtr, ref Response);
}
/// <summary>
/// Asynchronously complete a Write operation.
/// </summary>
/// <param name="RequestHint">
/// A reference to the operation to complete.
/// </param>
/// <param name="Status">
/// STATUS_SUCCESS or error code.
/// </param>
/// <param name="BytesTransferred">
/// The number of bytes written.
/// </param>
/// <param name="FileInfo">
/// Updated file information.
/// </param>
public void SendWriteResponse(UInt64 RequestHint, Int32 Status, UInt32 BytesTransferred, ref FileInfo FileInfo)
{
FspFsctlTransactRsp Response = default(FspFsctlTransactRsp);
Response.Size = 128;
Response.Kind = (UInt32)FspFsctlTransact.WriteKind;
Response.Hint = RequestHint;
Response.IoStatus.Information = BytesTransferred;
Response.IoStatus.Status = (UInt32)Status;
Response.WriteFileInfo = FileInfo;
Api.FspFileSystemSendResponse(_FileSystemPtr, ref Response);
}
/// <summary>
/// Asynchronously complete a ReadDirectory operation.
/// </summary>
/// <param name="RequestHint">
/// A reference to the operation to complete.
/// </param>
/// <param name="Status">
/// STATUS_SUCCESS or error code.
/// </param>
/// <param name="BytesTransferred">
/// Number of bytes read.
/// </param>
public void SendReadDirectoryResponse(UInt64 RequestHint, Int32 Status, UInt32 BytesTransferred)
{
FspFsctlTransactRsp Response = default(FspFsctlTransactRsp);
Response.Size = 128;
Response.Kind = (UInt32)FspFsctlTransact.QueryDirectoryKind;
Response.Hint = RequestHint;
Response.IoStatus.Information = BytesTransferred;
Response.IoStatus.Status = (UInt32)Status;
Api.FspFileSystemSendResponse(_FileSystemPtr, ref Response);
}
/* FSP_FILE_SYSTEM_INTERFACE */ /* FSP_FILE_SYSTEM_INTERFACE */
private static Byte[] ByteBufferNotNull = new Byte[0]; private static Byte[] ByteBufferNotNull = new Byte[0];
@ -472,8 +668,9 @@ namespace Fsp
UInt32 FileAttributes, UInt32 FileAttributes,
IntPtr SecurityDescriptor, IntPtr SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
ref FullContext FullContext, ref FullContext FullContext,
ref OpenFileInfo OpenFileInfo) ref OpenFileInfo OpenFileInfo)
{ {
@ -490,8 +687,9 @@ namespace Fsp
FileAttributes, FileAttributes,
Api.MakeSecurityDescriptor(SecurityDescriptor), Api.MakeSecurityDescriptor(SecurityDescriptor),
AllocationSize, AllocationSize,
Ea, ExtraBuffer,
EaLength, ExtraLength,
ExtraBufferIsReparsePoint,
out FileNode, out FileNode,
out FileDesc, out FileDesc,
out OpenFileInfo.FileInfo, out OpenFileInfo.FileInfo,

View File

@ -53,9 +53,16 @@ namespace Fsp.Interop
internal const UInt32 UmFileContextIsFullContext = 0x00020000; internal const UInt32 UmFileContextIsFullContext = 0x00020000;
internal const UInt32 AllowOpenInKernelMode = 0x01000000; internal const UInt32 AllowOpenInKernelMode = 0x01000000;
internal const UInt32 CasePreservedExtendedAttributes = 0x02000000; internal const UInt32 CasePreservedExtendedAttributes = 0x02000000;
internal const UInt32 WslFeatures = 0x04000000;
internal const int PrefixSize = 192; internal const int PrefixSize = 192;
internal const int FileSystemNameSize = 16; internal const int FileSystemNameSize = 16;
internal const UInt32 VolumeInfoTimeoutValid = 0x00000001;
internal const UInt32 DirInfoTimeoutValid = 0x00000002;
internal const UInt32 SecurityTimeoutValid = 0x00000004;
internal const UInt32 StreamInfoTimeoutValid = 0x00000008;
internal const UInt32 EaTimeoutValid = 0x00000010;
internal UInt16 Version; internal UInt16 Version;
internal UInt16 SectorSize; internal UInt16 SectorSize;
internal UInt16 SectorsPerAllocationUnit; internal UInt16 SectorsPerAllocationUnit;
@ -69,6 +76,15 @@ namespace Fsp.Interop
internal UInt32 Flags; internal UInt32 Flags;
internal unsafe fixed UInt16 Prefix[PrefixSize]; internal unsafe fixed UInt16 Prefix[PrefixSize];
internal unsafe fixed UInt16 FileSystemName[FileSystemNameSize]; internal unsafe fixed UInt16 FileSystemName[FileSystemNameSize];
internal UInt32 AdditionalFlags;
internal UInt32 VolumeInfoTimeout;
internal UInt32 DirInfoTimeout;
internal UInt32 SecurityTimeout;
internal UInt32 StreamInfoTimeout;
internal UInt32 EaTimeout;
internal UInt32 FsextControlCode;
internal unsafe fixed UInt32 Reserved32[1];
internal unsafe fixed UInt64 Reserved64[2];
internal unsafe String GetPrefix() internal unsafe String GetPrefix()
{ {
@ -354,6 +370,65 @@ namespace Fsp.Interop
public IntPtr Information; public IntPtr Information;
} }
[StructLayout(LayoutKind.Sequential)]
internal struct IoStatus
{
internal UInt32 Information;
internal UInt32 Status;
}
internal enum FspFsctlTransact
{
ReadKind = 5,
WriteKind = 6,
QueryDirectoryKind = 14
}
[StructLayout(LayoutKind.Explicit)]
internal struct FspFsctlTransactReq
{
[FieldOffset(0)]
internal UInt16 Version;
[FieldOffset(2)]
internal UInt16 Size;
[FieldOffset(4)]
internal UInt32 Kind;
[FieldOffset(8)]
internal UInt64 Hint;
[FieldOffset(0)]
internal unsafe fixed Byte Padding[88];
}
[StructLayout(LayoutKind.Explicit)]
internal struct FspFsctlTransactRsp
{
[FieldOffset(0)]
internal UInt16 Version;
[FieldOffset(2)]
internal UInt16 Size;
[FieldOffset(4)]
internal UInt32 Kind;
[FieldOffset(8)]
internal UInt64 Hint;
[FieldOffset(16)]
internal IoStatus IoStatus;
[FieldOffset(24)]
internal FileInfo WriteFileInfo;
[FieldOffset(0)]
internal unsafe fixed Byte Padding[128];
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FspFileSystemOperationContext
{
internal FspFsctlTransactReq *Request;
internal FspFsctlTransactRsp *Response;
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct FileSystemInterface internal struct FileSystemInterface
{ {
@ -557,8 +632,9 @@ namespace Fsp.Interop
UInt32 FileAttributes, UInt32 FileAttributes,
IntPtr SecurityDescriptor, IntPtr SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
[MarshalAs(UnmanagedType.U1)] Boolean ExtraBufferIsReparsePoint,
ref FullContext FullContext, ref FullContext FullContext,
ref OpenFileInfo OpenFileInfo); ref OpenFileInfo OpenFileInfo);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@ -662,6 +738,12 @@ namespace Fsp.Interop
internal delegate Int32 FspFileSystemStopDispatcher( internal delegate Int32 FspFileSystemStopDispatcher(
IntPtr FileSystem); IntPtr FileSystem);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void FspFileSystemSendResponse(
IntPtr FileSystem,
ref FspFsctlTransactRsp Response);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal unsafe delegate FspFileSystemOperationContext *FspFileSystemGetOperationContext();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr FspFileSystemMountPointF( internal delegate IntPtr FspFileSystemMountPointF(
IntPtr FileSystem); IntPtr FileSystem);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@ -846,6 +928,8 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemRemoveMountPoint FspFileSystemRemoveMountPoint; internal static Proto.FspFileSystemRemoveMountPoint FspFileSystemRemoveMountPoint;
internal static Proto.FspFileSystemStartDispatcher FspFileSystemStartDispatcher; internal static Proto.FspFileSystemStartDispatcher FspFileSystemStartDispatcher;
internal static Proto.FspFileSystemStopDispatcher FspFileSystemStopDispatcher; internal static Proto.FspFileSystemStopDispatcher FspFileSystemStopDispatcher;
internal static Proto.FspFileSystemSendResponse FspFileSystemSendResponse;
internal static Proto.FspFileSystemGetOperationContext FspFileSystemGetOperationContext;
internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint; internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint;
internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy; internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy;
internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog; internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog;
@ -892,6 +976,10 @@ namespace Fsp.Interop
else else
return _FspFileSystemSetMountPointEx(FileSystem, MountPoint, IntPtr.Zero); return _FspFileSystemSetMountPointEx(FileSystem, MountPoint, IntPtr.Zero);
} }
internal static unsafe UInt64 FspFileSystemGetOperationRequestHint()
{
return FspFileSystemGetOperationContext()->Request->Hint;
}
internal static unsafe Boolean FspFileSystemAddDirInfo( internal static unsafe Boolean FspFileSystemAddDirInfo(
ref DirInfo DirInfo, ref DirInfo DirInfo,
IntPtr Buffer, IntPtr Buffer,
@ -1240,6 +1328,8 @@ namespace Fsp.Interop
FspFileSystemRemoveMountPoint = GetEntryPoint<Proto.FspFileSystemRemoveMountPoint>(Module); FspFileSystemRemoveMountPoint = GetEntryPoint<Proto.FspFileSystemRemoveMountPoint>(Module);
FspFileSystemStartDispatcher = GetEntryPoint<Proto.FspFileSystemStartDispatcher>(Module); FspFileSystemStartDispatcher = GetEntryPoint<Proto.FspFileSystemStartDispatcher>(Module);
FspFileSystemStopDispatcher = GetEntryPoint<Proto.FspFileSystemStopDispatcher>(Module); FspFileSystemStopDispatcher = GetEntryPoint<Proto.FspFileSystemStopDispatcher>(Module);
FspFileSystemSendResponse = GetEntryPoint<Proto.FspFileSystemSendResponse>(Module);
FspFileSystemGetOperationContext = GetEntryPoint<Proto.FspFileSystemGetOperationContext>(Module);
FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module); FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module);
FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module); FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module);
FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module); FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module);

222
src/ku/library.h Normal file
View File

@ -0,0 +1,222 @@
/**
* @file ku/library.h
*
* @copyright 2015-2019 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.
*/
#ifndef WINFSP_KU_LIBRARY_H_INCLUDED
#define WINFSP_KU_LIBRARY_H_INCLUDED
#if !defined(_KERNEL_MODE)
#include <dll/library.h>
#include <aclapi.h>
#define _NTDEF_
#include <ntsecapi.h>
#define FSP_KU_CODE ((void)0)
#else
#include <sys/driver.h>
#define FSP_KU_CODE PAGED_CODE(); NTSTATUS fsp_ku_status = STATUS_SUCCESS; (VOID)fsp_ku_status
#define FSP_API FSP_DDI
#define BYTE UINT8
#define BOOL BOOLEAN
#define LPBOOL PBOOLEAN
#define UINT ULONG
#define GetLastError() ((DWORD)fsp_ku_status)
#define FspNtStatusFromWin32(Err) ((NTSTATUS)(Err))
#define ERROR_INSUFFICIENT_BUFFER STATUS_BUFFER_TOO_SMALL
#define InitOnceExecuteOnce(I, F, P, C) RtlRunOnceExecuteOnce(I, F, P, C)
#define INIT_ONCE RTL_RUN_ONCE
#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT
#define AddAccessAllowedAce(Acl, Rev, Acc, Sid)\
(fsp_ku_status = RtlAddAccessAllowedAce(Acl, Rev, Acc, Sid),\
NT_SUCCESS(fsp_ku_status))
#define AddAccessDeniedAce(Acl, Rev, Acc, Sid)\
(fsp_ku_status = FspKuAddAccessDeniedAce(Acl, Rev, Acc, Sid),\
NT_SUCCESS(fsp_ku_status))
#define EqualSid(Sid1, Sid2) (fsp_ku_status = 0, RtlEqualSid(Sid1, Sid2))
#define GetAce(Acl, Idx, Ace) (fsp_ku_status = RtlGetAce(Acl, Idx, Ace), NT_SUCCESS(fsp_ku_status))
#define GetAclInformation(Acl, Inf, Len, Cls)\
(fsp_ku_status = FspKuQueryInformationAcl(Acl, Inf, Len, Cls),\
NT_SUCCESS(fsp_ku_status))
#define GetLengthSid(Sid) (fsp_ku_status = 0, RtlLengthSid(Sid))
#define GetSecurityDescriptorDacl(Sec, Prs, Dac, Def)\
(fsp_ku_status = RtlGetDaclSecurityDescriptor(Sec, Prs, Dac, Def),\
NT_SUCCESS(fsp_ku_status))
#define GetSecurityDescriptorGroup(Sec, Grp, Def)\
(fsp_ku_status = RtlGetGroupSecurityDescriptor(Sec, Grp, Def),\
NT_SUCCESS(fsp_ku_status))
#define GetSecurityDescriptorOwner(Sec, Own, Def)\
(fsp_ku_status = RtlGetOwnerSecurityDescriptor(Sec, Own, Def),\
NT_SUCCESS(fsp_ku_status))
#define GetSidIdentifierAuthority(Sid) (fsp_ku_status = 0, &((PISID)(Sid))->IdentifierAuthority)
#define GetSidSubAuthority(Sid, Sub) (fsp_ku_status = 0, RtlSubAuthoritySid(Sid, Sub))
#define GetSidSubAuthorityCount(Sid) (fsp_ku_status = 0, RtlSubAuthorityCountSid(Sid))
#define InitializeAcl(Acl, Len, Rev) (fsp_ku_status = RtlCreateAcl(Acl, Len, Rev), NT_SUCCESS(fsp_ku_status))
#define InitializeSecurityDescriptor(Sec, Rev)\
(fsp_ku_status = RtlCreateSecurityDescriptor(Sec, Rev),\
NT_SUCCESS(fsp_ku_status))
#define InitializeSid(Sid, Aut, Cnt) (fsp_ku_status = RtlInitializeSid(Sid, Aut, Cnt), NT_SUCCESS(fsp_ku_status))
#define IsValidSid(Sid) (RtlValidSid(Sid) || (fsp_ku_status = STATUS_INVALID_SID, FALSE))
#define MakeSelfRelativeSD(Abs, Rel, Len)\
(fsp_ku_status = RtlAbsoluteToSelfRelativeSD(Abs, Rel, Len),\
NT_SUCCESS(fsp_ku_status))
#define SetSecurityDescriptorControl(Sec, Msk, Bit)\
(fsp_ku_status = FspKuSetControlSecurityDescriptor(Sec, Msk, Bit),\
NT_SUCCESS(fsp_ku_status))
#define SetSecurityDescriptorDacl(Sec, Prs, Dac, Def)\
(fsp_ku_status = RtlSetDaclSecurityDescriptor(Sec, Prs, Dac, Def),\
NT_SUCCESS(fsp_ku_status))
#define SetSecurityDescriptorGroup(Sec, Grp, Def)\
(fsp_ku_status = RtlSetGroupSecurityDescriptor(Sec, Grp, Def),\
NT_SUCCESS(fsp_ku_status))
#define SetSecurityDescriptorOwner(Sec, Own, Def)\
(fsp_ku_status = RtlSetOwnerSecurityDescriptor(Sec, Own, Def),\
NT_SUCCESS(fsp_ku_status))
static inline NTSTATUS FspKuAddAccessDeniedAce(
PACL Acl,
ULONG AceRevision,
ACCESS_MASK AccessMask,
PSID Sid)
{
/* We are missing RtlAddAccessDeniedAce. So we need this malarkey! */
NTSTATUS Result;
PACE_HEADER Ace;
Result = RtlAddAccessAllowedAce(Acl, AceRevision, AccessMask, Sid);
if (!NT_SUCCESS(Result))
return Result;
Result = RtlGetAce(Acl, Acl->AceCount - 1, &Ace);
if (!NT_SUCCESS(Result))
return Result;
Ace->AceType = ACCESS_DENIED_ACE_TYPE;
return STATUS_SUCCESS;
}
typedef enum
{
AclRevisionInformation__DO_NOT_USE = 1,
AclSizeInformation,
} ACL_INFORMATION_CLASS;
typedef struct
{
DWORD AceCount;
DWORD AclBytesInUse__DO_NOT_USE;
DWORD AclBytesFree__DO_NOT_USE;
} ACL_SIZE_INFORMATION, *PACL_SIZE_INFORMATION;
static inline NTSTATUS FspKuQueryInformationAcl(
PACL Acl,
PVOID AclInformation,
ULONG AclInformationLength,
ACL_INFORMATION_CLASS AclInformationClass)
{
ASSERT(AclSizeInformation == AclInformationClass);
ASSERT(sizeof(ACL_SIZE_INFORMATION) <= AclInformationLength);
((PACL_SIZE_INFORMATION)AclInformation)->AceCount = Acl->AceCount;
return STATUS_SUCCESS;
}
static inline NTSTATUS FspKuSetControlSecurityDescriptor(
PSECURITY_DESCRIPTOR SecurityDescriptor,
SECURITY_DESCRIPTOR_CONTROL ControlMask,
SECURITY_DESCRIPTOR_CONTROL ControlBits)
{
((PUSHORT)(SecurityDescriptor))[1] &= ~ControlMask;
((PUSHORT)(SecurityDescriptor))[1] |= ControlBits;
return STATUS_SUCCESS;
}
#define WideCharToMultiByte(C, F, W, w, B, b, D, d)\
(FspKuWideCharToMultiByte(C, F, W, w, B, b, D, d, &fsp_ku_status))
#define MultiByteToWideChar(C, F, B, b, W, w)\
(FspKuMultiByteToWideChar(C, F, B, b, W, w, &fsp_ku_status))
#define CP_UTF8 65001
static inline int FspKuWideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWCH lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCCH lpDefaultChar,
LPBOOL lpUsedDefaultChar,
PNTSTATUS PResult)
{
ASSERT(CP_UTF8 == CodePage);
ASSERT(0 == dwFlags);
ASSERT(0 == lpDefaultChar);
ASSERT(0 == lpUsedDefaultChar);
NTSTATUS Result;
ULONG ByteCount;
if (-1 == cchWideChar)
cchWideChar = (int)wcslen(lpWideCharStr) + 1;
Result = RtlUnicodeToUTF8N(
lpMultiByteStr, cbMultiByte, &ByteCount,
lpWideCharStr, cchWideChar * sizeof(WCHAR));
if (STATUS_SOME_NOT_MAPPED == Result)
Result = STATUS_SUCCESS;
else if (!NT_SUCCESS(Result))
return 0;
*PResult = Result;
return ByteCount;
}
static inline int FspKuMultiByteToWideChar(
UINT CodePage,
DWORD dwFlags,
LPCCH lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar,
PNTSTATUS PResult)
{
ASSERT(CP_UTF8 == CodePage);
ASSERT(0 == dwFlags);
NTSTATUS Result;
ULONG ByteCount;
if (-1 == cbMultiByte)
cbMultiByte = (int)strlen(lpMultiByteStr) + 1;
Result = RtlUTF8ToUnicodeN(
lpWideCharStr, cchWideChar * sizeof(WCHAR), &ByteCount,
lpMultiByteStr, cbMultiByte);
if (STATUS_SOME_NOT_MAPPED == Result)
Result = STATUS_SUCCESS;
else if (!NT_SUCCESS(Result))
return 0;
*PResult = Result;
return ByteCount / sizeof(WCHAR);
}
static inline void *MemAlloc(size_t Size)
{
return FspAlloc(Size);
}
static inline void MemFree(void *Pointer)
{
if (0 != Pointer)
FspFree(Pointer);
}
#endif
#endif

View File

@ -1,5 +1,5 @@
/** /**
* @file dll/posix.c * @file ku/posix.c
* POSIX Interop. * POSIX Interop.
* *
* This file provides routines for Windows/POSIX interoperability. It is based * This file provides routines for Windows/POSIX interoperability. It is based
@ -32,15 +32,67 @@
* associated repository. * associated repository.
*/ */
#include <dll/library.h> #include <ku/library.h>
#include <aclapi.h>
#define _NTDEF_
#include <ntsecapi.h>
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid);
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid);
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...); static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)());
FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
PSECURITY_DESCRIPTOR SecurityDescriptor,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode);
FSP_API NTSTATUS FspPosixMapWindowsToPosixPathEx(PWSTR WindowsPath, char **PPosixPath,
BOOLEAN Translate);
FSP_API NTSTATUS FspPosixMapPosixToWindowsPathEx(const char *PosixPath, PWSTR *PWindowsPath,
BOOLEAN Translate);
FSP_API VOID FspPosixDeletePath(void *Path);
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT; #if defined(_KERNEL_MODE)
union #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspPosixMapUidToSid)
#pragma alloc_text(PAGE, FspPosixMapSidToUid)
#pragma alloc_text(PAGE, FspPosixCreateSid)
#pragma alloc_text(PAGE, FspDeleteSid)
#pragma alloc_text(PAGE, FspPosixMapPermissionsToSecurityDescriptor)
#pragma alloc_text(PAGE, FspPosixMapSecurityDescriptorToPermissions)
#pragma alloc_text(PAGE, FspPosixMapWindowsToPosixPathEx)
#pragma alloc_text(PAGE, FspPosixMapPosixToWindowsPathEx)
#pragma alloc_text(PAGE, FspPosixDeletePath)
#pragma alloc_text(PAGE, FspPosixEncodeWindowsPath)
#pragma alloc_text(PAGE, FspPosixDecodeWindowsPath)
#endif
#endif
static union
{
SID V;
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
} FspWorldSidBuf =
{
/* S-1-1-0 */
.V.Revision = SID_REVISION,
.V.SubAuthorityCount = 1,
.V.IdentifierAuthority.Value[5] = 1,
.V.SubAuthority[0] = 0,
};
static union
{
SID V;
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
} FspAuthUsersSidBuf =
{
/* S-1-5-11 */
.V.Revision = SID_REVISION,
.V.SubAuthorityCount = 1,
.V.IdentifierAuthority.Value[5] = 5,
.V.SubAuthority[0] = 11,
};
static union
{ {
SID V; SID V;
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))]; UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
@ -52,11 +104,15 @@ union
.V.IdentifierAuthority.Value[5] = 0, .V.IdentifierAuthority.Value[5] = 0,
.V.SubAuthority[0] = 65534, .V.SubAuthority[0] = 65534,
}; };
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
#define FspWorldSid (&FspWorldSidBuf.V)
#define FspAuthUsersSid (&FspAuthUsersSidBuf.V)
#define FspUnmappedSid (&FspUnmappedSidBuf.V) #define FspUnmappedSid (&FspUnmappedSidBuf.V)
#define FspUnmappedUid (65534) #define FspUnmappedUid (65534)
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
#if !defined(_KERNEL_MODE)
static BOOL WINAPI FspPosixInitialize( static BOOL WINAPI FspPosixInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{ {
@ -120,9 +176,79 @@ VOID FspPosixFinalize(BOOLEAN Dynamic)
MemFree(FspPrimaryDomainSid); MemFree(FspPrimaryDomainSid);
} }
} }
#else
ULONG NTAPI FspPosixInitialize(
PRTL_RUN_ONCE RunOnce, PVOID Parameter, PVOID *Context)
{
static union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} FspAccountDomainSidBuf;
static union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} FspPrimaryDomainSidBuf;
UNICODE_STRING Path;
UNICODE_STRING Name;
union
{
KEY_VALUE_PARTIAL_INFORMATION V;
UINT8 B[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + SECURITY_MAX_SID_SIZE];
} Value;
ULONG Length;
NTSTATUS Result;
RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\SECURITY\\Policy\\PolAcDmS");
RtlZeroMemory(&Name, sizeof Name);
Length = sizeof Value;
Result = FspRegistryGetValue(&Path, &Name, &Value.V, &Length);
if (NT_SUCCESS(Result) && REG_NONE == Value.V.Type &&
sizeof(SID) <= Value.V.DataLength && RtlValidSid((PSID)&Value.V.Data))
{
RtlCopyMemory(&FspAccountDomainSidBuf.V, &Value.V.Data, Value.V.DataLength);
FspAccountDomainSid = &FspAccountDomainSidBuf.V;
}
RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\SECURITY\\Policy\\PolPrDmS");
RtlZeroMemory(&Name, sizeof Name);
Length = sizeof Value;
Result = FspRegistryGetValue(&Path, &Name, &Value.V, &Length);
if (NT_SUCCESS(Result) && REG_NONE == Value.V.Type &&
sizeof(SID) <= Value.V.DataLength && RtlValidSid((PSID)&Value.V.Data))
{
RtlCopyMemory(&FspPrimaryDomainSidBuf.V, &Value.V.Data, Value.V.DataLength);
FspPrimaryDomainSid = &FspPrimaryDomainSidBuf.V;
}
return TRUE;
}
#endif
static inline BOOLEAN FspPosixIsRelativeSid(PISID Sid1, PISID Sid2)
{
if (Sid1->Revision != Sid2->Revision)
return FALSE;
if (Sid1->IdentifierAuthority.Value[0] != Sid2->IdentifierAuthority.Value[0] ||
Sid1->IdentifierAuthority.Value[1] != Sid2->IdentifierAuthority.Value[1] ||
Sid1->IdentifierAuthority.Value[2] != Sid2->IdentifierAuthority.Value[2] ||
Sid1->IdentifierAuthority.Value[3] != Sid2->IdentifierAuthority.Value[3] ||
Sid1->IdentifierAuthority.Value[4] != Sid2->IdentifierAuthority.Value[4] ||
Sid1->IdentifierAuthority.Value[5] != Sid2->IdentifierAuthority.Value[5])
return FALSE;
if (Sid1->SubAuthorityCount + 1 != Sid2->SubAuthorityCount)
return FALSE;
for (ULONG I = 0; Sid1->SubAuthorityCount > I; I++)
if (Sid1->SubAuthority[I] != Sid2->SubAuthority[I])
return FALSE;
return TRUE;
}
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid) FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
{ {
FSP_KU_CODE;
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0); InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
*PSid = 0; *PSid = 0;
@ -221,7 +347,7 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
* S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y * S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y
*/ */
else if (0x10000 <= Uid && Uid < 0x11000) else if (0x10000 <= Uid && Uid < 0x11000)
*PSid = FspPosixCreateSid((Uid - 0x10000) >> 8, 1, (Uid - 0x10000) & 0xff); *PSid = FspPosixCreateSid((BYTE)((Uid - 0x10000) >> 8), 1, (Uid - 0x10000) & 0xff);
/* [IDMAP] /* [IDMAP]
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID): * Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
@ -238,13 +364,15 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid) FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
{ {
FSP_KU_CODE;
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0); InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
BYTE Authority; BYTE Authority;
BYTE Count; BYTE Count;
UINT32 SubAuthority0, Rid; UINT32 SubAuthority0, Rid;
*PUid = -1; *PUid = (UINT32)-1;
if (!IsValidSid(Sid) || 0 == (Count = *GetSidSubAuthorityCount(Sid))) if (!IsValidSid(Sid) || 0 == (Count = *GetSidSubAuthorityCount(Sid)))
return STATUS_INVALID_SID; return STATUS_INVALID_SID;
@ -298,12 +426,11 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
* has PrimaryDomainSid == AccountDomainSid. * has PrimaryDomainSid == AccountDomainSid.
*/ */
BOOL EqualDomains = FALSE;
if (0 != FspPrimaryDomainSid && if (0 != FspPrimaryDomainSid &&
EqualDomainSid(FspPrimaryDomainSid, Sid, &EqualDomains) && EqualDomains) FspPosixIsRelativeSid(FspPrimaryDomainSid, Sid))
*PUid = 0x100000 + Rid; *PUid = 0x100000 + Rid;
else if (0 != FspAccountDomainSid && else if (0 != FspAccountDomainSid &&
EqualDomainSid(FspAccountDomainSid, Sid, &EqualDomains) && EqualDomains) FspPosixIsRelativeSid(FspAccountDomainSid, Sid))
*PUid = 0x30000 + Rid; *PUid = 0x30000 + Rid;
/* /*
@ -348,6 +475,8 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...) static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...)
{ {
FSP_KU_CODE;
PISID Sid; PISID Sid;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority; SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
va_list ap; va_list ap;
@ -370,6 +499,8 @@ static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...)
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)()) FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)())
{ {
FSP_KU_CODE;
if (FspUnmappedSid == Sid) if (FspUnmappedSid == Sid)
; ;
else if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc) else if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc)
@ -439,7 +570,9 @@ FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode, UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR *PSecurityDescriptor) PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{ {
PSID OwnerSid = 0, GroupSid = 0, WorldSid = 0; FSP_KU_CODE;
PSID OwnerSid = 0, GroupSid = 0;
UINT32 OwnerPerm, OwnerDeny, GroupPerm, GroupDeny, WorldPerm; UINT32 OwnerPerm, OwnerDeny, GroupPerm, GroupDeny, WorldPerm;
PACL Acl = 0; PACL Acl = 0;
SECURITY_DESCRIPTOR SecurityDescriptor; SECURITY_DESCRIPTOR SecurityDescriptor;
@ -457,13 +590,6 @@ FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
WorldSid = FspWksidGet(WinWorldSid);
if (0 == WorldSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
OwnerPerm = (Mode & 0700) >> 6; OwnerPerm = (Mode & 0700) >> 6;
GroupPerm = (Mode & 0070) >> 3; GroupPerm = (Mode & 0070) >> 3;
WorldPerm = (Mode & 0007); WorldPerm = (Mode & 0007);
@ -502,7 +628,7 @@ FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
sizeof(ACCESS_DENIED_ACE) * (!!OwnerDeny + !!GroupDeny); sizeof(ACCESS_DENIED_ACE) * (!!OwnerDeny + !!GroupDeny);
Size += GetLengthSid(OwnerSid) - sizeof(DWORD); Size += GetLengthSid(OwnerSid) - sizeof(DWORD);
Size += GetLengthSid(GroupSid) - sizeof(DWORD); Size += GetLengthSid(GroupSid) - sizeof(DWORD);
Size += GetLengthSid(WorldSid) - sizeof(DWORD); Size += GetLengthSid(FspWorldSid) - sizeof(DWORD);
if (OwnerDeny) if (OwnerDeny)
Size += GetLengthSid(OwnerSid) - sizeof(DWORD); Size += GetLengthSid(OwnerSid) - sizeof(DWORD);
if (GroupDeny) if (GroupDeny)
@ -546,7 +672,7 @@ FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
if (!AddAccessAllowedAce(Acl, ACL_REVISION, if (!AddAccessAllowedAce(Acl, ACL_REVISION,
FspPosixDefaultPerm | FspPosixMapPermissionToAccessMask(Mode, WorldPerm), FspPosixDefaultPerm | FspPosixMapPermissionToAccessMask(Mode, WorldPerm),
WorldSid)) FspWorldSid))
goto lasterror; goto lasterror;
if (!InitializeSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) if (!InitializeSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
@ -621,7 +747,9 @@ FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
PSECURITY_DESCRIPTOR SecurityDescriptor, PSECURITY_DESCRIPTOR SecurityDescriptor,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode) PUINT32 PUid, PUINT32 PGid, PUINT32 PMode)
{ {
PSID OwnerSid = 0, GroupSid = 0, WorldSid = 0, AuthUsersSid = 0; FSP_KU_CODE;
PSID OwnerSid = 0, GroupSid = 0;
BOOL Defaulted, DaclPresent; BOOL Defaulted, DaclPresent;
PACL Acl = 0; PACL Acl = 0;
ACL_SIZE_INFORMATION AclSizeInfo; ACL_SIZE_INFORMATION AclSizeInfo;
@ -653,20 +781,6 @@ FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
if (0 != Acl) if (0 != Acl)
{ {
WorldSid = FspWksidGet(WinWorldSid);
if (0 == WorldSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
AuthUsersSid = FspWksidGet(WinAuthenticatedUserSid);
if (0 == AuthUsersSid)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
OwnerAllow = OwnerDeny = GroupAllow = GroupDeny = WorldAllow = WorldDeny = 0; OwnerAllow = OwnerDeny = GroupAllow = GroupDeny = WorldAllow = WorldDeny = 0;
if (!GetAclInformation(Acl, &AclSizeInfo, sizeof AclSizeInfo, AclSizeInformation)) if (!GetAclInformation(Acl, &AclSizeInfo, sizeof AclSizeInfo, AclSizeInformation))
@ -701,7 +815,7 @@ FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
* add the allowed or denied access right bits into the "owner", "group" * add the allowed or denied access right bits into the "owner", "group"
* and "other" collections. * and "other" collections.
*/ */
if (EqualSid(WorldSid, AceSid) || EqualSid(AuthUsersSid, AceSid)) if (EqualSid(FspWorldSid, AceSid) || EqualSid(FspAuthUsersSid, AceSid))
{ {
/* [PERMS] /* [PERMS]
* If this is an access-denied ACE, then add each access right to the set * If this is an access-denied ACE, then add each access right to the set
@ -812,6 +926,8 @@ static UINT32 FspPosixInvalidPathChars[4] =
FSP_API NTSTATUS FspPosixMapWindowsToPosixPathEx(PWSTR WindowsPath, char **PPosixPath, FSP_API NTSTATUS FspPosixMapWindowsToPosixPathEx(PWSTR WindowsPath, char **PPosixPath,
BOOLEAN Translate) BOOLEAN Translate)
{ {
FSP_KU_CODE;
NTSTATUS Result; NTSTATUS Result;
ULONG Size; ULONG Size;
char *PosixPath = 0, *p, *q; char *PosixPath = 0, *p, *q;
@ -874,6 +990,8 @@ lasterror:
FSP_API NTSTATUS FspPosixMapPosixToWindowsPathEx(const char *PosixPath, PWSTR *PWindowsPath, FSP_API NTSTATUS FspPosixMapPosixToWindowsPathEx(const char *PosixPath, PWSTR *PWindowsPath,
BOOLEAN Translate) BOOLEAN Translate)
{ {
FSP_KU_CODE;
NTSTATUS Result; NTSTATUS Result;
ULONG Size; ULONG Size;
PWSTR WindowsPath = 0, p; PWSTR WindowsPath = 0, p;
@ -925,11 +1043,15 @@ lasterror:
FSP_API VOID FspPosixDeletePath(void *Path) FSP_API VOID FspPosixDeletePath(void *Path)
{ {
FSP_KU_CODE;
MemFree(Path); MemFree(Path);
} }
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size) FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size)
{ {
FSP_KU_CODE;
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++) for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
{ {
WCHAR c = *p; WCHAR c = *p;
@ -944,6 +1066,8 @@ FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size)
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size) FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size)
{ {
FSP_KU_CODE;
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++) for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
{ {
WCHAR c = *p; WCHAR c = *p;

134
src/ku/uuid5.c Normal file
View File

@ -0,0 +1,134 @@
/**
* @file dll/uuid5.c
*
* @copyright 2015-2019 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 <ku/library.h>
#include <bcrypt.h>
/*
* This module is used to create UUID v5 identifiers. UUID v5 identifiers
* are effectively SHA1 hashes that are modified to fit within the UUID
* format. The resulting identifiers use version 5 and variant 2. The hash
* is taken over the concatenation of a namespace ID and a name; the namespace
* ID is another UUID and the name can be any string of bytes ("octets").
*
* For details see RFC 4122: https://tools.ietf.org/html/rfc4122
*/
NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUID *Uuid)
{
BCRYPT_ALG_HANDLE ProvHandle = 0;
BCRYPT_HASH_HANDLE HashHandle = 0;
UINT8 Temp[20];
NTSTATUS Result;
/*
* Windows UUID's are encoded in little-endian format. RFC 4122 specifies that for
* UUID v5 computation, UUID's must be converted to/from big-endian.
*
* Note that Windows is always little-endian:
* https://community.osr.com/discussion/comment/146810/#Comment_146810
*/
/* copy Namespace to local buffer in network byte order (big-endian) */
Temp[ 0] = ((PUINT8)Namespace)[ 3];
Temp[ 1] = ((PUINT8)Namespace)[ 2];
Temp[ 2] = ((PUINT8)Namespace)[ 1];
Temp[ 3] = ((PUINT8)Namespace)[ 0];
Temp[ 4] = ((PUINT8)Namespace)[ 5];
Temp[ 5] = ((PUINT8)Namespace)[ 4];
Temp[ 6] = ((PUINT8)Namespace)[ 7];
Temp[ 7] = ((PUINT8)Namespace)[ 6];
Temp[ 8] = ((PUINT8)Namespace)[ 8];
Temp[ 9] = ((PUINT8)Namespace)[ 9];
Temp[10] = ((PUINT8)Namespace)[10];
Temp[11] = ((PUINT8)Namespace)[11];
Temp[12] = ((PUINT8)Namespace)[12];
Temp[13] = ((PUINT8)Namespace)[13];
Temp[14] = ((PUINT8)Namespace)[14];
Temp[15] = ((PUINT8)Namespace)[15];
/*
* Unfortunately we cannot reuse the hashing object, because BCRYPT_HASH_REUSABLE_FLAG
* is available in Windows 8 and later. (WinFsp currently supports Windows 7 or later).
*/
Result = BCryptOpenAlgorithmProvider(&ProvHandle, BCRYPT_SHA1_ALGORITHM, 0, 0);
if (!NT_SUCCESS(Result))
goto exit;
Result = BCryptCreateHash(ProvHandle, &HashHandle, 0, 0, 0, 0, 0);
if (!NT_SUCCESS(Result))
goto exit;
Result = BCryptHashData(HashHandle, (PVOID)Temp, 16, 0);
if (!NT_SUCCESS(Result))
goto exit;
Result = BCryptHashData(HashHandle, (PVOID)Buffer, Size, 0);
if (!NT_SUCCESS(Result))
goto exit;
Result = BCryptFinishHash(HashHandle, Temp, 20, 0);
if (!NT_SUCCESS(Result))
goto exit;
/* copy local buffer to Uuid in host byte order (little-endian) */
((PUINT8)Uuid)[ 0] = Temp[ 3];
((PUINT8)Uuid)[ 1] = Temp[ 2];
((PUINT8)Uuid)[ 2] = Temp[ 1];
((PUINT8)Uuid)[ 3] = Temp[ 0];
((PUINT8)Uuid)[ 4] = Temp[ 5];
((PUINT8)Uuid)[ 5] = Temp[ 4];
((PUINT8)Uuid)[ 6] = Temp[ 7];
((PUINT8)Uuid)[ 7] = Temp[ 6];
((PUINT8)Uuid)[ 8] = Temp[ 8];
((PUINT8)Uuid)[ 9] = Temp[ 9];
((PUINT8)Uuid)[10] = Temp[10];
((PUINT8)Uuid)[11] = Temp[11];
((PUINT8)Uuid)[12] = Temp[12];
((PUINT8)Uuid)[13] = Temp[13];
((PUINT8)Uuid)[14] = Temp[14];
((PUINT8)Uuid)[15] = Temp[15];
/* [RFC 4122 Section 4.3]
* Set the four most significant bits (bits 12 through 15) of the
* time_hi_and_version field to the appropriate 4-bit version number
* from Section 4.1.3.
*/
Uuid->Data3 = (5 << 12) | (Uuid->Data3 & 0x0fff);
/* [RFC 4122 Section 4.3]
* Set the two most significant bits (bits 6 and 7) of the
* clock_seq_hi_and_reserved to zero and one, respectively.
*/
Uuid->Data4[0] = (2 << 6) | (Uuid->Data4[0] & 0x3f);
Result = STATUS_SUCCESS;
exit:
if (0 != HashHandle)
BCryptDestroyHash(HashHandle);
if (0 != ProvHandle)
BCryptCloseAlgorithmProvider(ProvHandle, 0);
return Result;
}

View File

@ -503,24 +503,19 @@ static SVC_INSTANCE *SvcInstanceLookup(PWSTR ClassName, PWSTR InstanceName)
return 0; return 0;
} }
static ULONG SvcInstanceArgumentLength(PWSTR Arg) static inline ULONG SvcInstanceArgumentLength(PWSTR Arg, PWSTR Pattern)
{ {
ULONG Length; PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
Length = 2; /* for beginning and ending quotes */ return 2 + (ULONG)(UINT_PTR)PathTransform(0, Arg, Pattern);
for (PWSTR P = Arg; *P; P++)
if (L'"' != *P)
Length++;
return Length;
} }
static PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg) static inline PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg, PWSTR Pattern)
{ {
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern);
*Dest++ = L'"'; *Dest++ = L'"';
for (PWSTR P = Arg; *P; P++) Dest = PathTransform(Dest, Arg, Pattern);
if (L'"' != *P)
*Dest++ = *P;
*Dest++ = L'"'; *Dest++ = L'"';
return Dest; return Dest;
@ -532,6 +527,7 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
PWSTR NewString = 0, P, Q; PWSTR NewString = 0, P, Q;
PWSTR EmptyArg = L""; PWSTR EmptyArg = L"";
ULONG Length; ULONG Length;
PWSTR Pattern;
*PNewString = 0; *PNewString = 0;
@ -541,24 +537,36 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
switch (*P) switch (*P)
{ {
case L'%': case L'%':
Pattern = 0;
P++; P++;
if (L'\\' == *P)
{
Pattern = ++P;
while (!(L'\0' == *P ||
(L'0' <= *P && *P <= '9') ||
(L'A' <= *P && *P <= 'Z')))
P++;
}
if (L'0' <= *P && *P <= '9') if (L'0' <= *P && *P <= '9')
{ {
if (Argc > (ULONG)(*P - L'0')) if (Argc > (ULONG)(*P - L'0'))
Length += SvcInstanceArgumentLength(Argv[*P - L'0']); Length += SvcInstanceArgumentLength(Argv[*P - L'0'], Pattern);
else else
Length += SvcInstanceArgumentLength(EmptyArg); Length += SvcInstanceArgumentLength(EmptyArg, 0);
} }
else else
if (L'U' == *P) if (L'U' == *P)
{ {
if (0 != SvcInstanceUserName()) if (0 != SvcInstanceUserName())
Length += SvcInstanceArgumentLength(SvcInstanceUserName()); Length += SvcInstanceArgumentLength(SvcInstanceUserName(), Pattern);
else else
Length += SvcInstanceArgumentLength(EmptyArg); Length += SvcInstanceArgumentLength(EmptyArg, 0);
} }
else else
if (*P)
Length++; Length++;
else
P--;
break; break;
default: default:
Length++; Length++;
@ -575,24 +583,36 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
switch (*P) switch (*P)
{ {
case L'%': case L'%':
Pattern = 0;
P++; P++;
if (L'\\' == *P)
{
Pattern = ++P;
while (!(L'\0' == *P ||
(L'0' <= *P && *P <= '9') ||
(L'A' <= *P && *P <= 'Z')))
P++;
}
if (L'0' <= *P && *P <= '9') if (L'0' <= *P && *P <= '9')
{ {
if (Argc > (ULONG)(*P - L'0')) if (Argc > (ULONG)(*P - L'0'))
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0']); Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0'], Pattern);
else else
Q = SvcInstanceArgumentCopy(Q, EmptyArg); Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0);
} }
else else
if (L'U' == *P) if (L'U' == *P)
{ {
if (0 != SvcInstanceUserName()) if (0 != SvcInstanceUserName())
Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName()); Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName(), Pattern);
else else
Q = SvcInstanceArgumentCopy(Q, EmptyArg); Q = SvcInstanceArgumentCopy(Q, EmptyArg, 0);
} }
else else
if (*P)
*Q++ = *P; *Q++ = *P;
else
P--;
break; break;
default: default:
*Q++ = *P; *Q++ = *P;

182
src/launcher/ptrans.c Normal file
View File

@ -0,0 +1,182 @@
/**
* @file launcher/ptrans.c
*
* @copyright 2015-2019 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.
*/
/**
* Path Transformation Language
*
* Syntax:
* PERCENT BACKLASH replace-sep *(*sep component) [*sep UNDERSCORE] arg
*
* Arg:
* The command line argument that a rule is applied on. These are denoted
* by digits [0-9] or a capital letter (A-Z).
*
* Component:
* A path component denoted by a small letter (a-z). The letter a denotes
* the first path component, the letter b the second path component, etc.
*
* UNDERSCORE:
* The UNDERSCORE (_) denotes the "rest of the path". This is any path
* left after any path components explicitly mentioned by using small
* letters (a-z).
*
* Sep:
* A separator symbol that is used to separated components.
* E.g. slash (/), colon (:), etc.
*
* Replace-sep:
* A separator symbol that replaces the backslash (\) separator in the
* "rest of the path" (UNDERSCORE). E.g. slash (/), colon (:), etc.
*
*
* Examples:
* - %\/b:_1
* - Transforms \rclone\REMOTE\PATH\TO\FILES to REMOTE:PATH/TO/FILES
* - %\/b:/_1
* - Transforms \rclone\REMOTE\PATH\TO\FILES to REMOTE:/PATH/TO/FILES
* - %\/_1
* - Transforms \P1\P2\P3 to /P1/P2/P3
* - %\+_1
* - Transforms \P1\P2\P3 to +P1+P2+P3
* - %\\_1
* - Transforms \P1\P2\P3 to \\P1\\P2\\P3
* (Backslash is doubled up when used as a replacement separator!)
*/
#include <winfsp/launch.h>
#include <shared/minimal.h>
static PWSTR PathCopy(PWSTR Dest, PWSTR Arg, PWSTR ArgEnd, BOOLEAN WriteDest, WCHAR Replacement)
{
if (0 != Replacement)
{
for (PWSTR P = Arg, EndP = (0 != ArgEnd ? ArgEnd : (PWSTR)(UINT_PTR)~0); EndP > P && *P; P++)
if (L'\\' == *P)
{
if (L'\\' == Replacement)
{
if (WriteDest)
*Dest = Replacement;
Dest++;
}
if (WriteDest)
*Dest = Replacement;
Dest++;
}
else if (L'"' != *P)
{
if (WriteDest)
*Dest = *P;
Dest++;
}
}
else
{
for (PWSTR P = Arg, EndP = (0 != ArgEnd ? ArgEnd : (PWSTR)(UINT_PTR)~0); EndP > P && *P; P++)
if (L'"' != *P)
{
if (WriteDest)
*Dest = *P;
Dest++;
}
}
return Dest;
}
static inline BOOLEAN PatternEnd(WCHAR C)
{
return L'\0' == C ||
(L'0' <= C && C <= '9') ||
(L'A' <= C && C <= 'Z');
}
PWSTR PathTransform(PWSTR Dest, PWSTR Arg, PWSTR Pattern)
{
BOOLEAN WriteDest = 0 != Dest;
WCHAR Replacement;
PWSTR Components[26][2];
PWSTR Remainder = Arg;
ULONG RemainderIndex = 0;
PWSTR P;
if (0 == Pattern)
return PathCopy(Dest, Arg, 0, WriteDest, 0);
for (ULONG I = 0; 26 > I; I++)
Components[I][0] = 0;
Replacement = *Pattern++;
if (PatternEnd(Replacement))
return Dest;
while (!PatternEnd(*Pattern))
{
if (L'a' <= *Pattern && *Pattern <= 'z')
{
ULONG I = *Pattern - 'a', J;
if (0 == Components[I][0])
{
P = Remainder;
J = RemainderIndex;
while (L'\\' == *P)
P++;
for (;;)
{
Components[J][0] = P;
while (*P && L'\\' != *P)
P++;
Components[J][1] = P;
while (L'\\' == *P)
P++;
if (I == J)
{
Remainder = P;
RemainderIndex = I + 1;
break;
}
J++;
}
}
Dest = PathCopy(Dest, Components[I][0], Components[I][1], WriteDest, Replacement);
}
else
if (L'_' == *Pattern)
Dest = PathCopy(Dest, Remainder, 0, WriteDest, Replacement);
else
{
if (WriteDest)
*Dest = *Pattern;
Dest++;
}
Pattern++;
}
return Dest;
}

View File

@ -72,6 +72,7 @@ NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD L
#pragma function(memset) #pragma function(memset)
#pragma function(memcpy) #pragma function(memcpy)
#pragma function(memmove)
static inline static inline
void *memset(void *dst, int val, size_t siz) void *memset(void *dst, int val, size_t siz)
{ {

View File

@ -29,7 +29,7 @@ static NTSTATUS FspFsvolCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolCreateNoLock( static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen); BOOLEAN MainFileOpen, PFSP_ATOMIC_CREATE_ECP_CONTEXT AtomicCreateEcp);
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
@ -144,6 +144,7 @@ static NTSTATUS FspFsvolCreate(
PECP_LIST ExtraCreateParameters; PECP_LIST ExtraCreateParameters;
PVOID ExtraCreateParameter; PVOID ExtraCreateParameter;
BOOLEAN MainFileOpen = FALSE; BOOLEAN MainFileOpen = FALSE;
PFSP_ATOMIC_CREATE_ECP_CONTEXT AtomicCreateEcp = 0;
/* /*
* Check if the IRP has ECP's. * Check if the IRP has ECP's.
@ -219,6 +220,21 @@ static NTSTATUS FspFsvolCreate(
} }
} }
#endif #endif
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.WslFeatures)
{
// {4720bd83-52ac-4104-a130-d1ec6a8cc8e5}
static const GUID FspAtomicCreateEcpGuid =
{ 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
ExtraCreateParameter = 0;
AtomicCreateEcp =
NT_SUCCESS(FsRtlFindExtraCreateParameter(ExtraCreateParameters,
&FspAtomicCreateEcpGuid, &ExtraCreateParameter, 0)) &&
0 != ExtraCreateParameter &&
!FsRtlIsEcpFromUserMode(ExtraCreateParameter) ?
ExtraCreateParameter : 0;
}
} }
if (!MainFileOpen) if (!MainFileOpen)
@ -226,7 +242,8 @@ static NTSTATUS FspFsvolCreate(
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject); FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
try try
{ {
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, FALSE); Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp,
MainFileOpen, AtomicCreateEcp);
} }
finally finally
{ {
@ -235,14 +252,15 @@ static NTSTATUS FspFsvolCreate(
} }
} }
else else
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, TRUE); Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp,
MainFileOpen, AtomicCreateEcp);
return Result; return Result;
} }
static NTSTATUS FspFsvolCreateNoLock( static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen) BOOLEAN MainFileOpen, PFSP_ATOMIC_CREATE_ECP_CONTEXT AtomicCreateEcp)
{ {
PAGED_CODE(); PAGED_CODE();
@ -279,6 +297,8 @@ static NTSTATUS FspFsvolCreateNoLock(
USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess;
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG EaLength = IrpSp->Parameters.Create.EaLength; ULONG EaLength = IrpSp->Parameters.Create.EaLength;
PVOID ExtraBuffer = 0;
ULONG ExtraLength = 0;
ULONG Flags = IrpSp->Flags; ULONG Flags = IrpSp->Flags;
KPROCESSOR_MODE RequestorMode = KPROCESSOR_MODE RequestorMode =
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
@ -292,6 +312,7 @@ static NTSTATUS FspFsvolCreateNoLock(
BOOLEAN HasRestorePrivilege = BOOLEAN HasRestorePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE); BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE);
BOOLEAN HasTrailingBackslash = FALSE; BOOLEAN HasTrailingBackslash = FALSE;
BOOLEAN EaIsReparsePoint = FALSE;
FSP_FILE_NODE *FileNode, *RelatedFileNode; FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc; FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 }; UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
@ -302,6 +323,36 @@ static NTSTATUS FspFsvolCreateNoLock(
if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID)) if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID))
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
/* is there an AtomicCreateEcp attached? */
if (0 != AtomicCreateEcp)
{
if ((FILE_CREATE != CreateDisposition && FILE_OPEN_IF != CreateDisposition) ||
0 != EaBuffer ||
RTL_SIZEOF_THROUGH_FIELD(FSP_ATOMIC_CREATE_ECP_CONTEXT, ReparseBuffer) >
AtomicCreateEcp->Size ||
/* !!!: revisit: FlagOn*/
!FlagOn(AtomicCreateEcp->InFlags,
ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT |
ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED))
return STATUS_INVALID_PARAMETER; /* docs do not say what to return on failure! */
if (FlagOn(AtomicCreateEcp->InFlags,
ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED))
{
Result = FsRtlValidateReparsePointBuffer(AtomicCreateEcp->ReparseBufferLength,
AtomicCreateEcp->ReparseBuffer);
if (!NT_SUCCESS(Result))
return Result;
/* mark that we satisfied the reparse point request, although we may fail it later! */
AtomicCreateEcp->OutFlags = ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET;
ExtraBuffer = AtomicCreateEcp->ReparseBuffer;
ExtraLength = AtomicCreateEcp->ReparseBufferLength;
EaIsReparsePoint = TRUE;
}
}
/* was an EA buffer specified? */ /* was an EA buffer specified? */
if (0 != EaBuffer) if (0 != EaBuffer)
{ {
@ -318,6 +369,9 @@ static NTSTATUS FspFsvolCreateNoLock(
EaBuffer, EaLength, (PULONG)&Irp->IoStatus.Information); EaBuffer, EaLength, (PULONG)&Irp->IoStatus.Information);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
ExtraBuffer = EaBuffer;
ExtraLength = EaLength;
} }
/* cannot open a paging file */ /* cannot open a paging file */
@ -555,9 +609,9 @@ static NTSTATUS FspFsvolCreateNoLock(
SecurityDescriptorSize = 0; SecurityDescriptorSize = 0;
FileAttributes = 0; FileAttributes = 0;
/* cannot set EA on named stream */ /* cannot set extra buffer on named stream */
EaBuffer = 0; ExtraBuffer = 0;
EaLength = 0; ExtraLength = 0;
/* remember the main file node */ /* remember the main file node */
ASSERT(0 == FileNode->MainFileNode); ASSERT(0 == FileNode->MainFileNode);
@ -577,8 +631,8 @@ static NTSTATUS FspFsvolCreateNoLock(
/* create the user-mode file system request */ /* create the user-mode file system request */
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, Result = FspIopCreateRequestEx(Irp, &FileNode->FileName,
0 != EaBuffer ? 0 != ExtraBuffer ?
FSP_FSCTL_DEFAULT_ALIGN_UP(SecurityDescriptorSize) + EaLength : SecurityDescriptorSize, FSP_FSCTL_DEFAULT_ALIGN_UP(SecurityDescriptorSize) + ExtraLength : SecurityDescriptorSize,
FspFsvolCreateRequestFini, &Request); FspFsvolCreateRequestFini, &Request);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
@ -616,10 +670,10 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.DesiredAccess = DesiredAccess; Request->Req.Create.DesiredAccess = DesiredAccess;
Request->Req.Create.GrantedAccess = GrantedAccess; Request->Req.Create.GrantedAccess = GrantedAccess;
Request->Req.Create.ShareAccess = ShareAccess; Request->Req.Create.ShareAccess = ShareAccess;
Request->Req.Create.Ea.Offset = 0 != EaBuffer ? Request->Req.Create.Ea.Offset = 0 != ExtraBuffer ?
(0 != Request->Req.Create.SecurityDescriptor.Offset ? (0 != Request->Req.Create.SecurityDescriptor.Offset ?
NEXTOFS(Request->Req.Create.SecurityDescriptor) : NEXTOFS(Request->FileName)) : 0; NEXTOFS(Request->Req.Create.SecurityDescriptor) : NEXTOFS(Request->FileName)) : 0;
Request->Req.Create.Ea.Size = 0 != EaBuffer ? (UINT16)EaLength : 0; Request->Req.Create.Ea.Size = 0 != ExtraBuffer ? (UINT16)ExtraLength : 0;
Request->Req.Create.UserMode = UserMode == RequestorMode; Request->Req.Create.UserMode = UserMode == RequestorMode;
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege; Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
Request->Req.Create.HasBackupPrivilege = HasBackupPrivilege; Request->Req.Create.HasBackupPrivilege = HasBackupPrivilege;
@ -628,10 +682,10 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.CaseSensitive = CaseSensitive; Request->Req.Create.CaseSensitive = CaseSensitive;
Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash; Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash;
Request->Req.Create.NamedStream = MainFileName.Length; Request->Req.Create.NamedStream = MainFileName.Length;
#undef NEXTOFS
Request->Req.Create.AcceptsSecurityDescriptor = 0 == Request->Req.Create.NamedStream && Request->Req.Create.AcceptsSecurityDescriptor = 0 == Request->Req.Create.NamedStream &&
!!FsvolDeviceExtension->VolumeParams.AllowOpenInKernelMode; !!FsvolDeviceExtension->VolumeParams.AllowOpenInKernelMode;
Request->Req.Create.EaIsReparsePoint = EaIsReparsePoint;
#undef NEXTOFS
ASSERT( ASSERT(
0 == StreamPart.Length && 0 == MainFileName.Length || 0 == StreamPart.Length && 0 == MainFileName.Length ||
@ -642,10 +696,10 @@ static NTSTATUS FspFsvolCreateNoLock(
RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
SecurityDescriptor, SecurityDescriptorSize); SecurityDescriptor, SecurityDescriptorSize);
/* copy the EA buffer (if any) into the request */ /* copy the extra buffer (if any) into the request */
if (0 != EaBuffer) if (0 != ExtraBuffer)
RtlCopyMemory(Request->Buffer + Request->Req.Create.Ea.Offset, RtlCopyMemory(Request->Buffer + Request->Req.Create.Ea.Offset,
EaBuffer, EaLength); ExtraBuffer, ExtraLength);
/* fix FileNode->FileName if we are doing SL_OPEN_TARGET_DIRECTORY */ /* fix FileNode->FileName if we are doing SL_OPEN_TARGET_DIRECTORY */
if (Request->Req.Create.OpenTargetDirectory) if (Request->Req.Create.OpenTargetDirectory)

View File

@ -252,6 +252,8 @@ const char *FileInformationClassSym(FILE_INFORMATION_CLASS FileInformationClass)
SYM(FileReplaceCompletionInformation) SYM(FileReplaceCompletionInformation)
SYM(FileHardLinkFullIdInformation) SYM(FileHardLinkFullIdInformation)
SYM(FileIdExtdBothDirectoryInformation) SYM(FileIdExtdBothDirectoryInformation)
case 68: return "FileStatInformation";
case 70: return "FileStatLxInformation";
default: default:
return "FILE_INFORMATION_CLASS:Unknown"; return "FILE_INFORMATION_CLASS:Unknown";
} }

View File

@ -23,6 +23,9 @@
static NTSTATUS FspFsvrtDeviceControl( static NTSTATUS FspFsvrtDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static BOOLEAN FspFsvrtDeviceControlStorageQuery(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult);
static NTSTATUS FspFsvolDeviceControl( static NTSTATUS FspFsvolDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete; FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete;
@ -31,6 +34,7 @@ FSP_DRIVER_DISPATCH FspDeviceControl;
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsvrtDeviceControl) #pragma alloc_text(PAGE, FspFsvrtDeviceControl)
#pragma alloc_text(PAGE, FspFsvrtDeviceControlStorageQuery)
#pragma alloc_text(PAGE, FspFsvolDeviceControl) #pragma alloc_text(PAGE, FspFsvolDeviceControl)
#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete) #pragma alloc_text(PAGE, FspFsvolDeviceControlComplete)
#pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini) #pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini)
@ -43,10 +47,18 @@ enum
}; };
static NTSTATUS FspFsvrtDeviceControl( static NTSTATUS FspFsvrtDeviceControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
PAGED_CODE(); PAGED_CODE();
NTSTATUS Result;
if (FspFsvrtDeviceControlStorageQuery(FsvrtDeviceObject, Irp, IrpSp, &Result))
return Result;
if (FspMountdevDeviceControl(FsvrtDeviceObject, Irp, IrpSp, &Result))
return Result;
/* /*
* Fix GitHub issue #177. All credit for the investigation of this issue * Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes * and the suggested steps to reproduce and work around the problem goes
@ -64,6 +76,62 @@ static NTSTATUS FspFsvrtDeviceControl(
return STATUS_UNRECOGNIZED_VOLUME; return STATUS_UNRECOGNIZED_VOLUME;
} }
static BOOLEAN FspFsvrtDeviceControlStorageQuery(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult)
{
PAGED_CODE();
/*
* SQL Server insists on sending us storage level IOCTL's even though
* WinFsp file systems are not on top of a real disk. So bite the bullet
* and implement some of those storage IOCTL's to make SQL Server happy.
*/
if (IOCTL_STORAGE_QUERY_PROPERTY != IrpSp->Parameters.DeviceIoControl.IoControlCode ||
sizeof(STORAGE_PROPERTY_QUERY) > IrpSp->Parameters.DeviceIoControl.InputBufferLength)
return FALSE;
PSTORAGE_PROPERTY_QUERY Query = Irp->AssociatedIrp.SystemBuffer;
switch (Query->PropertyId)
{
case StorageAccessAlignmentProperty:
if (PropertyExistsQuery == Query->QueryType)
*PResult = STATUS_SUCCESS;
else if (PropertyStandardQuery == Query->QueryType)
{
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR Descriptor = Irp->AssociatedIrp.SystemBuffer;
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
if (sizeof(STORAGE_DESCRIPTOR_HEADER) > OutputBufferLength)
*PResult = STATUS_BUFFER_TOO_SMALL;
else if (sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) > OutputBufferLength)
{
Descriptor->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
Descriptor->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
*PResult = STATUS_SUCCESS;
}
else
{
RtlZeroMemory(Descriptor, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR));
Descriptor->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
Descriptor->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
Descriptor->BytesPerLogicalSector = FsvrtDeviceExtension->SectorSize;
Descriptor->BytesPerPhysicalSector = FsvrtDeviceExtension->SectorSize;
Irp->IoStatus.Information = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
*PResult = STATUS_SUCCESS;
}
}
else
*PResult = STATUS_NOT_SUPPORTED;
return TRUE;
}
return FALSE;
}
static NTSTATUS FspFsvolDeviceControl( static NTSTATUS FspFsvolDeviceControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
@ -72,6 +140,15 @@ static NTSTATUS FspFsvolDeviceControl(
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
NTSTATUS Result;
/*
* Possibly forward the IOCTL request to the user mode file system. The rules are:
*
* - File system must support DeviceControl.
* - Only IOCTL with custom devices (see DEVICE_TYPE_FROM_CTL_CODE) and
* METHOD_BUFFERED will be forwarded.
*/
/* do we support DeviceControl? */ /* do we support DeviceControl? */
if (!FsvolDeviceExtension->VolumeParams.DeviceControl) if (!FsvolDeviceExtension->VolumeParams.DeviceControl)
@ -90,7 +167,6 @@ static NTSTATUS FspFsvolDeviceControl(
if (!FspFileNodeIsValid(FileObject->FsContext)) if (!FspFileNodeIsValid(FileObject->FsContext))
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer; PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;

View File

@ -126,10 +126,12 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
case FspFsvolDeviceExtensionKind: case FspFsvolDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_FSVOL_DEVICE_EXTENSION); DeviceExtensionSize = sizeof(FSP_FSVOL_DEVICE_EXTENSION);
break; break;
case FspFsvrtDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_FSVRT_DEVICE_EXTENSION);
break;
case FspFsmupDeviceExtensionKind: case FspFsmupDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_FSMUP_DEVICE_EXTENSION); DeviceExtensionSize = sizeof(FSP_FSMUP_DEVICE_EXTENSION);
break; break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind: case FspFsctlDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_DEVICE_EXTENSION); DeviceExtensionSize = sizeof(FSP_DEVICE_EXTENSION);
break; break;
@ -184,10 +186,12 @@ NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject)
case FspFsvolDeviceExtensionKind: case FspFsvolDeviceExtensionKind:
Result = FspFsvolDeviceInit(DeviceObject); Result = FspFsvolDeviceInit(DeviceObject);
break; break;
case FspFsvrtDeviceExtensionKind:
Result = STATUS_SUCCESS;
break;
case FspFsmupDeviceExtensionKind: case FspFsmupDeviceExtensionKind:
Result = FspFsmupDeviceInit(DeviceObject); Result = FspFsmupDeviceInit(DeviceObject);
break; break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind: case FspFsctlDeviceExtensionKind:
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
break; break;
@ -213,10 +217,11 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
case FspFsvolDeviceExtensionKind: case FspFsvolDeviceExtensionKind:
FspFsvolDeviceFini(DeviceObject); FspFsvolDeviceFini(DeviceObject);
break; break;
case FspFsvrtDeviceExtensionKind:
break;
case FspFsmupDeviceExtensionKind: case FspFsmupDeviceExtensionKind:
FspFsmupDeviceFini(DeviceObject); FspFsmupDeviceFini(DeviceObject);
break; break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind: case FspFsctlDeviceExtensionKind:
break; break;
default: default:
@ -325,6 +330,22 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
* to track what has been initialized! * to track what has been initialized!
*/ */
/* initialize any fsext provider */
if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode, 0);
if (0 != Provider)
{
Result = Provider->DeviceInit(DeviceObject, &FsvolDeviceExtension->VolumeParams);
if (!NT_SUCCESS(Result))
return Result;
FsvolDeviceExtension->InitDoneFsext = 1;
}
else
return STATUS_OBJECT_NAME_NOT_FOUND;
}
/* is there a virtual disk? */ /* is there a virtual disk? */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject) if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
{ {
@ -500,6 +521,15 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
if (0 != FsvolDeviceExtension->SwapVpb) if (0 != FsvolDeviceExtension->SwapVpb)
FspFreeExternal(FsvolDeviceExtension->SwapVpb); FspFreeExternal(FsvolDeviceExtension->SwapVpb);
} }
/* finalize any fsext provider */
if (FsvolDeviceExtension->InitDoneFsext)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode, 0);
if (0 != Provider)
Provider->DeviceFini(DeviceObject);
}
} }
static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context) static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context)
@ -546,6 +576,14 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
/* run any fsext provider expiration routine */
if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode, 0);
if (0 != Provider)
Provider->DeviceExpirationRoutine(DeviceObject, InterruptTime);
}
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime); FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql); KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);

View File

@ -26,9 +26,12 @@
#define POOL_NX_OPTIN 1 #define POOL_NX_OPTIN 1
#include <ntifs.h> #include <ntifs.h>
#include <mountdev.h>
#include <ntddstor.h>
#include <ntstrsafe.h> #include <ntstrsafe.h>
#include <wdmsec.h> #include <wdmsec.h>
#include <winfsp/fsctl.h> #include <winfsp/fsctl.h>
#include <winfsp/fsext.h>
/* disable warnings */ /* disable warnings */
#pragma warning(disable:4100) /* unreferenced formal parameter */ #pragma warning(disable:4100) /* unreferenced formal parameter */
@ -36,6 +39,12 @@
#define DRIVER_NAME FSP_FSCTL_DRIVER_NAME #define DRIVER_NAME FSP_FSCTL_DRIVER_NAME
#if _WIN64
#define FSP_REGKEY "\\Registry\\Machine\\Software\\WOW6432Node\\WinFsp"
#else
#define FSP_REGKEY "\\Registry\\Machine\\Software\\WinFsp"
#endif
/* IoCreateDeviceSecure default SDDL's */ /* IoCreateDeviceSecure default SDDL's */
#define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)" #define FSP_FSCTL_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)"
/* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */ /* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */
@ -486,14 +495,28 @@ NTSTATUS FspFileNameInExpression(
PWCH UpcaseTable, PWCH UpcaseTable,
PBOOLEAN PResult); PBOOLEAN PResult);
/* UUID5 creation (ku) */
NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUID *Uuid);
/* utility */ /* utility */
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag); PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize); PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess, NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject); PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspRegistryGetValue(PUNICODE_STRING Path, PUNICODE_STRING ValueName,
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation, PULONG PValueInformationLength);
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length); FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PULONG PLength);
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength);
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength);
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation); NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation); NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress, ULONG ExtraPriorityFlags); NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress, ULONG ExtraPriorityFlags);
@ -1048,7 +1071,8 @@ typedef struct
{ {
FSP_DEVICE_EXTENSION Base; FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, InitDoneEa:1, UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, InitDoneEa:1,
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1; InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1,
InitDoneFsext;
PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject;
PDEVICE_OBJECT FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject;
@ -1078,8 +1102,19 @@ typedef struct
PNOTIFY_SYNC NotifySync; PNOTIFY_SYNC NotifySync;
LIST_ENTRY NotifyList; LIST_ENTRY NotifyList;
FSP_STATISTICS *Statistics; FSP_STATISTICS *Statistics;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 FsextData[];
} FSP_FSVOL_DEVICE_EXTENSION; } FSP_FSVOL_DEVICE_EXTENSION;
typedef struct typedef struct
{
FSP_DEVICE_EXTENSION Base;
UINT16 SectorSize;
LONG IsMountdev;
BOOLEAN Persistent;
GUID UniqueId;
UNICODE_STRING VolumeName;
WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)];
} FSP_FSVRT_DEVICE_EXTENSION;
typedef struct
{ {
FSP_DEVICE_EXTENSION Base; FSP_DEVICE_EXTENSION Base;
UINT32 InitDonePfxTab:1; UINT32 InitDonePfxTab:1;
@ -1099,6 +1134,12 @@ FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject)
return DeviceObject->DeviceExtension; return DeviceObject->DeviceExtension;
} }
static inline static inline
FSP_FSVRT_DEVICE_EXTENSION *FspFsvrtDeviceExtension(PDEVICE_OBJECT DeviceObject)
{
ASSERT(FspFsvrtDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
return DeviceObject->DeviceExtension;
}
static inline
FSP_FSMUP_DEVICE_EXTENSION *FspFsmupDeviceExtension(PDEVICE_OBJECT DeviceObject) FSP_FSMUP_DEVICE_EXTENSION *FspFsmupDeviceExtension(PDEVICE_OBJECT DeviceObject)
{ {
ASSERT(FspFsmupDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind); ASSERT(FspFsmupDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
@ -1169,6 +1210,9 @@ VOID FspDeviceGlobalUnlock(VOID)
//(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\ //(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED) // STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
/* fsext */
FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 FsextControlCode, PNTSTATUS PLoadResult);
/* process buffers conditional usage */ /* process buffers conditional usage */
static inline static inline
BOOLEAN FspReadIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize) BOOLEAN FspReadIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
@ -1200,6 +1244,20 @@ BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
} }
#endif #endif
/* mountdev */
NTSTATUS FspMountdevQueryDeviceName(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspMountdevQueryUniqueId(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
BOOLEAN FspMountdevDeviceControl(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult);
NTSTATUS FspMountdevMake(
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
BOOLEAN Persistent);
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject);
/* fsmup */ /* fsmup */
NTSTATUS FspMupRegister( NTSTATUS FspMupRegister(
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject); PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
@ -1209,19 +1267,22 @@ NTSTATUS FspMupHandleIrp(
PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp); PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp);
/* volume management */ /* volume management */
#define FspVolumeTransactEarlyTimeout (1 * 10000ULL)
NTSTATUS FspVolumeCreate( NTSTATUS FspVolumeCreate(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
VOID FspVolumeDelete( VOID FspVolumeDelete(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeMount( NTSTATUS FspVolumeMount(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeMakeMountdev(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeGetName( NTSTATUS FspVolumeGetName(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeGetNameList( NTSTATUS FspVolumeGetNameList(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeTransact( NTSTATUS FspVolumeTransact(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeStop( NTSTATUS FspVolumeStop(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeWork( NTSTATUS FspVolumeWork(
@ -1571,7 +1632,7 @@ NTSTATUS FspFileNodeOplockCheckAsyncEx(
CompletionRoutine, CompletionRoutine,
PostIrpRoutine); PostIrpRoutine);
#if DBG #if DBG
if (STATUS_SUCCESS == Result && DEBUGTEST(10)) if (DEBUGTEST_EX(STATUS_SUCCESS == Result, 10, FALSE))
{ {
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
@ -1636,4 +1697,74 @@ LOGICAL RtlEqualMemory(const VOID *Source1, const VOID *Source2, SIZE_T Length)
return Length == RtlCompareMemory(Source1, Source2, Length); return Length == RtlCompareMemory(Source1, Source2, Length);
} }
/* FILE_STAT_INFORMATION and FILE_STAT_LX_INFORMATION are missings on some WDK's. */
typedef struct
{
LARGE_INTEGER FileId;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER AllocationSize;
LARGE_INTEGER EndOfFile;
ULONG FileAttributes;
ULONG ReparseTag;
ULONG NumberOfLinks;
ACCESS_MASK EffectiveAccess;
} FSP_FILE_STAT_INFORMATION, *PFSP_FILE_STAT_INFORMATION;
typedef struct
{
LARGE_INTEGER FileId;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER AllocationSize;
LARGE_INTEGER EndOfFile;
ULONG FileAttributes;
ULONG ReparseTag;
ULONG NumberOfLinks;
ACCESS_MASK EffectiveAccess;
ULONG LxFlags;
ULONG LxUid;
ULONG LxGid;
ULONG LxMode;
ULONG LxDeviceIdMajor;
ULONG LxDeviceIdMinor;
} FSP_FILE_STAT_LX_INFORMATION, *PFSP_FILE_STAT_LX_INFORMATION;
/* ATOMIC_CREATE_ECP_CONTEXT is missing on some WDK's */
#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
typedef struct
{
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
} FSP_FILE_TIMESTAMPS, *PFSP_FILE_TIMESTAMPS;
typedef struct
{
USHORT Size;
USHORT InFlags;
USHORT OutFlags;
USHORT ReparseBufferLength;
PREPARSE_DATA_BUFFER ReparseBuffer;
LONGLONG FileSize;
LONGLONG ValidDataLength;
PFSP_FILE_TIMESTAMPS FileTimestamps;
ULONG FileAttributes;
ULONG UsnSourceInfo;
USN Usn;
ULONG SuppressFileAttributeInheritanceMask;
ULONG InOpFlags;
ULONG OutOpFlags;
ULONG InGenFlags;
ULONG OutGenFlags;
ULONG CaseSensitiveFlagsMask;
ULONG InCaseSensitiveFlags;
ULONG OutCaseSensitiveFlags;
} FSP_ATOMIC_CREATE_ECP_CONTEXT, *PFSP_ATOMIC_CREATE_ECP_CONTEXT;
#endif #endif

View File

@ -55,6 +55,7 @@ FSP_DRIVER_DISPATCH FspSetEa;
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsvolQueryEaGetCopy) #pragma alloc_text(PAGE, FspFsvolQueryEaGetCopy)
#pragma alloc_text(PAGE, FspFsvolQueryEaIndexCopy) #pragma alloc_text(PAGE, FspFsvolQueryEaIndexCopy)
#pragma alloc_text(PAGE, FspFsvolQueryEaCopy)
#pragma alloc_text(PAGE, FspFsvolQueryEa) #pragma alloc_text(PAGE, FspFsvolQueryEa)
#pragma alloc_text(PAGE, FspFsvolQueryEaComplete) #pragma alloc_text(PAGE, FspFsvolQueryEaComplete)
#pragma alloc_text(PAGE, FspFsvolQueryEaRequestFini) #pragma alloc_text(PAGE, FspFsvolQueryEaRequestFini)

View File

@ -45,6 +45,15 @@ static NTSTATUS FspFsvolQueryPositionInformation(PFILE_OBJECT FileObject,
static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject, static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd, PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo); const FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS FspFsvolQueryStatBaseInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS FspFsvolQueryStatLxBaseInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS FspFsvolQueryStatLxEaInformation(
PDEVICE_OBJECT FsvolDeviceObject, PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd);
static NTSTATUS FspFsvolQueryStreamInformationCopy( static NTSTATUS FspFsvolQueryStreamInformationCopy(
FSP_FSCTL_STREAM_INFO *StreamInfoBuffer, ULONG StreamInfoBufferSize, FSP_FSCTL_STREAM_INFO *StreamInfoBuffer, ULONG StreamInfoBufferSize,
PVOID DestBuf, PULONG PDestLen); PVOID DestBuf, PULONG PDestLen);
@ -52,6 +61,9 @@ static NTSTATUS FspFsvolQueryStreamInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolQueryStreamInformationSuccess( static NTSTATUS FspFsvolQueryStreamInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolQueryInformationEffectiveAccess(
PDEVICE_OBJECT FsvolDeviceObject, PFILE_OBJECT FileObject,
PACCESS_MASK PEffectiveAccess);
static NTSTATUS FspFsvolQueryInformation( static NTSTATUS FspFsvolQueryInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete; FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete;
@ -97,9 +109,13 @@ FAST_IO_QUERY_OPEN FspFastIoQueryOpen;
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation) #pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
#pragma alloc_text(PAGE, FspFsvolQueryPositionInformation) #pragma alloc_text(PAGE, FspFsvolQueryPositionInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStandardInformation) #pragma alloc_text(PAGE, FspFsvolQueryStandardInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStatBaseInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStatLxBaseInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStatLxEaInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationCopy) #pragma alloc_text(PAGE, FspFsvolQueryStreamInformationCopy)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformation) #pragma alloc_text(PAGE, FspFsvolQueryStreamInformation)
#pragma alloc_text(PAGE, FspFsvolQueryStreamInformationSuccess) #pragma alloc_text(PAGE, FspFsvolQueryStreamInformationSuccess)
#pragma alloc_text(PAGE, FspFsvolQueryInformationEffectiveAccess)
#pragma alloc_text(PAGE, FspFsvolQueryInformation) #pragma alloc_text(PAGE, FspFsvolQueryInformation)
#pragma alloc_text(PAGE, FspFsvolQueryInformationComplete) #pragma alloc_text(PAGE, FspFsvolQueryInformationComplete)
#pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini) #pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini)
@ -301,7 +317,7 @@ static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
if ((PVOID)(Info + 1) > BufferEnd) if ((PVOID)((PUINT8)Info + FIELD_OFFSET(FILE_NAME_INFORMATION, FileName)) > BufferEnd)
return STATUS_BUFFER_TOO_SMALL; return STATUS_BUFFER_TOO_SMALL;
FspFileNodeAcquireShared(FileNode, Main); FspFileNodeAcquireShared(FileNode, Main);
@ -417,6 +433,187 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS FspFsvolQueryStatBaseInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo)
{
PAGED_CODE();
PFSP_FILE_STAT_INFORMATION Info = (PFSP_FILE_STAT_INFORMATION)*PBuffer;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
if (0 == FileInfo)
{
if ((PVOID)(Info + 1) > BufferEnd)
return STATUS_BUFFER_TOO_SMALL;
return STATUS_SUCCESS;
}
Info->FileId.QuadPart = FileNode->IndexNumber;
Info->CreationTime.QuadPart = FileInfo->CreationTime;
Info->LastAccessTime.QuadPart = FileInfo->LastAccessTime;
Info->LastWriteTime.QuadPart = FileInfo->LastWriteTime;
Info->ChangeTime.QuadPart = FileInfo->ChangeTime;
Info->AllocationSize.QuadPart = FileInfo->AllocationSize;
Info->EndOfFile.QuadPart = FileInfo->FileSize;
Info->FileAttributes = 0 != FileInfo->FileAttributes ?
FileInfo->FileAttributes : FILE_ATTRIBUTE_NORMAL;
Info->ReparseTag = FileInfo->ReparseTag;
Info->NumberOfLinks = 1;
*PBuffer = (PVOID)(Info + 1);
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryStatLxBaseInformation(PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd,
const FSP_FSCTL_FILE_INFO *FileInfo)
{
PAGED_CODE();
PFSP_FILE_STAT_LX_INFORMATION Info = (PFSP_FILE_STAT_LX_INFORMATION)*PBuffer;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
if (0 == FileInfo)
{
if ((PVOID)(Info + 1) > BufferEnd)
return STATUS_BUFFER_TOO_SMALL;
return STATUS_SUCCESS;
}
Info->FileId.QuadPart = FileNode->IndexNumber;
Info->CreationTime.QuadPart = FileInfo->CreationTime;
Info->LastAccessTime.QuadPart = FileInfo->LastAccessTime;
Info->LastWriteTime.QuadPart = FileInfo->LastWriteTime;
Info->ChangeTime.QuadPart = FileInfo->ChangeTime;
Info->AllocationSize.QuadPart = FileInfo->AllocationSize;
Info->EndOfFile.QuadPart = FileInfo->FileSize;
Info->FileAttributes = 0 != FileInfo->FileAttributes ?
FileInfo->FileAttributes : FILE_ATTRIBUTE_NORMAL;
Info->ReparseTag = FileInfo->ReparseTag;
Info->NumberOfLinks = 1;
*PBuffer = (PVOID)(Info + 1);
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryStatLxEaInformation(
PDEVICE_OBJECT FsvolDeviceObject, PFILE_OBJECT FileObject,
PVOID *PBuffer, PVOID BufferEnd)
{
#define ADD_GET_EA(Name, End) \
GetEa->NextEntryOffset = (ULONG)(End ? 0 :\
FSP_FSCTL_ALIGN_UP( \
FIELD_OFFSET(FILE_GET_EA_INFORMATION, EaName) + sizeof("" Name),\
sizeof(ULONG))); \
GetEa->EaNameLength = (UCHAR)(sizeof("" Name) - 1);\
RtlCopyMemory(GetEa->EaName, "" Name, sizeof("" Name));\
GetEaLength = (ULONG)((PUINT8)GetEa - (PUINT8)&GetEaBuf.V +\
FIELD_OFFSET(FILE_GET_EA_INFORMATION, EaName) + sizeof("" Name));\
GetEa = (PVOID)((PUINT8)GetEa + GetEa->NextEntryOffset);
#define EQUAL_EA_NAME(Name) \
CmpName.Length = \
CmpName.MaximumLength = sizeof("" Name) - 1,\
CmpName.Buffer = "" Name, \
RtlEqualString(&CmpName, &EaName, TRUE/* always case-insensitive */)
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFSP_FILE_STAT_LX_INFORMATION Info = (PFSP_FILE_STAT_LX_INFORMATION)*PBuffer;
union
{
FILE_GET_EA_INFORMATION V;
UINT8 B[64];
} GetEaBuf;
PFILE_GET_EA_INFORMATION GetEa = &GetEaBuf.V;
ULONG GetEaLength = 0;
union
{
FILE_FULL_EA_INFORMATION V;
UINT8 B[128];
} EaBuf;
ULONG EaLength = sizeof EaBuf;
STRING EaName, CmpName;
NTSTATUS Result;
Info->LxFlags = 0;
Info->LxUid = 0;
Info->LxGid = 0;
Info->LxMode = 0;
Info->LxDeviceIdMajor = 0;
Info->LxDeviceIdMinor = 0;
if (!FsvolDeviceExtension->VolumeParams.ExtendedAttributes)
return STATUS_SUCCESS;
ADD_GET_EA("$LXUID", 0);
ADD_GET_EA("$LXGID", 0);
ADD_GET_EA("$LXMOD", 0);
ADD_GET_EA("$LXDEV", 1);
Result = FspSendQueryEaIrp(FsvolDeviceObject/* bypass filters */, FileObject,
&GetEaBuf.V, GetEaLength,
&EaBuf.V, &EaLength);
if (!NT_SUCCESS(Result))
return Result;
for (PFILE_FULL_EA_INFORMATION Ea = &EaBuf.V, EaEnd = (PVOID)((PUINT8)Ea + EaLength);
EaEnd > Ea; Ea = FSP_NEXT_EA(Ea, EaEnd))
{
EaName.Length =
EaName.MaximumLength = Ea->EaNameLength,
EaName.Buffer = Ea->EaName;
if (EQUAL_EA_NAME("$LXUID"))
{
if (sizeof(ULONG) == Ea->EaValueLength)
{
Info->LxFlags |= 0x1/*LX_FILE_METADATA_HAS_UID*/;
Info->LxUid = *(PULONG)(Ea->EaName + sizeof "$LXUID");
}
}
else
if (EQUAL_EA_NAME("$LXGID"))
{
if (sizeof(ULONG) == Ea->EaValueLength)
{
Info->LxFlags |= 0x2/*LX_FILE_METADATA_HAS_GID*/;
Info->LxGid = *(PULONG)(Ea->EaName + sizeof "$LXGID");
}
}
else
if (EQUAL_EA_NAME("$LXMOD"))
{
if (sizeof(ULONG) == Ea->EaValueLength)
{
Info->LxFlags |= 0x4/*LX_FILE_METADATA_HAS_MODE*/;
Info->LxMode = *(PULONG)(Ea->EaName + sizeof "$LXMOD");
}
}
else
if (EQUAL_EA_NAME("$LXDEV"))
{
if (sizeof(UINT64) == Ea->EaValueLength)
{
Info->LxFlags |= 0x8/*LX_FILE_METADATA_HAS_DEVICE_ID*/;
UINT64 Dev = *(PUINT64)(Ea->EaName + sizeof "$LXDEV");
Info->LxDeviceIdMajor = (Dev >> 32) & 0xffffffff;
Info->LxDeviceIdMinor = Dev & 0xffffffff;
}
}
}
return STATUS_SUCCESS;
#undef EQUAL_EA_NAME
#undef ADD_GET_EA
}
static NTSTATUS FspFsvolQueryStreamInformationCopy( static NTSTATUS FspFsvolQueryStreamInformationCopy(
FSP_FSCTL_STREAM_INFO *StreamInfo, ULONG StreamInfoSize, FSP_FSCTL_STREAM_INFO *StreamInfo, ULONG StreamInfoSize,
PVOID DestBuf, PULONG PDestLen) PVOID DestBuf, PULONG PDestLen)
@ -646,6 +843,71 @@ static NTSTATUS FspFsvolQueryStreamInformationSuccess(
return Result; return Result;
} }
static NTSTATUS FspFsvolQueryInformationEffectiveAccess(
PDEVICE_OBJECT FsvolDeviceObject, PFILE_OBJECT FileObject,
PACCESS_MASK PEffectiveAccess)
{
PAGED_CODE();
union
{
SECURITY_DESCRIPTOR V;
UINT8 B[256];
} SecurityDescriptorBuf;
PSECURITY_DESCRIPTOR SecurityDescriptor = &SecurityDescriptorBuf.V;
ULONG Length;
SECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
ACCESS_MASK EffectiveAccess;
NTSTATUS Result;
BOOLEAN AccessResult;
*PEffectiveAccess = 0;
Length = sizeof SecurityDescriptorBuf;
Result = FspSendQuerySecurityIrp(FsvolDeviceObject/* bypass filters */, FileObject,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
SecurityDescriptor, &Length);
if (STATUS_BUFFER_OVERFLOW == Result)
{
SecurityDescriptor = FspAlloc(Length);
if (0 == SecurityDescriptor)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Result = FspSendQuerySecurityIrp(FsvolDeviceObject/* bypass filters */, FileObject,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
SecurityDescriptor, &Length);
}
if (!NT_SUCCESS(Result))
goto exit;
SeCaptureSubjectContext(&SecuritySubjectContext);
AccessResult = SeAccessCheck(
SecurityDescriptor,
&SecuritySubjectContext,
FALSE,
MAXIMUM_ALLOWED,
0,
0,
IoGetFileObjectGenericMapping(),
UserMode,
&EffectiveAccess,
&Result);
if (!AccessResult)
goto exit;
*PEffectiveAccess = EffectiveAccess;
exit:
if (&SecurityDescriptorBuf.V != SecurityDescriptor && 0 != SecurityDescriptor)
FspFree(SecurityDescriptor);
return Result;
}
static NTSTATUS FspFsvolQueryInformation( static NTSTATUS FspFsvolQueryInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
@ -720,6 +982,18 @@ static NTSTATUS FspFsvolQueryInformation(
case FileStandardInformation: case FileStandardInformation:
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0); Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0);
break; break;
case 68/*FileStatInformation*/:
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.WslFeatures)
Result = FspFsvolQueryStatBaseInformation(FileObject, &Buffer, BufferEnd, 0);
else
Result = STATUS_INVALID_PARAMETER;
break;
case 70/*FileStatLxInformation*/:
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.WslFeatures)
Result = FspFsvolQueryStatLxBaseInformation(FileObject, &Buffer, BufferEnd, 0);
else
Result = STATUS_INVALID_PARAMETER;
break;
default: default:
Result = STATUS_INVALID_PARAMETER; Result = STATUS_INVALID_PARAMETER;
return Result; return Result;
@ -729,6 +1003,26 @@ static NTSTATUS FspFsvolQueryInformation(
return Result; return Result;
FspFileNodeAcquireShared(FileNode, Main); FspFileNodeAcquireShared(FileNode, Main);
switch (FileInformationClass)
{
case 68/*FileStatInformation*/:
FspFsvolQueryInformationEffectiveAccess(
FsvolDeviceObject, FileObject, &((FSP_FILE_STAT_INFORMATION *)Buffer)->EffectiveAccess);
break;
case 70/*FileStatLxInformation*/:
FspFsvolQueryInformationEffectiveAccess(
FsvolDeviceObject, FileObject, &((FSP_FILE_STAT_LX_INFORMATION *)Buffer)->EffectiveAccess);
Result = FspFsvolQueryStatLxEaInformation(
FsvolDeviceObject, FileObject, &Buffer, BufferEnd);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Main);
return Result;
}
break;
}
if (FspFileNodeTryGetFileInfo(FileNode, &FileInfoBuf)) if (FspFileNodeTryGetFileInfo(FileNode, &FileInfoBuf))
{ {
FspFileNodeRelease(FileNode, Main); FspFileNodeRelease(FileNode, Main);
@ -755,6 +1049,12 @@ static NTSTATUS FspFsvolQueryInformation(
case FileStandardInformation: case FileStandardInformation:
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf); Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
break; break;
case 68/*FileStatInformation*/:
Result = FspFsvolQueryStatBaseInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
break;
case 70/*FileStatLxInformation*/:
Result = FspFsvolQueryStatLxBaseInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
break;
default: default:
ASSERT(0); ASSERT(0);
Result = STATUS_INVALID_PARAMETER; Result = STATUS_INVALID_PARAMETER;
@ -865,6 +1165,12 @@ NTSTATUS FspFsvolQueryInformationComplete(
case FileStandardInformation: case FileStandardInformation:
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, FileInfo); Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, FileInfo);
break; break;
case 68/*FileStatInformation*/:
Result = FspFsvolQueryStatBaseInformation(FileObject, &Buffer, BufferEnd, FileInfo);
break;
case 70/*FileStatLxInformation*/:
Result = FspFsvolQueryStatLxBaseInformation(FileObject, &Buffer, BufferEnd, FileInfo);
break;
default: default:
ASSERT(0); ASSERT(0);
Result = STATUS_INVALID_PARAMETER; Result = STATUS_INVALID_PARAMETER;
@ -1813,7 +2119,7 @@ BOOLEAN FspFastIoQueryBasicInfo(
if (Result) if (Result)
{ {
PVOID Buffer = Info; PVOID Buffer = Info;
PVOID BufferEnd = (PUINT8)Info + sizeof Info; PVOID BufferEnd = (PUINT8)Info + sizeof *Info;
NTSTATUS Result0 = FspFsvolQueryBasicInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf); NTSTATUS Result0 = FspFsvolQueryBasicInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
if (!NT_SUCCESS(Result0)) if (!NT_SUCCESS(Result0))
FSP_RETURN(Result = FALSE); FSP_RETURN(Result = FALSE);
@ -1851,7 +2157,7 @@ BOOLEAN FspFastIoQueryStandardInfo(
if (Result) if (Result)
{ {
PVOID Buffer = Info; PVOID Buffer = Info;
PVOID BufferEnd = (PUINT8)Info + sizeof Info; PVOID BufferEnd = (PUINT8)Info + sizeof *Info;
NTSTATUS Result0 = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf); NTSTATUS Result0 = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
if (!NT_SUCCESS(Result0)) if (!NT_SUCCESS(Result0))
FSP_RETURN(Result = FALSE); FSP_RETURN(Result = FALSE);
@ -1889,7 +2195,7 @@ BOOLEAN FspFastIoQueryNetworkOpenInfo(
if (Result) if (Result)
{ {
PVOID Buffer = Info; PVOID Buffer = Info;
PVOID BufferEnd = (PUINT8)Info + sizeof Info; PVOID BufferEnd = (PUINT8)Info + sizeof *Info;
NTSTATUS Result0 = FspFsvolQueryNetworkOpenInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf); NTSTATUS Result0 = FspFsvolQueryNetworkOpenInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
if (!NT_SUCCESS(Result0)) if (!NT_SUCCESS(Result0))
FSP_RETURN(Result = FALSE); FSP_RETURN(Result = FALSE);
@ -1933,7 +2239,7 @@ BOOLEAN FspFastIoQueryOpen(
if (Result) if (Result)
{ {
PVOID Buffer = Info; PVOID Buffer = Info;
PVOID BufferEnd = (PUINT8)Info + sizeof Info; PVOID BufferEnd = (PUINT8)Info + sizeof *Info;
NTSTATUS Result0 = FspFsvolQueryNetworkOpenInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf); NTSTATUS Result0 = FspFsvolQueryNetworkOpenInformation(FileObject, &Buffer, BufferEnd, &FileInfoBuf);
if (!NT_SUCCESS(Result0)) if (!NT_SUCCESS(Result0))
FSP_RETURN(Result = FALSE); FSP_RETURN(Result = FALSE);

View File

@ -77,6 +77,10 @@ static NTSTATUS FspFsctlFileSystemControl(
case IRP_MN_USER_FS_REQUEST: case IRP_MN_USER_FS_REQUEST:
switch (IrpSp->Parameters.FileSystemControl.FsControlCode) switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
{ {
case FSP_FSCTL_MOUNTDEV:
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeMakeMountdev(FsctlDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_VOLUME_NAME: case FSP_FSCTL_VOLUME_NAME:
if (0 != IrpSp->FileObject->FsContext2) if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp); Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp);
@ -86,6 +90,7 @@ static NTSTATUS FspFsctlFileSystemControl(
break; break;
case FSP_FSCTL_TRANSACT: case FSP_FSCTL_TRANSACT:
case FSP_FSCTL_TRANSACT_BATCH: case FSP_FSCTL_TRANSACT_BATCH:
case FSP_FSCTL_TRANSACT_INTERNAL:
if (0 != IrpSp->FileObject->FsContext2) if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp); Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
break; break;
@ -93,6 +98,14 @@ static NTSTATUS FspFsctlFileSystemControl(
if (0 != IrpSp->FileObject->FsContext2) if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp); Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
break; break;
default:
if (CTL_CODE(0, 0xC00, 0, 0) ==
(IrpSp->Parameters.FileSystemControl.FsControlCode & CTL_CODE(0, 0xC00, 0, 0)))
{
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeTransactFsext(FsctlDeviceObject, Irp, IrpSp);
}
break;
} }
break; break;
case IRP_MN_MOUNT_VOLUME: case IRP_MN_MOUNT_VOLUME:

148
src/sys/fsext.c Normal file
View File

@ -0,0 +1,148 @@
/**
* @file sys/fsext.c
*
* @copyright 2015-2019 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 <sys/driver.h>
#include <winfsp/fsext.h>
/*
* Maximum number of allowed fsext providers. This must be kept small,
* because we do a linear search to find the provider. If this changes
* the data structure used to store providers (currently 2 parallel
* arrays) must be revisited.
*/
#define FSP_FSEXT_PROVIDER_COUNTMAX 4
static KSPIN_LOCK FsextSpinLock = 0;
static UINT32 FsextControlCodes[FSP_FSEXT_PROVIDER_COUNTMAX];
static FSP_FSEXT_PROVIDER *FsextProviders[FSP_FSEXT_PROVIDER_COUNTMAX];
static inline
FSP_FSEXT_PROVIDER *FspFsextProviderGet(UINT32 FsextControlCode)
{
#if 0
for (ULONG I = 0; FSP_FSEXT_PROVIDER_COUNTMAX > I; I++)
if (FsextControlCode == FsextControlCodes[I])
return FsextProviders[I];
#else
/* unroll by hand */
FSP_FSCTL_STATIC_ASSERT(4 == FSP_FSEXT_PROVIDER_COUNTMAX,
"unrolled loop expects FsextProviders to have 4 elements");
if (FsextControlCode == FsextControlCodes[0])
return FsextProviders[0];
if (FsextControlCode == FsextControlCodes[1])
return FsextProviders[1];
if (FsextControlCode == FsextControlCodes[2])
return FsextProviders[2];
if (FsextControlCode == FsextControlCodes[3])
return FsextProviders[3];
#endif
return 0;
}
FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 FsextControlCode, PNTSTATUS PLoadResult)
{
FSP_FSEXT_PROVIDER *Provider;
KIRQL Irql;
KeAcquireSpinLock(&FsextSpinLock, &Irql);
Provider = FspFsextProviderGet(FsextControlCode);
KeReleaseSpinLock(&FsextSpinLock, Irql);
ASSERT(0 == Provider || FsextControlCode == Provider->DeviceTransactCode);
if (0 != PLoadResult)
{
if (0 == Provider)
{
WCHAR Buf[64 + 256];
UNICODE_STRING Path;
UNICODE_STRING Name;
union
{
KEY_VALUE_PARTIAL_INFORMATION V;
UINT8 B[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 256];
} Value;
ULONG Length;
NTSTATUS Result;
RtlInitUnicodeString(&Path, L"" FSP_REGKEY "\\Fsext");
RtlInitEmptyUnicodeString(&Name, Buf, sizeof Buf);
Result = RtlUnicodeStringPrintf(&Name, L"%08x", FsextControlCode);
ASSERT(NT_SUCCESS(Result));
Length = sizeof Value;
Result = FspRegistryGetValue(&Path, &Name, &Value.V, &Length);
if (!NT_SUCCESS(Result))
{
*PLoadResult = Result;
return 0;
}
if (REG_SZ != Value.V.Type)
{
*PLoadResult = STATUS_OBJECT_NAME_NOT_FOUND;
return 0;
}
RtlInitEmptyUnicodeString(&Path, Buf, sizeof Buf);
Result = RtlUnicodeStringPrintf(&Path,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%s", (PWSTR)Value.V.Data);
ASSERT(NT_SUCCESS(Result));
Result = ZwLoadDriver(&Path);
if (!NT_SUCCESS(Result) && STATUS_IMAGE_ALREADY_LOADED != Result)
{
*PLoadResult = Result;
return 0;
}
KeAcquireSpinLock(&FsextSpinLock, &Irql);
Provider = FspFsextProviderGet(FsextControlCode);
KeReleaseSpinLock(&FsextSpinLock, Irql);
ASSERT(0 == Provider || FsextControlCode == Provider->DeviceTransactCode);
}
*PLoadResult = 0 != Provider ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
}
return Provider;
}
NTSTATUS FspFsextProviderRegister(FSP_FSEXT_PROVIDER *Provider)
{
NTSTATUS Result;
KIRQL Irql;
KeAcquireSpinLock(&FsextSpinLock, &Irql);
Result = STATUS_TOO_LATE;
for (ULONG I = 0; FSP_FSEXT_PROVIDER_COUNTMAX > I; I++)
if (0 == FsextControlCodes[I])
{
Provider->DeviceExtensionOffset = FIELD_OFFSET(FSP_FSVOL_DEVICE_EXTENSION, FsextData);
FsextControlCodes[I] = Provider->DeviceTransactCode;
FsextProviders[I] = Provider;
Result = STATUS_SUCCESS;
break;
}
KeReleaseSpinLock(&FsextSpinLock, Irql);
return Result;
}

View File

@ -688,6 +688,12 @@ BOOLEAN FspIoqRetryCompleteIrp(FSP_IOQ *Ioq, PIRP Irp, NTSTATUS *PResult)
Result = FspCsqInsertIrpEx(&Ioq->RetriedIoCsq, Irp, 0, 0); Result = FspCsqInsertIrpEx(&Ioq->RetriedIoCsq, Irp, 0, 0);
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
/* wake up a waiter */
KIRQL Irql;
KeAcquireSpinLock(&Ioq->SpinLock, &Irql);
FspIoqEventSet(&Ioq->PendingIrpEvent);
KeReleaseSpinLock(&Ioq->SpinLock, Irql);
if (0 != PResult) if (0 != PResult)
*PResult = STATUS_PENDING; *PResult = STATUS_PENDING;
return TRUE; return TRUE;

View File

@ -103,7 +103,7 @@ static inline FSP_META_CACHE_ITEM *FspMetaCacheRemoveExpiredItemAtDpcLevel(FSP_M
if (Head == Entry) if (Head == Entry)
return 0; return 0;
FSP_META_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, FSP_META_CACHE_ITEM, ListEntry); FSP_META_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, FSP_META_CACHE_ITEM, ListEntry);
if (!FspExpirationTimeValid2(Item->ExpirationTime, ExpirationTime)) if (FspExpirationTimeValid2(Item->ExpirationTime, ExpirationTime))
return 0; return 0;
ULONG HashIndex = Item->ItemIndex % MetaCache->ItemBucketCount; ULONG HashIndex = Item->ItemIndex % MetaCache->ItemBucketCount;
for (FSP_META_CACHE_ITEM **P = (PVOID)&MetaCache->ItemBuckets[HashIndex]; *P; P = &(*P)->DictNext) for (FSP_META_CACHE_ITEM **P = (PVOID)&MetaCache->ItemBuckets[HashIndex]; *P; P = &(*P)->DictNext)
@ -202,7 +202,7 @@ UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size)
{ {
if (0 == MetaCache) if (0 == MetaCache)
return 0; return 0;
FSP_META_CACHE_ITEM *Item; FSP_META_CACHE_ITEM *Item, *ExpiredItem = 0;
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer; FSP_META_CACHE_ITEM_BUFFER *ItemBuffer;
UINT64 ItemIndex = 0; UINT64 ItemIndex = 0;
KIRQL Irql; KIRQL Irql;
@ -236,12 +236,14 @@ UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size)
} }
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql); KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
if (MetaCache->ItemCount >= MetaCache->MetaCapacity) if (MetaCache->ItemCount >= MetaCache->MetaCapacity)
FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL); ExpiredItem = FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL);
ItemIndex = MetaCache->ItemIndex; ItemIndex = MetaCache->ItemIndex;
ItemIndex = (UINT64)-1LL == ItemIndex ? 1 : ItemIndex + 1; ItemIndex = (UINT64)-1LL == ItemIndex ? 1 : ItemIndex + 1;
MetaCache->ItemIndex = Item->ItemIndex = ItemIndex; MetaCache->ItemIndex = Item->ItemIndex = ItemIndex;
FspMetaCacheAddItemAtDpcLevel(MetaCache, Item); FspMetaCacheAddItemAtDpcLevel(MetaCache, Item);
KeReleaseSpinLock(&MetaCache->SpinLock, Irql); KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (0 != ExpiredItem)
FspMetaCacheDereferenceItem(ExpiredItem);
return ItemIndex; return ItemIndex;
} }

232
src/sys/mountdev.c Normal file
View File

@ -0,0 +1,232 @@
/**
* @file sys/mountdev.c
*
* @copyright 2015-2019 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 <sys/driver.h>
NTSTATUS FspMountdevQueryDeviceName(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspMountdevQueryUniqueId(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
BOOLEAN FspMountdevDeviceControl(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult);
NTSTATUS FspMountdevMake(
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
BOOLEAN Persistent);
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspMountdevQueryDeviceName)
#pragma alloc_text(PAGE, FspMountdevQueryUniqueId)
#pragma alloc_text(PAGE, FspMountdevDeviceControl)
#pragma alloc_text(PAGE, FspMountdevMake)
#pragma alloc_text(PAGE, FspMountdevFini)
#endif
NTSTATUS FspMountdevQueryDeviceName(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
PMOUNTDEV_NAME OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (sizeof(MOUNTDEV_NAME) > OutputBufferLength)
/* NOTE: Windows storage samples also set: Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME) */
return STATUS_BUFFER_TOO_SMALL;
RtlZeroMemory(OutputBuffer, sizeof(MOUNTDEV_NAME));
OutputBuffer->NameLength = FsvrtDeviceExtension->VolumeName.Length;
Irp->IoStatus.Information =
FIELD_OFFSET(MOUNTDEV_NAME, Name) + OutputBuffer->NameLength;
if (Irp->IoStatus.Information > OutputBufferLength)
{
Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(OutputBuffer->Name,
FsvrtDeviceExtension->VolumeName.Buffer, OutputBuffer->NameLength);
return STATUS_SUCCESS;
}
NTSTATUS FspMountdevQueryUniqueId(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
PMOUNTDEV_UNIQUE_ID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (sizeof(MOUNTDEV_UNIQUE_ID) > OutputBufferLength)
/* NOTE: Windows storage samples also set: Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID) */
return STATUS_BUFFER_TOO_SMALL;
RtlZeroMemory(OutputBuffer, sizeof(MOUNTDEV_UNIQUE_ID));
OutputBuffer->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
Irp->IoStatus.Information =
FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + OutputBuffer->UniqueIdLength;
if (Irp->IoStatus.Information > OutputBufferLength)
{
Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(OutputBuffer->UniqueId,
&FsvrtDeviceExtension->UniqueId, OutputBuffer->UniqueIdLength);
return STATUS_SUCCESS;
}
BOOLEAN FspMountdevDeviceControl(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult)
{
PAGED_CODE();
if (0 != FsvrtDeviceObject)
{
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
{
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
*PResult = FspMountdevQueryDeviceName(FsvrtDeviceObject, Irp, IrpSp);
return TRUE;
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
*PResult = FspMountdevQueryUniqueId(FsvrtDeviceObject, Irp, IrpSp);
return TRUE;
}
}
}
return FALSE;
}
NTSTATUS FspMountdevMake(
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
BOOLEAN Persistent)
{
/*
* This function converts the fsvrt device into a mountdev device that
* responds to MountManager IOCTL's. This allows the fsvrt device to
* be mounted using the MountManager.
*
* This function requires protection against concurrency. In general this
* is achieved by acquiring the GlobalDeviceLock.
*/
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
UNICODE_STRING String;
WCHAR StringBuf[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR) + 18];
GUID Guid;
NTSTATUS Result;
ASSERT(FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject);
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
return Persistent == FsvrtDeviceExtension->Persistent ?
STATUS_TOO_LATE : STATUS_ACCESS_DENIED;
FsvrtDeviceExtension->Persistent = Persistent;
if (Persistent)
{
/* make UUID v5 from the fsvrt device GUID and a unique string derived from VolumeParams */
RtlInitEmptyUnicodeString(&String, StringBuf, sizeof StringBuf);
Result = RtlUnicodeStringPrintf(&String,
L"%s:%08lx:%08lx",
FsvolDeviceExtension->VolumeParams.FileSystemName,
FsvolDeviceExtension->VolumeParams.VolumeSerialNumber,
FsvolDeviceExtension->VolumeParams.VolumeCreationTime);
ASSERT(NT_SUCCESS(Result));
Result = FspUuid5Make(&FspFsvrtDeviceClassGuid, String.Buffer, String.Length, &Guid);
}
else
/* create volume guid */
Result = FspCreateGuid(&Guid);
if (!NT_SUCCESS(Result))
goto exit;
/* initialize the fsvrt device extension */
RtlCopyMemory(&FsvrtDeviceExtension->UniqueId, &Guid, sizeof Guid);
RtlInitEmptyUnicodeString(&FsvrtDeviceExtension->VolumeName,
FsvrtDeviceExtension->VolumeNameBuf, sizeof FsvrtDeviceExtension->VolumeNameBuf);
RtlCopyUnicodeString(&FsvrtDeviceExtension->VolumeName, &FsvolDeviceExtension->VolumeName);
/* mark the fsvrt device as initialized */
InterlockedIncrement(&FspFsvrtDeviceExtension(FsvrtDeviceObject)->IsMountdev);
Result = STATUS_SUCCESS;
exit:
return Result;
}
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
PVOID Buffer = 0;
ULONG Length = 4096;
MOUNTMGR_MOUNT_POINT *MountPoint;
NTSTATUS Result;
if (0 == InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
return;
if (FsvrtDeviceExtension->Persistent)
/* if the mountdev is marked as persistent do not purge the MountManager */
return;
Buffer = FspAllocNonPaged(Length);
if (0 == Buffer)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
MountPoint = Buffer;
RtlZeroMemory(MountPoint, sizeof *MountPoint);
MountPoint->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
MountPoint->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
RtlCopyMemory((PUINT8)MountPoint + MountPoint->UniqueIdOffset,
&FsvrtDeviceExtension->UniqueId, MountPoint->UniqueIdLength);
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_DELETE_POINTS,
Buffer, MountPoint->UniqueIdOffset + MountPoint->UniqueIdLength, &Length);
exit:
if (0 != Buffer)
FspFree(Buffer);
}

View File

@ -275,6 +275,7 @@ NTSTATUS FspMupHandleIrp(
if (FspFileNodeIsValid(FileObject->FsContext)) if (FspFileNodeIsValid(FileObject->FsContext))
FsvolDeviceObject = ((FSP_FILE_NODE *)FileObject->FsContext)->FsvolDeviceObject; FsvolDeviceObject = ((FSP_FILE_NODE *)FileObject->FsContext)->FsvolDeviceObject;
else if (0 != FileObject->FsContext2 && else if (0 != FileObject->FsContext2 &&
#pragma prefast(disable:28175, "We are a filesystem: ok to access DeviceObject->Type")
3 == ((PDEVICE_OBJECT)FileObject->FsContext2)->Type && 3 == ((PDEVICE_OBJECT)FileObject->FsContext2)->Type &&
0 != ((PDEVICE_OBJECT)FileObject->FsContext2)->DeviceExtension && 0 != ((PDEVICE_OBJECT)FileObject->FsContext2)->DeviceExtension &&
FspFsvolDeviceExtensionKind == FspDeviceExtension((PDEVICE_OBJECT)FileObject->FsContext2)->Kind) FspFsvolDeviceExtensionKind == FspDeviceExtension((PDEVICE_OBJECT)FileObject->FsContext2)->Kind)

View File

@ -24,9 +24,20 @@
NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspCreateGuid(GUID *Guid);
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess, NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject); PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspRegistryGetValue(PUNICODE_STRING Path, PUNICODE_STRING ValueName,
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation, PULONG PValueInformationLength);
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length); FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
static NTSTATUS FspSendSetInformationIrpCompletion( NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PULONG PLength);
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength);
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength);
static NTSTATUS FspSendIrpCompletion(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0); PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0);
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation); NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation); NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
@ -123,7 +134,11 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspCreateGuid) #pragma alloc_text(PAGE, FspCreateGuid)
#pragma alloc_text(PAGE, FspGetDeviceObjectPointer) #pragma alloc_text(PAGE, FspGetDeviceObjectPointer)
#pragma alloc_text(PAGE, FspRegistryGetValue)
#pragma alloc_text(PAGE, FspSendSetInformationIrp) #pragma alloc_text(PAGE, FspSendSetInformationIrp)
#pragma alloc_text(PAGE, FspSendQuerySecurityIrp)
#pragma alloc_text(PAGE, FspSendQueryEaIrp)
#pragma alloc_text(PAGE, FspSendMountmgrDeviceControlIrp)
#pragma alloc_text(PAGE, FspBufferUserBuffer) #pragma alloc_text(PAGE, FspBufferUserBuffer)
#pragma alloc_text(PAGE, FspLockUserBuffer) #pragma alloc_text(PAGE, FspLockUserBuffer)
#pragma alloc_text(PAGE, FspMapLockedPagesInUserMode) #pragma alloc_text(PAGE, FspMapLockedPagesInUserMode)
@ -271,11 +286,43 @@ NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK Desir
return Result; return Result;
} }
NTSTATUS FspRegistryGetValue(PUNICODE_STRING Path, PUNICODE_STRING ValueName,
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation, PULONG PValueInformationLength)
{
PAGED_CODE();
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Handle = 0;
NTSTATUS Result;
InitializeObjectAttributes(&ObjectAttributes,
Path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
Result = ZwOpenKey(&Handle, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Result))
goto exit;
Result = ZwQueryValueKey(Handle, ValueName,
KeyValuePartialInformation, ValueInformation,
*PValueInformationLength, PValueInformationLength);
if (!NT_SUCCESS(Result))
goto exit;
Result = STATUS_SUCCESS;
/* NOTE: also converts STATUS_BUFFER_OVERFLOW to STATUS_SUCCESS */
exit:
if (0 != Handle)
ZwClose(Handle);
return Result;
}
typedef struct typedef struct
{ {
IO_STATUS_BLOCK IoStatus; IO_STATUS_BLOCK IoStatus;
KEVENT Event; KEVENT Event;
} FSP_SEND_SET_INFORMATION_IRP_CONTEXT; } FSP_SEND_IRP_CONTEXT;
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length) FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length)
@ -289,7 +336,7 @@ NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT File
NTSTATUS Result; NTSTATUS Result;
PIRP Irp; PIRP Irp;
PIO_STACK_LOCATION IrpSp; PIO_STACK_LOCATION IrpSp;
FSP_SEND_SET_INFORMATION_IRP_CONTEXT Context; FSP_SEND_IRP_CONTEXT Context;
if (0 == DeviceObject) if (0 == DeviceObject)
DeviceObject = IoGetRelatedDeviceObject(FileObject); DeviceObject = IoGetRelatedDeviceObject(FileObject);
@ -304,24 +351,165 @@ NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT File
IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION; IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
IrpSp->FileObject = FileObject; IrpSp->FileObject = FileObject;
IrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass; IrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
IrpSp->Parameters.SetFile.Length = FileInformationClass; IrpSp->Parameters.SetFile.Length = Length;
IoSetCompletionRoutine(Irp, FspSendSetInformationIrpCompletion, &Context, TRUE, TRUE, TRUE);
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE); KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, FspSendIrpCompletion, &Context, TRUE, TRUE, TRUE);
Result = IoCallDriver(DeviceObject, Irp); Result = IoCallDriver(DeviceObject, Irp);
if (STATUS_PENDING == Result) if (STATUS_PENDING == Result)
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0); KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
return NT_SUCCESS(Result) ? Context.IoStatus.Status : Result; return Context.IoStatus.Status;
} }
static NTSTATUS FspSendSetInformationIrpCompletion( NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PULONG PLength)
{
PAGED_CODE();
NTSTATUS Result;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
FSP_SEND_IRP_CONTEXT Context;
ULONG Length = *PLength;
*PLength = 0;
if (0 == DeviceObject)
DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (0 == Irp)
return STATUS_INSUFFICIENT_RESOURCES;
IrpSp = IoGetNextIrpStackLocation(Irp);
Irp->RequestorMode = KernelMode;
Irp->AssociatedIrp.SystemBuffer = SecurityDescriptor;
Irp->UserBuffer = SecurityDescriptor;
IrpSp->MajorFunction = IRP_MJ_QUERY_SECURITY;
IrpSp->FileObject = FileObject;
IrpSp->Parameters.QuerySecurity.SecurityInformation = SecurityInformation;
IrpSp->Parameters.QuerySecurity.Length = Length;
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, FspSendIrpCompletion, &Context, TRUE, TRUE, TRUE);
Result = IoCallDriver(DeviceObject, Irp);
if (STATUS_PENDING == Result)
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
*PLength = (ULONG)Context.IoStatus.Information;
return Context.IoStatus.Status;
}
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength)
{
PAGED_CODE();
NTSTATUS Result;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
FSP_SEND_IRP_CONTEXT Context;
ULONG EaLength = *PEaLength;
*PEaLength = 0;
if (0 == DeviceObject)
DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (0 == Irp)
return STATUS_INSUFFICIENT_RESOURCES;
IrpSp = IoGetNextIrpStackLocation(Irp);
Irp->RequestorMode = KernelMode;
Irp->AssociatedIrp.SystemBuffer = Ea;
Irp->UserBuffer = Ea;
IrpSp->MajorFunction = IRP_MJ_QUERY_EA;
IrpSp->FileObject = FileObject;
IrpSp->Parameters.QueryEa.Length = EaLength;
IrpSp->Parameters.QueryEa.EaList = GetEa;
IrpSp->Parameters.QueryEa.EaListLength = GetEaLength;
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, FspSendIrpCompletion, &Context, TRUE, TRUE, TRUE);
Result = IoCallDriver(DeviceObject, Irp);
if (STATUS_PENDING == Result)
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
*PEaLength = (ULONG)Context.IoStatus.Information;
return Context.IoStatus.Status;
}
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength)
{
PAGED_CODE();
ASSERT(METHOD_BUFFERED == (IoControlCode & 3));
NTSTATUS Result;
UNICODE_STRING DeviceName;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
FSP_SEND_IRP_CONTEXT Context;
ULONG OutputBufferLength = 0;
if (0 == POutputBufferLength)
POutputBufferLength = &OutputBufferLength;
RtlInitUnicodeString(&DeviceName, MOUNTMGR_DEVICE_NAME);
Result = IoGetDeviceObjectPointer(&DeviceName, FILE_READ_ATTRIBUTES,
&FileObject, &DeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (0 == Irp)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
IrpSp = IoGetNextIrpStackLocation(Irp);
Irp->RequestorMode = KernelMode;
Irp->AssociatedIrp.SystemBuffer = SystemBuffer;
IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
IrpSp->Parameters.DeviceIoControl.OutputBufferLength = *POutputBufferLength;
IrpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
IrpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, FspSendIrpCompletion, &Context, TRUE, TRUE, TRUE);
Result = IoCallDriver(DeviceObject, Irp);
if (STATUS_PENDING == Result)
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
*POutputBufferLength = (ULONG)Context.IoStatus.Information;
Result = Context.IoStatus.Status;
exit:
if (0 != FileObject)
ObDereferenceObject(FileObject);
return Result;
}
static NTSTATUS FspSendIrpCompletion(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0) PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0)
{ {
// !PAGED_CODE(); // !PAGED_CODE();
FSP_SEND_SET_INFORMATION_IRP_CONTEXT *Context = Context0; FSP_SEND_IRP_CONTEXT *Context = Context0;
Context->IoStatus = Irp->IoStatus; Context->IoStatus = Irp->IoStatus;
KeSetEvent(&Context->Event, 1, FALSE); KeSetEvent(&Context->Event, 1, FALSE);
@ -633,6 +821,10 @@ NTSTATUS FspEaBufferFromFileSystemValidate(
*PErrorOffset = 0; *PErrorOffset = 0;
/* EA buffers from the user mode file system are allowed to have zero length */
if (0 == Length)
return STATUS_SUCCESS;
/* EA buffers from the user mode file system are allowed to end with NextEntryOffset != 0 */ /* EA buffers from the user mode file system are allowed to end with NextEntryOffset != 0 */
for (PFILE_FULL_EA_INFORMATION Ea = Buffer, EaEnd = (PVOID)((PUINT8)Ea + Length); for (PFILE_FULL_EA_INFORMATION Ea = Buffer, EaEnd = (PVOID)((PUINT8)Ea + Length);
EaEnd > Ea; Ea = FSP_NEXT_EA(Ea, EaEnd)) EaEnd > Ea; Ea = FSP_NEXT_EA(Ea, EaEnd))

View File

@ -28,6 +28,9 @@ static NTSTATUS FspFsvolQueryFsDeviceInformation(
static NTSTATUS FspFsvolQueryFsFullSizeInformation( static NTSTATUS FspFsvolQueryFsFullSizeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
const FSP_FSCTL_VOLUME_INFO *VolumeInfo); const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
static NTSTATUS FspFsvolQueryFsSectorSizeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
static NTSTATUS FspFsvolQueryFsSizeInformation( static NTSTATUS FspFsvolQueryFsSizeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
const FSP_FSCTL_VOLUME_INFO *VolumeInfo); const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
@ -50,6 +53,7 @@ FSP_DRIVER_DISPATCH FspSetVolumeInformation;
#pragma alloc_text(PAGE, FspFsvolQueryFsAttributeInformation) #pragma alloc_text(PAGE, FspFsvolQueryFsAttributeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryFsDeviceInformation) #pragma alloc_text(PAGE, FspFsvolQueryFsDeviceInformation)
#pragma alloc_text(PAGE, FspFsvolQueryFsFullSizeInformation) #pragma alloc_text(PAGE, FspFsvolQueryFsFullSizeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryFsSectorSizeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryFsSizeInformation) #pragma alloc_text(PAGE, FspFsvolQueryFsSizeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryFsVolumeInformation) #pragma alloc_text(PAGE, FspFsvolQueryFsVolumeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryVolumeInformation) #pragma alloc_text(PAGE, FspFsvolQueryVolumeInformation)
@ -186,6 +190,35 @@ static NTSTATUS FspFsvolQueryFsFullSizeInformation(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS FspFsvolQueryFsSectorSizeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
const FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{
PAGED_CODE();
if (*PBuffer + sizeof(FILE_FS_SECTOR_SIZE_INFORMATION) > BufferEnd)
return STATUS_BUFFER_TOO_SMALL;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_FS_SECTOR_SIZE_INFORMATION Info = (PFILE_FS_SECTOR_SIZE_INFORMATION)*PBuffer;
Info->LogicalBytesPerSector =
Info->PhysicalBytesPerSectorForAtomicity =
Info->PhysicalBytesPerSectorForPerformance =
Info->FileSystemEffectivePhysicalBytesPerSectorForAtomicity =
FsvolDeviceExtension->VolumeParams.SectorSize;
Info->Flags =
SSINFO_FLAGS_ALIGNED_DEVICE |
SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE |
SSINFO_FLAGS_NO_SEEK_PENALTY;
Info->ByteOffsetForSectorAlignment = 0;
Info->ByteOffsetForPartitionAlignment = 0;
*PBuffer += sizeof(FILE_FS_SECTOR_SIZE_INFORMATION);
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolQueryFsSizeInformation( static NTSTATUS FspFsvolQueryFsSizeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
const FSP_FSCTL_VOLUME_INFO *VolumeInfo) const FSP_FSCTL_VOLUME_INFO *VolumeInfo)
@ -255,7 +288,7 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
NTSTATUS Result; NTSTATUS Result;
PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer; PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer;
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryFile.Length; PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryVolume.Length;
switch (IrpSp->Parameters.QueryVolume.FsInformationClass) switch (IrpSp->Parameters.QueryVolume.FsInformationClass)
{ {
@ -268,6 +301,9 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
case FileFsFullSizeInformation: case FileFsFullSizeInformation:
Result = FspFsvolQueryFsFullSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0); Result = FspFsvolQueryFsFullSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0);
break; break;
case FileFsSectorSizeInformation:
Result = FspFsvolQueryFsSectorSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0);
break;
case FileFsSizeInformation: case FileFsSizeInformation:
Result = FspFsvolQueryFsSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0); Result = FspFsvolQueryFsSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0);
break; break;
@ -310,7 +346,7 @@ NTSTATUS FspFsvolQueryVolumeInformationComplete(
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject; PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer; PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer;
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryFile.Length; PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryVolume.Length;
FspFsvolDeviceSetVolumeInfo(FsvolDeviceObject, &Response->Rsp.QueryVolumeInformation.VolumeInfo); FspFsvolDeviceSetVolumeInfo(FsvolDeviceObject, &Response->Rsp.QueryVolumeInformation.VolumeInfo);

View File

@ -34,6 +34,8 @@ NTSTATUS FspVolumeMount(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspVolumeMountNoLock( static NTSTATUS FspVolumeMountNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeMakeMountdev(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeGetName( NTSTATUS FspVolumeGetName(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeGetNameList( NTSTATUS FspVolumeGetNameList(
@ -42,6 +44,8 @@ static NTSTATUS FspVolumeGetNameListNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeTransact( NTSTATUS FspVolumeTransact(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeStop( NTSTATUS FspVolumeStop(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeWork( NTSTATUS FspVolumeWork(
@ -55,10 +59,12 @@ NTSTATUS FspVolumeWork(
// ! #pragma alloc_text(PAGE, FspVolumeDeleteDelayed) // ! #pragma alloc_text(PAGE, FspVolumeDeleteDelayed)
// ! #pragma alloc_text(PAGE, FspVolumeMount) // ! #pragma alloc_text(PAGE, FspVolumeMount)
// ! #pragma alloc_text(PAGE, FspVolumeMountNoLock) // ! #pragma alloc_text(PAGE, FspVolumeMountNoLock)
#pragma alloc_text(PAGE, FspVolumeMakeMountdev)
#pragma alloc_text(PAGE, FspVolumeGetName) #pragma alloc_text(PAGE, FspVolumeGetName)
#pragma alloc_text(PAGE, FspVolumeGetNameList) #pragma alloc_text(PAGE, FspVolumeGetNameList)
#pragma alloc_text(PAGE, FspVolumeGetNameListNoLock) #pragma alloc_text(PAGE, FspVolumeGetNameListNoLock)
#pragma alloc_text(PAGE, FspVolumeTransact) #pragma alloc_text(PAGE, FspVolumeTransact)
#pragma alloc_text(PAGE, FspVolumeTransactFsext)
#pragma alloc_text(PAGE, FspVolumeStop) #pragma alloc_text(PAGE, FspVolumeStop)
#pragma alloc_text(PAGE, FspVolumeWork) #pragma alloc_text(PAGE, FspVolumeWork)
#endif #endif
@ -100,6 +106,7 @@ static NTSTATUS FspVolumeCreateNoLock(
UNICODE_STRING VolumeName; UNICODE_STRING VolumeName;
UNICODE_STRING FsmupDeviceName; UNICODE_STRING FsmupDeviceName;
WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)]; WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)];
FSP_FSEXT_PROVIDER *Provider = 0;
PDEVICE_OBJECT FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
@ -132,7 +139,9 @@ static NTSTATUS FspVolumeCreateNoLock(
VolumeParams.SectorsPerAllocationUnit = 1; VolumeParams.SectorsPerAllocationUnit = 1;
if (0 == VolumeParams.MaxComponentLength) if (0 == VolumeParams.MaxComponentLength)
VolumeParams.MaxComponentLength = 255; VolumeParams.MaxComponentLength = 255;
if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout || if (0 == VolumeParams.TransactTimeout)
VolumeParams.TransactTimeout = 24 * 60 * 60 * 1000; /* 1 day */
else if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout ||
VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum) VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum)
VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault; VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault;
if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout || if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout ||
@ -207,6 +216,14 @@ static NTSTATUS FspVolumeCreateNoLock(
VolumeParams.AlwaysUseDoubleBuffering = 1; VolumeParams.AlwaysUseDoubleBuffering = 1;
#endif #endif
/* load any fsext provider */
if (0 != VolumeParams.FsextControlCode)
{
Provider = FspFsextProvider(VolumeParams.FsextControlCode, &Result);
if (0 == Provider)
return Result;
}
/* create volume guid */ /* create volume guid */
Result = FspCreateGuid(&Guid); Result = FspCreateGuid(&Guid);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -224,7 +241,8 @@ static NTSTATUS FspVolumeCreateNoLock(
VolumeName.MaximumLength = VolumeName.Length; VolumeName.MaximumLength = VolumeName.Length;
/* create the volume (and virtual disk) device(s) */ /* create the volume (and virtual disk) device(s) */
Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0, Result = FspDeviceCreate(FspFsvolDeviceExtensionKind,
0 == Provider ? 0 : Provider->DeviceExtensionSize,
FsctlDeviceObject->DeviceType, FsctlDeviceObject->DeviceType,
FILE_DEVICE_DISK_FILE_SYSTEM == FsctlDeviceObject->DeviceType ? 0 : FILE_REMOTE_DEVICE, FILE_DEVICE_DISK_FILE_SYSTEM == FsctlDeviceObject->DeviceType ? 0 : FILE_REMOTE_DEVICE,
&FsvolDeviceObject); &FsvolDeviceObject);
@ -263,13 +281,18 @@ static NTSTATUS FspVolumeCreateNoLock(
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
if (0 != FsvrtDeviceObject) if (0 != FsvrtDeviceObject)
{
FspFsvrtDeviceExtension(FsvrtDeviceObject)->SectorSize =
FsvolDeviceExtension->VolumeParams.SectorSize;
Result = FspDeviceInitialize(FsvrtDeviceObject); Result = FspDeviceInitialize(FsvrtDeviceObject);
}
} }
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
if (0 != FsvrtDeviceObject) if (0 != FsvrtDeviceObject)
FspDeviceDereference(FsvrtDeviceObject); FspDeviceDereference(FsvrtDeviceObject);
FspDeviceDereference(FsvolDeviceObject); FspDeviceDereference(FsvolDeviceObject);
return Result;
} }
/* do we need to register with fsmup? */ /* do we need to register with fsmup? */
@ -305,10 +328,22 @@ VOID FspVolumeDelete(
// !PAGED_CODE(); // !PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
FSP_FILE_NODE **FileNodes; FSP_FILE_NODE **FileNodes;
ULONG FileNodeCount, Index; ULONG FileNodeCount, Index;
NTSTATUS Result; NTSTATUS Result;
/*
* If we have an fsvrt that is a mountdev, finalize it now! Finalizing a mountdev
* involves interaction with the MountManager, which tries to open our devices.
* So if we delay this interaction and we do it during final fsvrt teardown (i.e.
* FspDeviceDelete time) we will fail such opens with STATUS_CANCELLED, which will
* confuse the MountManager.
*/
if (0 != FsvrtDeviceObject)
FspMountdevFini(FsvrtDeviceObject);
FspDeviceReference(FsvolDeviceObject); FspDeviceReference(FsvolDeviceObject);
FspDeviceGlobalLock(); FspDeviceGlobalLock();
@ -527,6 +562,50 @@ static NTSTATUS FspVolumeMountNoLock(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS FspVolumeMakeMountdev(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT(FSP_FSCTL_MOUNTDEV == IrpSp->Parameters.FileSystemControl.FsControlCode);
ASSERT(0 != IrpSp->FileObject->FsContext2);
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
BOOLEAN Persistent = 0 < InputBufferLength ? !!*(PBOOLEAN)Irp->AssociatedIrp.SystemBuffer : FALSE;
NTSTATUS Result;
if (0 == FsvrtDeviceObject)
return STATUS_INVALID_PARAMETER;
if (sizeof(GUID) > OutputBufferLength)
return STATUS_INVALID_PARAMETER;
FspDeviceGlobalLock();
Result = FspMountdevMake(FsvrtDeviceObject, FsvolDeviceObject, Persistent);
if (!NT_SUCCESS(Result))
{
if (STATUS_TOO_LATE != Result)
goto exit;
}
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
&FspFsvrtDeviceExtension(FsvrtDeviceObject)->UniqueId, sizeof(GUID));
Irp->IoStatus.Information = sizeof(GUID);
Result = STATUS_SUCCESS;
exit:
FspDeviceGlobalUnlock();
return Result;
}
NTSTATUS FspVolumeGetName( NTSTATUS FspVolumeGetName(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
@ -650,10 +729,8 @@ NTSTATUS FspVolumeTransact(
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction); ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT( ASSERT(
FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode || FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode ||
FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode); FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode ||
ASSERT( FSP_FSCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode);
METHOD_BUFFERED == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3) ||
METHOD_OUT_DIRECT == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3));
ASSERT(0 != IrpSp->FileObject->FsContext2); ASSERT(0 != IrpSp->FileObject->FsContext2);
/* check parameters */ /* check parameters */
@ -661,17 +738,31 @@ NTSTATUS FspVolumeTransact(
ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer; PVOID InputBuffer = 0;
PVOID OutputBuffer = 0; PVOID OutputBuffer = 0;
if (0 != InputBufferLength && if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength) {
return STATUS_INVALID_PARAMETER; InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
if (0 != OutputBufferLength && if (KernelMode != Irp->RequestorMode)
((FSP_FSCTL_TRANSACT == ControlCode && return STATUS_INVALID_DEVICE_REQUEST;
FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) || ASSERT(0 == InputBufferLength ||
(FSP_FSCTL_TRANSACT_BATCH == ControlCode && FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) <= InputBufferLength);
FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength))) ASSERT(0 == OutputBufferLength ||
return STATUS_BUFFER_TOO_SMALL; sizeof(PVOID) <= OutputBufferLength);
}
else
{
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (0 != InputBufferLength &&
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)
return STATUS_INVALID_PARAMETER;
if (0 != OutputBufferLength &&
((FSP_FSCTL_TRANSACT == ControlCode &&
FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) ||
(FSP_FSCTL_TRANSACT_BATCH == ControlCode &&
FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength)))
return STATUS_BUFFER_TOO_SMALL;
}
if (!FspDeviceReference(FsvolDeviceObject)) if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED; return STATUS_CANCELLED;
@ -681,6 +772,7 @@ NTSTATUS FspVolumeTransact(
PUINT8 BufferEnd; PUINT8 BufferEnd;
FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest;
PVOID InternalBuffer = 0;
PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp; PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp;
ULONG LoopCount; ULONG LoopCount;
LARGE_INTEGER Timeout; LARGE_INTEGER Timeout;
@ -749,6 +841,9 @@ NTSTATUS FspVolumeTransact(
/* were we sent an output buffer? */ /* were we sent an output buffer? */
switch (ControlCode & 3) switch (ControlCode & 3)
{ {
case METHOD_NEITHER:
OutputBuffer = Irp->UserBuffer;
break;
case METHOD_OUT_DIRECT: case METHOD_OUT_DIRECT:
if (0 != Irp->MdlAddress) if (0 != Irp->MdlAddress)
OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
@ -770,17 +865,17 @@ NTSTATUS FspVolumeTransact(
/* wait for an IRP to arrive */ /* wait for an IRP to arrive */
KeQuerySystemTime(&Timeout); KeQuerySystemTime(&Timeout);
Timeout.QuadPart += 0 == RepostedIrp ? Timeout.QuadPart += FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000ULL;
FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000ULL :
FspVolumeTransactEarlyTimeout;
/* convert millis to nanos and add to absolute time */ /* convert millis to nanos and add to absolute time */
while (0 == (PendingIrp = FspIoqNextPendingIrp(FsvolDeviceExtension->Ioq, 0, &Timeout, Irp))) if (0 == (PendingIrp = FspIoqNextPendingIrp(FsvolDeviceExtension->Ioq, 0, &Timeout, Irp)))
{ {
if (FspIoqStopped(FsvolDeviceExtension->Ioq)) if (FspIoqStopped(FsvolDeviceExtension->Ioq))
{ {
Result = STATUS_CANCELLED; Result = STATUS_CANCELLED;
goto exit; goto exit;
} }
PendingIrp = FspIoqTimeout;
} }
if (FspIoqTimeout == PendingIrp || FspIoqCancelled == PendingIrp) if (FspIoqTimeout == PendingIrp || FspIoqCancelled == PendingIrp)
{ {
@ -793,7 +888,9 @@ NTSTATUS FspVolumeTransact(
RepostedIrp = 0; RepostedIrp = 0;
Request = OutputBuffer; Request = OutputBuffer;
BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength; BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength;
ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd)); ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ?
TRUE :
FspFsctlTransactCanProduceRequest(Request, BufferEnd));
LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq); LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq);
for (;;) for (;;)
{ {
@ -814,8 +911,18 @@ NTSTATUS FspVolumeTransact(
FspIopCompleteIrp(PendingIrp, Result); FspIopCompleteIrp(PendingIrp, Result);
else else
{ {
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size); if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size); {
InternalBuffer = FspAllocatePoolMustSucceed(
PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG);
RtlCopyMemory(InternalBuffer, PendingIrpRequest, PendingIrpRequest->Size);
*(PVOID *)OutputBuffer = InternalBuffer;
}
else
{
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size);
}
if (!FspIoqStartProcessingIrp(FsvolDeviceExtension->Ioq, PendingIrp)) if (!FspIoqStartProcessingIrp(FsvolDeviceExtension->Ioq, PendingIrp))
{ {
@ -826,12 +933,24 @@ NTSTATUS FspVolumeTransact(
* also cancel the PendingIrp we have in our hands. * also cancel the PendingIrp we have in our hands.
*/ */
ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq)); ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
if (0 != InternalBuffer)
{
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode);
FspFree(InternalBuffer);
}
FspIopCompleteCanceledIrp(PendingIrp); FspIopCompleteCanceledIrp(PendingIrp);
Result = STATUS_CANCELLED; Result = STATUS_CANCELLED;
goto exit; goto exit;
} }
/* are we doing single request or batch mode? */ /* are we doing single request or batch mode? */
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
{
Irp->IoStatus.Information = sizeof(PVOID);
Result = STATUS_SUCCESS;
goto exit;
}
else
if (FSP_FSCTL_TRANSACT == ControlCode) if (FSP_FSCTL_TRANSACT == ControlCode)
break; break;
@ -858,6 +977,36 @@ exit:
return Result; return Result;
} }
NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT(CTL_CODE(0, 0xC00, 0, 0) ==
(IrpSp->Parameters.FileSystemControl.FsControlCode & CTL_CODE(0, 0xC00, 0, 0)));
ASSERT(0 != IrpSp->FileObject->FsContext2);
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED;
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
if (IrpSp->Parameters.FileSystemControl.FsControlCode ==
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FsextControlCode)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
IrpSp->Parameters.FileSystemControl.FsControlCode, 0);
if (0 != Provider)
Result = Provider->DeviceTransact(FsvolDeviceObject, Irp);
}
FspDeviceDereference(FsvolDeviceObject);
return Result;
}
NTSTATUS FspVolumeStop( NTSTATUS FspVolumeStop(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {

View File

@ -6,7 +6,7 @@ setlocal EnableDelayedExpansion
set MsiName="WinFsp - Windows File System Proxy" set MsiName="WinFsp - Windows File System Proxy"
set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt" set CrossCert="%~dp0DigiCert High Assurance EV Root CA.crt"
set Issuer="DigiCert" set Issuer="DigiCert"
set Subject="Navimatics Corporation" set Subject="Navimatics LLC"
set Configuration=Release set Configuration=Release
set SignedPackage= set SignedPackage=

View File

@ -4,7 +4,7 @@ setlocal
set DebugWorkspace=winfsp set DebugWorkspace=winfsp
set DebugPort=50000 set DebugPort=50000
set DebugKey=win8.debug.net.key set DebugKey=1.1.1.1
set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots" set RegKey="HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
set RegVal="KitsRoot10" set RegVal="KitsRoot10"

View File

@ -5,6 +5,7 @@ setlocal
set CONFIG=Debug set CONFIG=Debug
set SUFFIX=x64 set SUFFIX=x64
set TARGET_MACHINE=WIN8DBG set TARGET_MACHINE=WIN8DBG
if not X%1==X set TARGET_MACHINE=%1
set TARGET_ACCOUNT=\Users\%USERNAME%\Downloads\winfsp\ set TARGET_ACCOUNT=\Users\%USERNAME%\Downloads\winfsp\
set TARGET=\\%TARGET_MACHINE%%TARGET_ACCOUNT% set TARGET=\\%TARGET_MACHINE%%TARGET_ACCOUNT%
@ -14,7 +15,7 @@ for %%f in (winfsp-%SUFFIX%.sys winfsp-%SUFFIX%.dll winfsp-tests-%SUFFIX%.exe fs
copy build\VStudio\build\%CONFIG%\%%f %TARGET% >nul copy build\VStudio\build\%CONFIG%\%%f %TARGET% >nul
) )
copy tools\ifstest.bat %TARGET% >nul copy tools\ifstest.bat %TARGET% >nul
echo sc create WinFsp type=filesys binPath=%%~dp0%DRIVER% >%TARGET%sc-create.bat echo sc create WinFsp type=filesys binPath=%%~dp0winfsp-%SUFFIX%.sys >%TARGET%sc-create.bat
echo sc start WinFsp >%TARGET%sc-start.bat echo sc start WinFsp >%TARGET%sc-start.bat
echo sc stop WinFsp >%TARGET%sc-stop.bat echo sc stop WinFsp >%TARGET%sc-stop.bat
echo sc delete WinFsp >%TARGET%sc-delete.bat echo sc delete WinFsp >%TARGET%sc-delete.bat

44
tools/impdef.bat Normal file
View File

@ -0,0 +1,44 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
if X%1==X goto usage
if X%2==X goto usage
set infile=%1
set infile=%infile:/=\%
set outfile=%2
set outfile=%outfile:/=\%
set workdir=!infile!.work
set workbase=!workdir!\%~n2
set outarch=%~n2
set outarch=%outarch:~-3%
set arch=x64
set cdef=/D_AMD64_
if /i X%outarch%==Xx86 set arch=x86
if /i X%outarch%==Xx86 set cdef=/D_X86_
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" !arch!
set INCLUDE=%~dp0..\opt\fsext\inc;%~dp0..\inc;!WindowsSdkDir!Include\!WindowsSDKVersion!km\crt;!WindowsSdkDir!Include\!WindowsSDKVersion!km;!WindowsSdkDir!Include\!WindowsSDKVersion!km\shared;!INCLUDE!
if exist !workdir! rmdir /s/q !workdir!
mkdir !workdir!
type !infile! >>!workbase!.c
cl /LD /Fe!workbase!.sys /Fo!workbase!.obj !cdef! /D_KERNEL_MODE /wd4716 !workbase!.c
if errorlevel 1 goto fail
copy !workbase!.lib !outfile!
if errorlevel 1 goto fail
rmdir /s/q !workdir!
exit /b 0
:fail
exit /b 1
:usage
echo usage: impdef.bat infile.impdef outfile.lib 1>&2
exit /b 2

View File

@ -71,12 +71,17 @@ set dfl_tests=^
winfsp-tests-dotnet-external-share ^ winfsp-tests-dotnet-external-share ^
fsx-memfs-dotnet-disk ^ fsx-memfs-dotnet-disk ^
fsx-memfs-dotnet-net ^ fsx-memfs-dotnet-net ^
fsx-memfs-dotnet-slowio ^
winfstest-memfs-dotnet-disk ^ winfstest-memfs-dotnet-disk ^
winfstest-memfs-dotnet-net winfstest-memfs-dotnet-net
set opt_tests=^ set opt_tests=^
ifstest-memfs-x64-disk ^ ifstest-memfs-x64-disk ^
ifstest-memfs-x86-disk ^ ifstest-memfs-x86-disk ^
ifstest-memfs-dotnet-disk ^ ifstest-memfs-dotnet-disk ^
sample-memfs-fuse3-x64 ^
sample-fsx-memfs-fuse3-x64 ^
sample-memfs-fuse3-x86 ^
sample-fsx-memfs-fuse3-x86 ^
sample-airfs-x64 ^ sample-airfs-x64 ^
sample-airfs-x86 ^ sample-airfs-x86 ^
sample-passthrough-x64 ^ sample-passthrough-x64 ^
@ -498,6 +503,11 @@ call :__run_fsx_memfs_slowio_test memfs32-slowio memfs-x86
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:fsx-memfs-dotnet-slowio
call :__run_fsx_memfs_slowio_test memfs.net-slowio memfs-dotnet-msil
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:__run_fsx_memfs_slowio_test :__run_fsx_memfs_slowio_test
set RunSampleTestExit=0 set RunSampleTestExit=0
call "%ProjRoot%\tools\fsreg" %1 "%ProjRoot%\build\VStudio\build\%Configuration%\%2.exe" "-u %%%%1 -m %%%%2 -M 50 -P 10 -R 5" "D:P(A;;RPWPLC;;;WD)" call "%ProjRoot%\tools\fsreg" %1 "%ProjRoot%\build\VStudio\build\%Configuration%\%2.exe" "-u %%%%1 -m %%%%2 -M 50 -P 10 -R 5" "D:P(A;;RPWPLC;;;WD)"
@ -669,6 +679,28 @@ for /F "delims=" %%l in ('call "%ProjRoot%\tools\ifstest.bat" %* /v ^| findstr /
if not X!IfsTestFound!==XYES set IfsTestExit=1 if not X!IfsTestFound!==XYES set IfsTestExit=1
exit /b !IfsTestExit! exit /b !IfsTestExit!
:sample-memfs-fuse3-x64
call :__run_sample_fuse_test memfs-fuse3 x64 memfs-fuse3-x64 winfsp-tests-x64 ^
"-create_fileattr_test -create_readonlydir_test -setfileinfo_test"
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:sample-memfs-fuse3-x86
call :__run_sample_fuse_test memfs-fuse3 x86 memfs-fuse3-x86 winfsp-tests-x86 ^
"-create_fileattr_test -create_readonlydir_test -setfileinfo_test"
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:sample-fsx-memfs-fuse3-x64
call :__run_sample_fsx_fuse_test memfs-fuse3 x64 memfs-fuse3-x64 fsx
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:sample-fsx-memfs-fuse3-x86
call :__run_sample_fsx_fuse_test memfs-fuse3 x86 memfs-fuse3-x86 fsx
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:sample-airfs-x64 :sample-airfs-x64
call :__run_sample_disk_test airfs x64 airfs-x64 winfsp-tests-x64 NOEXCL call :__run_sample_disk_test airfs x64 airfs-x64 winfsp-tests-x64 NOEXCL
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail

View File

@ -3,3 +3,6 @@ build
*.suo *.suo
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.VC.db
*.VC.opendb
.vs

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
@ -22,32 +22,32 @@
<ProjectGuid>{CA441CE7-C4DE-4B5E-AA72-D4D483413EF0}</ProjectGuid> <ProjectGuid>{CA441CE7-C4DE-4B5E-AA72-D4D483413EF0}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>airfs</RootNamespace> <RootNamespace>airfs</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -171,6 +171,10 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="airfs.cpp" /> <ClCompile Include="airfs.cpp" />
<ClCompile Include="persistence.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="common.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<Filter Include="Source"> <Filter Include="Source">
@ -10,5 +10,13 @@
<ClCompile Include="airfs.cpp"> <ClCompile Include="airfs.cpp">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="persistence.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="common.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

210
tst/airfs/common.h Normal file
View File

@ -0,0 +1,210 @@
/**
* @file common.h
*
* @copyright 2015-2019 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.
*/
/*
* Airfs is based on Memfs with changes contributed by John Oberschelp.
* The contributed changes are under joint copyright by Bill Zissimopoulos
* and John Oberschelp per the Contributor Agreement found at the
* root of this project.
*/
#include <winfsp/winfsp.h>
#include <io.h>
#include <sddl.h>
#include <stdio.h>
#include <stdint.h>
#define PROGNAME "airfs"
#define ROUND_UP( bytes, units ) (((bytes) + (units) - 1) / (units) * (units))
#define ROUND_DOWN( bytes, units ) (((bytes) ) / (units) * (units))
#define MINIMUM_ALLOCSIZE 196
#define MAXIMUM_ALLOCSIZE ROUND_DOWN(10*1024*1024, MINIMUM_ALLOCSIZE)
#define SECTOR_SIZE 512
#define SECTORS_PER_ALLOCATION_UNIT 1
#define ALLOCATION_UNIT ( SECTOR_SIZE * SECTORS_PER_ALLOCATION_UNIT )
#define INFO(format, ...) FspServiceLog(EVENTLOG_INFORMATION_TYPE , format, __VA_ARGS__)
#define WARN(format, ...) FspServiceLog(EVENTLOG_WARNING_TYPE , format, __VA_ARGS__)
#define FAIL(format, ...) FspServiceLog(EVENTLOG_ERROR_TYPE , format, __VA_ARGS__)
#define AIRFS_MAX_PATH 512
#define FILEBLOCK_OVERHEAD 40 // size of ( P + E + L + R + FileOffset ) = 8 * 5 = 40
#define ARG_TO_S(v) if (arge > ++argp) v = *argp; else goto usage
#define ARG_TO_4(v) if (arge > ++argp) v = (int32_t) wcstoll_default(*argp, v); else goto usage
#define ARG_TO_8(v) if (arge > ++argp) v = wcstoll_default(*argp, v); else goto usage
enum StorageFileAccessType {ZERO=0,READ,WRITE};
enum Neighbor {LT=-2,LE=-1,EQ=0,GE=1,GT=2};
struct NODE;
typedef NODE* NODE_;
typedef int CompareFunction (void* key, NODE_);
inline NTSTATUS GetLastErrorAsStatus()
{
return FspNtStatusFromWin32(GetLastError());
}
inline UINT64 SystemTime()
{
FILETIME FileTime;
GetSystemTimeAsFileTime(&FileTime);
return ((PLARGE_INTEGER)&FileTime)->QuadPart;
}
static int64_t wcstoll_default(wchar_t *w, int64_t deflt)
{
wchar_t *endp;
int64_t i = wcstoll(w, &endp, 0);
return L'\0' != w[0] && L'\0' == *endp ? i : deflt;
}
//////////////////////////////////////////////////////////////////////
//
// Where<T> Class: This class manages an offset within our memory-mapped
// volume to another location within our memory-mapped volume. Because it is
// a self-relative offset, this delta is constant regardless of where in
// memory the file system is mapped, so we can always reobtain its address.
// A delta of 0 is the special case for "null".
//
template <class T> class Where
{
int64_t delta;
public:
Where() = default;
~Where() = default;
Where(T t) : delta( t ?( (char*)t -(char*)this ):0) {}
Where(Where& w) : delta( w.delta?( ((char*)&w+w.delta)-(char*)this ):0) {}
operator bool () { return delta != 0; }
operator T () { return (T) ( delta?( (char*)this+delta ):0); }
T operator -> () { return (T) ( delta?( (char*)this+delta ):0); }
operator void* () { return (void*)( delta?( (char*)this+delta ):0); }
bool operator == (Where& rhs) { return (char*)this+delta == (char*)&rhs+rhs.delta; }
bool operator != (Where& rhs) { return (char*)this+delta != (char*)&rhs+rhs.delta; }
bool operator == (T rhs) { return (char*)this+delta == (char*)rhs; }
bool operator != (T rhs) { return (char*)this+delta != (char*)rhs; }
Where& operator = (Where& rhs) { delta = rhs.delta?( ((char*)&rhs+rhs.delta) - ((char*)this) ):0; return *this; }
Where& operator = (void* rhs) { delta = rhs ?( (char*)rhs - ((char*)this) ):0; return *this; }
char* Address () { return (char*)this+delta; }
};
//////////////////////////////////////////////////////////////////////
//
// The header for an Airfs volume
//
typedef struct
{
char Signature[8]; // Airfs\0\0\0
char MapFormatVersion[4]; // Major.Minor.Patch.Build
char filler[4];
Where<NODE_> Root;
Where<NODE_> Available;
UINT64 VolumeSize;
UINT64 FreeSize;
WCHAR VolumeLabel[32];
UINT16 VolumeLabelLength;
UINT16 filler1,filler2,filler3;
UINT32 CaseInsensitive;
UINT32 filler4;
int64_t VolumeLength;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
FSP_FILE_SYSTEM *FileSystem;
HANDLE MapFileHandle;
HANDLE MapHandle;
} AIRFS, *AIRFS_;
//////////////////////////////////////////////////////////////////////
//
// Information per file or directory
//
struct NODE
{
Where<NODE_> P,L,R,E; // Sorted sibling tree: Parent, Left, Right, and Equal
union
{
Where<WCHAR*> Name;
int64_t FileOffset;
};
Where<NODE_> Parent;
Where<NODE_> Children;
FSP_FSCTL_FILE_INFO FileInfo;
uint64_t SecurityDescriptorSize;
Where<char*> SecurityDescriptor;
Where<NODE_> FileBlocks;
uint64_t ReparseDataSize;
Where<char*> ReparseData;
volatile LONG RefCount;
Where<NODE_> Streams;
BOOLEAN IsAStream;
};
//////////////////////////////////////////////////////////////////////
class SpinLock
{
LONG C; // Counter
HANDLE S; // Semaphore
public:
SpinLock() { C = 0; S = CreateSemaphore(NULL, 0, 1, NULL); }
~SpinLock() { CloseHandle(S); }
void Acquire() { if (_InterlockedIncrement(&C) > 1) WaitForSingleObject(S, INFINITE); }
void Release() { if (_InterlockedDecrement(&C) > 0) ReleaseSemaphore(S, 1, NULL); }
};
//////////////////////////////////////////////////////////////////////
void Airprint (const char * format, ...);
int SizeCmp (void* key, NODE_);
int ExactNameCmp (void* key, NODE_);
int CaselessNameCmp (void* key, NODE_);
NODE_ Find (Where<NODE_> &root, void* key, CompareFunction);
NODE_ Near (Where<NODE_> &root, void* key, CompareFunction, Neighbor);
void Attach (Where<NODE_> &root, NODE_ attach, CompareFunction, void* key);
void Detach (Where<NODE_> &root, NODE_ detach);
NODE_ First (NODE_ start);
NODE_ Last (NODE_ start);
NODE_ Next (NODE_);
NODE_ Prev (NODE_);
NTSTATUS StorageStartup (AIRFS_ &, WCHAR* MapName, WCHAR* StorageFileName, int64_t Length);
NTSTATUS StorageShutdown (AIRFS_);
void* StorageAllocate (AIRFS_, int64_t RequestedSize);
void* StorageReallocate (AIRFS_, void* Reallocate, int64_t RequestedSize);
void StorageFree (AIRFS_, void* Release);
NTSTATUS StorageSetFileCapacity (AIRFS_, NODE_, int64_t MinimumRequiredCapacity);
void StorageAccessFile (StorageFileAccessType, NODE_, int64_t Offset, int64_t NumBytes, char* Address);
static_assert(AIRFS_MAX_PATH > MAX_PATH, "AIRFS_MAX_PATH must be greater than MAX_PATH.");
static_assert(sizeof NODE + sizeof int32_t == MINIMUM_ALLOCSIZE, "MINIMUM_ALLOCSIZE should be 196.");
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

594
tst/airfs/persistence.cpp Normal file
View File

@ -0,0 +1,594 @@
/**
* @file persistence.cpp
*
* @copyright 2015-2019 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.
*/
/*
* Airfs is based on Memfs with changes contributed by John Oberschelp.
* The contributed changes are under joint copyright by Bill Zissimopoulos
* and John Oberschelp per the Contributor Agreement found at the
* root of this project.
*/
/*
* Airfs uses a memory-mapped file per volume to achieve persistence.
* The primary advantage of this is that volume loads and saves are automatic.
* The two primary disadvantages, and our workarounds are:
* 1. We can't use standard containers or memory management,
* so the below Rubbertree and Storage functions are used instead.
* 2. Each process will map the volume to an arbitrary address,
* so Where<T> offsets are used in place of pointers.
*/
#include "common.h"
SpinLock StorageLock, AirprintLock, SetLock;
int SizeCmp ( void* key, NODE_ x)
{
return *(int32_t*)key - ((int32_t*)x)[-1];
}
int BlockCmp ( void* key, NODE_ x)
{
int64_t left = *(int64_t*)key;
int64_t right = x->FileOffset;
return left == right ? 0 : (left < right ? -1 : 1);
}
int CaselessNameCmp ( void* key, NODE_ x)
{
WCHAR* c1 = (WCHAR*) key;
WCHAR* c2 = x->Name;
return _wcsicmp(c1,c2);
}
int ExactNameCmp ( void* key, NODE_ x)
{
WCHAR* c1 = (WCHAR*) key;
WCHAR* c2 = x->Name;
return wcscmp(c1,c2);
}
//////////////////////////////////////////////////////////////////////
void Airprint (const char * format, ...)
{
AirprintLock.Acquire();
va_list args;
va_start(args, format);
char szBuffer[512];
sprintf_s(szBuffer, 511, "Airfs %5.5f ----", SystemTime() / 10'000'000.0);
vsnprintf(szBuffer+25, 511-25, format, args);
OutputDebugStringA(szBuffer);
va_end(args);
AirprintLock.Release();
}
//////////////////////////////////////////////////////////////////////
//
// Rubbertree (because it is flexible!)
// Implements a sorted set of elements, using a binary tree.
// Has a function, Near, that finds nodes at or adjacent to a key.
// Attach, Find, and Near use splay to improve random access times.
// First, Last, Next, and Prev do not, to improve sequential access times.
// Replacing each Where<NODE_> with NODE_ would make this a pointer-based tree.
// In addition to Left, Right, and Parent references, each node has an Equal
// reference that may be used to keep "equivalent" nodes. This is used by
// our memory heap manager's tree of available memory blocks, sorted by size.
//--------------------------------------------------------------------
inline void rotateL(Where<NODE_> &root, NODE_ x)
{
NODE_ y = x->R, p = x->P;
if (x->R = y->L) y->L->P = x;
if (!(y->P = p))
root = y;
else
{
if (x == p->L) p->L = y;
else p->R = y;
}
(y->L = x)->P = y;
}
//--------------------------------------------------------------------
inline void rotateR(Where<NODE_> &root, NODE_ y)
{
NODE_ x = y->L, p = y->P;
if (y->L = x->R) x->R->P = y;
if (!(x->P = p))
root = x;
else
{
if (y == p->L) p->L = x;
else p->R = x;
}
(x->R = y)->P = x;
}
//--------------------------------------------------------------------
static void splay(Where<NODE_> &root, NODE_ x)
{
while (NODE_ p = x->P)
{
if (!p->P)
{
if (p->L == x) rotateR(root, p);
else rotateL(root, p);
}
else
{
if (p == p->P->R)
{
if (p->R == x) rotateL(root, p->P);
else rotateR(root, p);
rotateL(root, x->P);
}
else
{
if (p->L == x) rotateR(root, p->P);
else rotateL(root, p);
rotateR(root, x->P);
}
}
}
}
//--------------------------------------------------------------------
inline int seek(Where<NODE_> &root, NODE_ &x, void* key, CompareFunction CMP)
{
x = root;
for (;;)
{
int diff = CMP(key, x);
if (diff < 0)
{
if (!x->L) return -1;
x = x->L;
}
else if (diff > 0)
{
if (!x->R) return 1;
x = x->R;
}
else return 0;
}
}
//--------------------------------------------------------------------
inline NODE_ next(NODE_ x)
{
if (x->R) { x = x->R; while (x->L) x = x->L; return x; }
NODE_ p = x->P;
while (p && x == p->R) { x = p; p = p->P; }
return p;
}
//--------------------------------------------------------------------
inline NODE_ prev(NODE_ x)
{
if (x->L) { x = x->L; while (x->R) x = x->R; return x; }
NODE_ p = x->P;
while (p && x == p->L) { x = p; p = p->P; }
return p;
}
//--------------------------------------------------------------------
NODE_ First(NODE_ x)
{
SetLock.Acquire();
if (x) while (x->L) x = x->L;
SetLock.Release();
return x;
}
//--------------------------------------------------------------------
NODE_ Last(NODE_ x)
{
SetLock.Acquire();
if (x) while (x->R) x = x->R;
SetLock.Release();
return x;
}
//--------------------------------------------------------------------
NODE_ Next(NODE_ x)
{
SetLock.Acquire();
x = next(x);
SetLock.Release();
return x;
}
//--------------------------------------------------------------------
NODE_ Prev(NODE_ x)
{
SetLock.Acquire();
x = prev(x);
SetLock.Release();
return x;
}
//--------------------------------------------------------------------
NODE_ Near(Where<NODE_> &root, void* key, CompareFunction CMP, Neighbor want)
{
// Return a node relative to (just <, <=, ==, >=, or >) a key.
if (!root) return 0;
SetLock.Acquire();
NODE_ x;
int dir = seek(root, x, key, CMP);
if ((dir == 0 && want == GT) || (dir > 0 && want >= GE)) x = next(x);
else
if ((dir == 0 && want == LT) || (dir < 0 && want <= LE)) x = prev(x);
else
if (dir != 0 && want == EQ) x = 0;
if (x) splay(root, x);
SetLock.Release();
return x;
}
//--------------------------------------------------------------------
NODE_ Find(Where<NODE_> &root, void* key, CompareFunction CMP)
{
if (!root) return 0;
SetLock.Acquire();
NODE_ x;
int direction = seek(root, x, key, CMP);
splay(root, x);
SetLock.Release();
return direction?0:x;
}
//--------------------------------------------------------------------
void Attach(Where<NODE_> &root, NODE_ x, CompareFunction CMP, void* key)
{
SetLock.Acquire();
if (!root)
{
root = x;
x->P = x->L = x->R = x->E = 0;
SetLock.Release();
return;
}
NODE_ f;
int diff = seek(root, f, key, CMP);
if (!diff)
{
if (x->L = f->L) x->L->P = x;
if (x->R = f->R) x->R->P = x;
NODE_ p = f->P;
if (x->P = p) { if (p->L == f) p->L = x; else p->R = x; }
else root = x;
(x->E = f)->P = x;
f->L = f->R = 0;
splay(root, x);
SetLock.Release();
return;
}
if (diff < 0) f->L = x; else f->R = x;
x->P = f;
x->L = x->R = x->E = 0;
splay(root, x);
SetLock.Release();
}
//--------------------------------------------------------------------
void Detach(Where<NODE_> &root, NODE_ x)
{
SetLock.Acquire();
NODE_ e = x->E, p = x->P;
if (p && p->E == x) { if (p->E = e) e->P = p; }
else if (e)
{
if (e->L = x->L) e->L->P = e;
if (e->R = x->R) e->R->P = e;
if (e->P = p) { if (p->L == x) p->L = e; else p->R = e; }
else root = e;
}
else if (!x->L)
{
if (p) { if ( p->L == x) p->L = x->R; else p->R = x->R; }
else root = x->R;
if (x->R) x->R->P = p;
}
else if (!x->R)
{
if (p) { if ( p->L == x) p->L = x->L; else p->R = x->L; }
else root = x->L;
if (x->L) x->L->P = p;
}
else
{
e = x->L;
if (e->R)
{
do { e = e->R; } while (e->R);
if (e->P->R = e->L) e->L->P = e->P;
(e->L = x->L)->P = e;
}
(e->R = x->R)->P = e;
if (e->P = x->P) { if (e->P->L == x) e->P->L = e; else e->P->R = e; }
else root = e;
}
SetLock.Release();
}
//////////////////////////////////////////////////////////////////////
//
// Storage Functions for our memory-mapped file-based persistent volumes
//--------------------------------------------------------------------
void* StorageAllocate(AIRFS_ Airfs, int64_t RequestedSize)
{
if (!RequestedSize) return 0;
if (RequestedSize + sizeof int32_t > MAXIMUM_ALLOCSIZE) return 0;
StorageLock.Acquire();
int32_t RoundedSize = (int32_t) ROUND_UP(RequestedSize, MINIMUM_ALLOCSIZE - sizeof int32_t);
int32_t SplitableSize = RoundedSize + MINIMUM_ALLOCSIZE;
// See if we have a freed node of the size we requested.
NODE_ NewItem = Near(Airfs->Available, &RoundedSize, SizeCmp, GE);
if (NewItem)
{
int32_t FoundSize = ((int32_t*)NewItem)[-1];
if (FoundSize < SplitableSize)
{
Detach(Airfs->Available, NewItem);
Airfs->FreeSize -= FoundSize;
StorageLock.Release();
return NewItem;
}
}
// If not, see if we can downsize a larger freed element.
NewItem = Near(Airfs->Available, &SplitableSize, SizeCmp, GE);
if (NewItem)
{
int32_t FoundSize = ((int32_t*)NewItem)[-1];
Detach(Airfs->Available, NewItem);
Airfs->FreeSize -= FoundSize;
char* Addr = (char*)NewItem + RoundedSize + sizeof int32_t;
NODE_ Remainder = (NODE_) Addr;
int32_t RemainderSize = FoundSize - (RoundedSize + sizeof int32_t);
((int32_t*)Remainder)[-1] = RemainderSize;
Attach(Airfs->Available, Remainder, SizeCmp, &RemainderSize);
Airfs->FreeSize += RemainderSize;
((int32_t*)NewItem)[-1] = RoundedSize;
StorageLock.Release();
return NewItem;
}
// If not, give up.
StorageLock.Release();
return 0;
}
//--------------------------------------------------------------------
void* StorageReallocate(AIRFS_ Airfs, void* OldAlloc, int64_t RequestedSize)
{
if (!OldAlloc)
{
return StorageAllocate(Airfs, RequestedSize);
}
if (!RequestedSize)
{
StorageFree(Airfs, OldAlloc);
return 0;
}
int32_t OldSize = ((int32_t*)OldAlloc)[-1];
void* NewAlloc = StorageAllocate(Airfs, RequestedSize);
if (!NewAlloc) return 0;
memcpy(NewAlloc, OldAlloc, min(RequestedSize, OldSize));
StorageFree(Airfs, OldAlloc);
return NewAlloc;
}
//--------------------------------------------------------------------
void StorageFree(AIRFS_ Airfs, void* r)
{
if (!r) return;
StorageLock.Acquire();
NODE_ release = (NODE_) r;
int32_t Size = ((int32_t*)r)[-1];
Attach(Airfs->Available, release, SizeCmp, &Size);
Airfs->FreeSize += Size;
StorageLock.Release();
}
//--------------------------------------------------------------------
void StorageAccessFile(StorageFileAccessType Type, NODE_ Node, int64_t AccessOffset, int64_t NumBytes, char* MemoryAddress)
{
StorageLock.Acquire();
NODE_ Block = Near(Node->FileBlocks, &AccessOffset, BlockCmp, LE);
for (;;)
{
int32_t BlockSize = ((int32_t*)Block)[-1];
int64_t BlockOffset = Block->FileOffset;
int64_t BlockIndex = AccessOffset - BlockOffset + FILEBLOCK_OVERHEAD;
int64_t BlockNum = min(BlockSize-BlockIndex, NumBytes);
switch (Type)
{
case ZERO : { memset((char*)Block + BlockIndex, 0, BlockNum); break; }
case READ : { memcpy(MemoryAddress, (char*)Block + BlockIndex, BlockNum); break; }
case WRITE : { memcpy((char*)Block + BlockIndex, MemoryAddress, BlockNum); break; }
}
NumBytes -= BlockNum;
if (!NumBytes) break;
MemoryAddress += BlockNum;
AccessOffset += BlockNum;
Block = Next(Block);
}
StorageLock.Release();
}
//--------------------------------------------------------------------
NTSTATUS StorageSetFileCapacity(AIRFS_ Airfs, NODE_ Node, int64_t minimumRequiredCapacity)
{
StorageLock.Acquire();
int64_t TargetCapacity = ROUND_UP(minimumRequiredCapacity, ALLOCATION_UNIT);
NODE_ Block = Last(Node->FileBlocks);
int32_t BlockSize = Block ? ((int32_t*)Block)[-1] : 0;
int64_t CurrentCapacity = Block ? Block->FileOffset + BlockSize - FILEBLOCK_OVERHEAD: 0;
int64_t Add = TargetCapacity - CurrentCapacity;
while (Add > 0)
{
// Add a block if we can, preferably as large or larger than we need.
Add += FILEBLOCK_OVERHEAD;
Block = Near(Airfs->Available, &Add, SizeCmp, GE);
if (!Block) Block = Near(Airfs->Available, &Add, SizeCmp, LT);
Add -= FILEBLOCK_OVERHEAD;
if (Block)
{
Detach(Airfs->Available, Block);
BlockSize = ((int32_t*)Block)[-1];
Airfs->FreeSize -= BlockSize;
Block->FileOffset = CurrentCapacity;
Attach(Node->FileBlocks, Block, BlockCmp, &CurrentCapacity);
CurrentCapacity += BlockSize - FILEBLOCK_OVERHEAD;
Add -= BlockSize - FILEBLOCK_OVERHEAD;
continue;
}
StorageLock.Release();
return STATUS_INSUFFICIENT_RESOURCES;
}
// Throw away any trailing blocks that are no longer needed.
while (Add < 0)
{
Block = Last(Node->FileBlocks);
BlockSize = ((int32_t*)Block)[-1];
if (BlockSize - FILEBLOCK_OVERHEAD > -Add) break;
Add += BlockSize - FILEBLOCK_OVERHEAD;
Detach(Node->FileBlocks, Block);
Attach(Airfs->Available, Block, SizeCmp, &BlockSize);
Airfs->FreeSize += BlockSize;
}
// Possibly downsize the last block.
if (Add < 0)
{
Block = Last(Node->FileBlocks);
int32_t OldBlockSize = ((int32_t*)Block)[-1];
int32_t NewBlockSize = OldBlockSize - (int32_t) ROUND_DOWN(-Add, MINIMUM_ALLOCSIZE);
if (NewBlockSize < MINIMUM_ALLOCSIZE) NewBlockSize = MINIMUM_ALLOCSIZE;
int32_t RemainderBlockSize = OldBlockSize - NewBlockSize - sizeof int32_t;
if (RemainderBlockSize >= MINIMUM_ALLOCSIZE) // i.e. if not too near the end
{
char* Addr = (char*)Block + NewBlockSize + sizeof int32_t;
NODE_ Remainder = (NODE_) Addr;
((int32_t*)Remainder)[-1] = RemainderBlockSize;
Attach(Airfs->Available, Remainder, SizeCmp, &RemainderBlockSize);
Airfs->FreeSize += RemainderBlockSize;
((int32_t*)Block)[-1] = NewBlockSize;
}
}
StorageLock.Release();
return 0;
}
//--------------------------------------------------------------------
NTSTATUS StorageStartup(AIRFS_ &Airfs, WCHAR* MapName, WCHAR* StorageFileName, int64_t VolumeLength)
{
HANDLE MapFileHandle = INVALID_HANDLE_VALUE;
Airfs = 0;
// Open.
if (*StorageFileName)
{
MapFileHandle = CreateFileW(StorageFileName, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, OPEN_ALWAYS, NULL, NULL);
if (MapFileHandle == INVALID_HANDLE_VALUE) return GetLastErrorAsStatus();
}
// Map.
HANDLE MapHandle = CreateFileMappingW(MapFileHandle, NULL, PAGE_EXECUTE_READWRITE, VolumeLength>>32, VolumeLength & 0xFFFFFFFF, MapName);
if (!MapHandle) return GetLastErrorAsStatus();
// Point.
char* MappedAddress = (char*) MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, VolumeLength);
if (!MappedAddress) return GetLastErrorAsStatus();
// Keep.
Airfs = (AIRFS_) MappedAddress;
Airfs->MapFileHandle = MapFileHandle;
Airfs->MapHandle = MapHandle;
Airfs->VolumeLength = VolumeLength;
return 0;
}
//--------------------------------------------------------------------
NTSTATUS StorageShutdown(AIRFS_ Airfs)
{
BOOL Ok;
NTSTATUS Result = 0;
HANDLE M = Airfs->MapHandle;
HANDLE F = Airfs->MapFileHandle;
Ok = FlushViewOfFile(Airfs, 0); if (!Ok && !Result) Result = GetLastErrorAsStatus();
if (F != INVALID_HANDLE_VALUE)
{
Ok = FlushFileBuffers(F); if (!Ok && !Result) Result = GetLastErrorAsStatus();
// TODO: Set and write a flag something like Airfs->UpdatesCompleted here?
}
Ok = UnmapViewOfFile(Airfs); if (!Ok && !Result) Result = GetLastErrorAsStatus();
if (M)
{
Ok = CloseHandle(M); if (!Ok && !Result) Result = GetLastErrorAsStatus();
}
if (F != INVALID_HANDLE_VALUE)
{
Ok = CloseHandle(F); if (!Ok && !Result) Result = GetLastErrorAsStatus();
}
return Result;
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

35
tst/launcher-tests/echo.c Normal file
View File

@ -0,0 +1,35 @@
/*
* Compile:
* - cl -I"%ProgramFiles(x86)%\WinFsp\inc" "%ProgramFiles(x86)%\WinFsp\lib\winfsp-x64.lib" echo.c
*
* Register:
* - echo.reg (fix Executable path first)
*
* Run:
* - launchctl-x64 start echo 1 \foo\bar\baz
*
* Expect:
* - "\foo\bar\baz" "bar:baz" "DOMAIN\\USERNAME"
*/
#include <winfsp/winfsp.h>
int wmain(int argc, wchar_t *argv[])
{
WCHAR buf[512], *bufp;
int len;
bufp = buf;
for (int i = 0; argc > i; i++)
{
len = lstrlenW(argv[i]);
memcpy(bufp, argv[i], len * sizeof(WCHAR));
bufp += len;
*bufp++ = '\n';
}
*bufp = '\0';
FspServiceLog(EVENTLOG_INFORMATION_TYPE, L"%s", buf);
return 0;
}

BIN
tst/launcher-tests/echo.reg Normal file

Binary file not shown.

Binary file not shown.

View File

@ -19,12 +19,17 @@
* associated repository. * associated repository.
*/ */
#define MEMFS_SLOWIO
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.AccessControl; using System.Security.AccessControl;
using System.Threading; using System.Threading;
#if MEMFS_SLOWIO
using System.Threading.Tasks;
#endif
using Fsp; using Fsp;
using VolumeInfo = Fsp.Interop.VolumeInfo; using VolumeInfo = Fsp.Interop.VolumeInfo;
@ -232,15 +237,20 @@ namespace memfs
class Memfs : FileSystemBase class Memfs : FileSystemBase
{ {
private FileSystemHost Host;
public const UInt16 MEMFS_SECTOR_SIZE = 512; public const UInt16 MEMFS_SECTOR_SIZE = 512;
public const UInt16 MEMFS_SECTORS_PER_ALLOCATION_UNIT = 1; public const UInt16 MEMFS_SECTORS_PER_ALLOCATION_UNIT = 1;
public Memfs( public Memfs(
Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl) Boolean CaseInsensitive, UInt32 MaxFileNodes, UInt32 MaxFileSize, String RootSddl,
UInt64 SlowioMaxDelay, UInt64 SlowioPercentDelay, UInt64 SlowioRarefyDelay)
{ {
this.FileNodeMap = new FileNodeMap(CaseInsensitive); this.FileNodeMap = new FileNodeMap(CaseInsensitive);
this.MaxFileNodes = MaxFileNodes; this.MaxFileNodes = MaxFileNodes;
this.MaxFileSize = MaxFileSize; this.MaxFileSize = MaxFileSize;
this.SlowioMaxDelay = SlowioMaxDelay;
this.SlowioPercentDelay = SlowioPercentDelay;
this.SlowioRarefyDelay = SlowioRarefyDelay;
/* /*
* Create root directory. * Create root directory.
@ -259,7 +269,7 @@ namespace memfs
public override Int32 Init(Object Host0) public override Int32 Init(Object Host0)
{ {
FileSystemHost Host = (FileSystemHost)Host0; Host = (FileSystemHost)Host0;
Host.SectorSize = Memfs.MEMFS_SECTOR_SIZE; Host.SectorSize = Memfs.MEMFS_SECTOR_SIZE;
Host.SectorsPerAllocationUnit = Memfs.MEMFS_SECTORS_PER_ALLOCATION_UNIT; Host.SectorsPerAllocationUnit = Memfs.MEMFS_SECTORS_PER_ALLOCATION_UNIT;
Host.VolumeCreationTime = (UInt64)DateTime.Now.ToFileTimeUtc(); Host.VolumeCreationTime = (UInt64)DateTime.Now.ToFileTimeUtc();
@ -274,9 +284,24 @@ namespace memfs
Host.PostCleanupWhenModifiedOnly = true; Host.PostCleanupWhenModifiedOnly = true;
Host.PassQueryDirectoryFileName = true; Host.PassQueryDirectoryFileName = true;
Host.ExtendedAttributes = true; Host.ExtendedAttributes = true;
Host.WslFeatures = true;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
#if MEMFS_SLOWIO
public override int Mounted(object Host)
{
SlowioTasksRunning = 0;
return STATUS_SUCCESS;
}
public override void Unmounted(object Host)
{
while (SlowioTasksRunning != 0)
Thread.Sleep(1000);
}
#endif
public override Int32 GetVolumeInfo( public override Int32 GetVolumeInfo(
out VolumeInfo VolumeInfo) out VolumeInfo VolumeInfo)
{ {
@ -331,8 +356,9 @@ namespace memfs
UInt32 FileAttributes, UInt32 FileAttributes,
Byte[] SecurityDescriptor, Byte[] SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
out Object FileNode0, out Object FileNode0,
out Object FileDesc, out Object FileDesc,
out FileInfo FileInfo, out FileInfo FileInfo,
@ -369,11 +395,21 @@ namespace memfs
FileNode.FileInfo.FileAttributes = 0 != (FileAttributes & (UInt32)System.IO.FileAttributes.Directory) ? FileNode.FileInfo.FileAttributes = 0 != (FileAttributes & (UInt32)System.IO.FileAttributes.Directory) ?
FileAttributes : FileAttributes | (UInt32)System.IO.FileAttributes.Archive; FileAttributes : FileAttributes | (UInt32)System.IO.FileAttributes.Archive;
FileNode.FileSecurity = SecurityDescriptor; FileNode.FileSecurity = SecurityDescriptor;
if (IntPtr.Zero != Ea) if (IntPtr.Zero != ExtraBuffer)
{ {
Result = SetEaEntries(FileNode, null, Ea, EaLength); if (!ExtraBufferIsReparsePoint)
if (0 > Result) {
return Result; Result = SetEaEntries(FileNode, null, ExtraBuffer, ExtraLength);
if (0 > Result)
return Result;
}
else
{
Byte[] ReparseData = MakeReparsePoint(ExtraBuffer, ExtraLength);
FileNode.FileInfo.FileAttributes |= (UInt32)System.IO.FileAttributes.ReparsePoint;
FileNode.FileInfo.ReparseTag = GetReparseTag(ReparseData);
FileNode.ReparseData = ReparseData;
}
} }
if (0 != AllocationSize) if (0 != AllocationSize)
{ {
@ -549,6 +585,93 @@ namespace memfs
Interlocked.Decrement(ref FileNode.OpenCount); Interlocked.Decrement(ref FileNode.OpenCount);
} }
#if MEMFS_SLOWIO
private UInt64 Hash(UInt64 X)
{
X = (X ^ (X >> 30)) * 0xbf58476d1ce4e5b9ul;
X = (X ^ (X >> 27)) * 0x94d049bb133111ebul;
X = X ^ (X >> 31);
return X;
}
private static int Spin = 0;
private UInt64 PseudoRandom(UInt64 To)
{
/* John Oberschelp's PRNG */
Interlocked.Increment(ref Spin);
return Hash((UInt64)Spin) % To;
}
private bool SlowioReturnPending()
{
if (0 == SlowioMaxDelay)
{
return false;
}
return PseudoRandom(100) < SlowioPercentDelay;
}
private void SlowioSnooze()
{
double Millis = PseudoRandom(SlowioMaxDelay + 1) >> (int) PseudoRandom(SlowioRarefyDelay + 1);
Thread.Sleep(TimeSpan.FromMilliseconds(Millis));
}
private void SlowioReadTask(
Object FileNode0,
IntPtr Buffer,
UInt64 Offset,
UInt64 EndOffset,
UInt64 RequestHint)
{
SlowioSnooze();
UInt32 BytesTransferred = (UInt32)(EndOffset - Offset);
FileNode FileNode = (FileNode)FileNode0;
Marshal.Copy(FileNode.FileData, (int)Offset, Buffer, (int)BytesTransferred);
Host.SendReadResponse(RequestHint, STATUS_SUCCESS, BytesTransferred);
Interlocked.Decrement(ref SlowioTasksRunning);
}
private void SlowioWriteTask(
Object FileNode0,
IntPtr Buffer,
UInt64 Offset,
UInt64 EndOffset,
UInt64 RequestHint)
{
SlowioSnooze();
UInt32 BytesTransferred = (UInt32)(EndOffset - Offset);
FileNode FileNode = (FileNode)FileNode0;
FileInfo FileInfo = FileNode.GetFileInfo();
Marshal.Copy(Buffer, FileNode.FileData, (int)Offset, (int)BytesTransferred);
Host.SendWriteResponse(RequestHint, STATUS_SUCCESS, BytesTransferred, ref FileInfo);
Interlocked.Decrement(ref SlowioTasksRunning);
}
private void SlowioReadDirectoryTask(
Object FileNode0,
Object FileDesc,
String Pattern,
String Marker,
IntPtr Buffer,
UInt32 Length,
UInt64 RequestHint)
{
SlowioSnooze();
UInt32 BytesTransferred;
var Status = SeekableReadDirectory(FileNode0, FileDesc, Pattern, Marker, Buffer, Length, out BytesTransferred);
Host.SendReadDirectoryResponse(RequestHint, Status, BytesTransferred);
Interlocked.Decrement(ref SlowioTasksRunning);
}
#endif
public override Int32 Read( public override Int32 Read(
Object FileNode0, Object FileNode0,
Object FileDesc, Object FileDesc,
@ -570,6 +693,25 @@ namespace memfs
if (EndOffset > FileNode.FileInfo.FileSize) if (EndOffset > FileNode.FileInfo.FileSize)
EndOffset = FileNode.FileInfo.FileSize; EndOffset = FileNode.FileInfo.FileSize;
#if MEMFS_SLOWIO
if (SlowioReturnPending())
{
var Hint = Host.GetOperationRequestHint();
try
{
Interlocked.Increment(ref SlowioTasksRunning);
Task.Run(() => SlowioReadTask(FileNode0, Buffer, Offset, EndOffset, Hint)).ConfigureAwait(false);
BytesTransferred = 0;
return STATUS_PENDING;
}
catch (Exception)
{
Interlocked.Decrement(ref SlowioTasksRunning);
}
}
#endif
BytesTransferred = (UInt32)(EndOffset - Offset); BytesTransferred = (UInt32)(EndOffset - Offset);
Marshal.Copy(FileNode.FileData, (int)Offset, Buffer, (int)BytesTransferred); Marshal.Copy(FileNode.FileData, (int)Offset, Buffer, (int)BytesTransferred);
@ -619,6 +761,26 @@ namespace memfs
} }
} }
#if MEMFS_SLOWIO
if (SlowioReturnPending())
{
var hint = Host.GetOperationRequestHint();
try
{
Interlocked.Increment(ref SlowioTasksRunning);
Task.Run(() => SlowioWriteTask(FileNode0, Buffer, Offset, EndOffset, hint)).ConfigureAwait(false);
BytesTransferred = 0;
FileInfo = default(FileInfo);
return STATUS_PENDING;
}
catch (Exception)
{
Interlocked.Decrement(ref SlowioTasksRunning);
}
}
#endif
BytesTransferred = (UInt32)(EndOffset - Offset); BytesTransferred = (UInt32)(EndOffset - Offset);
Marshal.Copy(Buffer, FileNode.FileData, (int)Offset, (int)BytesTransferred); Marshal.Copy(Buffer, FileNode.FileData, (int)Offset, (int)BytesTransferred);
@ -902,6 +1064,37 @@ namespace memfs
return false; return false;
} }
#if MEMFS_SLOWIO
public override int ReadDirectory(
Object FileNode0,
Object FileDesc,
String Pattern,
String Marker,
IntPtr Buffer,
UInt32 Length,
out UInt32 BytesTransferred)
{
if (SlowioReturnPending())
{
var Hint = Host.GetOperationRequestHint();
try
{
Interlocked.Increment(ref SlowioTasksRunning);
Task.Run(() => SlowioReadDirectoryTask(FileNode0, FileDesc, Pattern, Marker, Buffer, Length, Hint));
BytesTransferred = 0;
return STATUS_PENDING;
}
catch (Exception)
{
Interlocked.Decrement(ref SlowioTasksRunning);
}
}
return SeekableReadDirectory(FileNode0, FileDesc, Pattern, Marker, Buffer, Length, out BytesTransferred);
}
#endif
public override int GetDirInfoByName( public override int GetDirInfoByName(
Object ParentNode0, Object ParentNode0,
Object FileDesc, Object FileDesc,
@ -1140,6 +1333,10 @@ namespace memfs
private FileNodeMap FileNodeMap; private FileNodeMap FileNodeMap;
private UInt32 MaxFileNodes; private UInt32 MaxFileNodes;
private UInt32 MaxFileSize; private UInt32 MaxFileSize;
private UInt64 SlowioMaxDelay;
private UInt64 SlowioPercentDelay;
private UInt64 SlowioRarefyDelay;
private volatile Int32 SlowioTasksRunning;
private String VolumeLabel; private String VolumeLabel;
} }
@ -1170,6 +1367,9 @@ namespace memfs
UInt32 FileInfoTimeout = unchecked((UInt32)(-1)); UInt32 FileInfoTimeout = unchecked((UInt32)(-1));
UInt32 MaxFileNodes = 1024; UInt32 MaxFileNodes = 1024;
UInt32 MaxFileSize = 16 * 1024 * 1024; UInt32 MaxFileSize = 16 * 1024 * 1024;
UInt32 SlowioMaxDelay = 0;
UInt32 SlowioPercentDelay = 0;
UInt32 SlowioRarefyDelay = 0;
String FileSystemName = null; String FileSystemName = null;
String VolumePrefix = null; String VolumePrefix = null;
String MountPoint = null; String MountPoint = null;
@ -1202,9 +1402,18 @@ namespace memfs
case 'm': case 'm':
argtos(Args, ref I, ref MountPoint); argtos(Args, ref I, ref MountPoint);
break; break;
case 'M':
argtol(Args, ref I, ref SlowioMaxDelay);
break;
case 'n': case 'n':
argtol(Args, ref I, ref MaxFileNodes); argtol(Args, ref I, ref MaxFileNodes);
break; break;
case 'P':
argtol(Args, ref I, ref SlowioPercentDelay);
break;
case 'R':
argtol(Args, ref I, ref SlowioRarefyDelay);
break;
case 'S': case 'S':
argtos(Args, ref I, ref RootSddl); argtos(Args, ref I, ref RootSddl);
break; break;
@ -1233,7 +1442,8 @@ namespace memfs
throw new CommandLineUsageException("cannot open debug log file"); throw new CommandLineUsageException("cannot open debug log file");
Host = new FileSystemHost(Memfs = new Memfs( Host = new FileSystemHost(Memfs = new Memfs(
CaseInsensitive, MaxFileNodes, MaxFileSize, RootSddl)); CaseInsensitive, MaxFileNodes, MaxFileSize, RootSddl,
SlowioMaxDelay, SlowioPercentDelay, SlowioRarefyDelay));
Host.FileInfoTimeout = FileInfoTimeout; Host.FileInfoTimeout = FileInfoTimeout;
Host.Prefix = VolumePrefix; Host.Prefix = VolumePrefix;
Host.FileSystemName = null != FileSystemName ? FileSystemName : "-MEMFS"; Host.FileSystemName = null != FileSystemName ? FileSystemName : "-MEMFS";
@ -1262,6 +1472,9 @@ namespace memfs
" -t FileInfoTimeout [millis]\n" + " -t FileInfoTimeout [millis]\n" +
" -n MaxFileNodes\n" + " -n MaxFileNodes\n" +
" -s MaxFileSize [bytes]\n" + " -s MaxFileSize [bytes]\n" +
" -M MaxDelay [maximum slow IO delay in millis]\n" +
" -P PercentDelay [percent of slow IO to make pending]\n" +
" -R RarefyDelay [adjust the rarity of pending slow IO]\n" +
" -F FileSystemName\n" + " -F FileSystemName\n" +
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" + " -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" +
" -u \\Server\\Share [UNC prefix (single backslash)]\n" + " -u \\Server\\Share [UNC prefix (single backslash)]\n" +

10
tst/memfs-fuse3/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
build
*.ncb
*.suo
*.vcproj.*
*.vcxproj.user
*.VC.db
*.VC.opendb
.vs
*.exe
*.install

18
tst/memfs-fuse3/Makefile Normal file
View File

@ -0,0 +1,18 @@
usage:
@echo "make cygfuse3|winfsp-fuse3" 1>&2
@echo "" 1>&2
@echo " cygfuse3 Link with CYGFUSE3" 1>&2
@echo " winfsp-fuse3 Link with WinFsp-FUSE3" 1>&2
@exit 2
cygfuse3: memfs-cygfuse3
winfsp-fuse3: memfs-winfsp-fuse3
memfs-cygfuse3: memfs-fuse3.cpp
g++ $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
memfs-winfsp-fuse3: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib
memfs-winfsp-fuse3: memfs-fuse3.cpp
ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install
g++ $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`

View File

@ -0,0 +1,7 @@
`Memfs-fuse3` is an in-memory FUSE3 file system.
It can be built with the following tools:
- Using Visual Studio (`memfs-fuse3.sln`).
- Using Cygwin GCC and linking directly with the WinFsp DLL (`make winfsp-fuse3`).
- Using Cygwin GCC and linking to CYGFUSE3 (`make cygfuse3`).

104
tst/memfs-fuse3/compat.h Normal file
View File

@ -0,0 +1,104 @@
/**
* @file compat.h
*
* @copyright 2015-2019 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.
*/
#ifndef COMPAT_H_INCLUDED
#define COMPAT_H_INCLUDED
#if defined(_WIN32) && defined(FSP_FUSE_SYM)
#include <winfsp/winfsp.h>
#undef fuse_main
#define fuse_main(argc, argv, ops, data)\
(FspLoad(0), fuse_main_real(argc, argv, ops, sizeof *(ops), data))
#endif
#if !defined(_WIN32) && !defined(fuse_stat)
#define fuse_uid_t uid_t
#define fuse_gid_t gid_t
#define fuse_pid_t pid_t
#define fuse_dev_t dev_t
#define fuse_mode_t mode_t
#define fuse_nlink_t nlink_t
#define fuse_off_t off_t
#define fuse_fsblkcnt_t fsblkcnt_t
#define fuse_fsfilcnt_t fsfilcnt_t
#define fuse_blksize_t blksize_t
#define fuse_blkcnt_t blkcnt_t
#define fuse_timespec timespec
#define fuse_stat stat
#define fuse_statvfs statvfs
#define fuse_flock flock
#define fuse_iovec iovec
#endif
#if !defined(S_IFMT)
#define S_IFMT 0170000
#endif
#if !defined(S_IFDIR)
#define S_IFDIR 0040000
#endif
#if !defined(S_IFCHR)
#define S_IFCHR 0020000
#endif
#if !defined(S_IFBLK)
#define S_IFBLK 0060000
#endif
#if !defined(S_IFREG)
#define S_IFREG 0100000
#endif
#if !defined(S_IFLNK)
#define S_IFLNK 0120000
#endif
#if !defined(S_IFSOCK)
#define S_IFSOCK 0140000
#endif
#if !defined(S_IFIFO)
#define S_IFIFO 0010000
#endif
#if defined(__APPLE__)
#define st_atim st_atimespec
#define st_ctim st_ctimespec
#define st_mtim st_mtimespec
#endif
#if defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__)
#include <sys/xattr.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(_WIN32)
#define XATTR_CREATE 1
#define XATTR_REPLACE 2
#endif
#if !defined(ENOATTR)
#define ENOATTR ENODATA
#elif !defined(ENODATA)
#define ENODATA ENOATTR
#endif
#endif

View File

@ -0,0 +1,619 @@
/**
* @file memfs-fuse3.c
*
* @copyright 2015-2019 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 <cerrno>
#include <chrono>
#include <cstring>
#include <algorithm>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <fuse.h>
#include "compat.h"
class memfs
{
public:
memfs() : _ino(1), _root(std::make_shared<node_t>(_ino, S_IFDIR | 00777, 0, 0))
{
}
int main(int argc, char *argv[])
{
static fuse_operations ops =
{
getattr,
readlink,
mknod,
mkdir,
unlink,
rmdir,
symlink,
rename,
link,
chmod,
chown,
truncate,
open,
read,
write,
statfs,
flush,
release,
0, // fsync
setxattr,
getxattr,
listxattr,
removexattr,
opendir,
readdir,
releasedir,
0, // fsyncdir
init,
0, // destroy
0, // access
0, // create
0, // lock
utimens,
0, // bmap
#if 0
ioctl,
#endif
};
return fuse_main(argc, argv, &ops, this);
}
private:
struct node_t
{
node_t(fuse_ino_t ino, fuse_mode_t mode, fuse_uid_t uid, fuse_gid_t gid, fuse_dev_t dev = 0)
: stat()
{
stat.st_ino = ino;
stat.st_mode = mode;
stat.st_nlink = 1;
stat.st_uid = uid;
stat.st_gid = gid;
stat.st_rdev = dev;
stat.st_atim = stat.st_mtim = stat.st_ctim = now();
}
void resize(size_t size, bool capacity)
{
if (capacity)
{
const size_t unit = 64 * 1024;
size_t newcap = (size + unit - 1) / unit * unit;
size_t oldcap = data.capacity();
if (newcap > oldcap)
data.reserve(newcap);
else if (newcap < oldcap)
{
data.resize(newcap);
data.shrink_to_fit();
}
}
data.resize(size);
stat.st_size = size;
}
struct fuse_stat stat;
std::vector<uint8_t> data;
std::unordered_map<std::string, std::shared_ptr<node_t>> childmap;
std::unordered_map<std::string, std::vector<uint8_t>> xattrmap;
};
static fuse_timespec now()
{
using namespace std::chrono;
auto now = system_clock::now();
auto sec = floor<seconds>(now);
auto nsec = floor<nanoseconds>(now) - floor<nanoseconds>(sec);
return fuse_timespec
{
static_cast<decltype(fuse_timespec::tv_sec)>(sec.time_since_epoch().count()),
/* std::chrono epoch is UNIX epoch in C++20 */
static_cast<decltype(fuse_timespec::tv_nsec)>(nsec.count()),
};
}
static memfs *getself()
{
return static_cast<memfs *>(fuse_get_context()->private_data);
}
static int getattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
*stbuf = node->stat;
return 0;
}
static int readlink(const char *path, char *buf, size_t size)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path);
if (!node)
return -ENOENT;
if (S_IFLNK != (node->stat.st_mode & S_IFMT))
return EINVAL;
size = (std::min)(size - 1, node->data.size());
std::memcpy(buf, node->data.data(), size);
buf[size] = '\0';
return 0;
}
static int mknod(const char *path, fuse_mode_t mode, fuse_dev_t dev)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->make_node(path, mode, dev);
}
static int mkdir(const char *path, fuse_mode_t mode)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->make_node(path, S_IFDIR | (mode & 07777), 0);
}
static int unlink(const char *path)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->remove_node(path, false);
}
static int rmdir(const char *path)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->remove_node(path, true);
}
static int symlink(const char *dstpath, const char *srcpath)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->make_node(srcpath, S_IFLNK | 00777, 0, dstpath);
}
static int rename(const char *oldpath, const char *newpath, unsigned int flags)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto oldlookup = self->lookup_node(oldpath);
auto oldprnt = std::get<0>(oldlookup);
auto oldname = std::get<1>(oldlookup);
auto oldnode = std::get<2>(oldlookup);
if (!oldnode)
return -ENOENT;
auto newlookup = self->lookup_node(newpath);
auto newprnt = std::get<0>(newlookup);
auto newname = std::get<1>(newlookup);
auto newnode = std::get<2>(newlookup);
if (!newprnt)
return -ENOENT;
if (newname.empty())
// guard against directory loop creation
return -EINVAL;
if (oldprnt == newprnt && oldname == newname)
return 0;
if (newnode)
{
if (int errc = self->remove_node(newpath, S_IFDIR == (oldnode->stat.st_mode & S_IFMT)))
return errc;
}
oldprnt->childmap.erase(oldname);
newprnt->childmap[newname] = oldnode;
return 0;
}
static int link(const char *oldpath, const char *newpath)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto oldlookup = self->lookup_node(oldpath);
auto oldnode = std::get<2>(oldlookup);
if (!oldnode)
return -ENOENT;
auto newlookup = self->lookup_node(newpath);
auto newprnt = std::get<0>(newlookup);
auto newname = std::get<1>(newlookup);
auto newnode = std::get<2>(newlookup);
if (!newprnt)
return -ENOENT;
if (newnode)
return -EEXIST;
oldnode->stat.st_nlink++;
newprnt->childmap[newname] = oldnode;
oldnode->stat.st_ctim = newprnt->stat.st_ctim = newprnt->stat.st_mtim = now();
return 0;
}
static int chmod(const char *path, fuse_mode_t mode,
struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
node->stat.st_mode = (node->stat.st_mode & S_IFMT) | (mode & 07777);
node->stat.st_ctim = now();
return 0;
}
static int chown(const char *path, fuse_uid_t uid, fuse_gid_t gid,
struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
if (-1 != uid)
node->stat.st_uid = uid;
if (-1 != gid)
node->stat.st_gid = gid;
node->stat.st_ctim = now();
return 0;
}
static int truncate(const char *path, fuse_off_t size,
struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
if (SIZE_MAX < size)
return -EFBIG;
node->resize(static_cast<size_t>(size), true);
node->stat.st_ctim = node->stat.st_mtim = now();
return 0;
}
static int open(const char *path, struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->open_node(path, false, fi);
}
static int read(const char *path, char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
fuse_off_t endoff = (std::min)(
off + static_cast<fuse_off_t>(size), static_cast<fuse_off_t>(node->data.size()));
if (off > endoff)
return 0;
std::memcpy(buf, node->data.data() + off, static_cast<int>(endoff - off));
node->stat.st_atim = now();
return static_cast<int>(endoff - off);
}
static int write(const char *path, const char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
fuse_off_t endoff = off + static_cast<fuse_off_t>(size);
if (SIZE_MAX < endoff)
return -EFBIG;
if (node->data.size() < endoff)
node->resize(static_cast<size_t>(endoff), true);
std::memcpy(node->data.data() + off, buf, static_cast<int>(endoff - off));
node->stat.st_ctim = node->stat.st_mtim = now();
return static_cast<int>(endoff - off);
}
static int statfs(const char *path, struct fuse_statvfs *stbuf)
{
std::memset(stbuf, 0, sizeof *stbuf);
return 0;
}
static int flush(const char *path, struct fuse_file_info *fi)
{
return -ENOSYS;
}
static int release(const char *path, struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->close_node(fi);
}
static int setxattr(const char *path, const char *name0, const char *value, size_t size,
int flags)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path);
if (!node)
return -ENOENT;
if (0 == std::strcmp("com.apple.ResourceFork", name0))
return -ENOTSUP;
std::string name = name0;
if (XATTR_CREATE == flags)
{
if (node->xattrmap.end() != node->xattrmap.find(name))
return -EEXIST;
}
else if (XATTR_REPLACE == flags)
{
if (node->xattrmap.end() == node->xattrmap.find(name))
return -ENOATTR;
}
node->xattrmap[name].assign(value, value + size);
return 0;
}
static int getxattr(const char *path, const char *name0, char *value, size_t size)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path);
if (!node)
return -ENOENT;
if (0 == std::strcmp("com.apple.ResourceFork", name0))
return -ENOTSUP;
std::string name = name0;
auto iter = node->xattrmap.find(name);
if (node->xattrmap.end() == iter)
return -ENOATTR;
if (0 != size)
{
if (iter->second.size() > size)
return -ERANGE;
std::memcpy(value, iter->second.data(), iter->second.size());
}
return static_cast<int>(iter->second.size());
}
static int listxattr(const char *path, char *namebuf, size_t size)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path);
if (!node)
return -ENOENT;
size_t copysize = 0;
for (auto elem : node->xattrmap)
{
size_t namesize = elem.first.size() + 1;
if (0 != size)
{
if (copysize + namesize > size)
return -ERANGE;
std::memcpy(namebuf + copysize, elem.first.c_str(), namesize);
copysize += namesize;
}
}
return static_cast<int>(copysize);
}
static int removexattr(const char *path, const char *name0)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path);
if (!node)
return -ENOENT;
if (0 == std::strcmp("com.apple.ResourceFork", name0))
return -ENOTSUP;
std::string name = name0;
return node->xattrmap.erase(name) ? 0 : -ENOATTR;
}
static int opendir(const char *path, struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->open_node(path, true, fi);
}
static int readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
struct fuse_file_info *fi, enum fuse_readdir_flags)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
filler(buf, ".", &node->stat, 0, FUSE_FILL_DIR_PLUS);
filler(buf, "..", nullptr, 0, FUSE_FILL_DIR_PLUS);
for (auto elem : node->childmap)
if (0 != filler(buf, elem.first.c_str(), &elem.second->stat, 0, FUSE_FILL_DIR_PLUS))
break;
return 0;
}
static int releasedir(const char *path, struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
return self->close_node(fi);
}
static void *init(struct fuse_conn_info *conn,
struct fuse_config *conf)
{
conn->want |= (conn->capable & FUSE_CAP_READDIRPLUS);
return getself();
}
static int utimens(const char *path, const struct fuse_timespec tmsp[2],
struct fuse_file_info *fi)
{
auto self = getself();
std::lock_guard<std::mutex> lock(self->_mutex);
auto node = self->get_node(path, fi);
if (!node)
return -ENOENT;
if (tmsp)
{
node->stat.st_ctim = now();
node->stat.st_atim = tmsp[0];
node->stat.st_mtim = tmsp[1];
}
else
node->stat.st_ctim = node->stat.st_atim = node->stat.st_mtim = now();
return 0;
}
#if 0
static int ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
unsigned int flags, void *data)
{
return -ENOSYS;
}
#endif
std::tuple<std::shared_ptr<node_t>, std::string, std::shared_ptr<node_t>>
lookup_node(const char *path, node_t *ancestor = nullptr)
{
auto prnt = _root;
std::string name;
auto node = prnt;
for (const char *part = path, *p; *part; part = p + !!(*p))
{
for (p = part; *p && '/' != *p; p++)
;
if (part == p)
continue;
prnt = node;
if (!node)
break;
name.assign(part, p);
auto iter = node->childmap.find(name);
node = node->childmap.end() != iter ? iter->second : nullptr;
if (ancestor && node.get() == ancestor)
{
name.assign(""); // special case loop condition
break;
}
}
return std::make_tuple(prnt, name, node);
}
int make_node(const char *path, fuse_mode_t mode, fuse_dev_t dev, const char *data = nullptr)
{
auto lookup = lookup_node(path);
auto prnt = std::get<0>(lookup);
auto name = std::get<1>(lookup);
auto node = std::get<2>(lookup);
if (!prnt)
return -ENOENT;
if (node)
return -EEXIST;
fuse_context *context = fuse_get_context();
node = std::make_shared<node_t>(++_ino, mode, context->uid, context->gid, dev);
if (data)
{
node->resize(std::strlen(data), false);
std::memcpy(node->data.data(), data, node->data.size());
}
prnt->childmap[name] = node;
prnt->stat.st_ctim = prnt->stat.st_mtim = node->stat.st_ctim;
return 0;
}
int remove_node(const char *path, bool dir)
{
auto lookup = lookup_node(path);
auto prnt = std::get<0>(lookup);
auto name = std::get<1>(lookup);
auto node = std::get<2>(lookup);
if (!node)
return -ENOENT;
if (!dir && S_IFDIR == (node->stat.st_mode & S_IFMT))
return -EISDIR;
if (dir && S_IFDIR != (node->stat.st_mode & S_IFMT))
return -ENOTDIR;
if (0 < node->childmap.size())
return -ENOTEMPTY;
node->stat.st_nlink--;
prnt->childmap.erase(name);
node->stat.st_ctim = prnt->stat.st_ctim = prnt->stat.st_mtim = now();
return 0;
}
int open_node(const char *path, bool dir, struct fuse_file_info *fi)
{
auto node = std::get<2>(lookup_node(path));
if (!node)
return -ENOENT;
if (!dir && S_IFDIR == (node->stat.st_mode & S_IFMT))
return -EISDIR;
if (dir && S_IFDIR != (node->stat.st_mode & S_IFMT))
return -ENOTDIR;
// A file descriptor is a raw pointer to a shared_ptr.
// This has the effect of incrementing the shared_ptr
// refcount, thus keeping an open node around even
// if the node is unlinked.
fi->fh = (uint64_t)(uintptr_t)new std::shared_ptr<node_t>(node);
return 0;
}
int close_node(struct fuse_file_info *fi)
{
delete (std::shared_ptr<node_t> *)(uintptr_t)fi->fh;
return 0;
}
std::shared_ptr<node_t> get_node(const char *path, struct fuse_file_info *fi = nullptr)
{
if (!fi)
return std::get<2>(lookup_node(path));
else
return *(std::shared_ptr<node_t> *)(uintptr_t)fi->fh;
}
private:
std::mutex _mutex;
fuse_ino_t _ino;
std::shared_ptr<node_t> _root;
};
int main(int argc, char *argv[])
{
return memfs().main(argc, argv);
}

View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memfs-fuse3", "memfs-fuse3.vcxproj", "{CF538F42-C714-4653-B351-E72FD7B0B217}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x64.ActiveCfg = Debug|x64
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x64.Build.0 = Debug|x64
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x86.ActiveCfg = Debug|Win32
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x86.Build.0 = Debug|Win32
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x64.ActiveCfg = Release|x64
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x64.Build.0 = Release|x64
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x86.ActiveCfg = Release|Win32
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CF538F42-C714-4653-B351-E72FD7B0B217}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>memfsfuse3</RootNamespace>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4018</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4018</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4018</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4018</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="compat.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="memfs-fuse3.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="compat.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="memfs-fuse3.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -70,6 +70,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
#define MEMFS_EA #define MEMFS_EA
/* /*
* Define the MEMFS_WSL macro to include WSLinux support.
*/
#define MEMFS_WSL
/*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only. * a check for the Write buffer to ensure that it is read-only.
* *
@ -1047,8 +1052,8 @@ static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PVOID ExtraBuffer, ULONG ExtraLength, BOOLEAN ExtraBufferIsReparsePoint,
#endif #endif
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo) PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
{ {
@ -1129,15 +1134,43 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize); memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize);
} }
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
if (0 != Ea) if (0 != ExtraBuffer)
{ {
Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength); #if defined(MEMFS_EA)
if (!NT_SUCCESS(Result)) if (!ExtraBufferIsReparsePoint)
{ {
MemfsFileNodeDelete(FileNode); Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode,
return Result; (PFILE_FULL_EA_INFORMATION)ExtraBuffer, ExtraLength);
if (!NT_SUCCESS(Result))
{
MemfsFileNodeDelete(FileNode);
return Result;
}
} }
#endif
#if defined(MEMFS_WSL)
if (ExtraBufferIsReparsePoint)
{
#if defined(MEMFS_REPARSE_POINTS)
FileNode->ReparseDataSize = ExtraLength;
FileNode->ReparseData = malloc(ExtraLength);
if (0 == FileNode->ReparseData && 0 != ExtraLength)
{
MemfsFileNodeDelete(FileNode);
return STATUS_INSUFFICIENT_RESOURCES;
}
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
FileNode->FileInfo.ReparseTag = *(PULONG)ExtraBuffer;
/* the first field in a reparse buffer is the reparse tag */
memcpy(FileNode->ReparseData, ExtraBuffer, ExtraLength);
#else
MemfsFileNodeDelete(FileNode);
return STATUS_INVALID_PARAMETER;
#endif
}
#endif
} }
#endif #endif
@ -2189,7 +2222,7 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
GetVolumeInfo, GetVolumeInfo,
SetVolumeLabel, SetVolumeLabel,
GetSecurityByName, GetSecurityByName,
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
0, 0,
#else #else
Create, Create,
@ -2240,8 +2273,10 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
0, 0,
#endif #endif
0, 0,
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
Create, Create,
#endif
#if defined(MEMFS_EA)
Overwrite, Overwrite,
GetEa, GetEa,
SetEa SetEa
@ -2347,6 +2382,9 @@ NTSTATUS MemfsCreateFunnel(
#endif #endif
#if defined(MEMFS_EA) #if defined(MEMFS_EA)
VolumeParams.ExtendedAttributes = 1; VolumeParams.ExtendedAttributes = 1;
#endif
#if defined(MEMFS_WSL)
VolumeParams.WslFeatures = 1;
#endif #endif
VolumeParams.AllowOpenInKernelMode = 1; VolumeParams.AllowOpenInKernelMode = 1;
if (0 != VolumePrefix) if (0 != VolumePrefix)

View File

@ -3,3 +3,6 @@ build
*.suo *.suo
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.VC.db
*.VC.opendb
.vs

View File

@ -22,32 +22,32 @@
<ProjectGuid>{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}</ProjectGuid> <ProjectGuid>{E8A4060D-E6A4-42CC-9BCA-DC82E6EDB2C5}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>passthroughcpp</RootNamespace> <RootNamespace>passthroughcpp</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>

View File

@ -4,3 +4,6 @@ build
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.csproj.user *.csproj.user
*.VC.db
*.VC.opendb
.vs

View File

@ -3,5 +3,8 @@ build
*.suo *.suo
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.VC.db
*.VC.opendb
.vs
*.exe *.exe
*.install *.install

View File

@ -22,32 +22,32 @@
<ProjectGuid>{C753851C-142F-4AAD-B2F7-CBF905C2A600}</ProjectGuid> <ProjectGuid>{C753851C-142F-4AAD-B2F7-CBF905C2A600}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>passthroughfuse</RootNamespace> <RootNamespace>passthroughfuse</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>

View File

@ -3,5 +3,8 @@ build
*.suo *.suo
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.VC.db
*.VC.opendb
.vs
*.exe *.exe
*.install *.install

View File

@ -22,32 +22,32 @@
<ProjectGuid>{5E99498C-D30C-48EF-A04A-7977C0305FAC}</ProjectGuid> <ProjectGuid>{5E99498C-D30C-48EF-A04A-7977C0305FAC}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>passthroughfuse3</RootNamespace> <RootNamespace>passthroughfuse3</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>

View File

@ -3,3 +3,6 @@ build
*.suo *.suo
*.vcproj.* *.vcproj.*
*.vcxproj.user *.vcxproj.user
*.VC.db
*.VC.opendb
.vs

View File

@ -25,32 +25,32 @@
<ProjectGuid>{9E0E5997-7316-4818-A130-00B3AF1AD354}</ProjectGuid> <ProjectGuid>{9E0E5997-7316-4818-A130-00B3AF1AD354}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>passthrough</RootNamespace> <RootNamespace>passthrough</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>

Binary file not shown.

View File

@ -0,0 +1,112 @@
/**
* @file launcher-ptrans-test.c
*
* @copyright 2015-2019 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 <winfsp/launch.h>
#include <tlib/testsuite.h>
#include "winfsp-tests.h"
#include <launcher/ptrans.c>
static void launcher_ptrans_test(void)
{
PWSTR ipaths[] =
{
L"", 0,
L"\\foo\\bar", 0,
L"", L"",
L"\\foo\\bar", L"",
L"\\foo\\bar", L"/",
L"\\foo\\bar", L"/_",
L"\\foo\\bar", L"/_1",
L"\\foo\\bar", L"\\_",
L"\\foo\\bar", L"\\_A",
L"\\foo\\bar", L"/a",
L"\\foo\\bar", L"/b",
L"\\foo\\bar", L"/c",
L"\\foo\\bar", L"/d",
L"\\foo\\bar", L"/a:b",
L"\\foo\\bar", L"/a:b&c!d",
L"\\foo\\bar", L"/b:a",
L"\\foo\\bar", L"/d!c&b:a",
L"\\foo\\bar", L"/a:_",
L"\\foo\\bar", L"/b:_",
L"\\foo\\bar", L"/c:_",
L"\\foo\\bar\\baz", L"/b:_",
L"\\foo\\bar\\baz\\bag", L"/b:_",
L"\\foo\\bar\\baz", L"/b:/_",
L"\\foo\\bar\\baz\\bag", L"/b:/_",
L"\\foo\\bar\\baz\\bag", L"/a:_:b:_",
L"\\foo\\bar\\baz\\bag", L"/_:_",
};
PWSTR opaths[] =
{
L"",
L"\\foo\\bar",
L"",
L"",
L"",
L"/foo/bar",
L"/foo/bar",
L"\\\\foo\\\\bar",
L"\\\\foo\\\\bar",
L"foo",
L"bar",
L"",
L"",
L"foo:bar",
L"foo:bar&!",
L"bar:foo",
L"!&bar:foo",
L"foo:bar",
L"bar:",
L":",
L"bar:baz",
L"bar:baz/bag",
L"bar:/baz",
L"bar:/baz/bag",
L"foo:bar/baz/bag:bar:baz/bag",
L"/foo/bar/baz/bag:/foo/bar/baz/bag",
};
for (size_t i = 0; sizeof ipaths / (sizeof ipaths[0] * 2) > i; i++)
{
WCHAR Buf[1024];
ULONG Length;
PWSTR Dest;
Length = (ULONG)(UINT_PTR)PathTransform(0, ipaths[2 * i + 0], ipaths[2 * i + 1]);
ASSERT(Length == wcslen(opaths[i]) * sizeof(WCHAR));
Dest = PathTransform(Buf, ipaths[2 * i + 0], ipaths[2 * i + 1]);
*Dest = L'\0';
ASSERT(Dest == Buf + wcslen(opaths[i]));
ASSERT(0 == wcscmp(Buf, opaths[i]));
}
}
void launcher_ptrans_tests(void)
{
if (OptExternal)
return;
TEST_OPT(launcher_ptrans_test);
}

View File

@ -319,6 +319,15 @@ void mount_preflight_dotest(PWSTR DeviceName)
MountPoint[2] = L'\0'; MountPoint[2] = L'\0';
GetTestDirectory(DirBuf); GetTestDirectory(DirBuf);
/*
* Mount points starting with \\?\X: or \\.\X: are now considered MountManager mountpoints.
* So skip the \\?\ prefix to avoid this problem.
*/
if (L'\\' == DirBuf[0] &&
L'\\' == DirBuf[1] &&
(L'?' == DirBuf[2] || L'.' == DirBuf[2]) &&
L'\\' == DirBuf[3])
memmove(DirBuf, DirBuf + 4, (wcslen(DirBuf + 4) + 1) * sizeof(WCHAR));
Drives = GetLogicalDrives(); Drives = GetLogicalDrives();
ASSERT(0 != Drives); ASSERT(0 != Drives);

Some files were not shown because too many files have changed in this diff Show More