Compare commits

...

77 Commits

Author SHA1 Message Date
f85fb49f49 changelog: update for v2.0B1 2022-11-23 14:32:31 +00: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
4783902d1d tools: make-release.ps1 2022-10-12 16:57:43 +01:00
fd27c470b0 Merge branch 'master' into pvt-sxs 2022-10-12 16:36:22 +01:00
4cd2b8c612 tools: make-release.ps1 2022-10-12 16:35:40 +01:00
dacaff41e4 changelog: update for v1.12B2 2022-10-12 15:33:18 +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
be27a82879 dll: FspCreateDirectoryFileW
On Windows/ARM64 CreateFileW is no longer able to create directories
using the flags FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS.
The new FspCreateDirectoryFileW implements the same semantics and replaces
the previous CreateFileW call.
2022-10-07 11:47:25 +01:00
4f5ad93f00 Merge branch 'master' into pvt-sxs 2022-10-04 15:44:49 +01:00
b9ca46694e sys: FspFileNodeRenameCheck: fix handle oplock break 2022-10-04 15:44:27 +01:00
b47c42877a Merge branch 'master' into pvt-sxs 2022-10-04 13:45:19 +01:00
e50d7adc50 tools: run-tests: retire some tests
Retire some tests that are no longer useful.
This should shorten CI time considerably.
2022-10-04 13:44:31 +01:00
d1fc5e5d0f Merge branch 'pvt-vpb2' into pvt-sxs-vpb 2022-10-03 15:10:06 +01:00
7f73192f8d sys: FspVolumeCreate
If we have an fsvrt device, mount it via opening the volume.
This ensures that the fsvrt is mounted by the correct fsvol
device early on and remedies a rare case where NTFS crashes
the system when it attempts to mount our fsvrt.
2022-10-02 20:10:32 +01:00
c4ecd15c0a Merge branch 'master' into pvt-sxs 2022-10-02 17:49:47 +01:00
d71049225e sys: FSP_DEVICE_EXTENSION: remove unused SiloContainerId 2022-10-02 17:35:07 +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
c15006cce8 appveyor: silo testing 2022-09-28 19:06:16 +01:00
53b44dcb5c tst: winfsp-tests: silo testing 2022-09-28 18:46:17 +01:00
a3765d6360 sys: silo: FspSiloPostInitialize 2022-09-27 19:55:08 +01:00
98d68c4007 Merge branch 'master' into pvt-sxs 2022-09-26 17:52:29 +01:00
6c6dd8abcc tools: run-tests: disable exec tests for mountmgr 2022-09-26 17:51:05 +01:00
16dd729fc7 tools: run-tests: disable exec tests for mountmgr 2022-09-26 17:50:19 +01:00
e8cec5dfc1 Merge branch 'master' into pvt-sxs 2022-09-26 17:42:30 +01:00
a2d49a1ded build: version: 2022.2 Beta2 2022-09-26 17:35:57 +01:00
9ede097e73 changelog: update for v1.12B2 2022-09-26 17:34:36 +01:00
2c3800077f tst: passthrough: GetFileInfoInternal: fix IndexNumber 2022-09-26 17:26:25 +01:00
84b3f98d38 Merge branch 'pvt-fuse-mountmgr' 2022-09-26 17:01:35 +01:00
16734bf37a Merge pull request #450 from chyyran/patch-doc-add-winfsp-rs
doc: Add winfsp-rs to file system libraries
2022-09-26 15:31:26 +01:00
ea189c5b68 dll: fuse: fix mountmgr directory mount points under Cygwin 2022-09-26 15:26:34 +01:00
7735506cc7 legal: add Ronny Chan to contributors 2022-09-25 22:14:11 -04:00
ca3170c293 doc: Add winfsp-rs to file system libraries 2022-09-25 22:09:40 -04: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
ba13995d10 update changelog 2022-09-14 12:26:40 +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
49 changed files with 2617 additions and 319 deletions

View File

@ -1,7 +1,56 @@
# Changelog # Changelog
## v1.12B1 (2022.2) ## 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 (2022.2)
- [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.12B2 (2022.2 Beta2)
- [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.12B1 (2022.2 Beta1)
- [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. - [NEW] A new registry setting `MountUseMountmgrFromFSD` has been added. See [WinFsp Registry Settings](https://github.com/winfsp/winfsp/wiki/WinFsp-Registry-Settings) for details.

View File

@ -68,6 +68,7 @@ CONTRIBUTOR LIST
|John Tyner |jtyner at gmail.com |John Tyner |jtyner at gmail.com
|Paweł Wegner (Google LLC, https://google.com) |lemourin at google.com |Paweł Wegner (Google LLC, https://google.com) |lemourin at google.com
|Pedro Frejo (Arpa System, https://arpasystem.com) |pedro.frejo at arpasystem.com |Pedro Frejo (Arpa System, https://arpasystem.com) |pedro.frejo at arpasystem.com
|Ronny Chan |ronny at ronnychan.ca
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com |Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|Santiago Ganis |sganis at gmail.com |Santiago Ganis |sganis at gmail.com
|Tobias Urlaub |saibotu at outlook.de |Tobias Urlaub |saibotu at outlook.de

View File

@ -17,19 +17,25 @@ environment:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CONFIGURATION: Debug CONFIGURATION: Debug
TESTING: Func TESTING: Func
DOCKER_TESTING: None
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CONFIGURATION: Release CONFIGURATION: Release
TESTING: Func TESTING: Func
DOCKER_TESTING: None
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CONFIGURATION: Release CONFIGURATION: Release
TESTING: Func TESTING: Func
DOCKER_TESTING: None
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CONFIGURATION: Release CONFIGURATION: Release
TESTING: Func TESTING: Func
DOCKER_TESTING: Func
#- CONFIGURATION: Release #- CONFIGURATION: Release
# TESTING: Avast # TESTING: Avast
# DOCKER_TESTING: None
#- CONFIGURATION: Release #- CONFIGURATION: Release
# TESTING: Perf # TESTING: Perf
# DOCKER_TESTING: None
init: init:
- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
@ -81,6 +87,7 @@ test_script:
- if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn - if %TESTING%==Func start /wait msiexec /i "Test.Filter.Driver\HCK Filter.Driver Content-x86_en-us.msi" /qn
- if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION% - if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION%
#- ps: . "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags.exe" /k +spp * #- ps: . "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags.exe" /k +spp *
- if %DOCKER_TESTING%==Func docker run -d --name=Container0 --isolation=process "-vC:\Program Files (x86)\WinFsp:C:\Program Files (x86)\WinFsp:RO" "-vC:\projects:C:\projects:RO" mcr.microsoft.com/windows/servercore:ltsc2019 cmd.exe /c waitfor 7BF47D72F6664550B03248ECFE77C7DD
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample - if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample
@ -88,6 +95,9 @@ test_script:
- if %TESTING%==Avast choco install avastfreeantivirus && fltmc instances -v "C:" - if %TESTING%==Avast choco install avastfreeantivirus && fltmc instances -v "C:"
- if %TESTING%==Avast tools\run-tests.bat %CONFIGURATION% avast-tests - if %TESTING%==Avast tools\run-tests.bat %CONFIGURATION% avast-tests
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv - if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- if %DOCKER_TESTING%==Func docker exec Container0 cmd.exe /c C:\projects\winfsp\build\VStudio\build\%CONFIGURATION%\winfsp-tests-x64.exe +*
#- if %DOCKER_TESTING%==Func docker run -d --name=Container1 --isolation=process "-vC:\Program Files (x86)\WinFsp:C:\Program Files (x86)\WinFsp:RO" "-vC:\projects:C:\projects:RO" mcr.microsoft.com/windows/servercore:ltsc2019 cmd.exe /c waitfor 7BF47D72F6664550B03248ECFE77C7DD
#- if %DOCKER_TESTING%==Func docker exec Container1 cmd.exe /c C:\projects\winfsp\build\VStudio\build\%CONFIGURATION%\winfsp-tests-x64.exe +*
- choco uninstall winfsp -y - choco uninstall winfsp -y
on_finish: on_finish:

View File

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

View File

@ -21,10 +21,55 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <shellapi.h>
#include <msiquery.h> #include <msiquery.h>
#include <wcautil.h> #include <wcautil.h>
#include <strutil.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) UINT __stdcall ServiceRunning(MSIHANDLE MsiHandle)
{ {
#if 0 #if 0
@ -44,7 +89,7 @@ UINT __stdcall ServiceRunning(MSIHANDLE MsiHandle)
hr = WcaInitialize(MsiHandle, __FUNCTION__); hr = WcaInitialize(MsiHandle, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize"); ExitOnFailure(hr, "Failed to initialize");
WcaGetProperty(L"" __FUNCTION__, &ServiceName); hr = WcaGetProperty(L"" __FUNCTION__, &ServiceName);
ExitOnFailure(hr, "Failed to get ServiceName"); ExitOnFailure(hr, "Failed to get ServiceName");
WcaLog(LOGMSG_STANDARD, "Initialized: \"%S\"", ServiceName); WcaLog(LOGMSG_STANDARD, "Initialized: \"%S\"", ServiceName);
@ -70,12 +115,390 @@ LExit:
return WcaFinalize(err); 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" extern "C"
BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved) BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
{ {
switch(Reason) switch(Reason)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
DllInstance = Instance;
WcaGlobalInitialize(Instance); WcaGlobalInitialize(Instance);
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:

View File

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

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-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" <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension"> xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension">
<Product <Product
@ -7,7 +11,7 @@
Manufacturer="$(var.MyCompanyName)" Manufacturer="$(var.MyCompanyName)"
Version="$(var.MyVersion)" Version="$(var.MyVersion)"
Language="1033" Language="1033"
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B"> UpgradeCode="5466A3D8-3AA1-4240-B6A0-3A051940A3EC">
<Package <Package
Description="$(var.MyProductName) - $(var.MyDescription)" Description="$(var.MyProductName) - $(var.MyDescription)"
@ -15,13 +19,26 @@
Compressed="yes" Compressed="yes"
InstallScope="perMachine" /> InstallScope="perMachine" />
<MajorUpgrade <MajorUpgrade
Disallow="yes" Disallow="no"
AllowDowngrades="no" AllowDowngrades="no"
AllowSameVersionUpgrades="no" AllowSameVersionUpgrades="yes"
DisallowUpgradeErrorMessage="An older version of $(var.MyProductName) is already installed. You must uninstall it before you can install this version."
DowngradeErrorMessage="A newer version of $(var.MyProductName) is already installed." /> DowngradeErrorMessage="A newer version of $(var.MyProductName) is already installed." />
<Media Id="1" Cabinet="$(var.MyProductName).cab" EmbedCab="yes" /> <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"> <Property Id="OSARCH" Secure="yes" Value="AMD64">
<RegistrySearch <RegistrySearch
Id="R.OSARCH" Id="R.OSARCH"
@ -31,10 +48,10 @@
Type="raw" /> Type="raw" />
</Property> </Property>
<Property Id="P.LauncherName">$(var.MyProductName).Launcher</Property> <!-- Setup INSTALLDIR and SXSDIR from the registry or defaults. -->
<Property Id="P.LauncherRegistryKey">Software\$(var.MyProductName)\Services</Property>
<Property Id="P.RegistryKey">Software\$(var.MyProductName)</Property> <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 <RegistrySearch
Id="R.INSTALLDIR" Id="R.INSTALLDIR"
Root="HKLM" Root="HKLM"
@ -42,22 +59,40 @@
Name="InstallDir" Name="InstallDir"
Type="raw" /> Type="raw" />
</Property> </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="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder"> <Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="$(var.MyProductName)"> <Directory Id="INSTALLDIR" Name="DYNAMIC">
<Directory Id="SXSBASEDIR" Name="SxS">
<Directory Id="SXSDIR" Name="DYNAMIC">
<Directory Id="BINDIR" Name="bin" /> <Directory Id="BINDIR" Name="bin" />
</Directory>
</Directory>
<Directory Id="INCDIR" Name="inc" /> <Directory Id="INCDIR" Name="inc" />
<Directory Id="LIBDIR" Name="lib" /> <Directory Id="LIBDIR" Name="lib" />
<Directory Id="OPTDIR" Name="opt" /> <Directory Id="OPTDIR" Name="opt" />
<Directory Id="SMPDIR" Name="samples" /> <Directory Id="SMPDIR" Name="samples" />
<Directory Id="SYMDIR" Name="sym" />
</Directory> </Directory>
</Directory> </Directory>
</Directory> </Directory>
<DirectoryRef Id="INSTALLDIR"> <DirectoryRef Id="INSTALLDIR">
<Component Id="C.INSTALLDIR" Guid="{F876F26E-5016-4AC6-93B3-653C0312A6CE}"> <Component Id="C.INSTALLDIR" Guid="C086521F-8552-43D1-AAE2-CDD579F66FDD">
<RegistryValue <RegistryValue
Root="HKLM" Root="HKLM"
Key="[P.RegistryKey]" Key="[P.RegistryKey]"
@ -70,6 +105,17 @@
<File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" /> <File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" />
</Component> </Component>
</DirectoryRef> </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)"> <DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.$(var.MyProductFileName)_a64.sys"> <Component Id="C.$(var.MyProductFileName)_a64.sys">
<File Name="$(var.MyProductFileName)-a64.sys" KeyPath="yes" /> <File Name="$(var.MyProductFileName)-a64.sys" KeyPath="yes" />
@ -82,56 +128,56 @@
</Component> </Component>
<!-- On WinArm64 register $(var.MyProductFileName)-a64.dll --> <!-- 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" /> <File Id="FILE.$(var.MyProductFileName)_a64.dll.a64" Name="$(var.MyProductFileName)-a64.dll" KeyPath="yes" SelfRegCost="1" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition> <Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_x64.dll.a64" Name="$(var.MyProductFileName)-x64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition> <Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_x86.dll.a64" Name="$(var.MyProductFileName)-x86.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition> <Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component> </Component>
<!-- On Win64 register $(var.MyProductFileName)-x64.dll --> <!-- 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" /> <File Id="FILE.$(var.MyProductFileName)_a64.dll.x64" Name="$(var.MyProductFileName)-a64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition> <Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_x64.dll.x64" Name="$(var.MyProductFileName)-x64.dll" KeyPath="yes" SelfRegCost="1" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition> <Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_x86.dll.x64" Name="$(var.MyProductFileName)-x86.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition> <Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component> </Component>
<!-- On Win32 register $(var.MyProductFileName)-x86.dll --> <!-- 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" /> <File Id="FILE.$(var.MyProductFileName)_a64.dll.x86" Name="$(var.MyProductFileName)-a64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition> <Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_x64.dll.x86" Name="$(var.MyProductFileName)-x64.dll" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition> <Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_x86.dll.x86" Name="$(var.MyProductFileName)-x86.dll" KeyPath="yes" SelfRegCost="1" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition> <Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component> </Component>
<!-- install assembly --> <!-- 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" /> <File Id="FILE.$(var.MyProductFileName)_msil.dll" Name="$(var.MyProductFileName)-msil.dll" KeyPath="yes" />
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_msil.xml" Name="$(var.MyProductFileName)-msil.xml" KeyPath="yes" />
</Component> </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" /> <File Id="FILE.$(var.MyProductFileName)_msil.dll.GAC" Name="$(var.MyProductFileName)-msil.dll" KeyPath="yes" Assembly=".net" />
</Component> </Component>
<Component Id="C.policy.$(var.MyProductFileName)_msil.dll.GAC"> <Component Id="C.policy.$(var.MyProductFileName)_msil.dll.GAC">
@ -141,103 +187,103 @@
--> -->
<!-- On WinArm64 ServiceInstall launcher-a64.exe --> <!-- 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" /> <File Id="FILE.launcher_a64.exe.a64" Name="launcher-a64.exe" KeyPath="yes" />
<ServiceInstall <ServiceInstall
Id="launcher_a64.exe.a64" Id="launcher_a64.exe.a64"
Name="[P.LauncherName]" Name="$(var.MyProductName).Launcher"
Description="$(var.MyDescription)" Description="$(var.MyDescription)"
Type="ownProcess" Type="ownProcess"
Start="auto" Start="auto"
ErrorControl="ignore" /> ErrorControl="ignore" />
<ServiceControl <ServiceControl
Id="launcher_a64.exe.a64" Id="launcher_a64.exe.a64"
Name="[P.LauncherName]" Name="$(var.MyProductName).Launcher"
Start="install" Start="install"
Stop="both" Stop="both"
Remove="uninstall" /> Remove="uninstall" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition> <Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component> </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" /> <File Id="FILE.launcher_x64.exe.a64" Name="launcher-x64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition> <Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component> </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" /> <File Id="FILE.launcher_x86.exe.a64" Name="launcher-x86.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "ARM64"]]></Condition> <Condition><![CDATA[OSARCH = "ARM64"]]></Condition>
</Component> </Component>
<!-- On Win64 ServiceInstall launcher-x64.exe --> <!-- 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" /> <File Id="FILE.launcher_a64.exe.x64" Name="launcher-a64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition> <Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component> </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" /> <File Id="FILE.launcher_x64.exe.x64" Name="launcher-x64.exe" KeyPath="yes" />
<ServiceInstall <ServiceInstall
Id="launcher_x64.exe.x64" Id="launcher_x64.exe.x64"
Name="[P.LauncherName]" Name="$(var.MyProductName).Launcher"
Description="$(var.MyDescription)" Description="$(var.MyDescription)"
Type="ownProcess" Type="ownProcess"
Start="auto" Start="auto"
ErrorControl="ignore" /> ErrorControl="ignore" />
<ServiceControl <ServiceControl
Id="launcher_x64.exe.x64" Id="launcher_x64.exe.x64"
Name="[P.LauncherName]" Name="$(var.MyProductName).Launcher"
Start="install" Start="install"
Stop="both" Stop="both"
Remove="uninstall" /> Remove="uninstall" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition> <Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component> </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" /> <File Id="FILE.launcher_x86.exe.x64" Name="launcher-x86.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "AMD64"]]></Condition> <Condition><![CDATA[OSARCH = "AMD64"]]></Condition>
</Component> </Component>
<!-- On Win32 ServiceInstall launcher-x86.exe --> <!-- 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" /> <File Id="FILE.launcher_a64.exe.x86" Name="launcher-a64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition> <Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component> </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" /> <File Id="FILE.launcher_x64.exe.x86" Name="launcher-x64.exe" KeyPath="yes" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition> <Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component> </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" /> <File Id="FILE.launcher_x86.exe.x86" Name="launcher-x86.exe" KeyPath="yes" />
<ServiceInstall <ServiceInstall
Id="launcher_x86.exe.x86" Id="launcher_x86.exe.x86"
Name="[P.LauncherName]" Name="$(var.MyProductName).Launcher"
Description="$(var.MyDescription)" Description="$(var.MyDescription)"
Type="ownProcess" Type="ownProcess"
Start="auto" Start="auto"
ErrorControl="ignore" /> ErrorControl="ignore" />
<ServiceControl <ServiceControl
Id="launcher_x86.exe.x86" Id="launcher_x86.exe.x86"
Name="[P.LauncherName]" Name="$(var.MyProductName).Launcher"
Start="install" Start="install"
Stop="both" Stop="both"
Remove="uninstall" /> Remove="uninstall" />
<Condition><![CDATA[OSARCH = "x86"]]></Condition> <Condition><![CDATA[OSARCH = "x86"]]></Condition>
</Component> </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" /> <File Name="launchctl-a64.exe" KeyPath="yes" />
</Component> </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" /> <File Name="launchctl-x64.exe" KeyPath="yes" />
</Component> </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" /> <File Name="launchctl-x86.exe" KeyPath="yes" />
</Component> </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" /> <File Name="fsptool-a64.exe" KeyPath="yes" />
</Component> </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" /> <File Name="fsptool-x64.exe" KeyPath="yes" />
</Component> </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" /> <File Name="fsptool-x86.exe" KeyPath="yes" />
</Component> </Component>
@ -409,7 +455,7 @@
</Component> </Component>
<!-- On WinArm64 copy fuse-a64.pc --> <!-- 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 <File
Id="FILE.fuse_a64.pc" Id="FILE.fuse_a64.pc"
Name="fuse.pc" Name="fuse.pc"
@ -419,7 +465,7 @@
</Component> </Component>
<!-- On Win64 copy fuse-x64.pc --> <!-- 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 <File
Id="FILE.fuse_x64.pc" Id="FILE.fuse_x64.pc"
Name="fuse.pc" Name="fuse.pc"
@ -429,7 +475,7 @@
</Component> </Component>
<!-- On Win32 copy fuse-x86.pc --> <!-- 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 <File
Id="FILE.fuse_x86.pc" Id="FILE.fuse_x86.pc"
Name="fuse.pc" Name="fuse.pc"
@ -439,7 +485,7 @@
</Component> </Component>
<!-- On WinArm64 copy fuse3-x64.pc --> <!-- 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 <File
Id="FILE.fuse3_a64.pc" Id="FILE.fuse3_a64.pc"
Name="fuse3.pc" Name="fuse3.pc"
@ -449,7 +495,7 @@
</Component> </Component>
<!-- On Win64 copy fuse3-x64.pc --> <!-- 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 <File
Id="FILE.fuse3_x64.pc" Id="FILE.fuse3_x64.pc"
Name="fuse3.pc" Name="fuse3.pc"
@ -459,7 +505,7 @@
</Component> </Component>
<!-- On Win32 copy fuse3-x86.pc --> <!-- 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 <File
Id="FILE.fuse3_x86.pc" Id="FILE.fuse3_x86.pc"
Name="fuse3.pc" Name="fuse3.pc"
@ -737,62 +783,6 @@
</Component> </Component>
</Directory> </Directory>
</DirectoryRef> </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"> <ComponentGroup Id="C.$(var.MyProductName).bin">
<ComponentRef Id="C.$(var.MyProductFileName)_a64.sys" /> <ComponentRef Id="C.$(var.MyProductFileName)_a64.sys" />
@ -927,26 +917,6 @@
<ComponentRef Id="C.notifyfs.vcxproj" /> <ComponentRef Id="C.notifyfs.vcxproj" />
<ComponentRef Id="C.notifyfs.vcxproj.filters" /> <ComponentRef Id="C.notifyfs.vcxproj.filters" />
</ComponentGroup> </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"> <ComponentGroup Id="C.$(var.MyProductName).net">
<ComponentRef Id="C.$(var.MyProductFileName)_msil.dll" /> <ComponentRef Id="C.$(var.MyProductFileName)_msil.dll" />
<ComponentRef Id="C.$(var.MyProductFileName)_msil.xml" /> <ComponentRef Id="C.$(var.MyProductFileName)_msil.xml" />
@ -978,6 +948,7 @@
Absent="disallow"> Absent="disallow">
<ComponentRef Id="C.INSTALLDIR" /> <ComponentRef Id="C.INSTALLDIR" />
<ComponentRef Id="C.License.txt" /> <ComponentRef Id="C.License.txt" />
<ComponentRef Id="C.SXSDIR" />
<Feature <Feature
Id="F.User" Id="F.User"
Level="1" Level="1"
@ -1013,7 +984,6 @@
<ComponentGroupRef Id="C.$(var.MyProductName).lib" /> <ComponentGroupRef Id="C.$(var.MyProductName).lib" />
<ComponentGroupRef Id="C.$(var.MyProductName).smp" /> <ComponentGroupRef Id="C.$(var.MyProductName).smp" />
<ComponentGroupRef Id="C.$(var.MyProductName).smp.net" /> <ComponentGroupRef Id="C.$(var.MyProductName).smp.net" />
<ComponentGroupRef Id="C.$(var.MyProductName).sym" />
</Feature> </Feature>
<Feature <Feature
Id="F.KernelDeveloper" Id="F.KernelDeveloper"
@ -1056,7 +1026,24 @@
Order="10">NOT Installed</Publish> Order="10">NOT Installed</Publish>
</UI> </UI>
<!-- Custom Actions -->
<Binary Id="CustomActions" SourceFile="..\build\$(var.Configuration)\CustomActions.dll" /> <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 <CustomAction
Id="Params.ServiceRunning" Id="Params.ServiceRunning"
Property="ServiceRunning" Property="ServiceRunning"
@ -1069,16 +1056,109 @@
Return="ignore" /> Return="ignore" />
<CustomAction <CustomAction
Id="Action.ServiceRunning.Error" 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> <InstallExecuteSequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning" /> <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"> <Custom Action="Action.ServiceRunning.Error" After="Action.ServiceRunning">
<![CDATA[NOT Installed AND (0 <> ServiceRunning)]]> <![CDATA[NOT Installed AND (0 <> ServiceRunning)]]>
</Custom> </Custom>
<ScheduleReboot After="RemoveFiles">
<![CDATA[(REMOVE ~= "ALL") AND (0 <> ServiceRunning)]]>
</ScheduleReboot>
</InstallExecuteSequence> </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> </Product>
</Wix> </Wix>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -260,6 +260,7 @@
<ClCompile Include="..\..\src\sys\shutdown.c" /> <ClCompile Include="..\..\src\sys\shutdown.c" />
<ClCompile Include="..\..\src\sys\silo.c" /> <ClCompile Include="..\..\src\sys\silo.c" />
<ClCompile Include="..\..\src\sys\statistics.c" /> <ClCompile Include="..\..\src\sys\statistics.c" />
<ClCompile Include="..\..\src\sys\sxs.c" />
<ClCompile Include="..\..\src\sys\trace.c" /> <ClCompile Include="..\..\src\sys\trace.c" />
<ClCompile Include="..\..\src\sys\util.c" /> <ClCompile Include="..\..\src\sys\util.c" />
<ClCompile Include="..\..\src\sys\volinfo.c" /> <ClCompile Include="..\..\src\sys\volinfo.c" />

View File

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

View File

@ -34,3 +34,4 @@ This document contains a list of known open-source file systems and file system
- https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE - https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
- https://github.com/pleiszenburg/refuse[Python: refuse] - Simple cross-plattform ctypes bindings for libfuse / FUSE for macOS / WinFsp - https://github.com/pleiszenburg/refuse[Python: refuse] - Simple cross-plattform ctypes bindings for libfuse / FUSE for macOS / WinFsp
- https://github.com/Scille/winfspy[Python: winfspy] - WinFSP binding for Python - https://github.com/Scille/winfspy[Python: winfspy] - WinFSP binding for Python
- https://github.com/SnowflakePowered/winfsp-rs[Rust: winfsp-rs] - WinFSP binding for Rust

View File

@ -538,7 +538,8 @@ static NTSTATUS GetFileInfoInternal(HANDLE Handle, FSP_FSCTL_FILE_INFO *FileInfo
FileInfo->LastAccessTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastAccessTime)->QuadPart; FileInfo->LastAccessTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastAccessTime)->QuadPart;
FileInfo->LastWriteTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastWriteTime)->QuadPart; FileInfo->LastWriteTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastWriteTime)->QuadPart;
FileInfo->ChangeTime = FileInfo->LastWriteTime; FileInfo->ChangeTime = FileInfo->LastWriteTime;
FileInfo->IndexNumber = 0; FileInfo->IndexNumber =
((UINT64)ByHandleFileInfo.nFileIndexHigh << 32) | (UINT64)ByHandleFileInfo.nFileIndexLow;
FileInfo->HardLinks = 0; FileInfo->HardLinks = 0;
return STATUS_SUCCESS; return STATUS_SUCCESS;

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) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 's', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_NOTIFY \ #define FSP_FSCTL_NOTIFY \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'n', METHOD_NEITHER, FILE_ANY_ACCESS) 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) */ /* fsctl internal device codes (usable only in-kernel) */
#define FSP_FSCTL_TRANSACT_INTERNAL \ #define FSP_FSCTL_TRANSACT_INTERNAL \
@ -694,6 +696,11 @@ FSP_API NTSTATUS FspFsctlNotify(HANDLE VolumeHandle,
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath, FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize); PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath); FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
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 typedef struct
{ {

View File

@ -1047,11 +1047,14 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*Obsolete0)(VOID); NTSTATUS (*Obsolete0)(VOID);
VOID (*DispatcherStopped)(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally);
/* /*
* This ensures that this interface will always contain 64 function pointers. * This ensures that this interface will always contain 64 function pointers.
* Please update when changing the interface as it is important for future compatibility. * Please update when changing the interface as it is important for future compatibility.
*/ */
NTSTATUS (*Reserved[32])(); NTSTATUS (*Reserved[31])();
} FSP_FILE_SYSTEM_INTERFACE; } FSP_FILE_SYSTEM_INTERFACE;
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()), FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries."); "FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
@ -1074,7 +1077,8 @@ typedef struct _FSP_FILE_SYSTEM
SRWLOCK OpGuardLock; SRWLOCK OpGuardLock;
BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext; BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext;
UINT16 UmNoReparsePointsDirCheck:1; UINT16 UmNoReparsePointsDirCheck:1;
UINT16 UmReservedFlags:15; UINT16 UmReservedFlags:14;
UINT16 DispatcherStopping:1;
} FSP_FILE_SYSTEM; } FSP_FILE_SYSTEM;
FSP_FSCTL_STATIC_ASSERT( FSP_FSCTL_STATIC_ASSERT(
(4 == sizeof(PVOID) && 660 == sizeof(FSP_FILE_SYSTEM)) || (4 == sizeof(PVOID) && 660 == sizeof(FSP_FILE_SYSTEM)) ||
@ -2120,6 +2124,7 @@ FSP_API NTSTATUS FspCallNamedPipeSecurelyEx(PWSTR PipeName,
PULONG PBytesTransferred, ULONG Timeout, BOOLEAN AllowImpersonation, PULONG PBytesTransferred, ULONG Timeout, BOOLEAN AllowImpersonation,
PSID Sid); PSID Sid);
FSP_API NTSTATUS FspVersion(PUINT32 PVersion); FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
FSP_API PWSTR FspSxsIdent(VOID);
/* /*
* Delay load * Delay load

View File

@ -358,6 +358,21 @@ exit:
CloseHandle(DispatcherThread); 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; return Result;
} }
@ -399,6 +414,12 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem)
if (0 == FileSystem->DispatcherThread) if (0 == FileSystem->DispatcherThread)
return; return;
/* FileSystem->DispatcherStopping = 1 */
_InterlockedOr16(
(PVOID)((PUINT8)&FileSystem->UmFileContextIsFullContext +
sizeof(FileSystem->UmFileContextIsFullContext)),
0x8000);
FspFsctlStop0(FileSystem->VolumeHandle); FspFsctlStop0(FileSystem->VolumeHandle);
WaitForSingleObject(FileSystem->DispatcherThread, INFINITE); WaitForSingleObject(FileSystem->DispatcherThread, INFINITE);
@ -406,6 +427,12 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem)
FileSystem->DispatcherThread = 0; FileSystem->DispatcherThread = 0;
FspFsctlStop(FileSystem->VolumeHandle); FspFsctlStop(FileSystem->VolumeHandle);
/* FileSystem->DispatcherStopping = 0 */
_InterlockedAnd16(
(PVOID)((PUINT8)&FileSystem->UmFileContextIsFullContext +
sizeof(FileSystem->UmFileContextIsFullContext)),
0x7fff);
} }
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem, 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 DWORD FspFsctlTransactBatchCode = FSP_FSCTL_TRANSACT_BATCH;
static VOID FspFsctlServiceVersion(PUINT32 PVersion); static VOID FspFsctlServiceVersion(PUINT32 PVersion);
static NTSTATUS FspFsctlStartService(VOID);
FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize, PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
PHANDLE PVolumeHandle) PHANDLE PVolumeHandle)
{ {
NTSTATUS Result; WCHAR SxsDevicePathBuf[MAX_PATH];
PWSTR DeviceRoot; PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize, VolumeParamsSize; SIZE_T DeviceRootSize, DevicePathSize, VolumeParamsSize;
WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd; WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE; HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes; DWORD Bytes;
NTSTATUS Result;
DevicePath = FspSxsAppendSuffix(SxsDevicePathBuf, sizeof SxsDevicePathBuf, DevicePath);
if (sizeof(WCHAR) <= VolumeNameSize) if (sizeof(WCHAR) <= VolumeNameSize)
VolumeNameBuf[0] = L'\0'; VolumeNameBuf[0] = L'\0';
@ -229,12 +231,15 @@ exit:
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath, FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize) PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize)
{ {
NTSTATUS Result; WCHAR SxsDevicePathBuf[MAX_PATH];
PWSTR DeviceRoot; PWSTR DeviceRoot;
SIZE_T DeviceRootSize, DevicePathSize; SIZE_T DeviceRootSize, DevicePathSize;
WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr; WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr;
HANDLE VolumeHandle = INVALID_HANDLE_VALUE; HANDLE VolumeHandle = INVALID_HANDLE_VALUE;
DWORD Bytes; DWORD Bytes;
NTSTATUS Result;
DevicePath = FspSxsAppendSuffix(SxsDevicePathBuf, sizeof SxsDevicePathBuf, DevicePath);
/* check lengths; everything must fit within MAX_PATH */ /* check lengths; everything must fit within MAX_PATH */
DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\"; DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\";
@ -298,16 +303,71 @@ FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath)
return STATUS_SUCCESS; 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( static BOOL WINAPI FspFsctlServiceVersionInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{ {
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME; WCHAR DriverName[256];
PWSTR ModuleFileName; PWSTR ModuleFileName;
SC_HANDLE ScmHandle = 0; SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0; SC_HANDLE SvcHandle = 0;
QUERY_SERVICE_CONFIGW *ServiceConfig = 0; QUERY_SERVICE_CONFIGW *ServiceConfig = 0;
DWORD Size; DWORD Size;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
ScmHandle = OpenSCManagerW(0, 0, 0); ScmHandle = OpenSCManagerW(0, 0, 0);
if (0 == ScmHandle) if (0 == ScmHandle)
goto exit; goto exit;
@ -371,29 +431,33 @@ static VOID FspFsctlServiceVersion(PUINT32 PVersion)
*PVersion = FspFsctlServiceVersionValue; *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 ScmHandle = 0;
SC_HANDLE SvcHandle = 0; SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus; SERVICE_STATUS ServiceStatus;
DWORD LastError; DWORD LastError;
NTSTATUS Result; NTSTATUS Result;
AcquireSRWLockExclusive(&Lock); AcquireSRWLockExclusive(&FspFsctlStartStopServiceLock);
/* Determine if we are running inside container. if (FspFsctlRunningInContainer())
*
* 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)
{ {
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
goto exit; goto exit;
@ -453,7 +517,218 @@ exit:
if (0 != ScmHandle) if (0 != ScmHandle)
CloseServiceHandle(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; return Result;
} }
@ -461,14 +736,15 @@ exit:
static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle) 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; PSID WorldSid;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0; PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0; PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry; EXPLICIT_ACCESSW AccessEntries[2];
ACCESS_MASK AccessRights;
PACL Dacl; PACL Dacl;
BOOL DaclPresent, DaclDefaulted; BOOL DaclPresent, DaclDefaulted;
DWORD Size; DWORD Size;
@ -513,41 +789,28 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
goto exit; goto exit;
} }
/* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START right for Everyone */ /* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START rights for Everyone */
AccessEntry.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START; AccessEntries[0].grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START;
AccessEntry.grfAccessMode = GRANT_ACCESS; AccessEntries[0].grfAccessMode = GRANT_ACCESS;
AccessEntry.grfInheritance = NO_INHERITANCE; AccessEntries[0].grfInheritance = NO_INHERITANCE;
AccessEntry.Trustee.pMultipleTrustee = 0; AccessEntries[0].Trustee.pMultipleTrustee = 0;
AccessEntry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; AccessEntries[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntry.Trustee.TrusteeForm = TRUSTEE_IS_SID; AccessEntries[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntry.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; AccessEntries[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntry.Trustee.ptstrName = WorldSid; AccessEntries[0].Trustee.ptstrName = WorldSid;
/* get the effective rights for Everyone */ /* prepare an EXPLICIT_ACCESS to deny the SERVICE_STOP right to Everyone */
AccessRights = 0; AccessEntries[1].grfAccessPermissions = SERVICE_STOP;
if (DaclPresent && 0 != Dacl) AccessEntries[1].grfAccessMode = DENY_ACCESS;
{ AccessEntries[1].grfInheritance = NO_INHERITANCE;
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights); AccessEntries[1].Trustee.pMultipleTrustee = 0;
if (0 != LastError) AccessEntries[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
/* AccessEntries[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
* Apparently GetEffectiveRightsFromAclW can fail with ERROR_CIRCULAR_DEPENDENCY AccessEntries[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
* in some rare circumstances. Calling GetEffectiveRightsFromAclW is not essential AccessEntries[1].Trustee.ptstrName = WorldSid;
* 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;
}
/* do we have the required access rights? */
if (AccessEntry.grfAccessPermissions != (AccessRights & AccessEntry.grfAccessPermissions))
{
/* create a new security descriptor with the new access */ /* create a new security descriptor with the new access */
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor, LastError = BuildSecurityDescriptorW(0, 0, 2, AccessEntries, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor); &Size, &NewSecurityDescriptor);
if (0 != LastError) if (0 != LastError)
{ {
@ -561,7 +824,6 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
} }
}
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
@ -575,7 +837,7 @@ exit:
NTSTATUS FspFsctlRegister(VOID) NTSTATUS FspFsctlRegister(VOID)
{ {
extern HINSTANCE DllInstance; extern HINSTANCE DllInstance;
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME; WCHAR DriverName[256];
WCHAR DriverPath[MAX_PATH]; WCHAR DriverPath[MAX_PATH];
DWORD Size; DWORD Size;
SC_HANDLE ScmHandle = 0; SC_HANDLE ScmHandle = 0;
@ -584,6 +846,8 @@ NTSTATUS FspFsctlRegister(VOID)
SERVICE_DESCRIPTION ServiceDescription; SERVICE_DESCRIPTION ServiceDescription;
NTSTATUS Result; NTSTATUS Result;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
Result = FspGetModuleFileName(DllInstance, DriverPath, MAX_PATH, L"" MyFsctlRegisterPath); Result = FspGetModuleFileName(DllInstance, DriverPath, MAX_PATH, L"" MyFsctlRegisterPath);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -674,12 +938,16 @@ exit:
NTSTATUS FspFsctlUnregister(VOID) NTSTATUS FspFsctlUnregister(VOID)
{ {
PWSTR DriverName = L"" FSP_FSCTL_DRIVER_NAME; WCHAR DriverName[256];
SC_HANDLE ScmHandle = 0; SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0; SC_HANDLE SvcHandle = 0;
DWORD LastError; DWORD LastError;
NTSTATUS Result; NTSTATUS Result;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
FspFsctlStopService();
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE); ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_CREATE_SERVICE);
/* /*
* The SC_MANAGER_CREATE_SERVICE access right is not strictly needed here, * The SC_MANAGER_CREATE_SERVICE access right is not strictly needed here,

View File

@ -180,7 +180,7 @@ FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_args *args) const char *mountpoint, struct fuse_args *args)
{ {
struct fuse_chan *ch = 0; struct fuse_chan *ch = 0;
WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH]; WCHAR TempMountPointBuf[MAX_PATH], MountPointBuf[MAX_PATH + 4];
int Size; int Size;
if (0 == mountpoint || '\0' == mountpoint[0] || if (0 == mountpoint || '\0' == mountpoint[0] ||
@ -212,6 +212,33 @@ FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
MountPointBuf[6] = '\0'; MountPointBuf[6] = '\0';
Size = 7 * sizeof(WCHAR); Size = 7 * sizeof(WCHAR);
} }
else if (
(
'\\' == mountpoint[0] &&
'\\' == mountpoint[1] &&
('?' == mountpoint[2] || '.' == mountpoint[2]) &&
'\\' == mountpoint[3]
) &&
(
('A' <= mountpoint[4] && mountpoint[4] <= 'Z') ||
('a' <= mountpoint[4] && mountpoint[4] <= 'z')
) &&
':' == mountpoint[5] && '\\' == mountpoint[6])
{
MountPointBuf[0] = '\\';
MountPointBuf[1] = '\\';
MountPointBuf[2] = mountpoint[2];
MountPointBuf[3] = '\\';
Size = 0;
if (0 != MultiByteToWideChar(CP_UTF8, 0, mountpoint + 4, -1, TempMountPointBuf, MAX_PATH))
Size = GetFullPathNameW(TempMountPointBuf, MAX_PATH, MountPointBuf + 4, 0);
if (0 == Size || MAX_PATH <= Size)
goto fail;
Size = (Size + 4 + 1) * sizeof(WCHAR);
}
else if ( else if (
( (
('A' <= mountpoint[0] && mountpoint[0] <= 'Z') || ('A' <= mountpoint[0] && mountpoint[0] <= 'Z') ||

View File

@ -70,6 +70,9 @@ NTSTATUS FspNpUnregister(VOID);
NTSTATUS FspEventLogRegister(VOID); NTSTATUS FspEventLogRegister(VOID);
NTSTATUS FspEventLogUnregister(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 FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult);
PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType); PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);
@ -90,6 +93,12 @@ ULONG FspLdapGetDefaultNamingContext(PVOID Ldap, PWSTR *PValue);
ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue); ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue);
PWSTR FspDiagIdent(VOID); PWSTR FspDiagIdent(VOID);
HANDLE FspCreateDirectoryFileW(
PWSTR FileName,
DWORD DesiredAccess,
DWORD ShareAccess,
PSECURITY_ATTRIBUTES SecurityAttributes,
DWORD FlagsAndAttributes);
NTSTATUS FspGetModuleVersion(PWSTR ModuleFileName, PUINT32 PVersion); NTSTATUS FspGetModuleVersion(PWSTR ModuleFileName, PUINT32 PVersion);
NTSTATUS FspGetModuleFileName( NTSTATUS FspGetModuleFileName(
HMODULE Module, HMODULE Module,

View File

@ -488,14 +488,12 @@ static NTSTATUS FspMountSet_Directory(PWSTR VolumeName, PWSTR MountPoint,
SecurityAttributes.nLength = sizeof SecurityAttributes; SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor; SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
MountHandle = CreateFileW(MountPoint, MountHandle = FspCreateDirectoryFileW(MountPoint,
FILE_WRITE_ATTRIBUTES, FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&SecurityAttributes, &SecurityAttributes,
CREATE_NEW,
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DIRECTORY |
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE);
0);
if (INVALID_HANDLE_VALUE == MountHandle) if (INVALID_HANDLE_VALUE == MountHandle)
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());

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

@ -64,6 +64,145 @@ PWSTR FspDiagIdent(VOID)
return FspDiagIdentBuf; return FspDiagIdentBuf;
} }
static INIT_ONCE FspCreateDirectoryFileInitOnce = INIT_ONCE_STATIC_INIT;
static NTSTATUS (NTAPI *FspNtCreateFile)(
PHANDLE FileHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PIO_STATUS_BLOCK IoStatusBlock,
PLARGE_INTEGER AllocationSize,
ULONG FileAttributes,
ULONG ShareAccess,
ULONG CreateDisposition,
ULONG CreateOptions,
PVOID EaBuffer,
ULONG EaLength);
static BOOL WINAPI FspCreateDirectoryFileInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
HANDLE Handle;
Handle = GetModuleHandleW(L"ntdll.dll");
if (0 != Handle)
FspNtCreateFile = (PVOID)GetProcAddress(Handle, "NtCreateFile");
return TRUE;
}
HANDLE FspCreateDirectoryFileW(
PWSTR FileName,
DWORD DesiredAccess,
DWORD ShareAccess,
PSECURITY_ATTRIBUTES SecurityAttributes,
DWORD FlagsAndAttributes)
{
InitOnceExecuteOnce(&FspCreateDirectoryFileInitOnce, FspCreateDirectoryFileInitialize, 0, 0);
if (0 == FspNtCreateFile)
{
SetLastError(ERROR_INVALID_FUNCTION);
return INVALID_HANDLE_VALUE;
}
HANDLE Handle = INVALID_HANDLE_VALUE, ParentHandle = INVALID_HANDLE_VALUE;
PWSTR FullFileName = 0;
WCHAR *FilePart, FilePartChar;
DWORD Length;
UNICODE_STRING UFullFileName;
OBJECT_ATTRIBUTES Obja;
ULONG CreateFlags;
IO_STATUS_BLOCK IoStatus;
Length = GetFullPathNameW(FileName, 0, 0, 0);
if (0 == Length)
goto exit;
FullFileName = MemAlloc((Length + 1) * sizeof(WCHAR));
if (0 == FullFileName)
{
SetLastError(ERROR_NO_SYSTEM_RESOURCES);
goto exit;
}
Length = GetFullPathNameW(FileName, Length + 1, FullFileName, &FilePart);
if (0 == Length)
goto exit;
FilePartChar = *FilePart;
*FilePart = L'\0';
ParentHandle = CreateFileW(
FullFileName,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
0);
if (INVALID_HANDLE_VALUE == ParentHandle)
goto exit;
*FilePart = FilePartChar;
UFullFileName.Length = UFullFileName.MaximumLength = (USHORT)(lstrlenW(FilePart) * sizeof(WCHAR));
UFullFileName.Buffer = FilePart;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &UFullFileName;
Obja.Attributes =
(!(FlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS) ? OBJ_CASE_INSENSITIVE : 0) |
(SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0);
Obja.RootDirectory = ParentHandle;
Obja.SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
DesiredAccess |=
SYNCHRONIZE |
FILE_READ_ATTRIBUTES |
((FlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE) ? DELETE : 0);
CreateFlags =
FILE_DIRECTORY_FILE |
((FlagsAndAttributes & FILE_FLAG_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0) |
((FlagsAndAttributes & FILE_FLAG_OVERLAPPED) ? FILE_SYNCHRONOUS_IO_NONALERT : 0) |
((FlagsAndAttributes & FILE_FLAG_NO_BUFFERING) ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
((FlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS) ? FILE_RANDOM_ACCESS : 0) |
((FlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN) ? FILE_SEQUENTIAL_ONLY : 0) |
((FlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE) ? FILE_DELETE_ON_CLOSE : 0) |
((FlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS) ? FILE_OPEN_FOR_BACKUP_INTENT : 0) |
((FlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT) ? FILE_OPEN_REPARSE_POINT : 0) |
((FlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL) ? FILE_OPEN_NO_RECALL : 0);
IoStatus.Status = FspNtCreateFile(
&Handle,
DesiredAccess,
&Obja,
&IoStatus,
0,
FlagsAndAttributes & (0x7fff & ~FILE_ATTRIBUTE_DIRECTORY),
ShareAccess,
FILE_CREATE,
CreateFlags,
0,
0);
if (!NT_SUCCESS(IoStatus.Status))
{
SetLastError(FspWin32FromNtStatus(IoStatus.Status));
Handle = INVALID_HANDLE_VALUE;
goto exit;
}
SetLastError(0);
exit:
if (INVALID_HANDLE_VALUE != ParentHandle)
CloseHandle(ParentHandle);
MemFree(FullFileName);
return Handle;
}
FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName, FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize, PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout, PULONG PBytesTransferred, ULONG Timeout,

View File

@ -62,10 +62,12 @@ static void usage(void)
"\n" "\n"
"commands:\n" "commands:\n"
" lsvol list file system devices (volumes)\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" " 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); PROGNAME);
} }
@ -237,6 +239,29 @@ NTSTATUS FspToolGetSidFromName(PWSTR Name, PSID *PSid)
return STATUS_SUCCESS; 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) static NTSTATUS lsvol_dev(PWSTR DeviceName)
{ {
NTSTATUS Result; NTSTATUS Result;
@ -255,7 +280,7 @@ static NTSTATUS lsvol_dev(PWSTR DeviceName)
if (L'\0' == *P) if (L'\0' == *P)
{ {
Drive[0] = FspToolGetDriveLetter(&LogicalDrives, VolumeName); Drive[0] = FspToolGetDriveLetter(&LogicalDrives, VolumeName);
info("%-4S%S", Drive[0] ? Drive : L"", VolumeName); info("%-4S%S", Drive[0] ? Drive : L"-", VolumeName);
VolumeName = P + 1; VolumeName = P + 1;
} }
@ -541,6 +566,52 @@ static int perm(int argc, wchar_t **argv)
return FspWin32FromNtStatus(Result); 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) int wmain(int argc, wchar_t **argv)
{ {
argc--; argc--;
@ -549,6 +620,9 @@ int wmain(int argc, wchar_t **argv)
if (0 == argc) if (0 == argc)
usage(); usage();
if (0 == invariant_wcscmp(L"ver", argv[0]))
return ver(argc, argv);
else
if (0 == invariant_wcscmp(L"lsvol", argv[0])) if (0 == invariant_wcscmp(L"lsvol", argv[0]))
return lsvol(argc, argv); return lsvol(argc, argv);
else else
@ -557,6 +631,15 @@ int wmain(int argc, wchar_t **argv)
else else
if (0 == invariant_wcscmp(L"perm", argv[0])) if (0 == invariant_wcscmp(L"perm", argv[0]))
return perm(argc, argv); 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 else
usage(); usage();

View File

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

View File

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

View File

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

View File

@ -22,15 +22,24 @@
#include <sys/driver.h> #include <sys/driver.h>
DRIVER_INITIALIZE DriverEntry; DRIVER_INITIALIZE DriverEntry;
static DRIVER_UNLOAD DriverUnload;
static VOID FspDriverMultiVersionInitialize(VOID); static VOID FspDriverMultiVersionInitialize(VOID);
static NTSTATUS FspDriverInitializeDevices(VOID); static NTSTATUS FspDriverInitializeDevices(VOID);
static VOID FspDriverFinalizeDevices(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 #ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(INIT, FspDriverMultiVersionInitialize) #pragma alloc_text(INIT, FspDriverMultiVersionInitialize)
#pragma alloc_text(PAGE, FspDriverInitializeDevices) #pragma alloc_text(PAGE, FspDriverInitializeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevices) #pragma alloc_text(PAGE, FspDriverFinalizeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevicesForUnload)
#pragma alloc_text(PAGE, FspDriverFinalizeDevicesEx)
#pragma alloc_text(PAGE, FspDriverUnload)
#endif #endif
NTSTATUS DriverEntry( NTSTATUS DriverEntry(
@ -40,7 +49,10 @@ NTSTATUS DriverEntry(
FSP_TRACE_INIT(); FSP_TRACE_INIT();
FspSxsIdentInitialize(&DriverObject->DriverName);
/* setup the driver object */ /* setup the driver object */
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate; DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose;
DriverObject->MajorFunction[IRP_MJ_READ] = FspRead; DriverObject->MajorFunction[IRP_MJ_READ] = FspRead;
@ -128,6 +140,7 @@ NTSTATUS DriverEntry(
FspDriverObject = DriverObject; FspDriverObject = DriverObject;
FspDriverMultiVersionInitialize(); FspDriverMultiVersionInitialize();
ExInitializeFastMutex(&FspDriverUnloadMutex);
ExInitializeFastMutex(&FspDeviceGlobalMutex); ExInitializeFastMutex(&FspDeviceGlobalMutex);
Result = FspSiloInitialize(FspDriverInitializeDevices, FspDriverFinalizeDevices); Result = FspSiloInitialize(FspDriverInitializeDevices, FspDriverFinalizeDevices);
@ -150,6 +163,10 @@ NTSTATUS DriverEntry(
goto exit; goto exit;
InitDoneDevices = TRUE; InitDoneDevices = TRUE;
Result = FspSiloPostInitialize();
if (!NT_SUCCESS(Result))
goto exit;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
exit: exit:
@ -172,6 +189,26 @@ exit:
&DriverObject->DriverName, RegistryPath); &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) static VOID FspDriverMultiVersionInitialize(VOID)
{ {
FspProcessorCount = KeQueryActiveProcessorCount(0); FspProcessorCount = KeQueryActiveProcessorCount(0);
@ -202,6 +239,8 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
FSP_SILO_GLOBALS *Globals; FSP_SILO_GLOBALS *Globals;
UNICODE_STRING DeviceSddl; UNICODE_STRING DeviceSddl;
UNICODE_STRING DeviceName; UNICODE_STRING DeviceName;
WCHAR DeviceNameBuf[128];
UNICODE_STRING SymlinkName;
GUID Guid; GUID Guid;
NTSTATUS Result; NTSTATUS Result;
@ -210,20 +249,46 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
/* create the file system control device objects */ /* create the file system control device objects */
RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL); 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, Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, &DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid, &DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlDiskDeviceObject); &Globals->FsctlDiskDeviceObject);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; 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, Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, &DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid, &DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlNetDeviceObject); &Globals->FsctlNetDeviceObject);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; 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, Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0,
FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE,
&Globals->FsmupDeviceObject); &Globals->FsmupDeviceObject);
@ -257,8 +322,9 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
Result = RtlUnicodeStringPrintf(&DeviceName, Result = RtlUnicodeStringPrintf(&DeviceName,
0 == ((PULONG)&Guid)[0] && 0 == ((PULONG)&Guid)[1] && 0 == ((PULONG)&Guid)[0] && 0 == ((PULONG)&Guid)[1] &&
0 == ((PULONG)&Guid)[2] && 0 == ((PULONG)&Guid)[3] ? 0 == ((PULONG)&Guid)[2] && 0 == ((PULONG)&Guid)[3] ?
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME : L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "%wZ":
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{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
FspSxsSuffix(),
Guid.Data1, Guid.Data2, Guid.Data3, Guid.Data1, Guid.Data2, Guid.Data3,
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3], Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
@ -277,12 +343,25 @@ static NTSTATUS FspDriverInitializeDevices(VOID)
* as a file system; we register with the MUP instead. * as a file system; we register with the MUP instead.
*/ */
IoRegisterFileSystem(Globals->FsctlDiskDeviceObject); 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; Result = STATUS_SUCCESS;
exit: exit:
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
if (Globals->InitDoneRegisterDisk)
{
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 0;
}
if (0 != Globals->MupHandle) if (0 != Globals->MupHandle)
{ {
FsRtlDeregisterUncProvider(Globals->MupHandle); FsRtlDeregisterUncProvider(Globals->MupHandle);
@ -293,11 +372,23 @@ exit:
FspDeviceDelete(Globals->FsmupDeviceObject); FspDeviceDelete(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0; Globals->FsmupDeviceObject = 0;
} }
if (Globals->InitDoneSymlinkNet)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkNet = 0;
}
if (0 != Globals->FsctlNetDeviceObject) if (0 != Globals->FsctlNetDeviceObject)
{ {
FspDeviceDelete(Globals->FsctlNetDeviceObject); FspDeviceDelete(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0; Globals->FsctlNetDeviceObject = 0;
} }
if (Globals->InitDoneSymlinkDisk)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkDisk = 0;
}
if (0 != Globals->FsctlDiskDeviceObject) if (0 != Globals->FsctlDiskDeviceObject)
{ {
FspDeviceDelete(Globals->FsctlDiskDeviceObject); FspDeviceDelete(Globals->FsctlDiskDeviceObject);
@ -314,40 +405,151 @@ static VOID FspDriverFinalizeDevices(VOID)
{ {
PAGED_CODE(); PAGED_CODE();
FspDriverFinalizeDevicesEx(TRUE);
}
static VOID FspDriverFinalizeDevicesForUnload(VOID)
{
PAGED_CODE();
FspDriverFinalizeDevicesEx(FALSE);
}
static VOID FspDriverFinalizeDevicesEx(BOOLEAN DeleteDevices)
{
PAGED_CODE();
FSP_SILO_GLOBALS *Globals; FSP_SILO_GLOBALS *Globals;
UNICODE_STRING SymlinkName;
FspSiloGetGlobals(&Globals); FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals); ASSERT(0 != Globals);
if (Globals->InitDoneRegisterDisk)
{
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject); IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 0;
}
if (0 != Globals->MupHandle) if (0 != Globals->MupHandle)
{ {
FsRtlDeregisterUncProvider(Globals->MupHandle); FsRtlDeregisterUncProvider(Globals->MupHandle);
Globals->MupHandle = 0; Globals->MupHandle = 0;
} }
if (0 != Globals->FsmupDeviceObject) if (0 != Globals->FsmupDeviceObject)
{
if (DeleteDevices)
{ {
FspDeviceDelete(Globals->FsmupDeviceObject); FspDeviceDelete(Globals->FsmupDeviceObject);
ObDereferenceObject(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0; 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) if (0 != Globals->FsctlNetDeviceObject)
{
if (DeleteDevices)
{ {
FspDeviceDelete(Globals->FsctlNetDeviceObject); FspDeviceDelete(Globals->FsctlNetDeviceObject);
ObDereferenceObject(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0; 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) if (0 != Globals->FsctlDiskDeviceObject)
{
if (DeleteDevices)
{ {
FspDeviceDelete(Globals->FsctlDiskDeviceObject); FspDeviceDelete(Globals->FsctlDiskDeviceObject);
ObDereferenceObject(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0; Globals->FsctlDiskDeviceObject = 0;
} }
else
FspDeviceDoIoDeleteDevice(Globals->FsctlDiskDeviceObject);
}
FspSiloDereferenceGlobals(Globals); 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; PDRIVER_OBJECT FspDriverObject;
FAST_IO_DISPATCH FspFastIoDispatch; FAST_IO_DISPATCH FspFastIoDispatch;
CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
FAST_MUTEX FspDriverUnloadMutex;
BOOLEAN FspDriverUnloadDone;
ULONG FspProcessorCount; ULONG FspProcessorCount;
FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;

View File

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

View File

@ -1475,7 +1475,7 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
{ {
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result; Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 2); (PVOID)((UINT_PTR)DescendantFileNode | 4);
} }
else else
Result = STATUS_ACCESS_DENIED; Result = STATUS_ACCESS_DENIED;

View File

@ -128,6 +128,9 @@ static NTSTATUS FspFsctlFileSystemControl(
if (0 != IrpSp->FileObject->FsContext2) if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeNotify(FsctlDeviceObject, Irp, IrpSp); Result = FspVolumeNotify(FsctlDeviceObject, Irp, IrpSp);
break; break;
case FSP_FSCTL_UNLOAD:
Result = FspDriverUnload(FsctlDeviceObject, Irp, IrpSp);
break;
default: default:
if (CTL_CODE(0, 0xC00, 0, 0) == if (CTL_CODE(0, 0xC00, 0, 0) ==
(IrpSp->Parameters.FileSystemControl.FsControlCode & CTL_CODE(0, 0xC00, 0, 0))) (IrpSp->Parameters.FileSystemControl.FsControlCode & CTL_CODE(0, 0xC00, 0, 0)))

View File

@ -123,6 +123,27 @@ NTSTATUS FspProcessBufferInitialize(VOID)
VOID FspProcessBufferFinalize(VOID) VOID FspProcessBufferFinalize(VOID)
{ {
PsSetCreateProcessNotifyRoutine(FspProcessBufferNotifyRoutine, TRUE); 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) static VOID FspProcessBufferNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)

View File

@ -22,9 +22,11 @@
#include <sys/driver.h> #include <sys/driver.h>
NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini); NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini);
NTSTATUS FspSiloPostInitialize(VOID);
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, FspSiloInitialize) #pragma alloc_text(INIT, FspSiloInitialize)
#pragma alloc_text(INIT, FspSiloPostInitialize)
#endif #endif
typedef PEJOB FSP_PESILO; typedef PEJOB FSP_PESILO;
@ -108,6 +110,9 @@ static FSP_SILO_INIT_CALLBACK FspSiloInitCallback;
static FSP_SILO_FINI_CALLBACK FspSiloFiniCallback; static FSP_SILO_FINI_CALLBACK FspSiloFiniCallback;
static BOOLEAN FspSiloInitDone = FALSE; static BOOLEAN FspSiloInitDone = FALSE;
static FAST_MUTEX FspSiloListMutex;
static LIST_ENTRY FspSiloList;
static FSP_SILO_GLOBALS FspSiloHostGlobals; static FSP_SILO_GLOBALS FspSiloHostGlobals;
#define FSP_SILO_MONITOR_REGISTRATION_VERSION 1 #define FSP_SILO_MONITOR_REGISTRATION_VERSION 1
@ -123,6 +128,11 @@ static FSP_SILO_GLOBALS FspSiloHostGlobals;
} }
#define CALL(n) (FspSilo ## n) #define CALL(n) (FspSilo ## n)
BOOLEAN FspSiloIsHost(VOID)
{
return !FspSiloInitDone || 0 == CALL(PsGetCurrentServerSilo)();
}
NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals) NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals)
{ {
FSP_PESILO Silo; FSP_PESILO Silo;
@ -189,6 +199,7 @@ static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
RtlZeroMemory(Globals, sizeof(FSP_SILO_GLOBALS)); RtlZeroMemory(Globals, sizeof(FSP_SILO_GLOBALS));
Globals->Silo = Silo;
/* PsInsertSiloContext adds reference to Globals */ /* PsInsertSiloContext adds reference to Globals */
Result = CALL(PsInsertSiloContext)(Silo, ContextSlot, Globals); Result = CALL(PsInsertSiloContext)(Silo, ContextSlot, Globals);
@ -196,6 +207,9 @@ static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
goto exit; goto exit;
Inserted = TRUE; Inserted = TRUE;
FsRtlEnterFileSystem();
ExAcquireFastMutexUnsafe(&FspSiloListMutex);
if (0 != FspSiloInitCallback) if (0 != FspSiloInitCallback)
{ {
FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo); FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo);
@ -203,6 +217,12 @@ static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo)
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo); CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
} }
if (NT_SUCCESS(Result))
InsertTailList(&FspSiloList, &Globals->ListEntry);
ExReleaseFastMutexUnsafe(&FspSiloListMutex);
FsRtlExitFileSystem();
exit: exit:
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
@ -237,6 +257,11 @@ static VOID NTAPI FspSiloMonitorTerminateCallback(FSP_PESILO Silo)
Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals); Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return; return;
FsRtlEnterFileSystem();
ExAcquireFastMutexUnsafe(&FspSiloListMutex);
RemoveEntryList(&Globals->ListEntry);
CALL(PsDereferenceSiloContext)(Globals); CALL(PsDereferenceSiloContext)(Globals);
Globals = 0; Globals = 0;
@ -247,6 +272,9 @@ static VOID NTAPI FspSiloMonitorTerminateCallback(FSP_PESILO Silo)
CALL(PsDetachSiloFromCurrentThread)(PreviousSilo); CALL(PsDetachSiloFromCurrentThread)(PreviousSilo);
} }
ExReleaseFastMutexUnsafe(&FspSiloListMutex);
FsRtlExitFileSystem();
/* PsRemoveSiloContext removes reference to Globals (possibly freeing it) */ /* PsRemoveSiloContext removes reference to Globals (possibly freeing it) */
CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0); CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0);
} }
@ -255,6 +283,9 @@ NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK F
{ {
NTSTATUS Result = STATUS_SUCCESS; NTSTATUS Result = STATUS_SUCCESS;
ExInitializeFastMutex(&FspSiloListMutex);
InitializeListHead(&FspSiloList);
if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS5)) if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS5))
{ {
ULONG Fail = 0; ULONG Fail = 0;
@ -293,15 +324,11 @@ NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK F
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
Result = CALL(PsStartSiloMonitor)(Monitor);
if (!NT_SUCCESS(Result))
goto exit;
FspSiloMonitor = Monitor; FspSiloMonitor = Monitor;
FspSiloInitCallback = Init; FspSiloInitCallback = Init;
FspSiloFiniCallback = Fini; FspSiloFiniCallback = Fini;
FspSiloInitDone = TRUE; FspSiloInitDone = TRUE;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
exit: exit:
@ -316,10 +343,62 @@ NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK F
return Result; return Result;
} }
NTSTATUS FspSiloPostInitialize(VOID)
{
if (!FspSiloInitDone)
return STATUS_SUCCESS;
return CALL(PsStartSiloMonitor)(FspSiloMonitor);
}
VOID FspSiloFinalize(VOID) VOID FspSiloFinalize(VOID)
{ {
if (!FspSiloInitDone) if (!FspSiloInitDone)
return; return;
CALL(PsUnregisterSiloMonitor)(FspSiloMonitor); 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

@ -113,6 +113,57 @@ NTSTATUS FspVolumeCreate(
FspSiloDereferenceGlobals(Globals); FspSiloDereferenceGlobals(Globals);
if (NT_SUCCESS(Result))
{
/*
* If we have an fsvrt device, mount it NOW via opening the volume. This ensures
* that the fsvrt is mounted by the correct fsvol device early on and remedies
* a rare case where NTFS crashes the system when it attempts to mount our fsvrt.
*
* We use IoCreateFileEx with FILE_READ_DATA to ensure that the I/O Manager will
* mount the fsvrt device.
*
* We ignore the IoCreateFileEx return code as it is only used for its side effect
* of mounting the fsvrt. In the unlikely event that IoCreateFileEx fails, the
* system will retry the mount when a file is accessed, etc.
*/
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatus;
HANDLE Handle;
if (0 != FsvrtDeviceObject)
{
InitializeObjectAttributes(
&ObjectAttributes,
&FsvolDeviceExtension->VolumeName,
OBJ_KERNEL_HANDLE,
0/*RootDirectory*/,
0/*SecurityDescriptor*/);
IoStatus.Status = IoCreateFileEx(
&Handle,
FILE_READ_DATA,
&ObjectAttributes,
&IoStatus,
0/*AllocationSize*/,
0/*FileAttributes*/,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
0/*CreateOptions*/,
0/*EaBuffer*/,
0/*EaLength*/,
CreateFileTypeNone,
0/*InternalParameters*/,
0/*Options*/,
0/*DriverContext*/);
if (NT_SUCCESS(IoStatus.Status))
ObCloseHandle(Handle, KernelMode);
}
}
return Result; return Result;
} }

View File

@ -7,7 +7,8 @@ set Config=Debug
set Suffix=x64 set Suffix=x64
set Deploy=C:\Deploy\winfsp set Deploy=C:\Deploy\winfsp
set Target=Win10DBG set Target=Win10DBG
set Chkpnt=winfsp set Chkpnt=docker+winfsp
set CImage=mcr.microsoft.com/windows/servercore:1909
if not X%1==X set Target=%1 if not X%1==X set Target=%1
if not X%2==X set Chkpnt=%2 if not X%2==X set Chkpnt=%2
@ -15,6 +16,10 @@ if not X%2==X set Chkpnt=%2
echo regsvr32 /s winfsp-x64.dll echo regsvr32 /s winfsp-x64.dll
) > %~dp0..\build\VStudio\build\%Config%\deploy-setup.bat ) > %~dp0..\build\VStudio\build\%Config%\deploy-setup.bat
(
echo docker run -it --rm --isolation=process -v%Deploy%:%Deploy%:RW %CImage% cmd.exe /k cd %Deploy%
) > %~dp0..\build\VStudio\build\%Config%\docker-run.bat
set Files= set Files=
for %%f in ( for %%f in (
%~dp0..\build\VStudio\build\%Config%\ %~dp0..\build\VStudio\build\%Config%\
@ -22,7 +27,9 @@ for %%f in (
winfsp-%Suffix%.dll winfsp-%Suffix%.dll
winfsp-tests-%Suffix%.exe winfsp-tests-%Suffix%.exe
memfs-%Suffix%.exe memfs-%Suffix%.exe
fsptool-%Suffix%.exe
deploy-setup.bat deploy-setup.bat
docker-run.bat
) do ( ) do (
set File=%%~f set File=%%~f
if [!File:~-1!] == [\] ( if [!File:~-1!] == [\] (

View File

@ -1,28 +1,53 @@
@echo off @echo off
setlocal setlocal
setlocal EnableDelayedExpansion
echo WINFSP INSTALLATION DIRECTORY AND LAUNCHER REGISTRATIONS REM Determine the SxS (side-by-side) identifier.
reg query HKLM\SOFTWARE\WinFsp /s /reg:32 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.
echo WINFSP DLL REGISTRATIONS echo WINFSP DLL
reg query HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order reg query HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Np\NetworkProvider reg query HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Np\NetworkProvider
reg query HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\WinFsp reg query HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\WinFsp
echo. echo.
echo WINFSP FSD CONFIGURATION AND STATUS echo WINFSP LAUNCHER
sc query WinFsp
sc qc WinFsp
sc sdshow WinFsp
echo.
echo WINFSP LAUNCHER SERVICE CONFIGURATION AND STATUS
sc query WinFsp.Launcher sc query WinFsp.Launcher
sc qc WinFsp.Launcher sc qc WinFsp.Launcher
sc sdshow WinFsp.Launcher sc sdshow WinFsp.Launcher
echo. 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 echo OS INFORMATION
systeminfo systeminfo

341
tools/make-release.ps1 Normal file
View File

@ -0,0 +1,341 @@
param (
[string]$StateFile = "release.state"
)
function Write-Stdout ($Message) {
[System.Console]::WriteLine($Message)
}
function Write-Stderr ($Message) {
[System.Console]::Error.WriteLine($Message)
}
function Git-Describe {
$GitDesc = git describe --long --dirty
if ($GitDesc -match "^(.+)-([0-9]+)-g([0-9A-Fa-f]+)-?(dirty)?$") {
$matches[1]
$matches[2]
$matches[3]
$matches[4]
}
}
function Git-Dirty {
$Dirty = $False
git status --porcelain=v2 2>$null | ForEach-Object {
$Dirty = $True
}
return $Dirty
}
function Git-LogGrep ($Tag) {
git log -n 1 --grep $Tag
}
function Get-ReleaseInfo ($Tag) {
$Found = 0
$ReleaseInfo = [PSCustomObject]@{
Tag = ""
ProductVersion = ""
Prerelease = $False
PreviousTag = ""
PreviousProductVersion = ""
Text = @()
}
foreach ($Line in Get-Content "$ProjectRoot\Changelog.md") {
if ($Line -match "^## (v[^ ]+) *\(([^)]+)\)") {
if ($Found) {
$Found = 2
$PreviousTag = $matches[1]
$PreviousProductVersion = $matches[2]
if ($PreviousTag -match "^v[0-9.]+$") {
$ReleaseInfo.PreviousTag = $PreviousTag
$ReleaseInfo.PreviousProductVersion = $PreviousProductVersion
break
}
} elseif ($Tag -eq $matches[1]) {
$Found = 1
$ReleaseInfo.Tag = $matches[1]
$ReleaseInfo.ProductVersion = $matches[2]
$ReleaseInfo.Prerelease = !($ReleaseInfo.Tag -match "^v[0-9.]+$")
}
} elseif (1 -eq $Found) {
$ReleaseInfo.Text += $Line
}
}
if ($Found) {
return $ReleaseInfo
}
}
function Get-FileVersion ($FileName) {
return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
}
function Task ($ScriptBlock) {
$Name = (Get-PSCallStack)[1].FunctionName
if ($State -contains $Name) {
return
}
Write-Stdout $Name
Invoke-Command -ScriptBlock $ScriptBlock
Write-Stdout "$Name COMPLETE"
Add-Content $StateFile -Value $Name
exit 0
}
function Check-Prerequisites {
$Name = (Get-PSCallStack)[0].FunctionName
# check git.exe
if (!(Get-Command "git.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find git.exe"
exit 1
}
# check gh.exe
if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find gh.exe"
exit 1
}
# check choco.exe
if (!(Get-Command "choco.exe" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find choco.exe"
exit 1
}
# check git tag
$Tag, $CommitCount, $Commit, $_ = Git-Describe
if ("0" -ne $CommitCount) {
Write-Stderr "error: cannot find clean git tag"
exit 1
}
# check release info
$script:ReleaseInfo = Get-ReleaseInfo $Tag
if (!$script:ReleaseInfo) {
Write-Stderr "error: cannot get release info for tag $Tag"
exit 1
}
# check winfsp.sym
if (!(Test-Path "$ProjectRoot\..\winfsp.sym" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp.sym repository"
exit 1
}
# check winfsp.sym git status
Push-Location "$ProjectRoot\..\winfsp.sym"
$SymDirty = Git-Dirty
Pop-Location
if ($SymDirty) {
Write-Stderr "error: winfsp.sym repository is dirty"
exit 1
}
if ($State -contains $Name) {
if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
Write-Stderr "error: invalid state for tag $Tag"
exit 1
}
} else {
Add-Content $StateFile -Value $Name
Add-Content $StateFile -Value "$Tag-$CommitCount-g$Commit"
}
}
function Check-Assets {
# check winfsp.msi
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp*.msi"
exit 1
}
# check winfsp-tests.zip
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp-tests*.zip"
exit 1
}
# check winfsp.nupkg
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.nupkg" -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find winfsp*.nupkg"
exit 1
}
# check winfsp signature
if ("Valid" -ne (Get-AuthenticodeSignature "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys" -ErrorAction SilentlyContinue).Status) {
Write-Stderr "error: invalid winfsp signature"
exit 1
}
}
function Build-AssetsPhase1 {
Task -ScriptBlock {
Push-Location "$ProjectRoot"
tools\build.bat Release
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot build assets"
exit 1
}
Pop-Location
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
"@
}
}
function Build-AssetsPhase2 {
Task -ScriptBlock {
Check-Assets
# check signed drivers folder
if (!(Test-Path ~\Downloads\drivers -ErrorAction SilentlyContinue)) {
Write-Stderr "error: cannot find ~\Downloads\drivers"
exit 1
}
$SignedPackage = Resolve-Path ~\Downloads\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"
exit 1
}
Push-Location "$ProjectRoot"
tools\build.bat Release $SignedPackage
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot build assets"
exit 1
}
Pop-Location
Write-Stdout @"
Assets have been built and signed. You may want to perform some smoke testing.
"@
}
}
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) {
$DownloadColor = "e52e4b"
$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)
[VirusTotal Scan Results]()
## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion)
$($ReleaseInfo.Text -join "`n")
"@
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")
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot create GitHub release"
exit 1
}
Write-Stdout @"
Draft GitHub release for tag $($ReleaseInfo.Tag) has been created.
Publish the release on GitHub and update the VirusTotal link.
"@
}
}
function Upload-Symbols {
Task -ScriptBlock {
Check-Assets
# check winfsp.sym git log
Push-Location "$ProjectRoot\..\winfsp.sym"
$SymHasTag = Git-LogGrep $ReleaseInfo.Tag
Pop-Location
if ($SymHasTag) {
Write-Stderr "warning: winfsp.sym repository already has commit for tag $($ReleaseInfo.Tag)"
} else {
Push-Location "$ProjectRoot\..\winfsp.sym"
.\tools\symadd.ps1 ..\winfsp\build\VStudio\build\Release -PdbKind Private
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot add files to winfsp.sym repository"
exit 1
}
git add .
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot add files to winfsp.sym repository staging area"
exit 1
}
git commit -m $ReleaseInfo.Tag
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot commit files to winfsp.sym repository"
exit 1
}
Pop-Location
Write-Stdout @"
Commit for $($ReleaseInfo.Tag) symbols has been created.
Push the winfsp.sym repository to GitHub.
"@
}
}
}
function Make-ChocoRelease {
Task -ScriptBlock {
Check-Assets
Push-Location "$ProjectRoot\build\VStudio\build\Release"
choco push
if ($LastExitCode -ne 0) {
Write-Stderr "error: cannot push to Chocolatey"
exit 1
}
Pop-Location
Write-Stdout @"
Chocolatey release for $($ReleaseInfo.Tag) has been pushed.
"@
}
}
$ProjectRoot = Split-Path $PSScriptRoot
$StateFile = Join-Path $pwd $StateFile
Write-Stdout "Using state file $StateFile"
$State = @(Get-Content $StateFile -ErrorAction Ignore)
Check-Prerequisites
# Workflow tasks
Build-AssetsPhase1
Build-AssetsPhase2
Make-GitHubRelease
Upload-Symbols
Make-ChocoRelease

View File

@ -47,32 +47,32 @@ set dfl_tests=^
winfsp-tests-x64-external-share ^ winfsp-tests-x64-external-share ^
memfs-x64-disk-fsx ^ memfs-x64-disk-fsx ^
memfs-x64-net-fsx ^ memfs-x64-net-fsx ^
memfs-x64-disk-standby ^ RETIRED-memfs-x64-disk-standby ^
memfs-x64-net-standby ^ RETIRED-memfs-x64-net-standby ^
memfs-x64-net-use ^ memfs-x64-net-use ^
memfs-x64-disk-winfstest ^ memfs-x64-disk-winfstest ^
memfs-x64-net-winfstest ^ memfs-x64-net-winfstest ^
fscrash-x64 ^ fscrash-x64 ^
winfsp-tests-x86 ^ winfsp-tests-x86 ^
winfsp-tests-x86-case-randomize ^ RETIRED-winfsp-tests-x86-case-randomize ^
winfsp-tests-x86-flushpurge ^ RETIRED-winfsp-tests-x86-flushpurge ^
winfsp-tests-x86-legacy-unlink-rename ^ RETIRED-winfsp-tests-x86-legacy-unlink-rename ^
winfsp-tests-x86-mountpoint-drive ^ RETIRED-winfsp-tests-x86-mountpoint-drive ^
winfsp-tests-x86-mountpoint-dir ^ RETIRED-winfsp-tests-x86-mountpoint-dir ^
winfsp-tests-x86-mountpoint-dir-case-sensitive ^ RETIRED-winfsp-tests-x86-mountpoint-dir-case-sensitive ^
winfsp-tests-x86-mountmgr-drive ^ RETIRED-winfsp-tests-x86-mountmgr-drive ^
winfsp-tests-x86-mountmgr-dir ^ RETIRED-winfsp-tests-x86-mountmgr-dir ^
winfsp-tests-x86-mountmgrfsd-drive ^ RETIRED-winfsp-tests-x86-mountmgrfsd-drive ^
winfsp-tests-x86-mountmgrfsd-dir ^ RETIRED-winfsp-tests-x86-mountmgrfsd-dir ^
winfsp-tests-x86-no-traverse ^ RETIRED-winfsp-tests-x86-no-traverse ^
winfsp-tests-x86-oplock ^ RETIRED-winfsp-tests-x86-oplock ^
winfsp-tests-x86-notify ^ RETIRED-winfsp-tests-x86-notify ^
winfsp-tests-x86-external ^ winfsp-tests-x86-external ^
winfsp-tests-x86-external-share ^ winfsp-tests-x86-external-share ^
memfs-x86-disk-fsx ^ memfs-x86-disk-fsx ^
memfs-x86-net-fsx ^ memfs-x86-net-fsx ^
memfs-x86-disk-standby ^ RETIRED-memfs-x86-disk-standby ^
memfs-x86-net-standby ^ RETIRED-memfs-x86-net-standby ^
memfs-x86-net-use ^ memfs-x86-net-use ^
memfs-x86-disk-winfstest ^ memfs-x86-disk-winfstest ^
memfs-x86-net-winfstest ^ memfs-x86-net-winfstest ^
@ -123,20 +123,25 @@ set opt_tests=^
set tests= set tests=
for %%f in (%dfl_tests%) do ( for %%f in (%dfl_tests%) do (
set test=%%f
if NOT "XRETIRED-!test:RETIRED-=!"=="X!test!" (
if X%2==X ( if X%2==X (
set tests=!tests! %%f set tests=!tests! %%f
) else ( ) else (
set test=%%f
if "X%2!test:%2=!"=="X!test!" set tests=!tests! %%f if "X%2!test:%2=!"=="X!test!" set tests=!tests! %%f
) )
)
) )
for %%f in (%opt_tests%) do ( for %%f in (%opt_tests%) do (
set test=%%f
if NOT "XRETIRED-!test:RETIRED-=!"=="X!test!" (
if X%2==X ( if X%2==X (
rem rem
) else ( ) else (
set test=%%f set test=%%f
if "X%2!test:%2=!"=="X!test!" set tests=!tests! %%f if "X%2!test:%2=!"=="X!test!" set tests=!tests! %%f
) )
)
) )
set testpass=0 set testpass=0
@ -159,11 +164,12 @@ for %%f in (%tests%) do (
set "endtimecalc=!endtime:%time:~8,1%=%%100)*100+1!" & set "begtimecalc=!begtime:%time:~8,1%=%%100)*100+1!" set "endtimecalc=!endtime:%time:~8,1%=%%100)*100+1!" & set "begtimecalc=!begtime:%time:~8,1%=%%100)*100+1!"
set /A "duration=((((10!endtimecalc:%time:~2,1%=%%100)*60+1!%%100)-((((10!begtimecalc:%time:~2,1%=%%100)*60+1!%%100), duration-=(duration>>31)*24*60*60*100" set /A "duration=((((10!endtimecalc:%time:~2,1%=%%100)*60+1!%%100)-((((10!begtimecalc:%time:~2,1%=%%100)*60+1!%%100), duration-=(duration>>31)*24*60*60*100"
set /A "duration=10*duration" set /A "duration=10*duration"
set /A "durationSec=duration/1000"
if !ERRORLEVEL_save! neq 0 ( if !ERRORLEVEL_save! neq 0 (
set /a testfail=testfail+1 set /a testfail=testfail+1
echo === Failed %%f ^(!duration! ms^) echo === Failed %%f ^(!durationSec!s^)
if defined APPVEYOR ( if defined APPVEYOR (
appveyor UpdateTest "%%f" -FileName None -Framework None -Outcome Failed -Duration !duration! appveyor UpdateTest "%%f" -FileName None -Framework None -Outcome Failed -Duration !duration!
@ -171,7 +177,7 @@ for %%f in (%tests%) do (
) else ( ) else (
set /a testpass=testpass+1 set /a testpass=testpass+1
echo === Passed %%f ^(!duration! ms^) echo === Passed %%f ^(!durationSec!s^)
if defined APPVEYOR ( if defined APPVEYOR (
appveyor UpdateTest "%%f" -FileName None -Framework None -Outcome Passed -Duration !duration! appveyor UpdateTest "%%f" -FileName None -Framework None -Outcome Passed -Duration !duration!
@ -241,25 +247,25 @@ if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x64-mountmgr-drive :winfsp-tests-x64-mountmgr-drive
winfsp-tests-x64 --mountpoint=\\.\X: --resilient * +ea* winfsp-tests-x64 --mountpoint=\\.\X: --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x64-mountmgr-dir :winfsp-tests-x64-mountmgr-dir
winfsp-tests-x64 --mountpoint=\\.\%cd%\mnt --resilient * +ea* winfsp-tests-x64 --mountpoint=\\.\%cd%\mnt --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x64-mountmgrfsd-drive :winfsp-tests-x64-mountmgrfsd-drive
reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32 reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32
winfsp-tests-x64 --mountpoint=\\.\X: --resilient * +ea* winfsp-tests-x64 --mountpoint=\\.\X: --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32 reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32
exit /b 0 exit /b 0
:winfsp-tests-x64-mountmgrfsd-dir :winfsp-tests-x64-mountmgrfsd-dir
reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32 reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32
winfsp-tests-x64 --mountpoint=\\.\%cd%\mnt --resilient * +ea* winfsp-tests-x64 --mountpoint=\\.\%cd%\mnt --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32 reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32
exit /b 0 exit /b 0
@ -315,25 +321,25 @@ if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x86-mountmgr-drive :winfsp-tests-x86-mountmgr-drive
winfsp-tests-x86 --mountpoint=\\.\X: --resilient * +ea* winfsp-tests-x86 --mountpoint=\\.\X: --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x86-mountmgr-dir :winfsp-tests-x86-mountmgr-dir
winfsp-tests-x86 --mountpoint=\\.\%cd%\mnt --resilient * +ea* winfsp-tests-x86 --mountpoint=\\.\%cd%\mnt --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:winfsp-tests-x86-mountmgrfsd-drive :winfsp-tests-x86-mountmgrfsd-drive
reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32 reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32
winfsp-tests-x86 --mountpoint=\\.\X: --resilient * +ea* winfsp-tests-x86 --mountpoint=\\.\X: --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32 reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32
exit /b 0 exit /b 0
:winfsp-tests-x86-mountmgrfsd-dir :winfsp-tests-x86-mountmgrfsd-dir
reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32 reg add HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /t REG_DWORD /d 1 /f /reg:32
winfsp-tests-x86 --mountpoint=\\.\%cd%\mnt --resilient * +ea* winfsp-tests-x86 --mountpoint=\\.\%cd%\mnt --resilient * +ea* -exec*
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32 reg delete HKLM\Software\WinFsp /v MountUseMountmgrFromFSD /f /reg:32
exit /b 0 exit /b 0

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

View File

@ -40,6 +40,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
*/ */
//#define MEMFS_STANDALONE //#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. * Define the MEMFS_NAME_NORMALIZATION macro to include name normalization support.
*/ */
@ -2269,6 +2274,14 @@ static NTSTATUS SetEa(FSP_FILE_SYSTEM *FileSystem,
} }
#endif #endif
#if defined(MEMFS_DISPATCHER_STOPPED)
static void DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally)
{
//FspDebugLog(__FUNCTION__ ": Normally=%d\n", Normally);
}
#endif
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface = static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
{ {
GetVolumeInfo, GetVolumeInfo,
@ -2336,6 +2349,12 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
0, 0,
0, 0,
0, 0,
#endif
0,
#if defined(MEMFS_DISPATCHER_STOPPED)
DispatcherStopped,
#else
0,
#endif #endif
}; };

View File

@ -62,7 +62,8 @@ static NTSTATUS GetFileInfoInternal(HANDLE Handle, FSP_FSCTL_FILE_INFO *FileInfo
FileInfo->LastAccessTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastAccessTime)->QuadPart; FileInfo->LastAccessTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastAccessTime)->QuadPart;
FileInfo->LastWriteTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastWriteTime)->QuadPart; FileInfo->LastWriteTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastWriteTime)->QuadPart;
FileInfo->ChangeTime = FileInfo->LastWriteTime; FileInfo->ChangeTime = FileInfo->LastWriteTime;
FileInfo->IndexNumber = 0; FileInfo->IndexNumber =
((UINT64)ByHandleFileInfo.nFileIndexHigh << 32) | (UINT64)ByHandleFileInfo.nFileIndexLow;
FileInfo->HardLinks = 0; FileInfo->HardLinks = 0;
return STATUS_SUCCESS; return STATUS_SUCCESS;

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

@ -158,7 +158,10 @@ static void posix_map_sid_test(void)
CloseHandle(Token); CloseHandle(Token);
for (size_t i = 0; sizeof map / sizeof map[0] > i; i++) size_t n = sizeof map / sizeof map[0];
if (RunningInContainer)
n -= 2; /* container: disable tests for "user manager\containeradministrator" */
for (size_t i = 0; n > i; i++)
{ {
Success = ConvertStringSidToSidW(map[i].SidStr, &Sid0); Success = ConvertStringSidToSidW(map[i].SidStr, &Sid0);
ASSERT(Success); ASSERT(Success);

View File

@ -254,8 +254,13 @@ static void volpath_mount_test(void)
/* /*
* This test does FspFileSystemSetMountPoint and therefore * This test does FspFileSystemSetMountPoint and therefore
* cannot be used with --external or --mountpoint. * cannot be used with --external or --mountpoint.
*
* Also the MountMgr appears to be buggy and fail with spurious
* STATUS_NOT_SUPPORTED and STATUS_INVALID_PARAMETER error codes
* under Windows Containers (at least with ServerCore 1909). So
* disable if RunningInContainer.
*/ */
if (NtfsTests || OptMountPoint) if (NtfsTests || OptMountPoint || RunningInContainer)
return; return;
if (WinFspDiskTests) if (WinFspDiskTests)
@ -322,7 +327,12 @@ void volpath_tests(void)
/* /*
* This test does FspFileSystemSetMountPoint and therefore * This test does FspFileSystemSetMountPoint and therefore
* cannot be used with --external or --mountpoint. * cannot be used with --external or --mountpoint.
*
* Also the MountMgr appears to be buggy and fail with spurious
* STATUS_NOT_SUPPORTED and STATUS_INVALID_PARAMETER error codes
* under Windows Containers (at least with ServerCore 1909). So
* disable if RunningInContainer.
*/ */
if (!NtfsTests && !OptMountPoint) if (!NtfsTests && !OptMountPoint && !RunningInContainer)
TEST(volpath_mount_test); TEST(volpath_mount_test);
} }

View File

@ -32,6 +32,7 @@
int NtfsTests = 0; int NtfsTests = 0;
int WinFspDiskTests = 1; int WinFspDiskTests = 1;
int WinFspNetTests = 1; int WinFspNetTests = 1;
int RunningInContainer = 0;
BOOLEAN OptExternal = FALSE; BOOLEAN OptExternal = FALSE;
BOOLEAN OptFuseExternal = FALSE; BOOLEAN OptFuseExternal = FALSE;
@ -220,6 +221,7 @@ LONG WINAPI UnhandledExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
argv[argc] = 0 argv[argc] = 0
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
TESTSUITE(load_unload_tests);
TESTSUITE(fuse_opt_tests); TESTSUITE(fuse_opt_tests);
TESTSUITE(fuse_tests); TESTSUITE(fuse_tests);
TESTSUITE(posix_tests); TESTSUITE(posix_tests);
@ -258,6 +260,12 @@ int main(int argc, char *argv[])
if (0 == getenv("WINFSP_TESTS_EXCEPTION_FILTER_DISABLE")) if (0 == getenv("WINFSP_TESTS_EXCEPTION_FILTER_DISABLE"))
SetUnhandledExceptionFilter(UnhandledExceptionHandler); SetUnhandledExceptionFilter(UnhandledExceptionHandler);
RunningInContainer = ERROR_SUCCESS == RegGetValueW(
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control",
L"ContainerType",
RRF_RT_REG_DWORD, 0,
0, 0);
for (int argi = 1; argc > argi; argi++) for (int argi = 1; argc > argi; argi++)
{ {
const char *a = argv[argi]; const char *a = argv[argi];
@ -266,6 +274,7 @@ int main(int argc, char *argv[])
if (0 == strcmp("--ntfs", a) || 0 == strcmp("--external", a)) if (0 == strcmp("--ntfs", a) || 0 == strcmp("--external", a))
{ {
OptExternal = TRUE; OptExternal = TRUE;
OptFuseExternal = FALSE;
NtfsTests = 1; NtfsTests = 1;
WinFspDiskTests = 0; WinFspDiskTests = 0;
WinFspNetTests = 0; WinFspNetTests = 0;
@ -404,6 +413,10 @@ int main(int argc, char *argv[])
if (!NtfsTests && OptShareName) if (!NtfsTests && OptShareName)
ABORT("option --share requires --ntfs/--external"); ABORT("option --share requires --ntfs/--external");
if (RunningInContainer)
/* container: disable network file system tests */
WinFspNetTests = 0;
DisableBackupRestorePrivileges(); DisableBackupRestorePrivileges();
AddNetShareIfNeeded(); AddNetShareIfNeeded();

View File

@ -213,6 +213,7 @@ VOID GetTestDirectoryEx(PWSTR DirBuf, ULONG DirBufSize, PWSTR DriveBuf);
extern int NtfsTests; extern int NtfsTests;
extern int WinFspDiskTests; extern int WinFspDiskTests;
extern int WinFspNetTests; extern int WinFspNetTests;
extern int RunningInContainer;
extern BOOLEAN OptExternal; extern BOOLEAN OptExternal;
extern BOOLEAN OptFuseExternal; extern BOOLEAN OptFuseExternal;