Compare commits

..

107 Commits
v1.12 ... v2.0

Author SHA1 Message Date
5c03dd11ee changelog: version: 2023 2023-03-16 10:43:13 +00:00
1f37e5a81a build: version: 2023 2023-03-16 10:43:00 +00:00
db319bc3c1 sys,dll: mount improvements
- sys: FspFsvolFileSystemControl: FSCTL_IS_VOLUME_MOUNTED
- dll: mount: Transact0, FspMountNotifyShellDriveChange
2023-02-24 12:02:03 +00:00
c04e3d9534 doc: update FAQ 2023-02-23 13:50:11 +00:00
1912814d79 changelog: v2.0RC1 2023-02-23 13:29:10 +00:00
97c075e744 sys: FspFsvolQueryDirectoryCopy: add missing continue
A single line change in FspFsvolQueryDirectoryCopy fixes GitHub issue #475.
This commit also includes a test for detecting duplicate directory entries.
Credit for the investigation and reproduction of this issue goes to GitHub
user @hach-que.
2023-02-16 17:07:59 +00:00
874a223bcc build: version: 2023 RC1 2023-02-07 20:55:49 +00:00
901a98e118 tools: make-release.ps1: automate submissions to hardware dashboard 2023-02-07 20:54:05 +00:00
0ab4300738 github: workflows: avm: update files 2023-02-02 12:20:34 +00:00
52e6aa97b5 build: sys: pacify hardware center validation
Infverif /k no longer likes "undecorated" [DefaultInstall] sections and
instead it wants them "architecture decorated". For example,
[DefaultInstall.ntarm64]. So play along to have our driver signed.

For more information see:
https://learn.microsoft.com/en-us/windows-hardware/drivers/develop/creating-a-primitive-driver
2023-02-01 22:50:35 +00:00
a7d82d5f8d changelog: v2.0B2 update 2023-02-01 17:55:14 +00:00
3aadaee511 dll: FspFileSystemStopServiceIfNecessary 2023-02-01 17:42:11 +00:00
da3a8aa229 Merge pull request #478 from zeho11/patch-1
tst: passthrough-fuse: fix UNC path mount
2023-02-01 11:01:13 +00:00
1f0fd4c280 Update 2023-01-31 19:13:10 +08:00
6da92f0b54 tools: make-release: add nuget support 2023-01-09 23:04:03 +00:00
4f5f1dd350 build: version: bump to v2.0B2 2023-01-09 22:27:44 +00:00
ba5d52e9a5 dll: FspFileSystemStartDispatcher:
Send a Transact0 to inform the FSD that the dispatcher is almost ready.
2023-01-09 15:45:11 +00:00
d626fb9563 sys: FspReleaseForModWrite
In some rare cases and under load the mapped page writer's TopLevelIrp
may be trashed by some outside component (observed on Windows 10 1909).

For this reason remove an assertion that could trigger in debug builds.
2023-01-09 15:30:42 +00:00
69cc1820e1 tst: passthrough-fuse3: fix UNC path mount 2022-12-19 09:22:43 +08:00
c06141c8c8 tst: passthrough-fuse: fix UNC path mount 2022-12-19 09:22:16 +08:00
760c2acded Merge pull request #476 from zeho11/patch-1
dll: fuse: correct error handling when name exceeds limit
2022-12-16 22:29:37 +00:00
671efe625a Update 2022-12-15 20:49:01 +09:00
a59b32b1ee tst: winfsp-tests: add multibyte checks to querydir_namelen_test 2022-12-15 19:17:22 +09:00
22d81846df tst: passthrough-fuse3: multibyte support 2022-12-15 19:16:19 +09:00
8c9b8362b4 tst: passthrough-fuse: multibyte support 2022-12-15 19:14:44 +09:00
e92eb023fe Merge branch 'release/1.12' 2022-12-12 11:53:20 +00:00
e550e261f0 dll: fuse: correct error handling when name exceeds limit
Related to b62e1e920b
2022-12-12 12:08:48 +09:00
46054c03fe Merge pull request #474 from zeho11/patch-1
dll: fuse: change name limit to 255 chars
2022-12-08 16:02:38 +00:00
db07b24342 Update 2022-12-08 18:02:19 +09:00
cb81e81985 Update fuse_intf.c 2022-12-07 15:17:59 +09:00
b62e1e920b dll: fuse: change name limit to 255 chars
Fixes #191
Fixes #455
2022-12-07 14:39:36 +09:00
c61679a35d tools: build.bat: make cab file from unsigned drivers 2022-12-05 13:06:18 +00:00
619e41a18e changelog: update for v1.12.22335 2022-12-01 11:09:58 +00:00
80fa156e7b tools: build.bat: remove SHA1 signatures 2022-12-01 10:59:48 +00:00
01d9fa1719 Merge branch 'pvt-dotnetcore' 2022-11-30 10:06:42 +00:00
6846508631 tools: build.bat,make-release.ps1: accommodate winfsp.net.nupkg 2022-11-29 21:13:13 +00:00
0488451c3d build: fix dotnet output paths 2022-11-29 15:49:09 +00:00
7c3292af81 tools: build.bat: dotnet build 2022-11-29 12:53:33 +00:00
3d2ba637e5 build: minimize changes in .csproj files 2022-11-28 16:52:21 +00:00
db72b57ca4 build: dotnet: remove Directory.Build.props 2022-11-28 14:04:51 +00:00
020157a9ae Merge branch 'dotnetcore' of https://github.com/Noire001/winfsp into Noire001-dotnetcore 2022-11-28 12:13:50 +00:00
d99cb2d7d1 build: dotnet: set PlatformTarget to AnyCPU 2022-11-23 22:47:50 +02:00
298261c4af tools: make-release.ps1: add build hashes 2022-11-23 16:21:08 +00:00
3c674a556d tools: make-release.ps1: update download link 2022-11-23 15:18:25 +00:00
f85fb49f49 changelog: update for v2.0B1 2022-11-23 14:32:31 +00:00
92084a56c6 build: dotnet: add missing NuGet properties 2022-11-20 20:05:10 +02:00
53f97c9841 build: dotnet: revert optional changes/deletions 2022-11-20 19:39:06 +02:00
2770eca1bf tools: use dotnet build in VS2015 CI 2022-11-20 15:10:50 +02:00
2945971ba9 build: memfs-dotnet: migrate to .NET SDK 2022-11-19 21:01:44 +02:00
0a39ef60bd Update Contributors.asciidoc 2022-11-19 21:01:44 +02:00
e1faf1351e build: dotnet: generate NuGet package on build 2022-11-19 21:01:44 +02:00
7333451eac build: installer: update assembly location 2022-11-19 21:01:24 +02:00
c178db127c build: dotnet: migrate to .NET SDK 2022-11-19 20:57:50 +02:00
9747af22e8 changelog: update for v1.12 (2022.2) 2022-10-18 12:21:23 +01:00
ef9b7e22c6 Merge branch 'master' into pvt-sxs 2022-10-12 16:57:59 +01:00
fd27c470b0 Merge branch 'master' into pvt-sxs 2022-10-12 16:36:22 +01:00
c187209159 installer: check windows version 7 or higher 2022-10-07 14:09:19 +01:00
a2e92207c5 Merge branch 'master' into pvt-sxs 2022-10-07 12:10:20 +01:00
4f5ad93f00 Merge branch 'master' into pvt-sxs 2022-10-04 15:44:49 +01:00
b47c42877a Merge branch 'master' into pvt-sxs 2022-10-04 13:45:19 +01:00
d1fc5e5d0f Merge branch 'pvt-vpb2' into pvt-sxs-vpb 2022-10-03 15:10:06 +01:00
c4ecd15c0a Merge branch 'master' into pvt-sxs 2022-10-02 17:49:47 +01:00
91d7f3b673 sys: FspSiloInitialize: always initialize FspSiloList and Mutex 2022-10-01 21:08:01 +01:00
63e23c2039 fsptool: load command 2022-10-01 14:55:30 +01:00
4d1594b1cf sys: silo: ensure FspSiloListMutex in critical region 2022-10-01 14:44:17 +01:00
0eb6912296 sys: FspSiloEnumerate, FspDriverFinalizeDevicesForUnload 2022-10-01 10:47:18 +01:00
c237a55951 Merge branch 'master' into pvt-sxs 2022-09-29 17:00:10 +01:00
98d68c4007 Merge branch 'master' into pvt-sxs 2022-09-26 17:52:29 +01:00
e8cec5dfc1 Merge branch 'master' into pvt-sxs 2022-09-26 17:42:30 +01:00
9a27a3225b Merge branch 'master' into pvt-sxs 2022-09-16 12:32:59 +01:00
d44cb54bd5 tools: run-tests: disable exec tests for mountmgr 2022-09-14 17:16:56 +01:00
d1f863e9ac tools: run-tests: disable exec tests for mountmgr 2022-09-14 12:23:13 +01:00
ccdbc9daf9 tools: diag.bat: SxS support 2022-09-12 12:41:09 +01:00
1723179430 dll: FspFsctlStartService: fix bug in non-SxS mode 2022-09-10 17:14:19 +01:00
8e0f5b457c tools,appveyor: remove sxsident 2022-09-10 16:24:15 +01:00
2fc2c237d3 dll: FspFsctlEnumServices 2022-09-10 16:23:14 +01:00
b99fb9a5cb dll: FspFsctlRegister: sxs-ize driver display name 2022-09-09 23:57:44 +01:00
538fee8e54 installer: CustomActions: InstallJunctions 2022-09-09 22:59:14 +01:00
925fa4b6e4 installer: CustomActions: DeferredAction: minor fix 2022-09-09 14:35:17 +01:00
b179c7a933 tools: sxsident.bat 2022-09-08 17:55:57 +01:00
b25e116f08 tools: sxsident.bat 2022-09-08 16:00:22 +01:00
422c369b15 tools: sxsident.bat 2022-09-08 15:52:25 +01:00
d450683e2e installer: SxS: WIP 2022-09-07 21:59:42 +01:00
ad1aa156dc installer: SxS: WIP 2022-09-07 20:18:54 +01:00
aa012db099 installer: SxS: WIP 2022-09-07 17:37:25 +01:00
b08f60bfbd installer: SxS: WIP 2022-09-07 16:19:48 +01:00
a9b3cef253 installer: SxS: WIP 2022-09-07 15:31:18 +01:00
b43d1f5502 dll: FspFsctlUnregister: do FspFsctlStopService prior to unregister 2022-09-07 14:20:20 +01:00
de9112f6e6 installer: SxS: WIP 2022-09-06 18:42:39 +01:00
329b14d838 build: version: bump to v2.0 (2023) 2022-09-06 12:09:54 +01:00
7009324e7f installer: SxS: WIP 2022-09-06 12:08:09 +01:00
f4ae097722 installer: SxS: WIP 2022-09-05 17:28:31 +01:00
50be07e8ac installer: SxS: WIP 2022-09-05 17:23:49 +01:00
2dd054087c installer: SxS: fix whitespace 2022-09-05 16:46:10 +01:00
7f6608cf7d installer: SxS: WIP 2022-09-05 16:40:06 +01:00
39e9d8156b installer: SxS: WIP 2022-09-05 13:34:25 +01:00
90acd19014 sys: FspDeviceDelete: remove DBG code
FspDeviceDelete was recently changed and its DBG code is no longer valid.
2022-09-04 16:58:38 +01:00
9154ec784d installer: CustomActions: InstanceID 2022-09-04 15:55:47 +01:00
0b3ce52958 Merge branch 'master' into pvt-sxs 2022-09-01 14:42:27 +01:00
adeed2b79d fsptool: ver, unload commands 2022-08-21 07:59:28 +01:00
5dda5903a8 tst: winfsp-tests: disable load_unload_test 2022-08-21 07:25:25 +01:00
a7bc306b2d dll: FspSxsAppendSuffix 2022-08-20 11:58:00 +01:00
7e59c2e5a6 dll: FspFsctlFixServiceSecurity: deny SERVICE_STOP to Everyone
Although the FSD can now be unloaded, this can only be done safely via
the new FSP_FSCTL_UNLOAD control code. For this reason we disable the
ability to stop the FSD via the Service Manager.
2022-08-19 19:43:48 +01:00
9670caa3fe sys,dll: FSP_FSCTL_UNLOAD 2022-08-18 11:05:45 +01:00
005d3e4fb0 sys: FspUnload, FspSxsIdent 2022-08-05 17:41:12 +01:00
62a6bbab66 dll: FspSxsSuffix 2022-08-03 17:29:45 +01:00
40ba537dc2 dll: FspSxsIdent 2022-08-03 16:33:13 +01:00
66 changed files with 3539 additions and 468 deletions

View File

@ -11,8 +11,8 @@ jobs:
- uses: billziss-gh/avm@v1
with:
files: |
https://github.com/winfsp/winfsp/releases/download/v1.6/winfsp-1.6.20027.msi
https://github.com/winfsp/winfsp/releases/download/v1.7/winfsp-1.7.20172.msi
https://github.com/winfsp/winfsp/releases/download/v1.8/winfsp-1.8.20304.msi
https://github.com/winfsp/winfsp/releases/download/v1.9/winfsp-1.9.21096.msi
https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
https://github.com/winfsp/winfsp/releases/download/v1.11/winfsp-1.11.22176.msi
https://github.com/winfsp/winfsp/releases/download/v1.12/winfsp-1.12.22301.msi
https://github.com/winfsp/winfsp/releases/download/v1.12.22339/winfsp-1.12.22339.msi
https://github.com/winfsp/winfsp/releases/download/v2.0B2/winfsp-2.0.23033.msi

View File

@ -1,6 +1,135 @@
# Changelog
## v2.0 (2023)
This release is a major version change for WinFsp (from 1.x to 2.x). There are no backwards incompatible API changes in this release, but nevertheless enough things change that warrant a version change.
The major new feature of this release is that it allows uninstallation and reinstallation of WinFsp **without reboot**. Going forward installers named `winfsp-2.x.y.msi` can be uninstalled and reinstalled without reboot. Furthermore a later version `winfsp-2.x.y.msi` installer can be used to upgrade over an earlier version `winfsp-2.x.y.msi` installer. However note that a `winfsp-2.x.y.msi` installer cannot be used to upgrade over a legacy `winfsp-1.x.y.msi` installer; you will still need to uninstall the old `winfsp-1.x.y.msi` installer, potentially reboot and then install the new `winfsp-2.x.y.msi` installer.
Changes visible to file system developers are listed below:
- WinFsp executable files are now installed by default in the directory `C:\Program Files (x86)\WinFsp\SxS\sxs.<InstanceID>\bin`. The previous directory `C:\Program Files (x86)\WinFsp\bin` is now a junction that points to the above directory.
- The WinFsp driver name is no longer `winfsp`, but rather a name such as `winfsp+<InstanceID>`. This means that managing the driver using the `sc.exe` utility is no longer as easy.
- The `fsptool` utility has been updated with new commands `lsdrv`, `load`, `unload` and `ver`. The `lsdrv`, `load` and `unload` commands can be used to manage the driver from the command line. This is rarely necessary, but may be useful for troubleshooting purposes.
- Prior to this release the WinFsp driver would never unmount a file system volume unless the user mode file system requested the unmount. From this release onward it is possible for the WinFsp driver to unmount a file system volume, without a user mode file system request. This is to allow for the driver to be unloaded.
A new operation `DispatcherStopped` has been added to `FSP_FILE_SYSTEM_INTERFACE`, which is sent after the file system volume has been unmounted and the file system dispatcher has been stopped. This can happen because of a user mode file system request via `FspFileSystemStopDispatcher` or because of driver unload. The `DispatcherStopped` operation includes a `Normally` parameter, which is `TRUE` for normal file system shutdown via `FspFileSystemStopDispatcher` and `FALSE` otherwise.
Native file systems that use the `FspService` infrastructure can use the `FspFileSystemStopServiceIfNecessary` API to handle the `DispatcherStopped` operation (see the MEMFS and NTPTFS samples). FUSE file systems get this functionality for free. .NET file systems that use the `Service` class infrastructure also get this functionality for free.
- WinFsp now offers a .NET library that targets .NET Framework 3.5 (as before) and one that targets .NET Standard 2.0. This is due to work by @Noire001 in PR #451.
- There is now a winfsp.net nuget package at https://www.nuget.org/packages/winfsp.net
- FUSE now supports path components up to 255 characters long (previously it was 255 bytes). This is due to work by @zeho11 in PR #474.
- The FUSE passthrough file systems have been updated to support long paths. This is also due to work by @zeho11.
- In some rare circumstances WinFsp file systems could report duplicate directory entries. This problem has been fixed. (GitHub issue #475.)
- The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
## v2.0RC1 (2023 RC1)
This release is a major version change for WinFsp (from 1.x to 2.x). There are no backwards incompatible API changes in this release, but nevertheless enough things change that warrant a version change.
The major new feature of this release is that it allows uninstallation and reinstallation of WinFsp **without reboot**. Going forward installers named `winfsp-2.x.y.msi` can be uninstalled and reinstalled without reboot. Furthermore a later version `winfsp-2.x.y.msi` installer can be used to upgrade over an earlier version `winfsp-2.x.y.msi` installer. However note that a `winfsp-2.x.y.msi` installer cannot be used to upgrade over a legacy `winfsp-1.x.y.msi` installer; you will still need to uninstall the old `winfsp-1.x.y.msi` installer, potentially reboot and then install the new `winfsp-2.x.y.msi` installer.
Changes visible to file system developers are listed below:
- WinFsp executable files are now installed by default in the directory `C:\Program Files (x86)\WinFsp\SxS\sxs.<InstanceID>\bin`. The previous directory `C:\Program Files (x86)\WinFsp\bin` is now a junction that points to the above directory.
- The WinFsp driver name is no longer `winfsp`, but rather a name such as `winfsp+<InstanceID>`. This means that managing the driver using the `sc.exe` utility is no longer as easy.
- The `fsptool` utility has been updated with new commands `lsdrv`, `load`, `unload` and `ver`. The `lsdrv`, `load` and `unload` commands can be used to manage the driver from the command line. This is rarely necessary, but may be useful for troubleshooting purposes.
- Prior to this release the WinFsp driver would never unmount a file system volume unless the user mode file system requested the unmount. From this release onward it is possible for the WinFsp driver to unmount a file system volume, without a user mode file system request. This is to allow for the driver to be unloaded.
A new operation `DispatcherStopped` has been added to `FSP_FILE_SYSTEM_INTERFACE`, which is sent after the file system volume has been unmounted and the file system dispatcher has been stopped. This can happen because of a user mode file system request via `FspFileSystemStopDispatcher` or because of driver unload. The `DispatcherStopped` operation includes a `Normally` parameter, which is `TRUE` for normal file system shutdown via `FspFileSystemStopDispatcher` and `FALSE` otherwise.
Native file systems that use the `FspService` infrastructure can use the `FspFileSystemStopServiceIfNecessary` API to handle the `DispatcherStopped` operation (see the MEMFS and NTPTFS samples). FUSE file systems get this functionality for free. .NET file systems that use the `Service` class infrastructure also get this functionality for free.
- WinFsp now offers a .NET library that targets .NET Framework 3.5 (as before) and one that targets .NET Standard 2.0. This is due to work by @Noire001 in PR #451.
- There is now a winfsp.net nuget package at https://www.nuget.org/packages/winfsp.net
- FUSE now supports path components up to 255 characters long (previously it was 255 bytes). This is due to work by @zeho11 in PR #474.
- The FUSE passthrough file systems have been updated to support long paths. This is also due to work by @zeho11.
- In some rare circumstances WinFsp file systems could report duplicate directory entries. This problem has been fixed. (GitHub issue #475.)
- The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
## v2.0B2 (2023 Beta2)
This release is a major version change for WinFsp (from 1.x to 2.x). There are no backwards incompatible API changes in this release, but nevertheless enough things change that warrant a version change.
The major new feature of this release is that it allows uninstallation and reinstallation of WinFsp **without reboot**. Going forward installers named `winfsp-2.x.y.msi` can be uninstalled and reinstalled without reboot. Furthermore a later version `winfsp-2.x.y.msi` installer can be used to upgrade over an earlier version `winfsp-2.x.y.msi` installer. However note that a `winfsp-2.x.y.msi` installer cannot be used to upgrade over a "legacy" `winfsp-1.x.y.msi` installer; you will still need to uninstall the "old" `winfsp-1.x.y.msi` installer, potentially reboot and then install the "new" `winfsp-2.x.y.msi` installer.
Changes visible to file system developers are listed below:
- WinFsp executable files are now installed by default in the directory `C:\Program Files (x86)\WinFsp\SxS\sxs.<InstanceID>\bin`. The previous directory `C:\Program Files (x86)\WinFsp\bin` is now a junction that points to the above directory.
- The WinFsp driver name is no longer `winfsp`, but rather a name such as `winfsp+<InstanceID>`. This means that managing the driver using the `sc.exe` utility is no longer as easy.
- The `fsptool` utility has been updated with new commands `lsdrv`, `load`, `unload` and `ver`. The `lsdrv`, `load` and `unload` commands can be used to manage the driver from the command line. This is rarely necessary, but may be useful for troubleshooting purposes.
- Prior to this release the WinFsp driver would never unmount a file system volume unless the user mode file system requested the unmount. From this release onward it is possible for the WinFsp driver to unmount a file system volume, without a user mode file system request. This is to allow for the driver to be unloaded.
A new operation `DispatcherStopped` has been added to `FSP_FILE_SYSTEM_INTERFACE`, which is sent after the file system volume has been unmounted and the file system dispatcher has been stopped. This can happen because of a user mode file system request via `FspFileSystemStopDispatcher` or because of driver unload. The `DispatcherStopped` operation includes a `Normally` parameter, which is `TRUE` for normal file system shutdown via `FspFileSystemStopDispatcher` and `FALSE` otherwise.
Native file systems that use the `FspService` infrastructure can use the `FspFileSystemStopServiceIfNecessary` API to handle the `DispatcherStopped` operation (see the MEMFS and NTPTFS samples). FUSE file systems get this functionality for free. .NET file systems that use the `Service` class infrastructure also get this functionality for free.
- WinFsp now offers a .NET library that targets .NET Framework 3.5 (as before) and one that targets .NET Standard 2.0. This is due to work by @Noire001 in PR #451.
- FUSE now supports path components up to 255 characters long (previously it was 255 bytes). This is due to work by @zeho11 in PR #474.
- The FUSE passthrough file systems have been updated to support long paths. This is also due to work by @zeho11.
- The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
## v2.0B1 (2023 Beta1)
This release is a major version change for WinFsp (from 1.x to 2.x). There are no backwards incompatible API changes in this release, but nevertheless enough things change that warrant a version change.
The major new feature of this release is that it allows uninstallation and reinstallation of WinFsp **without reboot**. Going forward installers named `winfsp-2.x.y.msi` can be uninstalled and reinstalled without reboot. Furthermore a later version `winfsp-2.x.y.msi` installer can be used to upgrade over an earlier version `winfsp-2.x.y.msi` installer. However note that a `winfsp-2.x.y.msi` installer cannot be used to upgrade over a "legacy" `winfsp-1.x.y.msi` installer; you will still need to uninstall the "old" `winfsp-1.x.y.msi` installer, potentially reboot and then install the "new" `winfsp-2.x.y.msi` installer.
Some changes that may be visible to file system developers are listed below:
- WinFsp executable files are now installed by default in the directory `C:\Program Files (x86)\WinFsp\SxS\sxs.<InstanceID>\bin`. The previous directory `C:\Program Files (x86)\WinFsp\bin` is now a junction that points to the above directory.
- The WinFsp driver name is no longer `winfsp`, but rather a name such as `winfsp+<InstanceID>`. This means that managing the driver using the `sc.exe` utility is no longer as easy.
- The `fsptool` utility has been updated with new commands `lsdrv`, `load`, `unload` and `ver`. The `lsdrv`, `load` and `unload` commands can be used to manage the driver from the command line. This is rarely necessary, but may be useful for troubleshooting purposes.
- The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
## v1.12.22339 (2022.2 Update1)
*Note: This release (`v1.12.22339`) is the same as the previous release (`v1.12`) except that: (1) the kernel-mode drivers are now digitally signed only with the Microsoft Attestation signature, and that: (2) no release assets are digitally signed with SHA-1. (This change was necessary to fix a problem in older versions of Windows such as Windows 7.)*
- [NEW] WinFsp now supports mounting as directory using the Mount Manager. Use the syntax `\\.\C:\Path\To\Mount\Directory`.
- [NEW] A new registry setting `MountUseMountmgrFromFSD` has been added. See [WinFsp Registry Settings](https://github.com/winfsp/winfsp/wiki/WinFsp-Registry-Settings) for details.
- [FIX] A problem with Windows containers has been fixed. (GitHub issue #438.)
- [FIX] File systems can now be mounted as directories on ARM64. (GitHub issue #448.)
- [FIX] The passthrough file system now reports correct `IndexNumber`. (GitHub issue #325.)
- [BUILD] Product configuration for the relative paths to the File System Driver, Network Provider and EventLog is now possible via the file `build.version.props` located in `build\VStudio`.
## v1.12 (2022.2)
- [NEW] WinFsp now supports mounting as directory using the Mount Manager. Use the syntax `\\.\C:\Path\To\Mount\Directory`.

View File

@ -66,6 +66,7 @@ CONTRIBUTOR LIST
|Gal Hammer (Red Hat, https://www.redhat.com) |ghammer at redhat.com
|John Oberschelp |john at oberschelp.net
|John Tyner |jtyner at gmail.com
|Konstantinos Karakostas |noiredev at protonmail.com
|Paweł Wegner (Google LLC, https://google.com) |lemourin at google.com
|Pedro Frejo (Arpa System, https://arpasystem.com) |pedro.frejo at arpasystem.com
|Ronny Chan |ronny at ronnychan.ca
@ -73,4 +74,5 @@ CONTRIBUTOR LIST
|Santiago Ganis |sganis at gmail.com
|Tobias Urlaub |saibotu at outlook.de
|Victor Gao |victgm at outlook.com
|Zeho Huang |zeho11 at protonmail.com
|===

View File

@ -51,6 +51,11 @@ install:
$targets.Save("C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets")
Add-AppveyorMessage "Hack to make WDK 1903 work on VS2015"
}
# Install .NET SDK on VS2015 image
- ps: |
if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") {
& ([scriptblock]::Create((New-Object System.Net.WebClient).DownloadString('https://dot.net/v1/dotnet-install.ps1'))) -InstallDir "C:\dotnet"
}
# Submodules
- git submodule update --init --recursive
# Kernel and user mode dumps
@ -76,6 +81,9 @@ build_script:
# remove ARM64 project configurations to build in VS2015/VS2017
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" tools\gensrc\remove-build-arm64.bat
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" tools\gensrc\remove-build-arm64.bat
# remove .NET library from solution for VS2015 and use the .NET SDK instead
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" tools\gensrc\remove-build-dotnet.bat build\VStudio
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set PATH=C:\dotnet;%PATH%
# build winfsp
- tools\build.bat %CONFIGURATION%

View File

@ -18,9 +18,9 @@
<MyCompanyName>Navimatics LLC</MyCompanyName>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<MyCanonicalVersion>1.12</MyCanonicalVersion>
<MyCanonicalVersion>2.0</MyCanonicalVersion>
<MyProductVersion>2022.2</MyProductVersion>
<MyProductVersion>2023</MyProductVersion>
<MyProductStage>Gold</MyProductStage>
<MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert>

View File

@ -1,25 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(MSBuildProjectName).build\</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{94580219-CC8D-4FE5-A3BE-437B0B3481E1}</ProjectGuid>
<OutputType>Library</OutputType>
<ProjectName>winfsp.net</ProjectName>
<RootNamespace>Fsp</RootNamespace>
<AssemblyName>$(MyProductFileName)-msil</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<TargetFrameworks>netstandard2.0;net35</TargetFrameworks>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
@ -32,7 +36,6 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
@ -47,9 +50,6 @@
<PropertyGroup>
<AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
<Link>FileSystemBase+Const.cs</Link>
@ -70,29 +70,28 @@
<ItemGroup>
<None Include="winfsp.net.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="AfterBuild">
</Target>
-->
<Target Name="BeforeBuild">
<ItemGroup>
<AssemblyInfo Include="using System.Reflection%3b" />
<AssemblyInfo Include="[assembly: AssemblyProduct(&quot;$(MyProductName)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyTitle(&quot;$(MyDescription)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyCompany(&quot;$(MyCompanyName)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyCopyright(&quot;$(MyCopyright)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyVersion(&quot;$(MyAssemblyVersion)&quot;)]" />
<AssemblyInfo Include="[assembly: AssemblyFileVersion(&quot;$(MyVersion)&quot;)]" />
</ItemGroup>
<MakeDir Directories="$(IntermediateOutputPath)" />
<WriteLinesToFile File="$(IntermediateOutputPath)AssemblyInfo.cs" Lines="@(AssemblyInfo)" Overwrite="true" />
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
<FileWrites Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
</ItemGroup>
</Target>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.Win32.Registry">
<Version>5.0.0</Version>
</PackageReference>
<PackageReference Include="System.IO.FileSystem.AccessControl">
<Version>5.0.0</Version>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<AssemblyName>$(MyProductFileName)-msil</AssemblyName>
<AssemblyTitle>$(MyDescription)</AssemblyTitle>
<Product>$(MyProductName)</Product>
<Copyright>$(MyCopyright)</Copyright>
<AssemblyVersion>$(MyAssemblyVersion)</AssemblyVersion>
<FileVersion>$(MyVersion)</FileVersion>
<!-- NuGet metadata -->
<PackageId>$(MyProductFileName).net</PackageId>
<Version>$(MyVersion)</Version>
<Description>$(MyDescription)</Description>
<Authors>$(MyCopyright)</Authors>
<Company>$(MyCompanyName)</Company>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>exit /b 0
@ -110,4 +109,5 @@ for /f "delims=" %25%25l in ($(ProjectDir)winfsp.net.policy.config) do (
"$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.0A\Bin\al.exe" /product:"$(MyProductName)" /title:"$(MyDescription)" /company:"$(MyCompanyName)" /copyright:"$(MyCopyright)" /version:"$(MyAssemblyPolicyVersion)" /fileversion:"$(MyVersion)" /link:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config /out:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).dll /keyfile:$(ProjectDir)$(ProjectName).snk
</PostBuildEvent>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

View File

@ -21,10 +21,55 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <msiquery.h>
#include <wcautil.h>
#include <strutil.h>
static HINSTANCE DllInstance;
UINT __stdcall InstanceID(MSIHANDLE MsiHandle)
{
#if 0
WCHAR MessageBuf[64];
wsprintfW(MessageBuf, L"PID=%ld", GetCurrentProcessId());
MessageBoxW(0, MessageBuf, L"" __FUNCTION__ " Break", MB_OK);
#endif
HRESULT hr = S_OK;
UINT err = ERROR_SUCCESS;
SYSTEMTIME SystemTime;
WCHAR Result[32+1];
hr = WcaInitialize(MsiHandle, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized");
GetSystemTime(&SystemTime);
wsprintfW(Result, L"%04u%02u%02uT%02u%02u%02uZ",
SystemTime.wYear,
SystemTime.wMonth,
SystemTime.wDay,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond);
/*
* Sleep 1 second to ensure timestamp uniqueness.
*
* Note that this assumes that time is monotonic and users do not change time.
* Disable for now as it is assumed that the installation takes more than 1 second to complete.
*/
//Sleep(1000);
WcaSetProperty(L"" __FUNCTION__, Result);
LExit:
err = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(err);
}
UINT __stdcall ServiceRunning(MSIHANDLE MsiHandle)
{
#if 0
@ -44,7 +89,7 @@ UINT __stdcall ServiceRunning(MSIHANDLE MsiHandle)
hr = WcaInitialize(MsiHandle, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
WcaGetProperty(L"" __FUNCTION__, &ServiceName);
hr = WcaGetProperty(L"" __FUNCTION__, &ServiceName);
ExitOnFailure(hr, "Failed to get ServiceName");
WcaLog(LOGMSG_STANDARD, "Initialized: \"%S\"", ServiceName);
@ -70,12 +115,390 @@ LExit:
return WcaFinalize(err);
}
UINT __stdcall DeferredAction(MSIHANDLE MsiHandle)
{
#if 0
WCHAR MessageBuf[64];
wsprintfW(MessageBuf, L"PID=%ld", GetCurrentProcessId());
MessageBoxW(0, MessageBuf, L"" __FUNCTION__ " Break", MB_OK);
#endif
HRESULT hr = S_OK;
UINT err = ERROR_SUCCESS;
PWSTR CommandLine = 0;
PWSTR *Argv;
int Argc;
CHAR ProcName[64];
FARPROC Proc;
hr = WcaInitialize(MsiHandle, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
hr = WcaGetProperty(L"CustomActionData", &CommandLine);
ExitOnFailure(hr, "Failed to get CommandLine");
WcaLog(LOGMSG_STANDARD, "Initialized: \"%S\"", CommandLine);
Argv = CommandLineToArgvW(CommandLine, &Argc);
ExitOnNullWithLastError(Argv, hr, "Failed to CommandLineToArgvW");
if (0 < Argc)
{
if (0 == WideCharToMultiByte(CP_UTF8, 0, Argv[0], -1, ProcName, sizeof ProcName, 0, 0))
ExitWithLastError(hr, "Failed to WideCharToMultiByte");
Proc = GetProcAddress(DllInstance, ProcName);
ExitOnNullWithLastError(Proc, hr, "Failed to GetProcAddress");
err = ((HRESULT (*)(int, PWSTR *))Proc)(Argc, Argv);
ExitOnWin32Error(err, hr, "Failed to %s", ProcName);
}
else
{
hr = E_INVALIDARG;
ExitOnFailure(hr, "Failed to get arguments");
}
LExit:
LocalFree(Argv);
ReleaseStr(CommandLine);
err = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(err);
}
static DWORD MakeSymlink(PWSTR Symlink, PWSTR Target);
static DWORD MakeJunction(PWSTR Junction, PWSTR Target);
static DWORD CreateJunction(PWSTR Junction, PWSTR Target);
static DWORD RemoveFile(PWSTR FileName);
DWORD InstallSymlinks(int Argc, PWSTR *Argv)
{
/* usage: InstallSymlinks/InstallJunctions SourceDir TargetDir Name... */
DWORD Result;
BOOL Junctions;
PWSTR SourceDir, TargetDir;
WCHAR SourcePath[MAX_PATH], TargetPath[MAX_PATH];
int SourceDirLen, TargetDirLen, Len;
if (4 > Argc)
{
Result = ERROR_INVALID_PARAMETER;
goto exit;
}
Junctions = 0 == lstrcmpW(L"InstallJunctions", Argv[0]);
SourceDir = Argv[1];
TargetDir = Argv[2];
SourceDirLen = lstrlenW(SourceDir);
TargetDirLen = lstrlenW(TargetDir);
for (int Argi = 3; Argc > Argi; Argi++)
{
Len = lstrlenW(Argv[Argi]);
if (MAX_PATH < SourceDirLen + Len + 1 || MAX_PATH < TargetDirLen + Len + 1)
{
Result = ERROR_FILENAME_EXCED_RANGE;
goto exit;
}
memcpy(SourcePath, SourceDir, SourceDirLen * sizeof(WCHAR));
memcpy(SourcePath + SourceDirLen, Argv[Argi], Len * sizeof(WCHAR));
SourcePath[SourceDirLen + Len] = L'\0';
memcpy(TargetPath, TargetDir, TargetDirLen * sizeof(WCHAR));
memcpy(TargetPath + TargetDirLen, Argv[Argi], Len * sizeof(WCHAR));
TargetPath[TargetDirLen + Len] = L'\0';
if (!Junctions)
Result = MakeSymlink(SourcePath, TargetPath);
else
Result = MakeJunction(SourcePath, TargetPath);
#if 0
WCHAR MessageBuf[1024];
wsprintfW(MessageBuf, L"MakeSymlink(\"%s\", \"%s\") = %lu", SourcePath, TargetPath, Result);
MessageBoxW(0, MessageBuf, L"TRACE", MB_OK);
#endif
if (ERROR_SUCCESS != Result)
goto exit;
}
Result = ERROR_SUCCESS;
exit:
return Result;
}
DWORD InstallJunctions(int Argc, PWSTR *Argv)
{
return InstallSymlinks(Argc, Argv);
}
DWORD RemoveFiles(int Argc, PWSTR *Argv)
{
/* usage: RemoveFiles Dir Name... */
DWORD Result;
PWSTR Dir;
WCHAR Path[MAX_PATH];
int DirLen, Len;
if (3 > Argc)
{
Result = ERROR_INVALID_PARAMETER;
goto exit;
}
Dir = Argv[1];
DirLen = lstrlenW(Dir);
for (int Argi = 2; Argc > Argi; Argi++)
{
Len = lstrlenW(Argv[Argi]);
if (MAX_PATH < DirLen + Len + 1)
{
Result = ERROR_FILENAME_EXCED_RANGE;
goto exit;
}
memcpy(Path, Dir, DirLen * sizeof(WCHAR));
memcpy(Path + DirLen, Argv[Argi], Len * sizeof(WCHAR));
Path[DirLen + Len] = L'\0';
Result = RemoveFile(Path);
#if 0
WCHAR MessageBuf[1024];
wsprintfW(MessageBuf, L"RemoveFile(\"%s\") = %lu", Path, Result);
MessageBoxW(0, MessageBuf, L"TRACE", MB_OK);
#endif
if (ERROR_SUCCESS != Result)
goto exit;
}
Result = ERROR_SUCCESS;
exit:
return Result;
}
static DWORD MakeSymlink(PWSTR Symlink, PWSTR Target)
{
DWORD Result;
DWORD FileAttributes, Flags;
RemoveFile(Symlink);
FileAttributes = GetFileAttributesW(Target);
if (INVALID_FILE_ATTRIBUTES == FileAttributes)
{
Result = GetLastError();
goto exit;
}
Flags = 0 != (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
if (!CreateSymbolicLinkW(Symlink, Target, Flags))
{
Result = GetLastError();
RemoveFile(Symlink);
goto exit;
}
Result = ERROR_SUCCESS;
exit:
return Result;
}
static DWORD MakeJunction(PWSTR Junction, PWSTR Target)
{
DWORD Result;
DWORD FileAttributes;
RemoveFile(Junction);
FileAttributes = GetFileAttributesW(Target);
if (INVALID_FILE_ATTRIBUTES == FileAttributes)
{
Result = GetLastError();
goto exit;
}
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
Result = ERROR_DIRECTORY;
goto exit;
}
Result = CreateJunction(Junction, Target);
if (ERROR_SUCCESS != Result)
{
RemoveFile(Junction);
goto exit;
}
Result = ERROR_SUCCESS;
exit:
return Result;
}
static DWORD CreateJunction(PWSTR Junction, PWSTR Target)
{
/*
* The REPARSE_DATA_BUFFER definitions appear to be missing from the user mode headers.
*/
typedef struct _REPARSE_DATA_BUFFER
{
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union
{
struct
{
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct
{
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct
{
UCHAR DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
const LONG REPARSE_DATA_BUFFER_HEADER_SIZE =
FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer);
const DWORD FSCTL_SET_REPARSE_POINT = 0x000900a4;
DWORD Result;
HANDLE Handle = INVALID_HANDLE_VALUE;
USHORT TargetLength, ReparseDataLength;
PREPARSE_DATA_BUFFER ReparseData = 0;
PWSTR PathBuffer;
DWORD Bytes;
if (!(
((L'A' <= Target[0] && Target[0] <= L'Z') || (L'a' <= Target[0] && Target[0] <= L'z')) &&
L':' == Target[1]
))
{
Result = ERROR_INVALID_NAME;
goto exit;
}
Handle = CreateFileW(Junction,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS,
0);
if (INVALID_HANDLE_VALUE == Handle)
{
Result = GetLastError();
goto exit;
}
TargetLength = (USHORT)lstrlenW(Target) * sizeof(WCHAR);
ReparseDataLength = (USHORT)(
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer)) +
4 * sizeof(WCHAR) + 2 * (TargetLength + sizeof(WCHAR));
ReparseData = (PREPARSE_DATA_BUFFER)
HeapAlloc(GetProcessHeap(), 0, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength);
if (0 == ReparseData)
{
Result = ERROR_NO_SYSTEM_RESOURCES;
goto exit;
}
ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
ReparseData->ReparseDataLength = ReparseDataLength;
ReparseData->Reserved = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameOffset = 0;
ReparseData->MountPointReparseBuffer.SubstituteNameLength =
4 * sizeof(WCHAR) + TargetLength;
ReparseData->MountPointReparseBuffer.PrintNameOffset =
ReparseData->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
ReparseData->MountPointReparseBuffer.PrintNameLength =
TargetLength;
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer;
PathBuffer[0] = L'\\';
PathBuffer[1] = L'?';
PathBuffer[2] = L'?';
PathBuffer[3] = L'\\';
memcpy(PathBuffer + 4, Target, TargetLength);
PathBuffer[4 + TargetLength / sizeof(WCHAR)] = L'\0';
PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer +
(ReparseData->MountPointReparseBuffer.PrintNameOffset) / sizeof(WCHAR);
memcpy(PathBuffer, Target, TargetLength);
PathBuffer[TargetLength / sizeof(WCHAR)] = L'\0';
if (!DeviceIoControl(Handle, FSCTL_SET_REPARSE_POINT,
ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength,
0, 0,
&Bytes, 0))
{
Result = GetLastError();
goto exit;
}
Result = ERROR_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != Handle)
CloseHandle(Handle);
if (0 != ReparseData)
HeapFree(GetProcessHeap(), 0, ReparseData);
return Result;
}
static DWORD RemoveFile(PWSTR FileName)
{
DWORD Result;
if (!RemoveDirectoryW(FileName))
{
Result = GetLastError();
if (ERROR_DIRECTORY != Result)
goto exit;
if (!DeleteFileW(FileName))
{
Result = GetLastError();
goto exit;
}
}
Result = ERROR_SUCCESS;
exit:
return Result;
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
DllInstance = Instance;
WcaGlobalInitialize(Instance);
break;
case DLL_PROCESS_DETACH:

View File

@ -1,2 +1,7 @@
EXPORTS
InstanceID
ServiceRunning
DeferredAction
InstallSymlinks
InstallJunctions
RemoveFiles

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- The UpgradeCode of the old WinFsp installer that did not support upgrades. -->
<?define OldVersionUpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension">
<Product
@ -7,7 +11,7 @@
Manufacturer="$(var.MyCompanyName)"
Version="$(var.MyVersion)"
Language="1033"
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B">
UpgradeCode="5466A3D8-3AA1-4240-B6A0-3A051940A3EC">
<Package
Description="$(var.MyProductName) - $(var.MyDescription)"
@ -15,13 +19,26 @@
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade
Disallow="yes"
Disallow="no"
AllowDowngrades="no"
AllowSameVersionUpgrades="no"
DisallowUpgradeErrorMessage="An older version of $(var.MyProductName) is already installed. You must uninstall it before you can install this version."
AllowSameVersionUpgrades="yes"
DowngradeErrorMessage="A newer version of $(var.MyProductName) is already installed." />
<Media Id="1" Cabinet="$(var.MyProductName).cab" EmbedCab="yes" />
<!-- Determine if we are on Win7 or above. -->
<Condition Message="$(var.MyProductName) requires Windows version 7 or higher in order to be installed.">
<![CDATA[Installed OR (VersionNT >= 601)]]>
</Condition>
<!-- Determine if the old WinFsp installer that did not support upgrades is installed. -->
<Property Id="OLDVERSIONINSTALLED">
<ProductSearch UpgradeCode="$(var.OldVersionUpgradeCode)" Minimum="0.0.0.0" />
</Property>
<Condition Message="An older version of $(var.MyProductName) that cannot be upgraded is already installed. You must uninstall it before you can install this version.">
NOT OLDVERSIONINSTALLED
</Condition>
<!-- Determine OS architecture. -->
<Property Id="OSARCH" Secure="yes" Value="AMD64">
<RegistrySearch
Id="R.OSARCH"
@ -31,10 +48,10 @@
Type="raw" />
</Property>
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property>
<Property Id="P.LauncherRegistryKey">Software\$(var.MyProductName)\Services</Property>
<!-- Setup INSTALLDIR and SXSDIR from the registry or defaults. -->
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property>
<Property Id="INSTALLDIR">
<Property Id="P.LauncherRegistryKey">Software\$(var.MyProductName)\Services</Property>
<Property Id="INSTALLDIR" Secure="yes">
<RegistrySearch
Id="R.INSTALLDIR"
Root="HKLM"
@ -42,22 +59,40 @@
Name="InstallDir"
Type="raw" />
</Property>
<Property Id="SXSDIR" Secure="yes">
<RegistrySearch
Id="R.SXSDIR"
Root="HKLM"
Key="[P.RegistryKey]"
Name="SxsDir"
Type="raw" />
</Property>
<SetProperty Id="INSTALLDIR" Value="[ProgramFilesFolder]$(var.MyProductName)\" After="CostInitialize">
NOT INSTALLDIR
</SetProperty>
<SetProperty Id="SXSDIR" Value="[INSTALLDIR]SxS\sxs.[InstanceID]\" After="SetINSTALLDIR">
((NOT SXSDIR) OR WIX_UPGRADE_DETECTED) AND InstanceID
</SetProperty>
<!-- Setup directory structure. -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="$(var.MyProductName)">
<Directory Id="BINDIR" Name="bin" />
<Directory Id="INSTALLDIR" Name="DYNAMIC">
<Directory Id="SXSBASEDIR" Name="SxS">
<Directory Id="SXSDIR" Name="DYNAMIC">
<Directory Id="BINDIR" Name="bin" />
</Directory>
</Directory>
<Directory Id="INCDIR" Name="inc" />
<Directory Id="LIBDIR" Name="lib" />
<Directory Id="OPTDIR" Name="opt" />
<Directory Id="SMPDIR" Name="samples" />
<Directory Id="SYMDIR" Name="sym" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="INSTALLDIR">
<Component Id="C.INSTALLDIR" Guid="{F876F26E-5016-4AC6-93B3-653C0312A6CE}">
<Component Id="C.INSTALLDIR" Guid="C086521F-8552-43D1-AAE2-CDD579F66FDD">
<RegistryValue
Root="HKLM"
Key="[P.RegistryKey]"
@ -70,6 +105,17 @@
<File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="SXSDIR">
<Component Id="C.SXSDIR" Guid="0F09CD39-1137-4DB8-A783-27B1F51353D1">
<RegistryValue
Root="HKLM"
Key="[P.RegistryKey]"
Name="SxsDir"
Type="string"
Value="[SXSDIR]"
KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.$(var.MyProductFileName)_a64.sys">
<File Name="$(var.MyProductFileName)-a64.sys" KeyPath="yes" />
@ -82,56 +128,56 @@
</Component>
<!-- On WinArm64 register $(var.MyProductFileName)-a64.dll -->
<Component Id="C.$(var.MyProductFileName)_a64.dll.a64" Guid="86FB483B-0910-458E-93B4-3CCB66D27AF0">
<Component Id="C.$(var.MyProductFileName)_a64.dll.a64" Guid="2A7E68EB-D05F-4DD8-ABF2-EB8CB09697F0">
<File Id="FILE.$(var.MyProductFileName)_a64.dll.a64" Name="$(var.MyProductFileName)-a64.dll" KeyPath="yes" SelfRegCost="1" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component>
<Component Id="C.$(var.MyProductFileName)_x64.dll.a64" Guid="941FAE3E-A650-4BAC-97F5-F8C6E98DB5D2">
<Component Id="C.$(var.MyProductFileName)_x64.dll.a64" Guid="EA5ED4FB-FC72-4D27-9802-88D84DAE61B4">
<File Id="FILE.$(var.MyProductFileName)_x64.dll.a64" Name="$(var.MyProductFileName)-x64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component>
<Component Id="C.$(var.MyProductFileName)_x86.dll.a64" Guid="C312214D-F9A3-40EB-B2C3-4FAF5BF3F938">
<Component Id="C.$(var.MyProductFileName)_x86.dll.a64" Guid="2A9BD712-2F96-4794-8A58-929E39F3F3CC">
<File Id="FILE.$(var.MyProductFileName)_x86.dll.a64" Name="$(var.MyProductFileName)-x86.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component>
<!-- On Win64 register $(var.MyProductFileName)-x64.dll -->
<Component Id="C.$(var.MyProductFileName)_a64.dll.x64" Guid="4ABB46C2-A8E3-49E8-B051-05DBF2B351AE">
<Component Id="C.$(var.MyProductFileName)_a64.dll.x64" Guid="026DA201-43E1-450C-9687-8A684FBF2D2D">
<File Id="FILE.$(var.MyProductFileName)_a64.dll.x64" Name="$(var.MyProductFileName)-a64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component>
<Component Id="C.$(var.MyProductFileName)_x64.dll.x64" Guid="F0A67746-1A9C-4976-8EC0-882E9407FA6D">
<Component Id="C.$(var.MyProductFileName)_x64.dll.x64" Guid="89201BAF-5812-4ECE-91CD-12EDFFF11CB1">
<File Id="FILE.$(var.MyProductFileName)_x64.dll.x64" Name="$(var.MyProductFileName)-x64.dll" KeyPath="yes" SelfRegCost="1" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component>
<Component Id="C.$(var.MyProductFileName)_x86.dll.x64" Guid="950492FB-12F7-4E27-9124-8325A2BC9927">
<Component Id="C.$(var.MyProductFileName)_x86.dll.x64" Guid="E6EE48A4-6BC7-4135-9A2F-FBBA30DE80BE">
<File Id="FILE.$(var.MyProductFileName)_x86.dll.x64" Name="$(var.MyProductFileName)-x86.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component>
<!-- On Win32 register $(var.MyProductFileName)-x86.dll -->
<Component Id="C.$(var.MyProductFileName)_a64.dll.x86" Guid="071C0EB2-A0EB-46A1-B5B0-124F60ECD6B3">
<Component Id="C.$(var.MyProductFileName)_a64.dll.x86" Guid="2B264958-DECC-4B32-9BB2-DE32D6B6BE77">
<File Id="FILE.$(var.MyProductFileName)_a64.dll.x86" Name="$(var.MyProductFileName)-a64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component>
<Component Id="C.$(var.MyProductFileName)_x64.dll.x86" Guid="4D6E7A8E-0CA6-49BE-B312-1EDADE725756">
<Component Id="C.$(var.MyProductFileName)_x64.dll.x86" Guid="29FB908F-1D36-4789-9778-4CE2E9C19CEA">
<File Id="FILE.$(var.MyProductFileName)_x64.dll.x86" Name="$(var.MyProductFileName)-x64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component>
<Component Id="C.$(var.MyProductFileName)_x86.dll.x86" Guid="F0DEF7A6-AF55-419F-A58A-DF4018C6FA73">
<Component Id="C.$(var.MyProductFileName)_x86.dll.x86" Guid="80E87D91-69A8-4942-ABC1-36652B1CA700">
<File Id="FILE.$(var.MyProductFileName)_x86.dll.x86" Name="$(var.MyProductFileName)-x86.dll" KeyPath="yes" SelfRegCost="1" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component>
<!-- install assembly -->
<Component Id="C.$(var.MyProductFileName)_msil.dll" Guid="0D8BA6AE-9F87-402B-AE1A-95B0AE3BE179">
<Component Id="C.$(var.MyProductFileName)_msil.dll" Guid="1772CDE5-4B2F-48CF-B2DA-CA43818053A8">
<File Id="FILE.$(var.MyProductFileName)_msil.dll" Name="$(var.MyProductFileName)-msil.dll" KeyPath="yes" />
</Component>
<Component Id="C.$(var.MyProductFileName)_msil.xml" Guid="1657F707-C112-454C-91AE-0FDEBBF454AB">
<Component Id="C.$(var.MyProductFileName)_msil.xml" Guid="C76745D2-51FA-4028-B827-3F2F3F763751">
<File Id="FILE.$(var.MyProductFileName)_msil.xml" Name="$(var.MyProductFileName)-msil.xml" KeyPath="yes" />
</Component>
<!--
<Component Id="C.$(var.MyProductFileName)_msil.dll.GAC" Guid="6469467D-8C90-4889-8138-4028F9DA6E85">
<Component Id="C.$(var.MyProductFileName)_msil.dll.GAC" Guid="D86F8764-2FCC-43DA-A174-23E0FD6D45B7">
<File Id="FILE.$(var.MyProductFileName)_msil.dll.GAC" Name="$(var.MyProductFileName)-msil.dll" KeyPath="yes" Assembly=".net" />
</Component>
<Component Id="C.policy.$(var.MyProductFileName)_msil.dll.GAC">
@ -141,103 +187,103 @@
-->
<!-- On WinArm64 ServiceInstall launcher-a64.exe -->
<Component Id="C.launcher_a64.exe.a64" Guid="E37E6D75-C44B-4189-8E86-CE5A3E0B0626">
<Component Id="C.launcher_a64.exe.a64" Guid="D8B657EA-7B08-48D1-B5F7-76CFB68E1BD5">
<File Id="FILE.launcher_a64.exe.a64" Name="launcher-a64.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_a64.exe.a64"
Name="[P.LauncherName]"
Name="$(var.MyProductName).Launcher"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_a64.exe.a64"
Name="[P.LauncherName]"
Name="$(var.MyProductName).Launcher"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component>
<Component Id="C.launcher_x64.exe.a64" Guid="CF5F3EEE-F739-4F50-9938-13C0D2CD9C7A">
<Component Id="C.launcher_x64.exe.a64" Guid="3EFC0561-6EA2-4E7E-B707-C2EA706CFBA0">
<File Id="FILE.launcher_x64.exe.a64" Name="launcher-x64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component>
<Component Id="C.launcher_x86.exe.a64" Guid="D5E9FF96-9E00-46BA-8719-BC49CF35BBE6">
<Component Id="C.launcher_x86.exe.a64" Guid="69F16682-10AE-4FC4-9007-8D80CE0D8388">
<File Id="FILE.launcher_x86.exe.a64" Name="launcher-x86.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component>
<!-- On Win64 ServiceInstall launcher-x64.exe -->
<Component Id="C.launcher_a64.exe.x64" Guid="10A3F0F9-6555-4071-9C93-EA50E4B3F115">
<Component Id="C.launcher_a64.exe.x64" Guid="29760ACE-69CD-4061-8C0C-8A6E72D23A45">
<File Id="FILE.launcher_a64.exe.x64" Name="launcher-a64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component>
<Component Id="C.launcher_x64.exe.x64" Guid="2AB4E729-F7CB-4B4A-BE81-6C0C3B3194FC">
<Component Id="C.launcher_x64.exe.x64" Guid="36ACBA60-1C92-4D2A-B497-CD4FB13A042F">
<File Id="FILE.launcher_x64.exe.x64" Name="launcher-x64.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_x64.exe.x64"
Name="[P.LauncherName]"
Name="$(var.MyProductName).Launcher"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_x64.exe.x64"
Name="[P.LauncherName]"
Name="$(var.MyProductName).Launcher"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component>
<Component Id="C.launcher_x86.exe.x64" Guid="C5B6D411-8A6A-4944-8C4F-7D9FB9A72826">
<Component Id="C.launcher_x86.exe.x64" Guid="98F17F67-AC1D-4E16-A147-B7AE113E3CB3">
<File Id="FILE.launcher_x86.exe.x64" Name="launcher-x86.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component>
<!-- On Win32 ServiceInstall launcher-x86.exe -->
<Component Id="C.launcher_a64.exe.x86" Guid="5048AEF5-9DE2-406E-A2EA-F237BAD13286">
<Component Id="C.launcher_a64.exe.x86" Guid="9024A9FE-7445-4241-ADA3-82A57C92719A">
<File Id="FILE.launcher_a64.exe.x86" Name="launcher-a64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component>
<Component Id="C.launcher_x64.exe.x86" Guid="88CDBE92-8B67-485A-838F-FA4AD37F306F">
<Component Id="C.launcher_x64.exe.x86" Guid="A85DA9CD-26AA-460E-950D-CA9692B87465">
<File Id="FILE.launcher_x64.exe.x86" Name="launcher-x64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component>
<Component Id="C.launcher_x86.exe.x86" Guid="E995D906-0273-4758-9B26-99A3A8CD143A">
<Component Id="C.launcher_x86.exe.x86" Guid="01FCCF6B-9F4B-4F29-8149-489470FFD449">
<File Id="FILE.launcher_x86.exe.x86" Name="launcher-x86.exe" KeyPath="yes" />
<ServiceInstall
Id="launcher_x86.exe.x86"
Name="[P.LauncherName]"
Name="$(var.MyProductName).Launcher"
Description="$(var.MyDescription)"
Type="ownProcess"
Start="auto"
ErrorControl="ignore" />
<ServiceControl
Id="launcher_x86.exe.x86"
Name="[P.LauncherName]"
Name="$(var.MyProductName).Launcher"
Start="install"
Stop="both"
Remove="uninstall" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component>
<Component Id="C.launchctl_a64.exe" Guid="B9B5CF8E-317D-40EE-A208-BC46A2A99BAB">
<Component Id="C.launchctl_a64.exe" Guid="A7D830DD-20D2-48BF-85B6-E306BCCAFD2D">
<File Name="launchctl-a64.exe" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x64.exe" Guid="2753623B-66F1-4514-B9C7-F879178DFF49">
<Component Id="C.launchctl_x64.exe" Guid="CCC8974A-4CD0-443E-840D-1C92535BBD04">
<File Name="launchctl-x64.exe" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x86.exe" Guid="EBDEC4FB-07BB-47CA-BFFF-EB854CA2D22D">
<Component Id="C.launchctl_x86.exe" Guid="6E382342-10D4-4274-8FA9-F1B44C40C277">
<File Name="launchctl-x86.exe" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_a64.exe" Guid="F75A8B14-000C-4933-AD83-EC0D1D3AD3CA">
<Component Id="C.fsptool_a64.exe" Guid="8ACEB970-CAD5-491D-8CE8-12675CC0E812">
<File Name="fsptool-a64.exe" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_x64.exe" Guid="013FE508-097D-4433-9C60-717F5446E7F4">
<Component Id="C.fsptool_x64.exe" Guid="35EE49E2-9565-4FA2-A0AC-D51FD94FA380">
<File Name="fsptool-x64.exe" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_x86.exe" Guid="6C16DC2C-E12F-49FB-A665-3AF0475487AD">
<Component Id="C.fsptool_x86.exe" Guid="0E6D5742-D500-4E24-A0FA-E6316DB70D8B">
<File Name="fsptool-x86.exe" KeyPath="yes" />
</Component>
@ -409,7 +455,7 @@
</Component>
<!-- On WinArm64 copy fuse-a64.pc -->
<Component Id="C.fuse_a64.pc" Guid="74E6E9BD-AF16-4635-AE52-84B33E4E196E">
<Component Id="C.fuse_a64.pc" Guid="776C28B5-DA1A-4EB6-96E6-3D22FE1573AC">
<File
Id="FILE.fuse_a64.pc"
Name="fuse.pc"
@ -419,7 +465,7 @@
</Component>
<!-- On Win64 copy fuse-x64.pc -->
<Component Id="C.fuse_x64.pc" Guid="407395D2-D076-411E-B1D0-D97E21E11A3C">
<Component Id="C.fuse_x64.pc" Guid="89D39F6E-2994-4E6F-ACB6-5B544057C051">
<File
Id="FILE.fuse_x64.pc"
Name="fuse.pc"
@ -429,7 +475,7 @@
</Component>
<!-- On Win32 copy fuse-x86.pc -->
<Component Id="C.fuse_x86.pc" Guid="0568EBCB-782E-4C17-9B64-BAFCC43F64ED">
<Component Id="C.fuse_x86.pc" Guid="75637ECD-B3EC-4A19-98B7-9AFAB0722D9A">
<File
Id="FILE.fuse_x86.pc"
Name="fuse.pc"
@ -439,7 +485,7 @@
</Component>
<!-- On WinArm64 copy fuse3-x64.pc -->
<Component Id="C.fuse3_a64.pc" Guid="2B6444DB-25E5-45B4-BC61-157D3B992F2B">
<Component Id="C.fuse3_a64.pc" Guid="5A69B633-11E4-46E4-8D08-BED1BE7BF4F0">
<File
Id="FILE.fuse3_a64.pc"
Name="fuse3.pc"
@ -449,7 +495,7 @@
</Component>
<!-- On Win64 copy fuse3-x64.pc -->
<Component Id="C.fuse3_x64.pc" Guid="FE59E3BA-E5EA-4822-80B1-19A1DE6B62C7">
<Component Id="C.fuse3_x64.pc" Guid="EEAF35B5-5D6C-47D6-BEE3-5E44DD5A294B">
<File
Id="FILE.fuse3_x64.pc"
Name="fuse3.pc"
@ -459,7 +505,7 @@
</Component>
<!-- On Win32 copy fuse3-x86.pc -->
<Component Id="C.fuse3_x86.pc" Guid="176205D0-07EA-4DFC-947F-18E89ABDAFAB">
<Component Id="C.fuse3_x86.pc" Guid="476CF5E5-2B8E-4D75-B1A5-FFA8C3DAECB2">
<File
Id="FILE.fuse3_x86.pc"
Name="fuse3.pc"
@ -737,62 +783,6 @@
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="SYMDIR">
<Component Id="C.$(var.MyProductFileName)_a64.sys.pdb">
<File Name="$(var.MyProductFileName)-a64.sys.pdb" Source="..\build\$(var.Configuration)\$(var.MyProductFileName)-a64.sys.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.$(var.MyProductFileName)_x64.sys.pdb">
<File Name="$(var.MyProductFileName)-x64.sys.pdb" Source="..\build\$(var.Configuration)\$(var.MyProductFileName)-x64.sys.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.$(var.MyProductFileName)_x86.sys.pdb">
<File Name="$(var.MyProductFileName)-x86.sys.pdb" Source="..\build\$(var.Configuration)\$(var.MyProductFileName)-x86.sys.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.$(var.MyProductFileName)_a64.dll.pdb">
<File Name="$(var.MyProductFileName)-a64.dll.pdb" Source="..\build\$(var.Configuration)\$(var.MyProductFileName)-a64.dll.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.$(var.MyProductFileName)_x64.dll.pdb">
<File Name="$(var.MyProductFileName)-x64.dll.pdb" Source="..\build\$(var.Configuration)\$(var.MyProductFileName)-x64.dll.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.$(var.MyProductFileName)_x86.dll.pdb">
<File Name="$(var.MyProductFileName)-x86.dll.pdb" Source="..\build\$(var.Configuration)\$(var.MyProductFileName)-x86.dll.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launcher_a64.pdb">
<File Name="launcher-a64.pdb" Source="..\build\$(var.Configuration)\launcher-a64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launcher_x64.pdb">
<File Name="launcher-x64.pdb" Source="..\build\$(var.Configuration)\launcher-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launcher_x86.pdb">
<File Name="launcher-x86.pdb" Source="..\build\$(var.Configuration)\launcher-x86.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_a64.pdb">
<File Name="launchctl-a64.pdb" Source="..\build\$(var.Configuration)\launchctl-a64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x64.pdb">
<File Name="launchctl-x64.pdb" Source="..\build\$(var.Configuration)\launchctl-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.launchctl_x86.pdb">
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_a64.pdb">
<File Name="fsptool-a64.pdb" Source="..\build\$(var.Configuration)\fsptool-a64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_x64.pdb">
<File Name="fsptool-x64.pdb" Source="..\build\$(var.Configuration)\fsptool-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.fsptool_x86.pdb">
<File Name="fsptool-x86.pdb" Source="..\build\$(var.Configuration)\fsptool-x86.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.memfs_a64.pdb">
<File Name="memfs-a64.pdb" Source="..\build\$(var.Configuration)\memfs-a64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.pdb">
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x86.pdb">
<File Name="memfs-x86.pdb" Source="..\build\$(var.Configuration)\memfs-x86.public.pdb" KeyPath="yes" />
</Component>
</DirectoryRef>
<ComponentGroup Id="C.$(var.MyProductName).bin">
<ComponentRef Id="C.$(var.MyProductFileName)_a64.sys" />
@ -927,26 +917,6 @@
<ComponentRef Id="C.notifyfs.vcxproj" />
<ComponentRef Id="C.notifyfs.vcxproj.filters" />
</ComponentGroup>
<ComponentGroup Id="C.$(var.MyProductName).sym">
<ComponentRef Id="C.$(var.MyProductFileName)_a64.sys.pdb" />
<ComponentRef Id="C.$(var.MyProductFileName)_x64.sys.pdb" />
<ComponentRef Id="C.$(var.MyProductFileName)_x86.sys.pdb" />
<ComponentRef Id="C.$(var.MyProductFileName)_a64.dll.pdb" />
<ComponentRef Id="C.$(var.MyProductFileName)_x64.dll.pdb" />
<ComponentRef Id="C.$(var.MyProductFileName)_x86.dll.pdb" />
<ComponentRef Id="C.launcher_a64.pdb" />
<ComponentRef Id="C.launcher_x64.pdb" />
<ComponentRef Id="C.launcher_x86.pdb" />
<ComponentRef Id="C.launchctl_a64.pdb" />
<ComponentRef Id="C.launchctl_x64.pdb" />
<ComponentRef Id="C.launchctl_x86.pdb" />
<ComponentRef Id="C.fsptool_a64.pdb" />
<ComponentRef Id="C.fsptool_x64.pdb" />
<ComponentRef Id="C.fsptool_x86.pdb" />
<ComponentRef Id="C.memfs_a64.pdb" />
<ComponentRef Id="C.memfs_x64.pdb" />
<ComponentRef Id="C.memfs_x86.pdb" />
</ComponentGroup>
<ComponentGroup Id="C.$(var.MyProductName).net">
<ComponentRef Id="C.$(var.MyProductFileName)_msil.dll" />
<ComponentRef Id="C.$(var.MyProductFileName)_msil.xml" />
@ -978,6 +948,7 @@
Absent="disallow">
<ComponentRef Id="C.INSTALLDIR" />
<ComponentRef Id="C.License.txt" />
<ComponentRef Id="C.SXSDIR" />
<Feature
Id="F.User"
Level="1"
@ -1013,7 +984,6 @@
<ComponentGroupRef Id="C.$(var.MyProductName).lib" />
<ComponentGroupRef Id="C.$(var.MyProductName).smp" />
<ComponentGroupRef Id="C.$(var.MyProductName).smp.net" />
<ComponentGroupRef Id="C.$(var.MyProductName).sym" />
</Feature>
<Feature
Id="F.KernelDeveloper"
@ -1056,7 +1026,24 @@
Order="10">NOT Installed</Publish>
</UI>
<!-- Custom Actions -->
<Binary Id="CustomActions" SourceFile="..\build\$(var.Configuration)\CustomActions.dll" />
<!-- InstanceID computes a unique per-installer-run ID -->
<CustomAction
Id="Action.InstanceID"
BinaryKey="CustomActions"
DllEntry="InstanceID"
Execute="firstSequence"
Return="check" />
<InstallExecuteSequence>
<Custom Action="Action.InstanceID" Before="AppSearch" />
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="Action.InstanceID" Before="AppSearch" />
</InstallUISequence>
<!-- ServiceRunning determines if the old driver (that did not support unload) is running. -->
<CustomAction
Id="Params.ServiceRunning"
Property="ServiceRunning"
@ -1069,16 +1056,109 @@
Return="ignore" />
<CustomAction
Id="Action.ServiceRunning.Error"
Error="The $(var.MyProductName) service appears to be running. If you just uninstalled $(var.MyProductName) please restart your computer. If you are running a development version of $(var.MyProductName) please remove it before proceeding." />
Error="A component from an older version of $(var.MyProductName) that cannot be upgraded appears to be running. If you just uninstalled an older version of $(var.MyProductName) please restart your computer." />
<InstallExecuteSequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning" />
<Custom Action="Action.ServiceRunning" Before="LaunchConditions" />
<Custom Action="Action.ServiceRunning" After="LaunchConditions">
<![CDATA[NOT Installed]]>
</Custom>
<Custom Action="Action.ServiceRunning.Error" After="Action.ServiceRunning">
<![CDATA[NOT Installed AND (0 <> ServiceRunning)]]>
</Custom>
<ScheduleReboot After="RemoveFiles">
<![CDATA[(REMOVE ~= "ALL") AND (0 <> ServiceRunning)]]>
</ScheduleReboot>
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning" />
<Custom Action="Action.ServiceRunning" After="LaunchConditions">
<![CDATA[NOT Installed]]>
</Custom>
<Custom Action="Action.ServiceRunning.Error" After="Action.ServiceRunning">
<![CDATA[NOT Installed AND (0 <> ServiceRunning)]]>
</Custom>
</InstallUISequence>
<!-- InstallSymlinks installs SxS symlinks -->
<SetProperty
Id="Deferred.InstallSymlinks"
Value='InstallJunctions "[INSTALLDIR]\" "[SXSDIR]\" bin'
Before="Deferred.InstallSymlinks"
Sequence="execute" />
<CustomAction
Id="Deferred.InstallSymlinks"
BinaryKey="CustomActions"
DllEntry="DeferredAction"
Execute="deferred"
Impersonate="no"
Return="check" />
<SetProperty
Id="Rollback.InstallSymlinks"
Value='RemoveFiles "[INSTALLDIR]\" bin'
Before="Rollback.InstallSymlinks"
Sequence="execute" />
<CustomAction
Id="Rollback.InstallSymlinks"
BinaryKey="CustomActions"
DllEntry="DeferredAction"
Execute="rollback"
Impersonate="no"
Return="ignore" />
<InstallExecuteSequence>
<!--
deferred: `InstallSymlinks` on install or repair
rollback: `RemoveSymlinks` on install only
-->
<Custom Action="Rollback.InstallSymlinks" After="InstallFiles">
NOT Installed
</Custom>
<Custom Action="Deferred.InstallSymlinks" After="Rollback.InstallSymlinks">
(NOT Installed) OR REINSTALL
</Custom>
</InstallExecuteSequence>
<!-- RemoveSymlinks removes SxS symlinks -->
<SetProperty
Id="Deferred.RemoveSymlinks"
Value='RemoveFiles "[INSTALLDIR]\" bin'
Before="Deferred.RemoveSymlinks"
Sequence="execute" />
<CustomAction
Id="Deferred.RemoveSymlinks"
BinaryKey="CustomActions"
DllEntry="DeferredAction"
Execute="deferred"
Impersonate="no"
Return="ignore" />
<SetProperty
Id="Rollback.RemoveSymlinks"
Value='InstallJunctions "[INSTALLDIR]\" "[SXSDIR]\" bin'
Before="Rollback.RemoveSymlinks"
Sequence="execute" />
<CustomAction
Id="Rollback.RemoveSymlinks"
BinaryKey="CustomActions"
DllEntry="DeferredAction"
Execute="rollback"
Impersonate="no"
Return="check" />
<InstallExecuteSequence>
<!--
deferred: `RemoveSymlinks` on uninstall
rollback: `InstallSymlinks` on uninstall
-->
<Custom Action="Rollback.RemoveSymlinks" Before="RemoveFiles">
REMOVE ~= "ALL"
</Custom>
<Custom Action="Deferred.RemoveSymlinks" After="Rollback.RemoveSymlinks">
REMOVE ~= "ALL"
</Custom>
</InstallExecuteSequence>
<!--
Specify WIXFAILWHENDEFERRED=1 on the msiexec cmdline for rollback testing.
See http://tinyurl.com/yxkaywek
-->
<!--
<Property Id="WIXFAILWHENDEFERRED" Value="0" Secure="yes" />
<CustomActionRef Id="WixFailWhenDeferred" />
-->
</Product>
</Wix>

View File

@ -20,7 +20,7 @@
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
<SuppressIces>ICE30</SuppressIces>
<SuppressIces>ICE30;ICE61</SuppressIces>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
@ -29,12 +29,16 @@
<SuppressAllWarnings>False</SuppressAllWarnings>
<Pedantic>True</Pedantic>
<SuppressPdbOutput>True</SuppressPdbOutput>
<SuppressIces>ICE30</SuppressIces>
<SuppressIces>ICE30;ICE61</SuppressIces>
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<WixExtension Include="WixUtilExtension">
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
<Name>WixUtilExtension</Name>
</WixExtension>
<WixExtension Include="WixUIExtension">
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name>

View File

@ -1,27 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(MSBuildProjectName).build\</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4920E350-D496-4652-AE98-6C4208AEC1D8}</ProjectGuid>
<OutputType>Exe</OutputType>
<ProjectName>memfs-dotnet</ProjectName>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>memfs</RootNamespace>
<AssemblyName>memfs-dotnet-msil</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFramework>net452</TargetFramework>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
@ -33,32 +36,16 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<ProjectReference Include="..\dotnet\winfsp.net.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\tst\memfs-dotnet\Program.cs">
<Link>Program.cs</Link>
</Compile>
<Compile Include="..\..\..\tst\memfs-dotnet\Program.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\dotnet\winfsp.net.csproj">
<Project>{94580219-cc8d-4fe5-a3be-437b0b3481e1}</Project>
<Name>winfsp.net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

View File

@ -284,6 +284,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\loadun-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\uuid5-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\volpath-test.c" />

View File

@ -112,6 +112,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\notify-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\loadun-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -73,6 +73,7 @@
<ClCompile Include="..\..\src\dll\ntstatus.c" />
<ClCompile Include="..\..\src\dll\path.c" />
<ClCompile Include="..\..\src\dll\service.c" />
<ClCompile Include="..\..\src\dll\sxs.c" />
<ClCompile Include="..\..\src\dll\util.c" />
<ClCompile Include="..\..\src\dll\wksid.c" />
<ClCompile Include="..\..\src\shared\ku\mountmgr.c" />

View File

@ -178,6 +178,9 @@
<ClCompile Include="..\..\src\shared\ku\mountmgr.c">
<Filter>Source\shared\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\sxs.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\library.def">

View File

@ -260,6 +260,7 @@
<ClCompile Include="..\..\src\sys\shutdown.c" />
<ClCompile Include="..\..\src\sys\silo.c" />
<ClCompile Include="..\..\src\sys\statistics.c" />
<ClCompile Include="..\..\src\sys\sxs.c" />
<ClCompile Include="..\..\src\sys\trace.c" />
<ClCompile Include="..\..\src\sys\util.c" />
<ClCompile Include="..\..\src\sys\volinfo.c" />
@ -290,6 +291,9 @@
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(MyProductFileArch).cat
if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
@ -303,6 +307,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(MyProductFileArch).cat
if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
@ -316,6 +323,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(MyProductFileArch).cat
if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
@ -328,6 +338,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(MyProductFileArch).cat
if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
@ -342,6 +355,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(MyProductFileArch).cat
if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
@ -354,6 +370,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
<Command Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">set DriverFile=$(TargetFileName)
set Provider="$(MyCompanyName)"
set CatalogFile=driver-$(MyProductFileArch).cat
if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
setlocal EnableDelayedExpansion
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf

View File

@ -134,6 +134,9 @@
<ClCompile Include="..\..\src\shared\ku\mountmgr.c">
<Filter>Source\shared\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sys\sxs.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h">

View File

@ -6,18 +6,17 @@
I am running Windows 7 and I am finding that the installed driver is not signed.::
Your Windows 7 OS is missing SHA-2 Code Signing Support. You need to install the following security advisory that will rectify the problem:
https://technet.microsoft.com/en-us/library/security/3033929.aspx
Your Windows 7 OS is missing SHA-2 Code Signing Support. Make sure it is fully updated.
I cannot run a program located in a WinFsp drive as administrator. I cannot run `regedit.exe` from within a WinFsp drive.::
When running an executable as administrator, the Windows OS seems to require that the name of the file system that is housing the executable is "NTFS". For example, the MEMFS file system with the command line `memfs-x64.exe -i -F NTFS -m X:` works.
Disconnecting (unmapping) a network drive does not work.::
You may have Dokany installed. Dokany installs its own Network Provider DLL that unfortunately interferes with the WinFsp handling of network drives. The solution is to change your system's Network Provider order and ensure that the WinFsp Network Provider runs before the Dokany one. Instructions on how to change the Network Provider order can be found in this http://blogs.interfacett.com/changing-the-network-provider-order-in-windows-10[article].
Case-sensitive file systems do not work properly when mounted as a directory.::
This is fixed as of WinFsp 2018.2 B3.
You may have Dokany installed. Dokany installs its own Network Provider DLL that unfortunately interferes with the WinFsp handling of network drives. The solution is to change your system's Network Provider order and ensure that the WinFsp Network Provider runs before the Dokany one. Instructions on how to change the Network Provider order can be found in this https://www.interfacett.com/blogs/changing-the-network-provider-order-in-windows-10/[article].
Why is the DLL not installed in the Windows system directories?::
@ -29,7 +28,7 @@ There are a few alternative methods to overcome this problem. WinFsp recommends
Does WinFsp provide debugging symbols?::
Public debugging symbols are already included in the installer. You need to install the "Developer" feature; the symbols can be found in the `sym` directory under the WinFsp installation directory.
Debugging symbols can be found in the https://github.com/winfsp/winfsp.sym repository.
Is there a maximum number of concurrent file systems?::
@ -61,11 +60,6 @@ With this in mind here are the reasons for the current WinFsp-FUSE behavior:
- Most importantly: inability to guarantee that the mount point will cease to exist if the file system crashes. WinFsp attempts to guarantee that all resources used by a file system will get cleaned up. This is certainly true for the kernel-mode FSD, but an attempt is made to do so also in user mode. For this reason, drive symbolic links are marked as temporary and (importantly for our discussion) mount directories are opened with `FILE_FLAG_DELETE_ON_CLOSE`. There is no way to guarantee the removal of a reparse point in the same way.
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.
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.

View File

@ -111,6 +111,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 's', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_NOTIFY \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'n', METHOD_NEITHER, FILE_ANY_ACCESS)
#define FSP_FSCTL_UNLOAD \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'U', METHOD_NEITHER, FILE_ANY_ACCESS)
/* fsctl internal device codes (usable only in-kernel) */
#define FSP_FSCTL_TRANSACT_INTERNAL \
@ -694,6 +696,11 @@ FSP_API NTSTATUS FspFsctlNotify(HANDLE VolumeHandle,
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
FSP_API NTSTATUS FspFsctlStartService(VOID);
FSP_API NTSTATUS FspFsctlStopService(VOID);
FSP_API NTSTATUS FspFsctlEnumServices(
VOID (*EnumFn)(PVOID Context, PWSTR ServiceName, BOOLEAN Running),
PVOID Context);
typedef struct
{

View File

@ -1047,11 +1047,49 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*Obsolete0)(VOID);
/**
* Inform the file system that its dispatcher has been stopped.
*
* Prior to WinFsp v2.0 the FSD would never unmount a file system volume unless
* the user mode file system requested the unmount. Since WinFsp v2.0 it is possible
* for the FSD to unmount a file system volume without an explicit user mode file system
* request. For example, this happens when the FSD is being uninstalled.
*
* A user mode file system can use this operation to determine when its dispatcher
* has been stopped. The Normally parameter can be used to determine why the dispatcher
* was stopped: it is TRUE when the file system is being stopped via
* FspFileSystemStopDispatcher and FALSE otherwise.
*
* When the file system receives a request with Normally == TRUE it need not take any
* extra steps. This case is the same as for pre-v2.0 versions: since the file system
* stopped the dispatcher via FspFileSystemStopDispatcher, it will likely exit its
* process soon.
*
* When the file system receives a request with Normally == FALSE it may need to take
* extra steps to exit its process as this is not done by default.
*
* A file system that uses the FspService infrastructure may use the
* FspFileSystemStopServiceIfNecessary API to correctly handle all cases.
*
* This operation is the last one that a file system will receive.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Normally
* TRUE if the file system is being stopped via FspFileSystemStopDispatcher.
* FALSE if the file system is being stopped because of another reason such
* as driver unload/uninstall.
* @see
* FspFileSystemStopServiceIfNecessary
*/
VOID (*DispatcherStopped)(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally);
/*
* This ensures that this interface will always contain 64 function pointers.
* Please update when changing the interface as it is important for future compatibility.
*/
NTSTATUS (*Reserved[32])();
NTSTATUS (*Reserved[31])();
} FSP_FILE_SYSTEM_INTERFACE;
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
@ -1074,7 +1112,8 @@ typedef struct _FSP_FILE_SYSTEM
SRWLOCK OpGuardLock;
BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext;
UINT16 UmNoReparsePointsDirCheck:1;
UINT16 UmReservedFlags:15;
UINT16 UmReservedFlags:14;
UINT16 DispatcherStopping:1;
} FSP_FILE_SYSTEM;
FSP_FSCTL_STATIC_ASSERT(
(4 == sizeof(PVOID) && 660 == sizeof(FSP_FILE_SYSTEM)) ||
@ -1108,7 +1147,7 @@ FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
* @param VolumeParams
* Volume parameters for the newly created file system.
* @param Interface
* A pointer to the actual operations that actually implement this user mode file system.
* A pointer to the operations that implement this user mode file system.
* @param PFileSystem [out]
* Pointer that will receive the file system object created on successful return from this
* call.
@ -1746,6 +1785,23 @@ UINT32 FspFileSystemGetEaPackedSize(PFILE_FULL_EA_INFORMATION SingleEa)
*/
FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/**
* Stop a file system service, if any.
*
* This is a helper for implementing the DispatcherStopped operation, but only for file systems
* that use the FspService infrastructure.
*
* @param FileSystem
* The file system object.
* @param Normally
* TRUE if the file system is being stopped via FspFileSystemStopDispatcher.
* FALSE if the file system is being stopped because of another reason such
* as driver unload/uninstall.
* @see
* DispatcherStopped
*/
FSP_API VOID FspFileSystemStopServiceIfNecessary(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally);
/*
* Directory buffering
@ -2043,6 +2099,8 @@ FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service);
* to connect the service process to the Service Control Manager. If the Service Control Manager is
* not available (and console mode is allowed) it will enter console mode.
*
* This function should be called once per process.
*
* @param Service
* The service object.
* @return
@ -2120,6 +2178,7 @@ FSP_API NTSTATUS FspCallNamedPipeSecurelyEx(PWSTR PipeName,
PULONG PBytesTransferred, ULONG Timeout, BOOLEAN AllowImpersonation,
PSID Sid);
FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
FSP_API PWSTR FspSxsIdent(VOID);
/*
* Delay load

View File

@ -358,6 +358,21 @@ exit:
CloseHandle(DispatcherThread);
}
if (GetCurrentThreadId() == GetThreadId(FileSystem->DispatcherThread))
{
if (0 != FileSystem->Interface->DispatcherStopped)
{
/* Normally = !!FileSystem->DispatcherStopping */
BOOLEAN Normally = !!(
_InterlockedOr16(
(PVOID)((PUINT8)&FileSystem->UmFileContextIsFullContext +
sizeof(FileSystem->UmFileContextIsFullContext)),
0) &
0x8000);
FileSystem->Interface->DispatcherStopped(FileSystem, Normally);
}
}
return Result;
}
@ -391,6 +406,11 @@ FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG
if (0 == FileSystem->DispatcherThread)
return FspNtStatusFromWin32(GetLastError());
#if defined(FSP_CFG_REJECT_EARLY_IRP)
FspFsctlTransact(FileSystem->VolumeHandle, 0, 0, 0, 0, FALSE);
/* send a Transact0 to inform the FSD that the dispatcher is _almost_ ready */
#endif
return STATUS_SUCCESS;
}
@ -399,6 +419,12 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem)
if (0 == FileSystem->DispatcherThread)
return;
/* FileSystem->DispatcherStopping = 1 */
_InterlockedOr16(
(PVOID)((PUINT8)&FileSystem->UmFileContextIsFullContext +
sizeof(FileSystem->UmFileContextIsFullContext)),
0x8000);
FspFsctlStop0(FileSystem->VolumeHandle);
WaitForSingleObject(FileSystem->DispatcherThread, INFINITE);
@ -406,6 +432,12 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem)
FileSystem->DispatcherThread = 0;
FspFsctlStop(FileSystem->VolumeHandle);
/* FileSystem->DispatcherStopping = 0 */
_InterlockedAnd16(
(PVOID)((PUINT8)&FileSystem->UmFileContextIsFullContext +
sizeof(FileSystem->UmFileContextIsFullContext)),
0x7fff);
}
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,

View File

@ -32,19 +32,21 @@ static DWORD FspFsctlTransactCode = FSP_FSCTL_TRANSACT;
static DWORD FspFsctlTransactBatchCode = FSP_FSCTL_TRANSACT_BATCH;
static VOID FspFsctlServiceVersion(PUINT32 PVersion);
static NTSTATUS FspFsctlStartService(VOID);
FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
PHANDLE PVolumeHandle)
{
NTSTATUS Result;
WCHAR SxsDevicePathBuf[MAX_PATH];
PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize, VolumeParamsSize;
WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes;
NTSTATUS Result;
DevicePath = FspSxsAppendSuffix(SxsDevicePathBuf, sizeof SxsDevicePathBuf, DevicePath);
if (sizeof(WCHAR) <= VolumeNameSize)
VolumeNameBuf[0] = L'\0';
@ -229,12 +231,15 @@ exit:
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize)
{
NTSTATUS Result;
WCHAR SxsDevicePathBuf[MAX_PATH];
PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize;
WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes;
NTSTATUS Result;
DevicePath = FspSxsAppendSuffix(SxsDevicePathBuf, sizeof SxsDevicePathBuf, DevicePath);
/* check lengths; everything must fit within MAX_PATH */
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
@ -298,16 +303,71 @@ FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath)
return STATUS_SUCCESS;
}
static NTSTATUS FspFsctlUnload(PWSTR DevicePath)
{
WCHAR SxsDevicePathBuf[MAX_PATH];
PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize;
WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes;
NTSTATUS Result;
DevicePath = FspSxsAppendSuffix(SxsDevicePathBuf, sizeof SxsDevicePathBuf, DevicePath);
/* check lengths; everything must fit within MAX_PATH */
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
DeviceRootSize = lstrlenW(DeviceRoot) * sizeof(WCHAR);
DevicePathSize = lstrlenW(DevicePath) * sizeof(WCHAR);
if (DeviceRootSize + DevicePathSize + sizeof(WCHAR) > sizeof DevicePathBuf)
return STATUS_INVALID_PARAMETER;
/* prepare the device path to be opened */
DevicePathPtr = DevicePathBuf;
memcpy(DevicePathPtr, DeviceRoot, DeviceRootSize);
DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DeviceRootSize);
memcpy(DevicePathPtr, DevicePath, DevicePathSize);
DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DevicePathSize);
*DevicePathPtr = L'\0';
VolumeHandle = CreateFileW(DevicePathBuf,
0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (INVALID_HANDLE_VALUE == VolumeHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
if (STATUS_OBJECT_PATH_NOT_FOUND == Result ||
STATUS_OBJECT_NAME_NOT_FOUND == Result)
Result = STATUS_NO_SUCH_DEVICE;
goto exit;
}
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_UNLOAD, 0, 0, 0, 0, &Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != VolumeHandle)
CloseHandle(VolumeHandle);
return Result;
}
static BOOL WINAPI FspFsctlServiceVersionInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
WCHAR DriverName[256];
PWSTR ModuleFileName;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
QUERY_SERVICE_CONFIGW *ServiceConfig = 0;
DWORD Size;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
ScmHandle = OpenSCManagerW(0, 0, 0);
if (0 == ScmHandle)
goto exit;
@ -371,29 +431,33 @@ static VOID FspFsctlServiceVersion(PUINT32 PVersion)
*PVersion = FspFsctlServiceVersionValue;
}
static NTSTATUS FspFsctlStartService(VOID)
static SRWLOCK FspFsctlStartStopServiceLock = SRWLOCK_INIT;
static BOOLEAN FspFsctlRunningInContainer(VOID)
{
/* Determine if we are running inside container.
*
* See https://github.com/microsoft/perfview/blob/V1.9.65/src/TraceEvent/TraceEventSession.cs#L525
* See https://stackoverflow.com/a/50748300
*/
return ERROR_SUCCESS == RegGetValueW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control",
L"ContainerType",
RRF_RT_REG_DWORD, 0,
0, 0);
}
static NTSTATUS FspFsctlStartServiceByName(PWSTR DriverName)
{
static SRWLOCK Lock = SRWLOCK_INIT;
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus;
DWORD LastError;
NTSTATUS Result;
AcquireSRWLockExclusive(&Lock);
AcquireSRWLockExclusive(&FspFsctlStartStopServiceLock);
/* Determine if we are running inside container.
*
* See https://github.com/microsoft/perfview/blob/V1.9.65/src/TraceEvent/TraceEventSession.cs#L525
* See https://stackoverflow.com/a/50748300
*/
LastError = RegGetValueW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control",
L"ContainerType",
RRF_RT_REG_DWORD, 0,
0, 0);
if (ERROR_SUCCESS == LastError)
if (FspFsctlRunningInContainer())
{
Result = STATUS_SUCCESS;
goto exit;
@ -453,7 +517,218 @@ exit:
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
ReleaseSRWLockExclusive(&Lock);
ReleaseSRWLockExclusive(&FspFsctlStartStopServiceLock);
return Result;
}
static VOID FspFsctlStartService_EnumFn(PVOID Context, PWSTR ServiceName, BOOLEAN Running)
{
PWSTR DriverName = Context;
if (0 > invariant_wcscmp(DriverName, ServiceName))
lstrcpyW(DriverName, ServiceName);
}
FSP_API NTSTATUS FspFsctlStartService(VOID)
{
/*
* With the introduction of side-by-side (SxS) FSD installations,
* we revisit how the FSD is started:
*
* - If the DLL is started in non-SxS mode, we first try to start
* the non-SxS FSD. If that fails we then enumerate all SxS FSD's
* and make a best guess on which one to start.
*
* - If the DLL is started in SxS mode, we only attempt to start
* the associated SxS FSD.
*/
if (L'\0' == FspSxsIdent()[0])
{
/* non-SxS mode */
NTSTATUS Result;
WCHAR DriverName[256];
Result = FspFsctlStartServiceByName(L"" FSP_FSCTL_DRIVER_NAME);
if (NT_SUCCESS(Result) || STATUS_NO_SUCH_DEVICE != Result)
return Result;
/* DO NOT CLOBBER Result. We will return it if our best effort below fails. */
DriverName[0] = L'\0';
FspFsctlEnumServices(FspFsctlStartService_EnumFn, DriverName);
if (L'\0' == DriverName[0] || !NT_SUCCESS(FspFsctlStartServiceByName(DriverName)))
return Result;
return STATUS_SUCCESS;
}
else
{
/* SxS mode */
WCHAR DriverName[256];
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
return FspFsctlStartServiceByName(DriverName);
}
}
FSP_API NTSTATUS FspFsctlStopService(VOID)
{
WCHAR DriverName[256];
HANDLE ThreadToken = 0, ProcessToken = 0;
BOOL DidSetThreadToken = FALSE, DidAdjustTokenPrivileges = FALSE;
TOKEN_PRIVILEGES Privileges, PreviousPrivileges;
PRIVILEGE_SET RequiredPrivileges;
DWORD PreviousPrivilegesLength;
BOOL PrivilegeCheckResult;
NTSTATUS Result;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
AcquireSRWLockExclusive(&FspFsctlStartStopServiceLock);
if (FspFsctlRunningInContainer())
{
Result = STATUS_SUCCESS;
goto exit;
}
/* enable and check SeLoadDriverPrivilege required for FSP_FSCTL_UNLOAD */
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, TRUE, &ThreadToken))
{
if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &ProcessToken) ||
!DuplicateToken(ProcessToken, SecurityDelegation, &ThreadToken) ||
!SetThreadToken(0, ThreadToken))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
DidSetThreadToken = TRUE;
CloseHandle(ThreadToken);
ThreadToken = 0;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, TRUE, &ThreadToken))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (!LookupPrivilegeValueW(0, SE_LOAD_DRIVER_NAME, &Privileges.Privileges[0].Luid))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Privileges.PrivilegeCount = 1;
Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(ThreadToken, FALSE,
&Privileges, sizeof PreviousPrivileges, &PreviousPrivileges, &PreviousPrivilegesLength))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
DidAdjustTokenPrivileges = 0 == GetLastError();
RequiredPrivileges.PrivilegeCount = 1;
RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
RequiredPrivileges.Privilege[0].Attributes = 0;
RequiredPrivileges.Privilege[0].Luid = Privileges.Privileges[0].Luid;
if (!PrivilegeCheck(ThreadToken, &RequiredPrivileges, &PrivilegeCheckResult))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!PrivilegeCheckResult)
{
Result = STATUS_PRIVILEGE_NOT_HELD;
goto exit;
}
Result = FspFsctlUnload(L"" FSP_FSCTL_DISK_DEVICE_NAME);
if (!NT_SUCCESS(Result) && STATUS_NO_SUCH_DEVICE != Result)
goto exit;
Result = STATUS_SUCCESS;
exit:
if (DidAdjustTokenPrivileges)
AdjustTokenPrivileges(ThreadToken, FALSE, &PreviousPrivileges, 0, 0, 0);
if (DidSetThreadToken)
SetThreadToken(0, 0);
if (0 != ThreadToken)
CloseHandle(ThreadToken);
if (0 != ProcessToken)
CloseHandle(ProcessToken);
ReleaseSRWLockExclusive(&FspFsctlStartStopServiceLock);
return Result;
}
FSP_API NTSTATUS FspFsctlEnumServices(
VOID (*EnumFn)(PVOID Context, PWSTR ServiceName, BOOLEAN Running),
PVOID Context)
{
SC_HANDLE ScmHandle = 0;
LPENUM_SERVICE_STATUSW Services = 0;
DWORD Size, ServiceCount;
DWORD LastError;
NTSTATUS Result;
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_ENUMERATE_SERVICE);
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!EnumServicesStatusW(ScmHandle,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_STATE_ALL, 0, 0, &Size, &ServiceCount, 0))
{
LastError = GetLastError();
if (ERROR_MORE_DATA != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
}
if (0 == Size)
{
Result = STATUS_SUCCESS;
goto exit;
}
Services = MemAlloc(Size);
if (0 == Services)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!EnumServicesStatusW(ScmHandle,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_STATE_ALL, Services, Size, &Size, &ServiceCount, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
for (DWORD I = 0; ServiceCount > I; I++)
{
if (0 != invariant_wcsicmp(Services[I].lpServiceName, L"" FSP_FSCTL_DRIVER_NAME) &&
0 != invariant_wcsnicmp(Services[I].lpServiceName,
L"" FSP_FSCTL_DRIVER_NAME FSP_SXS_SEPARATOR_STRING,
sizeof(FSP_FSCTL_DRIVER_NAME FSP_SXS_SEPARATOR_STRING) - 1))
continue;
EnumFn(Context,
Services[I].lpServiceName,
SERVICE_STOPPED != Services[I].ServiceStatus.dwCurrentState);
}
Result = STATUS_SUCCESS;
exit:
MemFree(Services);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}
@ -461,14 +736,15 @@ exit:
static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
{
/*
* This function adds an ACE that allows Everyone to start a service.
* This function adds two ACE's:
* - An ACE that allows Everyone to start a service.
* - An ACE that denies Everyone (including Administrators) to stop a service.
*/
PSID WorldSid;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry;
ACCESS_MASK AccessRights;
EXPLICIT_ACCESSW AccessEntries[2];
PACL Dacl;
BOOL DaclPresent, DaclDefaulted;
DWORD Size;
@ -513,54 +789,40 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
goto exit;
}
/* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START right for Everyone */
AccessEntry.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START;
AccessEntry.grfAccessMode = GRANT_ACCESS;
AccessEntry.grfInheritance = NO_INHERITANCE;
AccessEntry.Trustee.pMultipleTrustee = 0;
AccessEntry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntry.Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntry.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntry.Trustee.ptstrName = WorldSid;
/* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START rights for Everyone */
AccessEntries[0].grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START;
AccessEntries[0].grfAccessMode = GRANT_ACCESS;
AccessEntries[0].grfInheritance = NO_INHERITANCE;
AccessEntries[0].Trustee.pMultipleTrustee = 0;
AccessEntries[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntries[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntries[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntries[0].Trustee.ptstrName = WorldSid;
/* get the effective rights for Everyone */
AccessRights = 0;
if (DaclPresent && 0 != Dacl)
/* prepare an EXPLICIT_ACCESS to deny the SERVICE_STOP right to Everyone */
AccessEntries[1].grfAccessPermissions = SERVICE_STOP;
AccessEntries[1].grfAccessMode = DENY_ACCESS;
AccessEntries[1].grfInheritance = NO_INHERITANCE;
AccessEntries[1].Trustee.pMultipleTrustee = 0;
AccessEntries[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntries[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntries[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntries[1].Trustee.ptstrName = WorldSid;
/* create a new security descriptor with the new access */
LastError = BuildSecurityDescriptorW(0, 0, 2, AccessEntries, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor);
if (0 != LastError)
{
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights);
if (0 != LastError)
/*
* Apparently GetEffectiveRightsFromAclW can fail with ERROR_CIRCULAR_DEPENDENCY
* in some rare circumstances. Calling GetEffectiveRightsFromAclW is not essential
* in this instance. It is only done to check whether the "Everyone/World" SID
* already has the access required to start the FSD; if it does not have those
* rights already they are added. It is probably safe to just assume that the
* required rights are not there if GetEffectiveRightsFromAclW fails; the worst
* that can happen is that the rights get added twice (which is benign).
*
* See https://github.com/winfsp/winfsp/issues/62
*/
AccessRights = 0;
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
/* do we have the required access rights? */
if (AccessEntry.grfAccessPermissions != (AccessRights & AccessEntry.grfAccessPermissions))
/* set the new service security descriptor DACL */
if (!SetServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
{
/* create a new security descriptor with the new access */
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor);
if (0 != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
/* set the new service security descriptor DACL */
if (!SetServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = STATUS_SUCCESS;
@ -575,7 +837,7 @@ exit:
NTSTATUS FspFsctlRegister(VOID)
{
extern HINSTANCE DllInstance;
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
WCHAR DriverName[256];
WCHAR DriverPath[MAX_PATH];
DWORD Size;
SC_HANDLE ScmHandle = 0;
@ -584,6 +846,8 @@ NTSTATUS FspFsctlRegister(VOID)
SERVICE_DESCRIPTION ServiceDescription;
NTSTATUS Result;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
Result = FspGetModuleFileName(DllInstance, DriverPath, MAX_PATH, L"" MyFsctlRegisterPath);
if (!NT_SUCCESS(Result))
return Result;
@ -674,12 +938,16 @@ exit:
NTSTATUS FspFsctlUnregister(VOID)
{
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME;
WCHAR DriverName[256];
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
DWORD LastError;
NTSTATUS Result;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
FspFsctlStopService();
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE);
/*
* The SC_MANAGER_CREATE_SERVICE access right is not strictly needed here,

View File

@ -1883,3 +1883,12 @@ FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
{
return FspFileSystemAddXxxInfo(NotifyInfo, Buffer, Length, PBytesTransferred);
}
FSP_API VOID FspFileSystemStopServiceIfNecessary(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally)
{
/* NOTE: .NET calls us with a zero FileSystem pointer! */
if (Normally)
return;
FspServiceStopLoop();
}

View File

@ -1939,7 +1939,7 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
}
SizeA = lstrlenA(name);
if (SizeA > 255)
if (SizeA > 255 * 4)
{
fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
"too long");
@ -1949,6 +1949,13 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255);
if (0 == SizeW)
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
"too long");
return 0;
}
fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
"MultiByteToWideChar failed");
return 0;
@ -1991,7 +1998,7 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
NTSTATUS Result;
SizeA = lstrlenA(filedesc->PosixPath);
PosixPath = MemAlloc(SizeA + 1 + 255 + 1);
PosixPath = MemAlloc(SizeA + 1 + 255 * 4 + 1);
if (0 == PosixPath)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
@ -2040,7 +2047,7 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
else
{
PosixPathEnd = 0;
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255 * 4, 0, 0);
if (0 == SizeA)
{
/* this should never happen because we just converted using MultiByteToWideChar */
@ -2628,6 +2635,17 @@ static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem,
&Uid, &Gid, &Mode, FileInfo);
}
static VOID fsp_fuse_intf_DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally)
{
if (Normally)
return;
struct fuse *f = FileSystem->UserContext;
fsp_fuse_exit(f->env, f);
}
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
{
fsp_fuse_intf_GetVolumeInfo,
@ -2661,6 +2679,8 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
fsp_fuse_intf_Overwrite,
fsp_fuse_intf_GetEa,
fsp_fuse_intf_SetEa,
0,
fsp_fuse_intf_DispatcherStopped,
};
/*

View File

@ -70,6 +70,9 @@ NTSTATUS FspNpUnregister(VOID);
NTSTATUS FspEventLogRegister(VOID);
NTSTATUS FspEventLogUnregister(VOID);
PWSTR FspSxsSuffix(VOID);
PWSTR FspSxsAppendSuffix(PWCHAR Buffer, SIZE_T Size, PWSTR Ident);
PSID FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult);
PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);
@ -107,6 +110,7 @@ NTSTATUS FspGetModuleFileName(
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
VOID FspServiceStopLoop(VOID);
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
static inline ULONG FspPathSuffixIndex(PWSTR FileName)

View File

@ -21,6 +21,7 @@
#include <dll/library.h>
#include <dbt.h>
#include <shlobj.h>
static INIT_ONCE FspMountInitOnce = INIT_ONCE_STATIC_INIT;
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
@ -350,6 +351,19 @@ exit:
return Result;
}
static VOID FspMountNotifyShellDriveChange(VOID)
{
HRESULT HResult;
LPITEMIDLIST Pidl;
HResult = SHGetKnownFolderIDList(&FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, 0, &Pidl);
if (SUCCEEDED(HResult))
{
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, Pidl, 0);
CoTaskMemFree(Pidl);
}
}
static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PMountHandle)
{
NTSTATUS Result;
@ -568,7 +582,7 @@ static NTSTATUS FspMountRemove_Directory(HANDLE MountHandle)
return CloseHandle(MountHandle) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
}
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
NTSTATUS FspMountSet_Internal(FSP_MOUNT_DESC *Desc)
{
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
@ -609,7 +623,7 @@ FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
&Desc->MountHandle);
}
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
NTSTATUS FspMountRemove_Internal(FSP_MOUNT_DESC *Desc)
{
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
@ -623,3 +637,81 @@ FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
else
return FspMountRemove_Directory(Desc->MountHandle);
}
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
{
NTSTATUS Result;
BOOLEAN IsDrive;
IsDrive =
(L'*' == Desc->MountPoint[0] && ':' == Desc->MountPoint[1] && L'\0' == Desc->MountPoint[2]) ||
FspPathIsMountmgrDrive(Desc->MountPoint) ||
FspPathIsDrive(Desc->MountPoint);
#if defined(FSP_CFG_REJECT_EARLY_IRP)
/*
* In the original WinFsp design the FSD could accept incoming file system requests
* immediately after the in-kernel file system instance was created. Such requests would
* be queued in the internal FSD queues and only delivered to the user mode file system
* when its dispatcher was started and actively receiving them.
*
* At the same time the original WinFsp API design was that a user mode file system first
* calls FspFileSystemSetMountPoint to create the file system mount point and then calls
* FspFileSystemStartDispatcher to start the dispatcher. This design made sense at the time:
* creating a mount point involved the creation of a symbolic link of one kind or another,
* which could fail for a number of reasons (e.g. drive already exists), so there was no
* point to start the dispatcher if the mounting did not succeed. Compatibility with FUSE
* and the Unix mounting protocol was another consideration.
*
* Unfortunately this API design has proved problematic. The problem is that with the
* proliferation of ways to mount a file system in WinFsp more and more system components and
* third party filters may attempt to access the mount point upon its creation and before the
* file system dispatcher is ready. This can result in various consequences.
*
* In order to properly fix this problem we should probably mandate that a user mode file
* system should start its dispatcher first and then create its mountpoint. This way the user
* mode file system would be ready to handle any requests from system components or third
* party filters during mount point creation. Unfortunately we cannot easily do so because
* of backwards compatibility.
*
* This problem first appeared as an incompatibility with Avast AntiVirus (GitHub issue #221).
* In order to avoid backwards incompatible API changes the "Transact0" work around was
* devised: when the FSD first creates an in-kernel file system it remains inoperative and any
* requests posted to it will fail with STATUS_CANCELLED, until it receives a Transact0
* message (an FSP_FSCTL_TRANSACT message with 0 buffers). In order to enable this work around
* a user mode file system would specify the RejectIrpPriorToTransact0 flag upon creation.
*
* Another instance of this problem appeared when support for directory mounting via the Mount
* Manager was added: mounting would not complete unless the RejectIrpPriorToTransact0 flag
* was set. At this point the RejectIrpPriorToTransact0 was hard coded to 1 in the FSD.
*
* However if we are creating a drive the Transact0 work around is unnecessary and perhaps
* harmful. So in this case send a Transact0 message to the FSD to allow file system requests
* to be queued rather than rejected with STATUS_CANCELLED.
*/
if (IsDrive)
FspFsctlTransact(Desc->VolumeHandle, 0, 0, 0, 0, FALSE);
#endif
Result = FspMountSet_Internal(Desc);
return Result;
}
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
{
NTSTATUS Result;
BOOLEAN IsDrive;
IsDrive =
FspPathIsMountmgrDrive(Desc->MountPoint) ||
FspPathIsDrive(Desc->MountPoint);
Result = FspMountRemove_Internal(Desc);
if (NT_SUCCESS(Result) && IsDrive)
/* send an extra notification to remove the "ghost" drive in the shell's navigation pane */
FspMountNotifyShellDriveChange();
return Result;
}

View File

@ -40,6 +40,8 @@ enum
GetStatus_WaitHint = 0x4000,
};
static SRWLOCK FspServiceLoopLock = SRWLOCK_INIT;
static SRWLOCK FspServiceTableLock = SRWLOCK_INIT;
static SERVICE_TABLE_ENTRYW *FspServiceTable;
static HANDLE FspServiceConsoleModeEvent;
static UINT32 FspServiceConsoleCtrlHandlerDisabled;
@ -220,6 +222,14 @@ FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service)
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
{
/*
* FspServiceLoop can only be called once per process, because of StartServiceCtrlDispatcherW
* (which returns ERROR_SERVICE_ALREADY_RUNNING if called more than once). Unfortunately this
* limitation was never documented and there may be users of FspServiceLoop out there that call
* it more than once per process.
*/
AcquireSRWLockExclusive(&FspServiceLoopLock);
NTSTATUS Result;
SERVICE_TABLE_ENTRYW ServiceTable[2];
@ -236,7 +246,9 @@ FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
ServiceTable[0].lpServiceProc = FspServiceEntry;
ServiceTable[1].lpServiceName = 0;
ServiceTable[1].lpServiceProc = 0;
AcquireSRWLockExclusive(&FspServiceTableLock);
FspServiceTable = ServiceTable;
ReleaseSRWLockExclusive(&FspServiceTableLock);
if (!StartServiceCtrlDispatcherW(ServiceTable))
{
@ -331,11 +343,42 @@ FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
Result = STATUS_SUCCESS;
exit:
AcquireSRWLockExclusive(&FspServiceTableLock);
FspServiceTable = 0;
ReleaseSRWLockExclusive(&FspServiceTableLock);
ReleaseSRWLockExclusive(&FspServiceLoopLock);
return Result;
}
static DWORD WINAPI FspServiceStopLoopThread(PVOID Context);
VOID FspServiceStopLoop(VOID)
{
BOOLEAN HasService;
HANDLE Thread;
AcquireSRWLockShared(&FspServiceTableLock);
HasService = 0 != FspServiceFromTable();
ReleaseSRWLockShared(&FspServiceTableLock);
if (HasService)
{
Thread = CreateThread(0, 0, FspServiceStopLoopThread, 0, 0, 0);
if (0 != Thread)
CloseHandle(Thread);
}
}
static DWORD WINAPI FspServiceStopLoopThread(PVOID Context)
{
AcquireSRWLockShared(&FspServiceTableLock);
FSP_SERVICE *Service = FspServiceFromTable();
if (0 != Service)
FspServiceStop(Service);
ReleaseSRWLockShared(&FspServiceTableLock);
return 0;
}
FSP_API VOID FspServiceStop(FSP_SERVICE *Service)
{
SERVICE_STATUS ServiceStatus;
@ -393,6 +436,7 @@ static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv)
FSP_SERVICE *Service;
Service = FspServiceFromTable();
/* we are subordinate to FspServiceLoop; no need to protect this access with FspServiceTableLock */
if (0 == Service)
{
FspServiceLog(EVENTLOG_ERROR_TYPE,
@ -501,6 +545,7 @@ static DWORD WINAPI FspServiceConsoleModeThread(PVOID Context)
;
Service = FspServiceFromTable();
/* we are subordinate to FspServiceLoop; no need to protect this access with FspServiceTableLock */
if (0 == Service)
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");

214
src/dll/sxs.c Normal file
View File

@ -0,0 +1,214 @@
/**
* @file dll/sxs.c
*
* @copyright 2015-2022 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include <dll/library.h>
static INIT_ONCE FspSxsIdentInitOnce = INIT_ONCE_STATIC_INIT;
static WCHAR FspSxsIdentBuf[32 + 2] = L"";
static BOOLEAN FspSxsIdentInitializeFromFile(VOID)
{
extern HINSTANCE DllInstance;
WCHAR Path[MAX_PATH];
DWORD Size;
HANDLE Handle = INVALID_HANDLE_VALUE;
CHAR Buffer[ARRAYSIZE(FspSxsIdentBuf) - 2];
WCHAR WBuffer[ARRAYSIZE(FspSxsIdentBuf) - 2];
BOOLEAN Result = FALSE;
if (0 == GetModuleFileNameW(DllInstance, Path, MAX_PATH))
goto exit;
Size = lstrlenW(Path);
if (4 < Size &&
(L'.' == Path[Size - 4]) &&
(L'D' == Path[Size - 3] || L'd' == Path[Size - 3]) &&
(L'L' == Path[Size - 2] || L'l' == Path[Size - 2]) &&
(L'L' == Path[Size - 1] || L'l' == Path[Size - 1]) &&
(L'\0' == Path[Size]))
;
else
goto exit;
Size -= 4;
for (PWCHAR P = Path + Size - 1; Path <= P; P--)
{
if (L'\\' == *P)
break;
if (L'-' == *P)
{
/* arch */
Size = (DWORD)(P - Path);
break;
}
}
Path[Size + 0] = L'.';
Path[Size + 1] = L's';
Path[Size + 2] = L'x';
Path[Size + 3] = L's';
Path[Size + 4] = L'\0';
Handle = CreateFileW(
Path,
FILE_READ_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
0,
0);
if (INVALID_HANDLE_VALUE == Handle)
goto exit;
if (!ReadFile(Handle, Buffer, sizeof Buffer, &Size, 0))
goto exit;
for (PCHAR P = Buffer, EndP = P + Size; EndP > P; P++)
if ('\r' == *P || '\n' == *P)
{
Size = (DWORD)(P - Buffer);
break;
}
Size = MultiByteToWideChar(CP_UTF8, 0,
Buffer, Size, WBuffer, ARRAYSIZE(WBuffer));
if (0 == Size)
goto exit;
FspSxsIdentBuf[0] = FSP_SXS_SEPARATOR_CHAR;
memcpy(FspSxsIdentBuf + 1, WBuffer, Size * sizeof(WCHAR));
FspSxsIdentBuf[1 + Size] = L'\0';
Result = TRUE;
exit:
if (INVALID_HANDLE_VALUE != Handle)
CloseHandle(Handle);
return Result;
}
static BOOLEAN FspSxsIdentInitializeFromDirectory(VOID)
{
extern HINSTANCE DllInstance;
WCHAR Path[MAX_PATH];
HANDLE Handle = INVALID_HANDLE_VALUE;
WCHAR FinalPath[MAX_PATH];
PWCHAR P, EndP, Q, EndQ;
PWCHAR Ident = 0;
BOOLEAN Result = FALSE;
if (0 == GetModuleFileNameW(DllInstance, Path, MAX_PATH))
goto exit;
Handle = CreateFileW(
Path,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
0,
0);
if (INVALID_HANDLE_VALUE == Handle)
goto exit;
if (!GetFinalPathNameByHandleW(Handle, FinalPath, MAX_PATH, VOLUME_NAME_NONE))
goto exit;
EndP = FinalPath + lstrlenW(FinalPath);
for (P = EndP - 1; FinalPath <= P; P--)
{
if (L'\\' == *P &&
P + 9 < EndP &&
(L'S' == P[1] || L's' == P[1]) &&
(L'X' == P[2] || L'x' == P[2]) &&
(L'S' == P[3] || L's' == P[3]) &&
L'\\' == P[4] &&
(L'S' == P[5] || L's' == P[5]) &&
(L'X' == P[6] || L'x' == P[6]) &&
(L'S' == P[7] || L's' == P[7]) &&
L'.' == P[8] &&
L'\\' != P[9])
{
Ident = P + 9;
break;
}
}
if (0 == Ident)
goto exit;
FspSxsIdentBuf[0] = FSP_SXS_SEPARATOR_CHAR;
EndQ = FspSxsIdentBuf + (ARRAYSIZE(FspSxsIdentBuf) - 1);
for (P = Ident, Q = FspSxsIdentBuf + 1; EndP > P && EndQ > Q && L'\\' != *P; P++, Q++)
*Q = *P;
*Q = L'\0';
Result = TRUE;
exit:
if (INVALID_HANDLE_VALUE != Handle)
CloseHandle(Handle);
return Result;
}
static BOOL WINAPI FspSxsIdentInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
if (FspSxsIdentInitializeFromFile())
goto exit;
if (FspSxsIdentInitializeFromDirectory())
goto exit;
exit:
return TRUE;
}
FSP_API PWSTR FspSxsIdent(VOID)
{
InitOnceExecuteOnce(&FspSxsIdentInitOnce, FspSxsIdentInitialize, 0, 0);
return FspSxsIdentBuf + 1;
}
PWSTR FspSxsSuffix(VOID)
{
InitOnceExecuteOnce(&FspSxsIdentInitOnce, FspSxsIdentInitialize, 0, 0);
return FspSxsIdentBuf;
}
PWSTR FspSxsAppendSuffix(PWCHAR Buffer, SIZE_T Size, PWSTR Ident)
{
PWSTR Suffix;
SIZE_T IdentSize, SuffixSize;
Suffix = FspSxsSuffix();
IdentSize = lstrlenW(Ident) * sizeof(WCHAR);
SuffixSize = lstrlenW(Suffix) * sizeof(WCHAR);
if (Size < IdentSize + SuffixSize + sizeof(WCHAR))
return L"<INVALID>";
memcpy(Buffer, Ident, IdentSize);
memcpy((PUINT8)Buffer + IdentSize, Suffix, SuffixSize);
*(PWCHAR)((PUINT8)Buffer + IdentSize + SuffixSize) = L'\0';
return Buffer;
}

View File

@ -1188,6 +1188,39 @@ namespace Fsp
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Inform the file system that its dispatcher has been stopped.
/// </summary>
/// <remarks>
/// <para>
/// Prior to WinFsp v2.0 the FSD would never unmount a file system volume unless
/// the user mode file system requested the unmount. Since WinFsp v2.0 it is possible
/// for the FSD to unmount a file system volume without an explicit user mode file system
/// request. For example, this happens when the FSD is being uninstalled.
/// </para><para>
/// A user mode file system can use this operation to determine when its dispatcher
/// has been stopped. The Normally parameter can be used to determine why the dispatcher
/// was stopped: it is TRUE when the file system is being stopped normally (i.e. via the
/// native FspFileSystemStopDispatcher) and FALSE otherwise.
/// </para><para>
/// A file system that uses the Service class infrastructure may use the
/// StopServiceIfNecessary method to correctly handle all cases. The base implementation
/// of this method calls the StopServiceIfNecessary method.
/// </para><para>
/// This operation is the last one that a file system will receive.
/// </para>
/// </remarks>
/// <param name="Normally">
/// TRUE if the file system is being stopped via the native FspFileSystemStopDispatcher.
/// FALSE if the file system is being stopped because of another reason such
/// as driver unload/uninstall.
/// </param>
/// <seealso cref="StopServiceIfNecessary"/>
public virtual void DispatcherStopped(
Boolean Normally)
{
StopServiceIfNecessary(Normally);
}
/* helpers */
/// <summary>
@ -1483,6 +1516,10 @@ namespace Fsp
{
return FullEaInformation.PackedSize(EaName, EaValue, NeedEa);
}
public void StopServiceIfNecessary(Boolean Normally)
{
Api.FspFileSystemStopServiceIfNecessary(IntPtr.Zero, Normally);
}
}
}

View File

@ -1426,6 +1426,21 @@ namespace Fsp
}
}
private static void DispatcherStopped(
IntPtr FileSystemPtr,
Boolean Normally)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
{
FileSystem.DispatcherStopped(Normally);
}
catch (Exception ex)
{
ExceptionHandler(FileSystem, ex);
}
}
static FileSystemHost()
{
_FileSystemInterface.GetVolumeInfo = GetVolumeInfo;
@ -1456,6 +1471,7 @@ namespace Fsp
_FileSystemInterface.SetDelete = SetDelete;
_FileSystemInterface.GetEa = GetEa;
_FileSystemInterface.SetEa = SetEa;
_FileSystemInterface.DispatcherStopped = DispatcherStopped;
_FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
/* Marshal.AllocHGlobal does not zero memory; we must do it ourselves! */

View File

@ -745,6 +745,10 @@ namespace Fsp.Interop
out FileInfo FileInfo);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 Obsolete0();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void DispatcherStopped(
IntPtr FileSystem,
[MarshalAs(UnmanagedType.U1)] Boolean Normally);
}
internal static int Size = IntPtr.Size * 64;
@ -781,6 +785,7 @@ namespace Fsp.Interop
internal Proto.GetEa GetEa;
internal Proto.SetEa SetEa;
internal Proto.Obsolete0 Obsolete0;
internal Proto.DispatcherStopped DispatcherStopped;
/* NTSTATUS (*Reserved[33])(); */
}
@ -907,6 +912,10 @@ namespace Fsp.Interop
UInt32 Length,
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void FspFileSystemStopServiceIfNecessary(
IntPtr FileSystem,
[MarshalAs(UnmanagedType.U1)] Boolean Normally);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAcquireDirectoryBuffer(
ref IntPtr PDirBuffer,
@ -1048,6 +1057,7 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo;
internal static Proto.FspFileSystemAddEa _FspFileSystemAddEa;
internal static Proto.FspFileSystemAddNotifyInfo _FspFileSystemAddNotifyInfo;
internal static Proto.FspFileSystemStopServiceIfNecessary FspFileSystemStopServiceIfNecessary;
internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer;
internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer;
internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer;
@ -1506,6 +1516,7 @@ namespace Fsp.Interop
_FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
_FspFileSystemAddEa = GetEntryPoint<Proto.FspFileSystemAddEa>(Module);
_FspFileSystemAddNotifyInfo = GetEntryPoint<Proto.FspFileSystemAddNotifyInfo>(Module);
FspFileSystemStopServiceIfNecessary = GetEntryPoint<Proto.FspFileSystemStopServiceIfNecessary>(Module);
FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);

View File

@ -62,10 +62,12 @@ static void usage(void)
"\n"
"commands:\n"
" lsvol list file system devices (volumes)\n"
//" list list running file system processes\n"
//" kill kill file system process\n"
" id [NAME|SID|UID] print user id\n"
" perm [PATH|SDDL|UID:GID:MODE] print permissions\n",
" perm [PATH|SDDL|UID:GID:MODE] print permissions\n"
" lsdrv list drivers\n"
" load load driver\n"
" unload unload driver (requires load driver priv)\n"
" ver print version\n",
PROGNAME);
}
@ -237,6 +239,29 @@ NTSTATUS FspToolGetSidFromName(PWSTR Name, PSID *PSid)
return STATUS_SUCCESS;
}
static int ver(int argc, wchar_t **argv)
{
if (1 != argc)
usage();
NTSTATUS Result;
UINT32 Version;
PWSTR SxsIdent;
Result = FspVersion(&Version);
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
SxsIdent = FspSxsIdent();
if (L'\0' == SxsIdent[0])
info("%u.%u", Version >> 16, Version & 0xFFFF);
else
info("%u.%u (SxS=%S)", Version >> 16, Version & 0xFFFF, SxsIdent);
return 0;
}
static NTSTATUS lsvol_dev(PWSTR DeviceName)
{
NTSTATUS Result;
@ -255,7 +280,7 @@ static NTSTATUS lsvol_dev(PWSTR DeviceName)
if (L'\0' == *P)
{
Drive[0] = FspToolGetDriveLetter(&LogicalDrives, VolumeName);
info("%-4S%S", Drive[0] ? Drive : L"", VolumeName);
info("%-4S%S", Drive[0] ? Drive : L"-", VolumeName);
VolumeName = P + 1;
}
@ -541,6 +566,52 @@ static int perm(int argc, wchar_t **argv)
return FspWin32FromNtStatus(Result);
}
static VOID lsdrv_enumfn(PVOID Context, PWSTR ServiceName, BOOLEAN Running)
{
info("%-4s%S", Running ? "R" : "-", ServiceName);
}
static int lsdrv(int argc, wchar_t **argv)
{
if (1 != argc)
usage();
NTSTATUS Result;
Result = FspFsctlEnumServices(lsdrv_enumfn, 0);
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
return 0;
}
static int load(int argc, wchar_t **argv)
{
if (1 != argc)
usage();
NTSTATUS Result;
Result = FspFsctlStartService();
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
return 0;
}
static int unload(int argc, wchar_t **argv)
{
if (1 != argc)
usage();
NTSTATUS Result;
Result = FspFsctlStopService();
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
return 0;
}
int wmain(int argc, wchar_t **argv)
{
argc--;
@ -549,6 +620,9 @@ int wmain(int argc, wchar_t **argv)
if (0 == argc)
usage();
if (0 == invariant_wcscmp(L"ver", argv[0]))
return ver(argc, argv);
else
if (0 == invariant_wcscmp(L"lsvol", argv[0]))
return lsvol(argc, argv);
else
@ -557,6 +631,15 @@ int wmain(int argc, wchar_t **argv)
else
if (0 == invariant_wcscmp(L"perm", argv[0]))
return perm(argc, argv);
else
if (0 == invariant_wcscmp(L"lsdrv", argv[0]))
return lsdrv(argc, argv);
else
if (0 == invariant_wcscmp(L"load", argv[0]))
return load(argc, argv);
else
if (0 == invariant_wcscmp(L"unload", argv[0]))
return unload(argc, argv);
else
usage();

View File

@ -30,4 +30,10 @@
*/
#define FSP_CFG_REJECT_EARLY_IRP
/*
* SxS separator. The '+' in "WinFsp+20220906T173701Z".
*/
#define FSP_SXS_SEPARATOR_CHAR '+'
#define FSP_SXS_SEPARATOR_STRING "+"
#endif

View File

@ -154,8 +154,16 @@ NTSTATUS FspReleaseForModWrite(
FSP_FILE_NODE *FileNode = FileObject->FsContext;
/*
* In some rare cases and under load the mapped page writer's TopLevelIrp
* may be trashed by some outside component (observed on Windows 10 1909).
*/
PIRP TopLevelIrp = IoGetTopLevelIrp();
IoSetTopLevelIrp((PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP);
FspFileNodeRelease(FileNode, Full);
ASSERT((PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP == IoGetTopLevelIrp());
IoSetTopLevelIrp(TopLevelIrp);
FSP_LEAVE("FileObject=%p", FileObject);
}

View File

@ -30,6 +30,7 @@ NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDoIoDeleteDevice(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceReference(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDereference(PDEVICE_OBJECT DeviceObject);
_IRQL_requires_(DISPATCH_LEVEL)
@ -67,13 +68,13 @@ NTSTATUS FspDeviceCopyList(
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
VOID FspDeviceDeleteList(
PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount);
VOID FspDeviceDeleteAll(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspDeviceCreateSecure)
#pragma alloc_text(PAGE, FspDeviceCreate)
#pragma alloc_text(PAGE, FspDeviceInitialize)
#pragma alloc_text(PAGE, FspDeviceDelete)
#pragma alloc_text(PAGE, FspDeviceDoIoDeleteDevice)
#pragma alloc_text(PAGE, FspFsvolDeviceInit)
#pragma alloc_text(PAGE, FspFsvolDeviceFini)
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList)
@ -92,7 +93,6 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsmupDeviceFini)
#pragma alloc_text(PAGE, FspDeviceCopyList)
#pragma alloc_text(PAGE, FspDeviceDeleteList)
#pragma alloc_text(PAGE, FspDeviceDeleteAll)
#endif
NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
@ -218,13 +218,17 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
return;
}
#if DBG
#pragma prefast(suppress:28175, "Debugging only: ok to access DeviceObject->Size")
RtlFillMemory(&DeviceExtension->Kind,
(PUINT8)DeviceObject + DeviceObject->Size - (PUINT8)&DeviceExtension->Kind, 0xBD);
#endif
FspDeviceDoIoDeleteDevice(DeviceObject);
}
IoDeleteDevice(DeviceObject);
VOID FspDeviceDoIoDeleteDevice(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject);
if (0 == InterlockedCompareExchange(&DeviceExtension->DidIoDeleteDevice, 1, 0))
IoDeleteDevice(DeviceObject);
}
BOOLEAN FspDeviceReference(PDEVICE_OBJECT DeviceObject)
@ -942,22 +946,4 @@ VOID FspDeviceDeleteList(
FspFree(DeviceObjects);
}
VOID FspDeviceDeleteAll(VOID)
{
PAGED_CODE();
NTSTATUS Result;
PDEVICE_OBJECT *DeviceObjects = 0;
ULONG DeviceObjectCount = 0;
Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount);
if (!NT_SUCCESS(Result))
return;
for (ULONG i = 0; DeviceObjectCount > i; i++)
FspDeviceDelete(DeviceObjects[i]);
FspDeviceDeleteList(DeviceObjects, DeviceObjectCount);
}
FAST_MUTEX FspDeviceGlobalMutex;

View File

@ -55,6 +55,7 @@ NTSTATUS FspDeviceInitializeAllTimers(VOID)
VOID FspDeviceFinalizeAllTimers(VOID)
{
KeCancelTimer(&FspDeviceTimer);
KeFlushQueuedDpcs();
#if DBG
KIRQL Irql;

View File

@ -205,6 +205,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
ASSERT(sizeof(UINT64) == DirectoryMarker->Length);
DirectoryMarkerFound = DirectoryNextOffset == *(PUINT64)DirectoryMarker->Buffer;
}
continue;
}
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */

View File

@ -22,15 +22,24 @@
#include <sys/driver.h>
DRIVER_INITIALIZE DriverEntry;
static DRIVER_UNLOAD DriverUnload;
static VOID FspDriverMultiVersionInitialize(VOID);
static NTSTATUS FspDriverInitializeDevices(VOID);
static VOID FspDriverFinalizeDevices(VOID);
static VOID FspDriverFinalizeDevicesForUnload(VOID);
static VOID FspDriverFinalizeDevicesEx(BOOLEAN DeleteDevices);
NTSTATUS FspDriverUnload(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(INIT, FspDriverMultiVersionInitialize)
#pragma alloc_text(PAGE, FspDriverInitializeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevicesForUnload)
#pragma alloc_text(PAGE, FspDriverFinalizeDevicesEx)
#pragma alloc_text(PAGE, FspDriverUnload)
#endif
NTSTATUS DriverEntry(
@ -40,7 +49,10 @@ NTSTATUS DriverEntry(
FSP_TRACE_INIT();
FspSxsIdentInitialize(&DriverObject->DriverName);
/* setup the driver object */
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose;
DriverObject->MajorFunction[IRP_MJ_READ] = FspRead;
@ -128,6 +140,7 @@ NTSTATUS DriverEntry(
FspDriverObject = DriverObject;
FspDriverMultiVersionInitialize();
ExInitializeFastMutex(&FspDriverUnloadMutex);
ExInitializeFastMutex(&FspDeviceGlobalMutex);
Result = FspSiloInitialize(FspDriverInitializeDevices, FspDriverFinalizeDevices);
@ -176,6 +189,26 @@ exit:
&DriverObject->DriverName, RegistryPath);
}
VOID DriverUnload(
PDRIVER_OBJECT DriverObject)
{
FSP_ENTER_VOID(PAGED_CODE());
FspDriverFinalizeDevices();
FspDeviceFinalizeAllTimers();
FspProcessBufferFinalize();
FspSiloFinalize();
FSP_TRACE_FINI();
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
&DriverObject->DriverName);
}
static VOID FspDriverMultiVersionInitialize(VOID)
{
FspProcessorCount = KeQueryActiveProcessorCount(0);
@ -206,6 +239,8 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
FSP_SILO_GLOBALS *Globals;
UNICODE_STRING DeviceSddl;
UNICODE_STRING DeviceName;
WCHAR DeviceNameBuf[128];
UNICODE_STRING SymlinkName;
GUID Guid;
NTSTATUS Result;
@ -214,20 +249,46 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
/* create the file system control device objects */
RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL);
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
RtlInitEmptyUnicodeString(&DeviceName, DeviceNameBuf, sizeof DeviceNameBuf);
Result = RtlUnicodeStringPrintf(&DeviceName,
L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME "%wZ",
FspSxsSuffix());
ASSERT(NT_SUCCESS(Result));
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlDiskDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
if (0 != FspSxsIdent()->Length)
{
/* \Device\WinFsp.Disk SxS symlink */
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
Result = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
if (!NT_SUCCESS(Result))
goto exit;
Globals->InitDoneSymlinkDisk = 1;
}
RtlInitEmptyUnicodeString(&DeviceName, DeviceNameBuf, sizeof DeviceNameBuf);
Result = RtlUnicodeStringPrintf(&DeviceName,
L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME "%wZ",
FspSxsSuffix());
ASSERT(NT_SUCCESS(Result));
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != FspSxsIdent()->Length)
{
/* \Device\WinFsp.Net SxS symlink */
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
Result = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
if (!NT_SUCCESS(Result))
goto exit;
Globals->InitDoneSymlinkNet = 1;
}
Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0,
FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE,
&Globals->FsmupDeviceObject);
@ -261,8 +322,9 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
Result = RtlUnicodeStringPrintf(&DeviceName,
0 == ((PULONG)&Guid)[0] && 0 == ((PULONG)&Guid)[1] &&
0 == ((PULONG)&Guid)[2] && 0 == ((PULONG)&Guid)[3] ?
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME :
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "%wZ":
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "%wZ{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
FspSxsSuffix(),
Guid.Data1, Guid.Data2, Guid.Data3,
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
@ -281,12 +343,25 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
* as a file system; we register with the MUP instead.
*/
IoRegisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 1;
/*
* Reference primary device objects to allow for IoDeleteDevice during FspDriverUnload.
*/
ObReferenceObject(Globals->FsctlDiskDeviceObject);
ObReferenceObject(Globals->FsctlNetDeviceObject);
ObReferenceObject(Globals->FsmupDeviceObject);
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (Globals->InitDoneRegisterDisk)
{
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 0;
}
if (0 != Globals->MupHandle)
{
FsRtlDeregisterUncProvider(Globals->MupHandle);
@ -297,11 +372,23 @@ exit:
FspDeviceDelete(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
}
if (Globals->InitDoneSymlinkNet)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkNet = 0;
}
if (0 != Globals->FsctlNetDeviceObject)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
}
if (Globals->InitDoneSymlinkDisk)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkDisk = 0;
}
if (0 != Globals->FsctlDiskDeviceObject)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
@ -318,13 +405,31 @@ static VOID FspDriverFinalizeDevices(VOID)
{
PAGED_CODE();
FspDriverFinalizeDevicesEx(TRUE);
}
static VOID FspDriverFinalizeDevicesForUnload(VOID)
{
PAGED_CODE();
FspDriverFinalizeDevicesEx(FALSE);
}
static VOID FspDriverFinalizeDevicesEx(BOOLEAN DeleteDevices)
{
PAGED_CODE();
FSP_SILO_GLOBALS *Globals;
UNICODE_STRING SymlinkName;
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
if (Globals->InitDoneRegisterDisk)
{
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 0;
}
if (0 != Globals->MupHandle)
{
FsRtlDeregisterUncProvider(Globals->MupHandle);
@ -332,26 +437,119 @@ static VOID FspDriverFinalizeDevices(VOID)
}
if (0 != Globals->FsmupDeviceObject)
{
FspDeviceDelete(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
if (DeleteDevices)
{
FspDeviceDelete(Globals->FsmupDeviceObject);
ObDereferenceObject(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
}
else
FspDeviceDoIoDeleteDevice(Globals->FsmupDeviceObject);
}
if (Globals->InitDoneSymlinkNet)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkNet = 0;
}
if (0 != Globals->FsctlNetDeviceObject)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
if (DeleteDevices)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
ObDereferenceObject(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
}
else
FspDeviceDoIoDeleteDevice(Globals->FsctlNetDeviceObject);
}
if (Globals->InitDoneSymlinkDisk)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkDisk = 0;
}
if (0 != Globals->FsctlDiskDeviceObject)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0;
if (DeleteDevices)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
ObDereferenceObject(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0;
}
else
FspDeviceDoIoDeleteDevice(Globals->FsctlDiskDeviceObject);
}
FspSiloDereferenceGlobals(Globals);
}
NTSTATUS FspDriverUnload(
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_UNLOAD == IrpSp->Parameters.FileSystemControl.FsControlCode);
NTSTATUS Result;
UNICODE_STRING DriverServiceName, DriverName, Remain;
WCHAR DriverServiceNameBuf[64 + 256];
PDEVICE_OBJECT *DeviceObjects = 0;
ULONG DeviceObjectCount = 0;
if (!FspSiloIsHost())
return STATUS_INVALID_DEVICE_REQUEST;
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_LOAD_DRIVER_PRIVILEGE), UserMode))
return STATUS_PRIVILEGE_NOT_HELD;
ExAcquireFastMutexUnsafe(&FspDriverUnloadMutex);
if (!FspDriverUnloadDone)
{
FspFileNameSuffix(&FspDriverObject->DriverName, &Remain, &DriverName);
RtlInitEmptyUnicodeString(&DriverServiceName, DriverServiceNameBuf, sizeof DriverServiceNameBuf);
Result = RtlUnicodeStringPrintf(&DriverServiceName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%wZ", &DriverName);
if (!NT_SUCCESS(Result))
goto exit;
Result = ZwUnloadDriver(&DriverServiceName);
if (!NT_SUCCESS(Result))
goto exit;
FspSiloEnumerate(FspDriverFinalizeDevicesForUnload);
FspDriverFinalizeDevicesForUnload();
Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount);
if (NT_SUCCESS(Result))
{
for (ULONG I = 0; DeviceObjectCount > I; I++)
{
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObjects[I]);
if (FspFsvolDeviceExtensionKind == DeviceExtension->Kind)
FspIoqStop(((FSP_FSVOL_DEVICE_EXTENSION *)DeviceExtension)->Ioq, FALSE);
}
FspDeviceDeleteList(DeviceObjects, DeviceObjectCount);
}
FspDriverUnloadDone = TRUE;
}
Result = STATUS_SUCCESS;
exit:
ExReleaseFastMutexUnsafe(&FspDriverUnloadMutex);
return Result;
}
PDRIVER_OBJECT FspDriverObject;
FAST_IO_DISPATCH FspFastIoDispatch;
CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
FAST_MUTEX FspDriverUnloadMutex;
BOOLEAN FspDriverUnloadDone;
ULONG FspProcessorCount;
FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;

View File

@ -364,6 +364,10 @@ VOID FspTraceNtStatus(const char *file, int line, const char *func, NTSTATUS Sta
/* missing typedef */
typedef const void *PCVOID;
/* driver unload */
NTSTATUS FspDriverUnload(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
/* driver major functions */
_Function_class_(DRIVER_DISPATCH)
_IRQL_requires_max_(APC_LEVEL)
@ -739,23 +743,34 @@ LONG FspCompareUnicodeString(
PCUNICODE_STRING String2,
BOOLEAN CaseInsensitive);
/* SxS */
VOID FspSxsIdentInitialize(PUNICODE_STRING DriverName);
PUNICODE_STRING FspSxsIdent(VOID);
PUNICODE_STRING FspSxsSuffix(VOID);
/* silos */
typedef struct
{
PVOID Silo;
LIST_ENTRY ListEntry;
PDEVICE_OBJECT FsctlDiskDeviceObject;
PDEVICE_OBJECT FsctlNetDeviceObject;
PDEVICE_OBJECT FsmupDeviceObject;
HANDLE MupHandle;
WCHAR FsmupDeviceNameBuf[64];
WCHAR FsmupDeviceNameBuf[128];
UINT32 InitDoneSymlinkDisk:1, InitDoneSymlinkNet:1, InitDoneRegisterDisk:1;
} FSP_SILO_GLOBALS;
typedef NTSTATUS (*FSP_SILO_INIT_CALLBACK)(VOID);
typedef VOID (*FSP_SILO_FINI_CALLBACK)(VOID);
typedef VOID (*FSP_SILO_ENUM_CALLBACK)(VOID);
BOOLEAN FspSiloIsHost(VOID);
NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals);
VOID FspSiloDereferenceGlobals(FSP_SILO_GLOBALS *Globals);
VOID FspSiloGetContainerId(GUID *ContainerId);
NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini);
NTSTATUS FspSiloPostInitialize(VOID);
VOID FspSiloFinalize(VOID);
VOID FspSiloEnumerate(FSP_SILO_ENUM_CALLBACK EnumFn);
/* process buffers */
#define FspProcessBufferSizeMax (64 * 1024)
@ -1182,8 +1197,8 @@ typedef struct
KSPIN_LOCK SpinLock;
LONG RefCount;
UINT32 Kind;
/* IoTimer emulation */
FSP_DEVICE_TIMER DeviceTimer;
FSP_DEVICE_TIMER DeviceTimer; /* IoTimer emulation */
LONG DidIoDeleteDevice;
} FSP_DEVICE_EXTENSION;
typedef struct
{
@ -1285,6 +1300,7 @@ NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
PDEVICE_OBJECT *PDeviceObject);
NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDoIoDeleteDevice(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceReference(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDereference(PDEVICE_OBJECT DeviceObject);
static inline
@ -1467,7 +1483,6 @@ NTSTATUS FspDeviceCopyList(
PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount);
VOID FspDeviceDeleteList(
PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount);
VOID FspDeviceDeleteAll(VOID);
NTSTATUS FspDeviceInitializeAllTimers(VOID);
VOID FspDeviceFinalizeAllTimers(VOID);
NTSTATUS FspDeviceInitializeTimer(PDEVICE_OBJECT DeviceObject,
@ -1999,6 +2014,8 @@ FSP_MV_CcCoherencyFlushAndPurgeCache(
extern PDRIVER_OBJECT FspDriverObject;
extern FAST_IO_DISPATCH FspFastIoDispatch;
extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
extern FAST_MUTEX FspDriverUnloadMutex;
extern BOOLEAN FspDriverUnloadDone;
extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[];
extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[];
extern FAST_MUTEX FspDeviceGlobalMutex;

View File

@ -8,7 +8,7 @@ Provider = !Provider!
[DestinationDirs]
DefaultDestDir = 12
[DefaultInstall]
[DefaultInstall.!ArchDecoration!]
CopyFiles = Driver.CopyFiles
[Driver.CopyFiles]

View File

@ -128,6 +128,9 @@ static NTSTATUS FspFsctlFileSystemControl(
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeNotify(FsctlDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_UNLOAD:
Result = FspDriverUnload(FsctlDeviceObject, Irp, IrpSp);
break;
default:
if (CTL_CODE(0, 0xC00, 0, 0) ==
(IrpSp->Parameters.FileSystemControl.FsControlCode & CTL_CODE(0, 0xC00, 0, 0)))
@ -728,6 +731,7 @@ static NTSTATUS FspFsvolFileSystemControl(
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_QUERY_WINFSP:
case FSCTL_IS_VOLUME_MOUNTED:
Irp->IoStatus.Information = 0;
Result = STATUS_SUCCESS;
break;

View File

@ -123,6 +123,27 @@ NTSTATUS FspProcessBufferInitialize(VOID)
VOID FspProcessBufferFinalize(VOID)
{
PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, TRUE);
/*
* Free any items in our process hash table.
* Any virtual memory was released when the corresponding processes went away.
*/
for (ULONG HashIndex = 0; ProcessBufferBucketCount > HashIndex; HashIndex++)
{
for (FSP_PROCESS_BUFFER_ITEM *Item = ProcessBufferBuckets[HashIndex], *DictNext; Item; Item = DictNext)
{
for (FSP_PROCESS_BUFFER_LIST_ENTRY *P = Item->BufferList, *Next; P; P = Next)
{
Next = P->Next;
FspFree(P);
}
DictNext = Item->DictNext;
FspFree(Item);
}
ProcessBufferBuckets[HashIndex] = 0;
}
}
static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)

View File

@ -110,6 +110,9 @@ static FSP_SILO_INIT_CALLBACK FspSiloInitCallback;
static FSP_SILO_FINI_CALLBACK FspSiloFiniCallback;
static BOOLEAN FspSiloInitDone = FALSE;
static FAST_MUTEX FspSiloListMutex;
static LIST_ENTRY FspSiloList;
static FSP_SILO_GLOBALS FspSiloHostGlobals;
#define FSP_SILO_MONITOR_REGISTRATION_VERSION 1
@ -125,6 +128,11 @@ static FSP_SILO_GLOBALS FspSiloHostGlobals;
}
#define CALL(n) (FspSilo ## n)
BOOLEAN FspSiloIsHost(VOID)
{
return !FspSiloInitDone || 0 == CALL(PsGetCurrentServerSilo)();
}
NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals)
{
FSP_PESILO Silo;
@ -191,6 +199,7 @@ static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
if (!NT_SUCCESS(Result))
goto exit;
RtlZeroMemory(Globals, sizeof(FSP_SILO_GLOBALS));
Globals->Silo = Silo;
/* PsInsertSiloContext adds reference to Globals */
Result = CALL(PsInsertSiloContext)(Silo, ContextSlot, Globals);
@ -198,6 +207,9 @@ static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
goto exit;
Inserted = TRUE;
FsRtlEnterFileSystem();
ExAcquireFastMutexUnsafe(&FspSiloListMutex);
if (0 != FspSiloInitCallback)
{
FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo);
@ -205,6 +217,12 @@ static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
}
if (NT_SUCCESS(Result))
InsertTailList(&FspSiloList, &Globals->ListEntry);
ExReleaseFastMutexUnsafe(&FspSiloListMutex);
FsRtlExitFileSystem();
exit:
if (!NT_SUCCESS(Result))
{
@ -239,6 +257,11 @@ static VOID NTAPI FspSiloMonitorTerminateCallback(FSP_PESILO Silo)
Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals);
if (!NT_SUCCESS(Result))
return;
FsRtlEnterFileSystem();
ExAcquireFastMutexUnsafe(&FspSiloListMutex);
RemoveEntryList(&Globals->ListEntry);
CALL(PsDereferenceSiloContext)(Globals);
Globals = 0;
@ -249,6 +272,9 @@ static VOID NTAPI FspSiloMonitorTerminateCallback(FSP_PESILO Silo)
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
}
ExReleaseFastMutexUnsafe(&FspSiloListMutex);
FsRtlExitFileSystem();
/* PsRemoveSiloContext removes reference to Globals (possibly freeing it) */
CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0);
}
@ -257,6 +283,9 @@ NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK F
{
NTSTATUS Result = STATUS_SUCCESS;
ExInitializeFastMutex(&FspSiloListMutex);
InitializeListHead(&FspSiloList);
if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS5))
{
ULONG Fail = 0;
@ -329,8 +358,47 @@ VOID FspSiloFinalize(VOID)
CALL(PsUnregisterSiloMonitor)(FspSiloMonitor);
#if DBG
FsRtlEnterFileSystem();
ExAcquireFastMutexUnsafe(&FspSiloListMutex);
ASSERT(IsListEmpty(&FspSiloList));
ExReleaseFastMutexUnsafe(&FspSiloListMutex);
FsRtlExitFileSystem();
#endif
FspSiloMonitor = 0;
FspSiloInitCallback = 0;
FspSiloFiniCallback = 0;
FspSiloInitDone = FALSE;
}
VOID FspSiloEnumerate(FSP_SILO_ENUM_CALLBACK EnumFn)
{
KAPC_STATE ApcState;
PLIST_ENTRY ListEntry;
FSP_SILO_GLOBALS *Globals;
FsRtlEnterFileSystem();
ExAcquireFastMutexUnsafe(&FspSiloListMutex);
if (!IsListEmpty(&FspSiloList))
{
KeStackAttachProcess(PsInitialSystemProcess, &ApcState);
for (ListEntry = FspSiloList.Flink;
&FspSiloList != ListEntry;
ListEntry = ListEntry->Flink)
{
Globals = CONTAINING_RECORD(ListEntry, FSP_SILO_GLOBALS, ListEntry);
FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Globals->Silo);
EnumFn();
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
}
KeUnstackDetachProcess(&ApcState);
}
ExReleaseFastMutexUnsafe(&FspSiloListMutex);
FsRtlExitFileSystem();
}

71
src/sys/sxs.c Normal file
View File

@ -0,0 +1,71 @@
/**
* @file sys/sxs.c
*
* @copyright 2015-2022 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include <sys/driver.h>
VOID FspSxsIdentInitialize(PUNICODE_STRING DriverName);
PUNICODE_STRING FspSxsIdent(VOID);
PUNICODE_STRING FspSxsSuffix(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, FspSxsIdentInitialize)
#endif
static WCHAR FspSxsIdentBuf[32 + 1] = L"";
static UNICODE_STRING FspSxsIdentStr = { 0, sizeof FspSxsIdentBuf - 1, FspSxsIdentBuf + 1 };
static UNICODE_STRING FspSxsSuffixStr = { 0, sizeof FspSxsIdentBuf, FspSxsIdentBuf };
VOID FspSxsIdentInitialize(PUNICODE_STRING DriverName)
{
PWCHAR Ident = 0;
USHORT Length;
for (PWCHAR P = DriverName->Buffer + DriverName->Length / sizeof(WCHAR) - 1; DriverName->Buffer <= P; P--)
{
if (L'\\' == *P)
break;
if (FSP_SXS_SEPARATOR_CHAR == *P)
{
Ident = P;
break;
}
}
if (0 == Ident)
return;
Length = (USHORT)(((PUINT8)DriverName->Buffer + DriverName->Length) - (PUINT8)Ident);
if (Length > sizeof FspSxsIdentBuf)
Length = sizeof FspSxsIdentBuf;
RtlCopyMemory(FspSxsIdentBuf, Ident, Length);
FspSxsIdentStr.Length = Length - sizeof(WCHAR);
FspSxsSuffixStr.Length = Length;
}
PUNICODE_STRING FspSxsIdent(VOID)
{
return &FspSxsIdentStr;
}
PUNICODE_STRING FspSxsSuffix(VOID)
{
return &FspSxsSuffixStr;
}

View File

@ -27,6 +27,7 @@ if X%~nx0==Xbuild-choco.bat (
set BuildArm64=yes
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
set BuildArm64=no
set UseDotnetSdk=yes
)
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
set BuildArm64=no
@ -42,8 +43,11 @@ call "%~dp0vcvarsall.bat" x64
if not X%SignedPackage%==X (
if not exist "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi" (echo previous build not found >&2 & exit /b 1)
if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
set Version=
for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do set Version=%%~nf
set Version=!Version:%MyProductFileName%-=!
del "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi"
if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg"
if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.!Version!.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.!Version!.nupkg"
for /R "%SignedPackage%" %%f in (*.sys) do (
copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
)
@ -70,6 +74,13 @@ if X%SignedPackage%==X (
if errorlevel 1 goto fail
)
if X%UseDotnetSdk%==Xyes (
dotnet build ./dotnet/winfsp.net.csproj -c "%Configuration%" -p:Platform=AnyCPU -p:SolutionDir="%cd%"\
if errorlevel 1 goto fail
dotnet build ./testing/memfs-dotnet.csproj -c "%Configuration%" -p:Platform=AnyCPU -p:SolutionDir="%cd%"\
if errorlevel 1 goto fail
)
pushd build\%Configuration%
set signfiles=^
%MyProductFileName%-a64.sys %MyProductFileName%-x64.sys %MyProductFileName%-x86.sys^
@ -78,13 +89,19 @@ if X%SignedPackage%==X (
launchctl-a64.exe launchctl-x64.exe launchctl-x86.exe^
fsptool-a64.exe fsptool-x64.exe fsptool-x86.exe^
memfs-a64.exe memfs-x64.exe memfs-x86.exe memfs-dotnet-msil.exe
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com !signfiles!
if errorlevel 1 set /a signfail=signfail+1
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 !signfiles!
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 !signfiles!
if errorlevel 1 set /a signfail=signfail+1
popd
pushd build\%Configuration%
mkdir unsigned
for %%f in (!signfiles!) do (
copy "%%f" unsigned >nul
)
pushd unsigned
signtool remove /q /s !signfiles!
if errorlevel 1 set /a signfail=signfail+1
popd
echo .OPTION EXPLICIT >driver.ddf
echo .Set CabinetFileCountThreshold=0 >>driver.ddf
echo .Set FolderFileCountThreshold=0 >>driver.ddf
@ -99,13 +116,13 @@ if X%SignedPackage%==X (
echo .Set DiskDirectory1=. >>driver.ddf
echo .Set DestinationDir=a64 >>driver.ddf
echo driver-a64.inf >>driver.ddf
echo %MyProductFileName%-a64.sys >>driver.ddf
echo unsigned\%MyProductFileName%-a64.sys >>driver.ddf
echo .Set DestinationDir=x64 >>driver.ddf
echo driver-x64.inf >>driver.ddf
echo %MyProductFileName%-x64.sys >>driver.ddf
echo unsigned\%MyProductFileName%-x64.sys >>driver.ddf
echo .Set DestinationDir=x86 >>driver.ddf
echo driver-x86.inf >>driver.ddf
echo %MyProductFileName%-x86.sys >>driver.ddf
echo unsigned\%MyProductFileName%-x86.sys >>driver.ddf
makecab /F driver.ddf
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 driver.cab
if errorlevel 1 set /a signfail=signfail+1
@ -116,10 +133,8 @@ devenv winfsp.sln /build "Installer.%Configuration%|x86"
if errorlevel 1 goto fail
for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do (
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com /d %MsiName% %%f
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
if errorlevel 1 set /a signfail=signfail+1
REM signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
REM if errorlevel 1 set /a signfail=signfail+1
)
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.

View File

@ -27,6 +27,7 @@ for %%f in (
winfsp-%Suffix%.dll
winfsp-tests-%Suffix%.exe
memfs-%Suffix%.exe
fsptool-%Suffix%.exe
deploy-setup.bat
docker-run.bat
) do (

View File

@ -1,28 +1,53 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
echo WINFSP INSTALLATION DIRECTORY AND LAUNCHER REGISTRATIONS
reg query HKLM\SOFTWARE\WinFsp /s /reg:32
REM Determine the SxS (side-by-side) identifier.
set SxsDir=
set RegKey="HKLM\SOFTWARE\WinFsp"
set RegVal="SxsDir"
reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do (
set SxsDir=%%j
)
)
set SxsSuffix=
if defined SxsDir (
set SxsSuffix=!SxsDir:*SxS\sxs.=!
if !SxsSuffix:~-1!==\ set SxsSuffix=!SxsSuffix:~0,-1!
set SxsSuffix=+!SxsSuffix!
)
echo WINFSP FSD
sc query WinFsp!SxsSuffix!
sc qc WinFsp!SxsSuffix!
sc sdshow WinFsp!SxsSuffix!
echo.
echo.
echo WINFSP DLL REGISTRATIONS
echo WINFSP DLL
reg query HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Np\NetworkProvider
reg query HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\WinFsp
echo.
echo WINFSP FSD CONFIGURATION AND STATUS
sc query WinFsp
sc qc WinFsp
sc sdshow WinFsp
echo.
echo WINFSP LAUNCHER SERVICE CONFIGURATION AND STATUS
echo WINFSP LAUNCHER
sc query WinFsp.Launcher
sc qc WinFsp.Launcher
sc sdshow WinFsp.Launcher
echo.
echo.
echo WINFSP REGISTRY
reg query HKLM\SOFTWARE\WinFsp /s /reg:32
echo.
echo FILE SYSTEM FILTERS (REQUIRES ADMINISTRATOR)
fltmc filters
echo.
echo.
echo OS INFORMATION
systeminfo

View File

@ -0,0 +1,17 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
if "%1"=="" (
cd %~dp0..\..
) else (
cd "%1"
)
if exist winfsp.sln (
powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0remove-sln-project.ps1' -Path '%cd%\winfsp.sln' -Match '*dotnet*'
) else (
echo winfsp.sln not found in %cd%
)

View File

@ -0,0 +1,12 @@
param (
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][string]$Match
)
echo "Removing projects that match $($Match) from $($Path)"
Get-Content $Path -Delimiter 'EndProject' |
Where-Object {$_ -notlike $Match} |
Set-Content "$($Path).new"
Move-Item -Path "$($Path).new" -Destination $Path -Force

View File

@ -68,6 +68,27 @@ function Get-ReleaseInfo ($Tag) {
}
}
function Get-HwapiCredentials {
$Credentials = (& "$ProjectRoot\tools\wincred.ps1" get "Hardware Dashboard API")
if ($Credentials) {
try { $Credentials = ConvertFrom-Json $Credentials[1] } catch {;}
}
if ($Credentials -and $Credentials.TenantId -and $Credentials.ClientId -and $Credentials.ClientId) {
return $Credentials
}
}
function Start-Sdcm {
Start-Job -ArgumentList $args -ScriptBlock {
$env:SDCM_CREDS_TENANTID = $using:HwapiCredentials.TenantId
$env:SDCM_CREDS_CLIENTID = $using:HwapiCredentials.ClientId
$env:SDCM_CREDS_KEY = $using:HwapiCredentials.Key
$env:SDCM_CREDS_URL = "https://manage.devcenter.microsoft.com"
$env:SDCM_CREDS_URLPREFIX = "v2.0/my"
& "$using:ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -creds envonly @args
} | Receive-Job -Wait -AutoRemoveJob
}
function Get-FileVersion ($FileName) {
return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
}
@ -96,6 +117,12 @@ function Check-Prerequisites {
exit 1
}
# check scdm.exe
if (!(Get-Command "$ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find sdcm.exe"
exit 1
}
# check gh.exe
if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find gh.exe"
@ -137,6 +164,17 @@ function Check-Prerequisites {
exit 1
}
# check hardware dashboard api credentials
$script:HwapiCredentials = Get-HwapiCredentials
if (!$script:HwapiCredentials) {
Write-Stderr "error: cannot get Hardware Dashboard API credentials"
Write-Stderr ' The expected format of the credentials is as follows:'
Write-Stderr ' TargetName: Hardware Dashboard API'
Write-Stderr ' UserName: Credentials'
Write-Stderr ' Password: {"TenantId":"TENANTID","ClientId":"CLIENTID","Key":"KEY"}'
exit 1
}
if ($State -contains $Name) {
if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
Write-Stderr "error: invalid state for tag $Tag"
@ -149,6 +187,12 @@ function Check-Prerequisites {
}
function Check-Assets {
# check driver.cab
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\driver.cab" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find driver.cab"
exit 1
}
# check winfsp.msi
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp*.msi"
@ -161,9 +205,15 @@ function Check-Assets {
exit 1
}
# check winfsp.net.nupkg
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp.net.*.nupkg" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp.net.*.nupkg"
exit 1
}
# check winfsp.nupkg
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.nupkg" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp*.nupkg"
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp.*.nupkg" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp.*.nupkg"
exit 1
}
@ -186,8 +236,215 @@ function Build-AssetsPhase1 {
Write-Stdout @"
Upload file driver.cab to Microsoft Partner Center for attestation signing.
When the file has been signed, download and extract to ~\Downloads\drivers
Assets have been built but are not properly signed.
Signable assets are ready for submission to the hardware dashboard.
"@
}
}
function Submit-AssetsToHwapi {
Task -ScriptBlock {
Check-Assets
$MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
$MsiName = Split-Path -Leaf $MsiFile
if ($MsiName -match "winfsp-(.+)\.msi") {
$Version = $matches[1]
}
if (!$Version) {
Write-Stderr "error: cannot determine version for winfsp.msi"
exit 1
}
$DocRequestedSignatures = @()
$Documentation = Invoke-WebRequest -Uri "https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
$Documentation = $Documentation.Content
$List = $false
foreach ($Line in $Documentation -Split "`n") {
if ($Line -match "^### List of Operating System Codes") {
$List = $true
} elseif ($Line -match "^###") {
$List = $false
} elseif ($List -and $Line -cmatch "\| *(WINDOWS_v100_[^| ]+) *\|") {
$DocRequestedSignatures += $matches[1]
}
}
if ($DocRequestedSignatures.length -lt 32) {
Write-Stderr "error: cannot determine signatures to request"
Write-Stderr ' Does the document at the URL below still contain a "List of Operating System Codes":'
Write-Stderr " https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
exit 1
}
# start with the base signatures and add any new ones found in the docs
$RequestedSignatures = @(
"WINDOWS_v100_TH2_FULL"
"WINDOWS_v100_X64_TH2_FULL"
"WINDOWS_v100_RS1_FULL"
"WINDOWS_v100_X64_RS1_FULL"
"WINDOWS_v100_RS2_FULL"
"WINDOWS_v100_X64_RS2_FULL"
"WINDOWS_v100_RS3_FULL"
"WINDOWS_v100_X64_RS3_FULL"
"WINDOWS_v100_ARM64_RS3_FULL"
"WINDOWS_v100_RS4_FULL"
"WINDOWS_v100_X64_RS4_FULL"
"WINDOWS_v100_ARM64_RS4_FULL"
"WINDOWS_v100_RS5_FULL"
"WINDOWS_v100_X64_RS5_FULL"
"WINDOWS_v100_ARM64_RS5_FULL"
"WINDOWS_v100_19H1_FULL"
"WINDOWS_v100_X64_19H1_FULL"
"WINDOWS_v100_ARM64_19H1_FULL"
"WINDOWS_v100_VB_FULL"
"WINDOWS_v100_X64_VB_FULL"
"WINDOWS_v100_ARM64_VB_FULL"
"WINDOWS_v100_X64_CO_FULL"
"WINDOWS_v100_ARM64_CO_FULL"
"WINDOWS_v100_X64_NI_FULL"
"WINDOWS_v100_ARM64_NI_FULL"
)
foreach ($Signature in $DocRequestedSignatures) {
if ($RequestedSignatures -contains $Signature) {
continue
}
if ($Signature.Contains("_SERVER_")) {
continue
}
if ($Signature -eq "WINDOWS_v100_TH1_FULL") {
continue
}
if ($Signature -eq "WINDOWS_v100_X64_TH1_FULL") {
continue
}
$RequestedSignatures += $Signature
Write-Stdout "New doc signature: $Signature"
}
$CreateProduct = @{
createType = "product"
createProduct = @{
productName = "winfsp-$Version"
testHarness = "attestation"
deviceType = "internalExternal"
requestedSignatures = $RequestedSignatures
# deviceMetaDataIds = $null
# firmwareVersion = "0"
# isTestSign = $false
# isFlightSign = $false
# markettingNames = $null
# selectedProductTypes = $null
# additionalAttributes = $null
}
}
$CreateSubmission = @{
createType = "submission"
createSubmission = @{
name = "winfsp-$Version"
type = "initial"
}
}
New-Item "$ProjectRoot\build\VStudio\build\Release\hwapi" -Type Directory -ErrorAction SilentlyContinue >$null
ConvertTo-Json $CreateProduct | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json"
ConvertTo-Json $CreateSubmission | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json"
Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json" | Tee-Object -Variable Output
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot create product on hardware dashboard"
exit 1
}
if (-not ([string]$Output -match "--- Product: (\d+)")) {
Write-Stderr "error: cannot get product id from hardware dashboard"
exit 1
}
$ProductId = $matches[1]
Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json" -productid $ProductId | Tee-Object -Variable Output
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot create submission on hardware dashboard"
exit 1
}
if (-not ([string]$Output -match "---- Submission: (\d+)")) {
Write-Stderr "error: cannot get submission id from hardware dashboard"
exit 1
}
$SubmissionId = $matches[1]
Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId" -Value $ProductId
Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId" -Value $SubmissionId
Write-Stdout @"
Product submission has been prepared on hardware dashboard.
"@
}
}
function Upload-AssetsToHwapi {
Task -ScriptBlock {
Check-Assets
$ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
$SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
Start-Sdcm -upload "$ProjectRoot\build\VStudio\build\Release\driver.cab" -productid $ProductId -submissionid $SubmissionId
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot upload driver.cab to hardware dashboard"
exit 1
}
Start-Sdcm -commit -productid $ProductId -submissionid $SubmissionId
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot commit submission to hardware dashboard"
exit 1
}
Write-Stdout @"
Signable assets have been uploaded to the hardware dashboard.
"@
}
}
function Download-AssetsFromHwapi {
Task -ScriptBlock {
Check-Assets
$ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
$SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
Remove-Item -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue
Start-Sdcm -download "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -productid $ProductId -submissionid $SubmissionId
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot download signed drivers from hardware dashboard"
exit 1
}
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot download signed drivers from hardware dashboard"
exit 1
}
$ExpandError = ""
Expand-Archive "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -DestinationPath "$ProjectRoot\build\VStudio\build\Release\hwapi" -ErrorVariable ExpandError
if ($ExpandError) {
Write-Stderr "error: cannot expand signed drivers archive"
exit 1
}
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot expand signed drivers archive"
exit 1
}
Write-Stdout @"
Signable assets have been downloaded and can be used to complete the build.
"@
}
@ -198,16 +455,16 @@ function Build-AssetsPhase2 {
Check-Assets
# check signed drivers folder
if (!(Test-Path ~\Downloads\drivers -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find ~\Downloads\drivers"
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find hwapi\drivers"
exit 1
}
$SignedPackage = Resolve-Path ~\Downloads\drivers
$SignedPackage = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers"
$VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys"
if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) {
Write-Stderr "error: incompatible versions in ~\Downloads\drivers"
Write-Stderr "error: incompatible versions in hwapi\drivers"
exit 1
}
@ -231,10 +488,6 @@ function Make-GitHubRelease {
Task -ScriptBlock {
Check-Assets
if ((Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi") -match "\\winfsp-(.+)\.msi") {
$Version = $matches[1]
}
$DownloadColor = "blue"
$PrereleaseOpt = ""
if ($ReleaseInfo.Prerelease) {
@ -242,16 +495,34 @@ function Make-GitHubRelease {
$PrereleaseOpt = "-p"
}
$ReleaseNotes = @"
[![Download WinFsp](https://img.shields.io/badge/-Download%20WinFsp-$DownloadColor.svg?style=for-the-badge&labelColor=grey&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0ODAgNDgwIj48cGF0aCBkPSJNMzg3LjAwMiAyMDEuMDAxQzM3Mi45OTggMTMyLjAwMiAzMTIuOTk4IDgwIDI0MCA4MGMtNTcuOTk4IDAtMTA3Ljk5OCAzMi45OTgtMTMyLjk5OCA4MS4wMDFDNDcuMDAyIDE2Ny4wMDIgMCAyMTcuOTk4IDAgMjgwYzAgNjUuOTk2IDUzLjk5OSAxMjAgMTIwIDEyMGgyNjBjNTUgMCAxMDAtNDUgMTAwLTEwMCAwLTUyLjk5OC00MC45OTYtOTYuMDAxLTkyLjk5OC05OC45OTl6TTIwOCAyNTJ2LTc2aDY0djc2aDY4TDI0MCAzNTIgMTQwIDI1Mmg2OHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://github.com/billziss-gh/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
$MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
$ZipFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip"
$MsiName = Split-Path -Leaf $MsiFile
$ZipName = Split-Path -Leaf $ZipFile
$MsiHash = (Get-FileHash -Algorithm SHA256 $MsiFile).Hash
$ZipHash = (Get-FileHash -Algorithm SHA256 $ZipFile).Hash
[VirusTotal Scan Results]()
if ($MsiName -match "winfsp-(.+)\.msi") {
$Version = $matches[1]
}
$ReleaseNotes = @"
[![Download WinFsp](https://img.shields.io/badge/-Download%20WinFsp-$DownloadColor.svg?style=for-the-badge&labelColor=grey&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0ODAgNDgwIj48cGF0aCBkPSJNMzg3LjAwMiAyMDEuMDAxQzM3Mi45OTggMTMyLjAwMiAzMTIuOTk4IDgwIDI0MCA4MGMtNTcuOTk4IDAtMTA3Ljk5OCAzMi45OTgtMTMyLjk5OCA4MS4wMDFDNDcuMDAyIDE2Ny4wMDIgMCAyMTcuOTk4IDAgMjgwYzAgNjUuOTk2IDUzLjk5OSAxMjAgMTIwIDEyMGgyNjBjNTUgMCAxMDAtNDUgMTAwLTEwMCAwLTUyLjk5OC00MC45OTYtOTYuMDAxLTkyLjk5OC05OC45OTl6TTIwOCAyNTJ2LTc2aDY0djc2aDY4TDI0MCAzNTIgMTQwIDI1Mmg2OHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://github.com/winfsp/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion)
$($ReleaseInfo.Text -join "`n")
<details>
<summary>
<b>BUILD HASHES (SHA256)</b>
<p/>
</summary>
- **``$MsiName``**: $MsiHash
- **``$ZipName``**: $ZipHash
</details>
"@
gh release create $ReleaseInfo.Tag --draft --title "WinFsp $($ReleaseInfo.ProductVersion)" --notes "$ReleaseNotes" $PrereleaseOpt (Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi") (Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip")
gh release create $ReleaseInfo.Tag --draft --title "WinFsp $($ReleaseInfo.ProductVersion)" --notes "$ReleaseNotes" $PrereleaseOpt $MsiFile $ZipFile
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot create GitHub release"
exit 1
@ -305,12 +576,32 @@ Push the winfsp.sym repository to GitHub.
}
}
function Make-NugetRelease {
Task -ScriptBlock {
Check-Assets
Push-Location "$ProjectRoot\build\VStudio\build\Release"
nuget push (Resolve-Path winfsp.net.[0-9]*.nupkg) -Source https://api.nuget.org/v3/index.json
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot push to Nuget"
exit 1
}
Pop-Location
Write-Stdout @"
Nuget release for $($ReleaseInfo.Tag) has been pushed.
"@
}
}
function Make-ChocoRelease {
Task -ScriptBlock {
Check-Assets
Push-Location "$ProjectRoot\build\VStudio\build\Release"
choco push
choco push (Resolve-Path winfsp.[0-9]*.nupkg)
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot push to Chocolatey"
exit 1
@ -335,7 +626,12 @@ Check-Prerequisites
# Workflow tasks
Build-AssetsPhase1
Submit-AssetsToHwapi
Upload-AssetsToHwapi
Download-AssetsFromHwapi
Build-AssetsPhase2
Make-GitHubRelease
Upload-Symbols
Make-NugetRelease
Make-ChocoRelease
Write-Stdout "ALL COMPLETE"

24
tools/sxsident.bat Normal file
View File

@ -0,0 +1,24 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
set SxsDir=
set RegKey="HKLM\SOFTWARE\WinFsp"
set RegVal="SxsDir"
reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do (
set SxsDir=%%j
)
)
if defined SxsDir (
set SxsDir=!SxsDir:*SxS\sxs.=!
if !SxsDir:~-1!==\ set SxsDir=!SxsDir:~0,-1!
echo !SxsDir!
)
exit /b 0
:fail
exit /b 1

124
tools/wincred.ps1 Normal file
View File

@ -0,0 +1,124 @@
Start-Job -ArgumentList $args -ScriptBlock {
param (
[ValidateSet("get", "set", "del")]
[string]$Command
)
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
namespace Win32
{
public class Api
{
public static String[] CredRead(
String TargetName)
{
String[] Result = null;
IntPtr CredentialPtr;
if (CredReadW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0, out CredentialPtr))
{
CREDENTIALW Credential = Marshal.PtrToStructure<CREDENTIALW>(CredentialPtr);
Result = new String[2]{
Credential.UserName,
Marshal.PtrToStringUni(
Credential.CredentialBlob, (int)Credential.CredentialBlobSize / 2)
};
CredFree(CredentialPtr);
}
return Result;
}
public static Boolean CredWrite(
String TargetName,
String UserName,
String Password)
{
CREDENTIALW Credential = new CREDENTIALW{
Type = 1/*CRED_TYPE_GENERIC*/,
Persist = 2/*CRED_PERSIST_LOCAL_MACHINE*/,
TargetName = TargetName,
UserName = UserName,
CredentialBlobSize = (UInt32)Password.Length * 2,
CredentialBlob = Marshal.StringToCoTaskMemUni(Password),
};
Boolean Result = CredWriteW(ref Credential, 0);
Marshal.FreeCoTaskMem(Credential.CredentialBlob);
return Result;
}
public static Boolean CredDelete(
String TargetName)
{
return CredDeleteW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0);
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern Boolean CredReadW(
String TargetName,
UInt32 Type,
UInt32 Flags,
out IntPtr Credential);
[DllImport("advapi32.dll")]
private static extern void CredFree(
IntPtr Buffer);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern Boolean CredWriteW(
ref CREDENTIALW Credential,
UInt32 Flags);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern Boolean CredDeleteW(
String TargetName,
UInt32 Type,
UInt32 Flags);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct CREDENTIALW
{
public UInt32 Flags;
public UInt32 Type;
public String TargetName;
public String Comment;
public UInt64 LastWritten;
public UInt32 CredentialBlobSize;
public IntPtr CredentialBlob;
public UInt32 Persist;
public UInt32 AttributeCount;
public IntPtr Attributes;
public String TargetAlias;
public String UserName;
};
};
};
"@
function Get-WindowsCredential {
param (
[Parameter(Mandatory)][string]$TargetName
)
return [Win32.Api]::CredRead($TargetName)
}
function Set-WindowsCredential {
param (
[Parameter(Mandatory)][string]$TargetName,
[Parameter(Mandatory)][string]$UserName,
[Parameter(Mandatory)][string]$Password
)
return [Win32.Api]::CredWrite($TargetName, $UserName, $Password)
}
function Delete-WindowsCredential {
param (
[Parameter(Mandatory)][string]$TargetName
)
return [Win32.Api]::CredDelete($TargetName)
}
$Function = @{
"get" = "Get-WindowsCredential"
"set" = "Set-WindowsCredential"
"del" = "Delete-WindowsCredential"
}[$Command]
& $Function @args
} | Receive-Job -Wait -AutoRemoveJob

View File

@ -40,6 +40,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
*/
//#define MEMFS_STANDALONE
/*
* Define the MEMFS_DISPATCHER_STOPPED macro to include DispatcherStopped support.
*/
#define MEMFS_DISPATCHER_STOPPED
/*
* Define the MEMFS_NAME_NORMALIZATION macro to include name normalization support.
*/
@ -2269,6 +2274,14 @@ static NTSTATUS SetEa(FSP_FILE_SYSTEM *FileSystem,
}
#endif
#if defined(MEMFS_DISPATCHER_STOPPED)
static VOID DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally)
{
FspFileSystemStopServiceIfNecessary(FileSystem, Normally);
}
#endif
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
{
GetVolumeInfo,
@ -2336,6 +2349,12 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
0,
0,
0,
#endif
0,
#if defined(MEMFS_DISPATCHER_STOPPED)
DispatcherStopped,
#else
0,
#endif
};

View File

@ -38,6 +38,7 @@ enum
MemfsCaseInsensitive = 0x80000000,
MemfsFlushAndPurgeOnCleanup = 0x40000000,
MemfsLegacyUnlinkRename = 0x20000000,
MemfsNoSlowio = 0x10000000,
};
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\

View File

@ -1143,6 +1143,12 @@ exit:
return Result;
}
static VOID DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally)
{
FspFileSystemStopServiceIfNecessary(FileSystem, Normally);
}
static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
{
.GetVolumeInfo = GetVolumeInfo,
@ -1171,6 +1177,7 @@ static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
.GetStreamInfo = GetStreamInfo,
.GetEa = GetEa,
.SetEa = SetEa,
.DispatcherStopped = DispatcherStopped,
};
NTSTATUS PtfsCreate(

View File

@ -52,7 +52,7 @@
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
#define ptfs_impl_fullpath(n) \
char full ## n[PATH_MAX]; \
char full ## n[PATH_MAX * 4]; \
if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
return -ENAMETOOLONG; \
n = full ## n

View File

@ -129,15 +129,50 @@ char *realpath(const char *path, char *resolved)
result = resolved;
int err = 0;
DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
if (0 == len)
WCHAR PathBuf[PATH_MAX];
WCHAR ResultBuf[PATH_MAX];
PWSTR ResultBufBgn = &ResultBuf[6];
if (0 == MultiByteToWideChar(CP_UTF8, 0, path, -1, PathBuf, PATH_MAX))
err = GetLastError();
else if (PATH_MAX < len)
err = ERROR_INVALID_PARAMETER;
else
{
DWORD len = GetFullPathNameW(PathBuf, PATH_MAX - 6, ResultBufBgn, 0);
if (0 == len)
err = GetLastError();
else if (PATH_MAX - 6 < len)
err = ERROR_INVALID_PARAMETER;
else
{
if (0 == WideCharToMultiByte(CP_UTF8, 0, ResultBufBgn, -1, result, PATH_MAX, 0, 0))
err = GetLastError();
else
{
if (L'\\' == ResultBufBgn[0] && L'\\' == ResultBufBgn[1])
{
ResultBufBgn = ResultBuf;
ResultBufBgn[0] = L'\\';
ResultBufBgn[1] = L'\\';
ResultBufBgn[2] = L'?';
ResultBufBgn[3] = L'\\';
ResultBufBgn[4] = L'U';
ResultBufBgn[5] = L'N';
ResultBufBgn[6] = L'C';
}
else
{
ResultBufBgn = &ResultBuf[2];
ResultBufBgn[0] = L'\\';
ResultBufBgn[1] = L'\\';
ResultBufBgn[2] = L'?';
ResultBufBgn[3] = L'\\';
}
}
}
}
if (0 == err)
{
HANDLE h = CreateFileA(result,
HANDLE h = CreateFileW(ResultBufBgn,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -155,13 +190,71 @@ char *realpath(const char *path, char *resolved)
errno = maperror(err);
result = 0;
}
return result;
}
static int uncpath(const char *path, WCHAR *buf, int nchar)
{
PWSTR BufP = 0;
if ('\\' == path[0] && '\\' == path[1])
{
if (8 < nchar &&
0 < MultiByteToWideChar(CP_UTF8, 0, &path[2], -1, &buf[8], nchar - 8))
{
BufP = &buf[8];
buf[0] = L'\\';
buf[1] = L'\\';
buf[2] = L'?';
buf[3] = L'\\';
buf[4] = L'U';
buf[5] = L'N';
buf[6] = L'C';
buf[7] = L'\\';
}
}
else
{
if (4 < nchar &&
0 < MultiByteToWideChar(CP_UTF8, 0, path, -1, &buf[4], nchar - 4))
{
BufP = &buf[4];
buf[0] = L'\\';
buf[1] = L'\\';
buf[2] = L'?';
buf[3] = L'\\';
}
}
if (0 == BufP)
{
if (0 < nchar)
buf[0] = 0;
return 0;
}
PWSTR P = BufP;
while (*BufP)
{
if (L'/' == *BufP || L'\\' == *BufP)
{
while (L'/' == BufP[1] || L'\\' == BufP[1])
BufP++;
}
if (L'/' == *BufP)
*P = L'\\';
else if (P != BufP)
*P = *BufP;
BufP++;
P++;
}
if (P != BufP)
*P = 0;
return 1;
}
int statvfs(const char *path, struct fuse_statvfs *stbuf)
{
char root[PATH_MAX];
WCHAR root[PATH_MAX];
DWORD
VolumeSerialNumber,
MaxComponentLength,
@ -170,9 +263,11 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
NumberOfFreeClusters,
TotalNumberOfClusters;
if (!GetVolumePathNameA(path, root, PATH_MAX) ||
!GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
!GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!GetVolumePathNameW(PathBuf, root, PATH_MAX) ||
!GetVolumeInformationW(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
!GetDiskFreeSpaceW(root, &SectorsPerCluster, &BytesPerSector,
&NumberOfFreeClusters, &TotalNumberOfClusters))
{
return error();
@ -201,7 +296,9 @@ int open(const char *path, int oflag, ...)
CREATE_NEW :
cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0/* default security */,
CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -325,7 +422,9 @@ int close(int fd)
int getpath(const char *path, char *buf, size_t size)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -341,7 +440,9 @@ int getpath(const char *path, char *buf, size_t size)
int lstat(const char *path, struct fuse_stat *stbuf)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -375,7 +476,9 @@ int lchflags(const char *path, uint32_t flags)
if (0 == FileAttributes)
FileAttributes = FILE_ATTRIBUTE_NORMAL;
if (!SetFileAttributesA(path, FileAttributes))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!SetFileAttributesW(PathBuf, FileAttributes))
return error();
#endif
@ -384,7 +487,9 @@ int lchflags(const char *path, uint32_t flags)
int truncate(const char *path, fuse_off_t size)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -418,7 +523,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
/* ignore dirfd and assume that it is always AT_FDCWD */
/* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -448,7 +555,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
int setcrtime(const char *path, const struct fuse_timespec *tv)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -468,7 +577,9 @@ int setcrtime(const char *path, const struct fuse_timespec *tv)
int unlink(const char *path)
{
if (!DeleteFileA(path))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!DeleteFileW(PathBuf))
return error();
return 0;
@ -476,7 +587,11 @@ int unlink(const char *path)
int rename(const char *oldpath, const char *newpath)
{
if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
WCHAR OldPathBuf[PATH_MAX];
WCHAR NewPathBuf[PATH_MAX];
uncpath(oldpath, OldPathBuf, PATH_MAX);
uncpath(newpath, NewPathBuf, PATH_MAX);
if (!MoveFileExW(OldPathBuf, NewPathBuf, MOVEFILE_REPLACE_EXISTING))
return error();
return 0;
@ -484,7 +599,9 @@ int rename(const char *oldpath, const char *newpath)
static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -519,7 +636,9 @@ static int lgetea(const char *path,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -711,7 +830,9 @@ int lremovexattr(const char *path, const char *name)
int mkdir(const char *path, fuse_mode_t mode)
{
if (!CreateDirectoryA(path, 0/* default security */))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!CreateDirectoryW(PathBuf, 0/* default security */))
return error();
return 0;
@ -719,7 +840,9 @@ int mkdir(const char *path, fuse_mode_t mode)
int rmdir(const char *path)
{
if (!RemoveDirectoryA(path))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!RemoveDirectoryW(PathBuf))
return error();
return 0;
@ -727,7 +850,9 @@ int rmdir(const char *path)
DIR *opendir(const char *path)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -772,18 +897,20 @@ void rewinddir(DIR *dirp)
struct dirent *readdir(DIR *dirp)
{
WIN32_FIND_DATAA FindData;
WIN32_FIND_DATAW FindData;
struct fuse_stat *stbuf = &dirp->de.d_stat;
if (INVALID_HANDLE_VALUE == dirp->fh)
{
dirp->fh = FindFirstFileA(dirp->path, &FindData);
WCHAR PathBuf[PATH_MAX];
uncpath(dirp->path, PathBuf, PATH_MAX);
dirp->fh = FindFirstFileW(PathBuf, &FindData);
if (INVALID_HANDLE_VALUE == dirp->fh)
return error0();
}
else
{
if (!FindNextFileA(dirp->fh, &FindData))
if (!FindNextFileW(dirp->fh, &FindData))
{
if (ERROR_NO_MORE_FILES == GetLastError())
return 0;
@ -804,7 +931,7 @@ struct dirent *readdir(DIR *dirp)
stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
#endif
strcpy(dirp->de.d_name, FindData.cFileName);
WideCharToMultiByte(CP_UTF8, 0, FindData.cFileName, -1, dirp->de.d_name, 255 * 4, 0, 0);
return &dirp->de;
}

View File

@ -38,7 +38,7 @@ typedef struct _DIR DIR;
struct dirent
{
struct fuse_stat d_stat;
char d_name[255];
char d_name[255 * 4];
};
char *realpath(const char *path, char *resolved);

View File

@ -49,7 +49,7 @@
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
#define ptfs_impl_fullpath(n) \
char full ## n[PATH_MAX]; \
char full ## n[PATH_MAX * 4]; \
if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
return -ENAMETOOLONG; \
n = full ## n

View File

@ -129,15 +129,50 @@ char *realpath(const char *path, char *resolved)
result = resolved;
int err = 0;
DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
if (0 == len)
WCHAR PathBuf[PATH_MAX];
WCHAR ResultBuf[PATH_MAX];
PWSTR ResultBufBgn = &ResultBuf[6];
if (0 == MultiByteToWideChar(CP_UTF8, 0, path, -1, PathBuf, PATH_MAX))
err = GetLastError();
else if (PATH_MAX < len)
err = ERROR_INVALID_PARAMETER;
else
{
DWORD len = GetFullPathNameW(PathBuf, PATH_MAX - 6, ResultBufBgn, 0);
if (0 == len)
err = GetLastError();
else if (PATH_MAX - 6 < len)
err = ERROR_INVALID_PARAMETER;
else
{
if (0 == WideCharToMultiByte(CP_UTF8, 0, ResultBufBgn, -1, result, PATH_MAX, 0, 0))
err = GetLastError();
else
{
if (L'\\' == ResultBufBgn[0] && L'\\' == ResultBufBgn[1])
{
ResultBufBgn = ResultBuf;
ResultBufBgn[0] = L'\\';
ResultBufBgn[1] = L'\\';
ResultBufBgn[2] = L'?';
ResultBufBgn[3] = L'\\';
ResultBufBgn[4] = L'U';
ResultBufBgn[5] = L'N';
ResultBufBgn[6] = L'C';
}
else
{
ResultBufBgn = &ResultBuf[2];
ResultBufBgn[0] = L'\\';
ResultBufBgn[1] = L'\\';
ResultBufBgn[2] = L'?';
ResultBufBgn[3] = L'\\';
}
}
}
}
if (0 == err)
{
HANDLE h = CreateFileA(result,
HANDLE h = CreateFileW(ResultBufBgn,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -155,13 +190,71 @@ char *realpath(const char *path, char *resolved)
errno = maperror(err);
result = 0;
}
return result;
}
static int uncpath(const char *path, WCHAR *buf, int nchar)
{
PWSTR BufP = 0;
if ('\\' == path[0] && '\\' == path[1])
{
if (8 < nchar &&
0 < MultiByteToWideChar(CP_UTF8, 0, &path[2], -1, &buf[8], nchar - 8))
{
BufP = &buf[8];
buf[0] = L'\\';
buf[1] = L'\\';
buf[2] = L'?';
buf[3] = L'\\';
buf[4] = L'U';
buf[5] = L'N';
buf[6] = L'C';
buf[7] = L'\\';
}
}
else
{
if (4 < nchar &&
0 < MultiByteToWideChar(CP_UTF8, 0, path, -1, &buf[4], nchar - 4))
{
BufP = &buf[4];
buf[0] = L'\\';
buf[1] = L'\\';
buf[2] = L'?';
buf[3] = L'\\';
}
}
if (0 == BufP)
{
if (0 < nchar)
buf[0] = 0;
return 0;
}
PWSTR P = BufP;
while (*BufP)
{
if (L'/' == *BufP || L'\\' == *BufP)
{
while (L'/' == BufP[1] || L'\\' == BufP[1])
BufP++;
}
if (L'/' == *BufP)
*P = L'\\';
else if (P != BufP)
*P = *BufP;
BufP++;
P++;
}
if (P != BufP)
*P = 0;
return 1;
}
int statvfs(const char *path, struct fuse_statvfs *stbuf)
{
char root[PATH_MAX];
WCHAR root[PATH_MAX];
DWORD
VolumeSerialNumber,
MaxComponentLength,
@ -170,9 +263,11 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
NumberOfFreeClusters,
TotalNumberOfClusters;
if (!GetVolumePathNameA(path, root, PATH_MAX) ||
!GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
!GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!GetVolumePathNameW(PathBuf, root, PATH_MAX) ||
!GetVolumeInformationW(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
!GetDiskFreeSpaceW(root, &SectorsPerCluster, &BytesPerSector,
&NumberOfFreeClusters, &TotalNumberOfClusters))
{
return error();
@ -201,7 +296,9 @@ int open(const char *path, int oflag, ...)
CREATE_NEW :
cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0/* default security */,
CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -305,7 +402,9 @@ int close(int fd)
int lstat(const char *path, struct fuse_stat *stbuf)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -339,7 +438,9 @@ int lchflags(const char *path, uint32_t flags)
if (0 == FileAttributes)
FileAttributes = FILE_ATTRIBUTE_NORMAL;
if (!SetFileAttributesA(path, FileAttributes))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!SetFileAttributesW(PathBuf, FileAttributes))
return error();
#endif
@ -348,7 +449,9 @@ int lchflags(const char *path, uint32_t flags)
int truncate(const char *path, fuse_off_t size)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -382,7 +485,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
/* ignore dirfd and assume that it is always AT_FDCWD */
/* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -412,7 +517,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
int setcrtime(const char *path, const struct fuse_timespec *tv)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -432,7 +539,9 @@ int setcrtime(const char *path, const struct fuse_timespec *tv)
int unlink(const char *path)
{
if (!DeleteFileA(path))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!DeleteFileW(PathBuf))
return error();
return 0;
@ -440,7 +549,11 @@ int unlink(const char *path)
int rename(const char *oldpath, const char *newpath)
{
if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
WCHAR OldPathBuf[PATH_MAX];
WCHAR NewPathBuf[PATH_MAX];
uncpath(oldpath, OldPathBuf, PATH_MAX);
uncpath(newpath, NewPathBuf, PATH_MAX);
if (!MoveFileExW(OldPathBuf, NewPathBuf, MOVEFILE_REPLACE_EXISTING))
return error();
return 0;
@ -448,7 +561,9 @@ int rename(const char *oldpath, const char *newpath)
static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -483,7 +598,9 @@ static int lgetea(const char *path,
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -675,7 +792,9 @@ int lremovexattr(const char *path, const char *name)
int mkdir(const char *path, fuse_mode_t mode)
{
if (!CreateDirectoryA(path, 0/* default security */))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!CreateDirectoryW(PathBuf, 0/* default security */))
return error();
return 0;
@ -683,7 +802,9 @@ int mkdir(const char *path, fuse_mode_t mode)
int rmdir(const char *path)
{
if (!RemoveDirectoryA(path))
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
if (!RemoveDirectoryW(PathBuf))
return error();
return 0;
@ -691,7 +812,9 @@ int rmdir(const char *path)
DIR *opendir(const char *path)
{
HANDLE h = CreateFileA(path,
WCHAR PathBuf[PATH_MAX];
uncpath(path, PathBuf, PATH_MAX);
HANDLE h = CreateFileW(PathBuf,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@ -736,18 +859,20 @@ void rewinddir(DIR *dirp)
struct dirent *readdir(DIR *dirp)
{
WIN32_FIND_DATAA FindData;
WIN32_FIND_DATAW FindData;
struct fuse_stat *stbuf = &dirp->de.d_stat;
if (INVALID_HANDLE_VALUE == dirp->fh)
{
dirp->fh = FindFirstFileA(dirp->path, &FindData);
WCHAR PathBuf[PATH_MAX];
uncpath(dirp->path, PathBuf, PATH_MAX);
dirp->fh = FindFirstFileW(PathBuf, &FindData);
if (INVALID_HANDLE_VALUE == dirp->fh)
return error0();
}
else
{
if (!FindNextFileA(dirp->fh, &FindData))
if (!FindNextFileW(dirp->fh, &FindData))
{
if (ERROR_NO_MORE_FILES == GetLastError())
return 0;
@ -768,7 +893,7 @@ struct dirent *readdir(DIR *dirp)
stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
#endif
strcpy(dirp->de.d_name, FindData.cFileName);
WideCharToMultiByte(CP_UTF8, 0, FindData.cFileName, -1, dirp->de.d_name, 255 * 4, 0, 0);
return &dirp->de;
}

View File

@ -38,7 +38,7 @@ typedef struct _DIR DIR;
struct dirent
{
struct fuse_stat d_stat;
char d_name[255];
char d_name[255 * 4];
};
char *realpath(const char *path, char *resolved);

View File

@ -1287,6 +1287,38 @@ void create_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + 0x3041;
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Success = CloseHandle(Handle);
ASSERT(Success);
for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + 0x3041;
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Success = CloseHandle(Handle);
ASSERT(Success);
for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + 0x3041;
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
memfs_stop(memfs);
}

View File

@ -28,6 +28,52 @@
#include "winfsp-tests.h"
typedef struct _FILE_FULL_DIR_INFORMATION
{
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
WCHAR FileName[1];
} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
typedef struct _FILE_DIRECTORY_INFORMATION
{
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
NTSTATUS
NTAPI
NtQueryDirectoryFile (
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PUNICODE_STRING FileName,
BOOLEAN RestartScan);
static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -269,6 +315,212 @@ void querydir_test(void)
}
}
static inline size_t hash_chars(const wchar_t *s, size_t length)
{
/* djb2: see http://www.cse.yorku.ca/~oz/hash.html */
size_t h = 5381;
for (const wchar_t *t = s + length; t > s; ++s)
h = 33 * h + *s;
return h;
}
static NTSTATUS querydir_nodup_dotest_thread_loop(void *FilePath)
{
NTSTATUS Result;
void *Buffer = 0;
HANDLE Handle = INVALID_HANDLE_VALUE;
IO_STATUS_BLOCK IoStatus;
size_t hash[64], hash_count = 0;
Buffer = malloc(4096);
if (0 == Buffer)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Handle = CreateFileW(
FilePath,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
0);
if (INVALID_HANDLE_VALUE == Handle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
for (;;)
{
Result = NtQueryDirectoryFile(
Handle,
0, 0, 0,
&IoStatus,
Buffer,
4096,
2/*FileFullDirectoryInformation*/,
FALSE,
0,
FALSE);
if (STATUS_NO_MORE_FILES == Result)
break;
if (!NT_SUCCESS(Result))
goto exit;
for (FILE_FULL_DIR_INFORMATION *DirInfo = Buffer;;
DirInfo = (PVOID)((PUINT8)DirInfo + DirInfo->NextEntryOffset))
{
size_t h = hash_chars(DirInfo->FileName, DirInfo->FileNameLength / sizeof(WCHAR));
for (size_t i = 0; hash_count > i; i++)
if (hash[i] == h)
{
WCHAR FileName[256];
memcpy(FileName, DirInfo->FileName, DirInfo->FileNameLength);
FileName[DirInfo->FileNameLength / sizeof(WCHAR)] = L'\0';
FspDebugLog(__FUNCTION__ ": duplicate \"%S\"\n", FileName);
Result = STATUS_UNSUCCESSFUL;
goto exit;
}
if (sizeof hash / sizeof hash[0] > hash_count)
hash[hash_count++] = h;
if (0 == DirInfo->NextEntryOffset)
break;
}
}
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != Handle)
CloseHandle(Handle);
free(Buffer);
return Result;
}
static unsigned __stdcall querydir_nodup_dotest_thread(void *FilePath)
{
FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
NTSTATUS Result;
for (size_t i = 0; 5000 > i; i++)
{
Result = querydir_nodup_dotest_thread_loop(FilePath);
if (!NT_SUCCESS(Result))
goto exit;
}
Result = STATUS_SUCCESS;
exit:
return Result;
}
static void querydir_nodup_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
static WCHAR *FileNames[] =
{
L"Extensions.cs",
L"JsonSchema.cs",
L"JsonSchemaBuilder.cs",
L"JsonSchemaConstants.cs",
L"JsonSchemaException.cs",
L"JsonSchemaGenerator.cs",
L"JsonSchemaModel.cs",
L"JsonSchemaModelBuilder.cs",
L"JsonSchemaNode.cs",
L"JsonSchemaNodeCollection.cs",
L"JsonSchemaResolver.cs",
L"JsonSchemaType.cs",
L"JsonSchemaWriter.cs",
L"UndefinedSchemaIdHandling.cs",
L"ValidationEventArgs.cs",
L"ValidationEventHandler.cs",
};
HANDLE Handle;
BOOL Success;
WCHAR FilePath[MAX_PATH];
HANDLE Threads[2];
DWORD ExitCode;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
for (size_t i = 0; sizeof FileNames / sizeof FileNames[0] > i; i++)
{
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\%s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), FileNames[i]);
Handle = CreateFileW(FilePath, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Success = CloseHandle(Handle);
ASSERT(Success);
}
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
for (size_t i = 0; sizeof Threads / sizeof Threads[0] > i; i++)
{
Threads[i] = (HANDLE)_beginthreadex(0, 0, querydir_nodup_dotest_thread, FilePath, 0, 0);
ASSERT(0 != Threads[i]);
}
for (size_t i = 0; sizeof Threads / sizeof Threads[0] > i; i++)
{
WaitForSingleObject(Threads[i], INFINITE);
GetExitCodeThread(Threads[i], &ExitCode);
CloseHandle(Threads[i]);
ASSERT(0 == ExitCode);
}
for (size_t i = 0; sizeof FileNames / sizeof FileNames[0] > i; i++)
{
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\%s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), FileNames[i]);
Success = DeleteFileW(FilePath);
ASSERT(Success);
}
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
memfs_stop(memfs);
}
static void querydir_nodup_test(void)
{
/*
* Test GitHub issue #475. Credit for the investigation and reproduction
* of this issue goes to GitHub user @hach-que.
*/
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
querydir_nodup_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
querydir_nodup_dotest(MemfsDisk | MemfsNoSlowio, 0, 0);
querydir_nodup_dotest(MemfsDisk | MemfsNoSlowio, 0, 1000);
}
#if 0
if (WinFspNetTests)
{
querydir_nodup_dotest(MemfsNet | MemfsNoSlowio, L"\\\\memfs\\share", 0);
querydir_nodup_dotest(MemfsNet | MemfsNoSlowio, L"\\\\memfs\\share", 1000);
}
#endif
}
static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -368,36 +620,6 @@ void querydir_expire_cache_test(void)
}
}
typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
NTSTATUS
NTAPI
NtQueryDirectoryFile (
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass,
_In_ BOOLEAN ReturnSingleEntry,
_In_opt_ PUNICODE_STRING FileName,
_In_ BOOLEAN RestartScan
);
static void querydir_buffer_overflow_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -576,6 +798,40 @@ static void querydir_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + 0x3041;
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
querydir_namelen_exists(FilePath);
Success = CloseHandle(Handle);
ASSERT(Success);
for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + 0x3041;
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
querydir_namelen_exists(FilePath);
Success = CloseHandle(Handle);
ASSERT(Success);
for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
*P = (P - FilePathBgn) % 10 + 0x3041;
*P = L'\0';
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE == Handle);
ASSERT(ERROR_INVALID_NAME == GetLastError());
memfs_stop(memfs);
}
@ -732,6 +988,7 @@ void dirnotify_test(void)
void dirctl_tests(void)
{
TEST(querydir_test);
TEST_OPT(querydir_nodup_test);
if (!OptShareName)
TEST_OPT(querydir_single_test);
TEST(querydir_expire_cache_test);

View File

@ -0,0 +1,48 @@
/**
* @file loadun-test.c
*
* @copyright 2015-2022 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include <winfsp/winfsp.h>
#include <tlib/testsuite.h>
#include "winfsp-tests.h"
static void load_unload_test(void)
{
/* this is not a real test! */
FspFsctlStartService();
FspFsctlStartService();
FspFsctlStopService();
FspFsctlStopService();
}
void load_unload_tests(void)
{
if (OptExternal)
return;
/*
* An attempt to unload the driver while other tests are executing can make all tests fail.
* For this reason we do not enable this test, except when doing specialized testing.
*/
//TEST_OPT(load_unload_test);
}

View File

@ -48,9 +48,9 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
FileInfoTimeout,
1024,
1024 * 1024,
50, /*SlowioMaxDelay*/
10, /*SlowioPercentDelay*/
5, /*SlowioRarefyDelay*/
(Flags & MemfsNoSlowio) ? 0 : 50, /*SlowioMaxDelay*/
(Flags & MemfsNoSlowio) ? 0 : 10, /*SlowioPercentDelay*/
(Flags & MemfsNoSlowio) ? 0 : 5, /*SlowioRarefyDelay*/
0,
MemfsNet == Flags ? L"\\memfs\\share" : 0,
0,

View File

@ -221,6 +221,7 @@ LONG WINAPI UnhandledExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
argv[argc] = 0
int main(int argc, char *argv[])
{
TESTSUITE(load_unload_tests);
TESTSUITE(fuse_opt_tests);
TESTSUITE(fuse_tests);
TESTSUITE(posix_tests);