mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-11-03 20:48:08 -06:00 
			
		
		
		
	Compare commits
	
		
			100 Commits
		
	
	
		
			v1.12.2233
			...
			pvt-idinfo
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					82f84f5bf7 | ||
| 
						 | 
					97c075e744 | ||
| 
						 | 
					874a223bcc | ||
| 
						 | 
					901a98e118 | ||
| 
						 | 
					0ab4300738 | ||
| 
						 | 
					52e6aa97b5 | ||
| 
						 | 
					a7d82d5f8d | ||
| 
						 | 
					3aadaee511 | ||
| 
						 | 
					da3a8aa229 | ||
| 
						 | 
					1f0fd4c280 | ||
| 
						 | 
					6da92f0b54 | ||
| 
						 | 
					4f5f1dd350 | ||
| 
						 | 
					ba5d52e9a5 | ||
| 
						 | 
					d626fb9563 | ||
| 
						 | 
					69cc1820e1 | ||
| 
						 | 
					c06141c8c8 | ||
| 
						 | 
					760c2acded | ||
| 
						 | 
					671efe625a | ||
| 
						 | 
					a59b32b1ee | ||
| 
						 | 
					22d81846df | ||
| 
						 | 
					8c9b8362b4 | ||
| 
						 | 
					e92eb023fe | ||
| 
						 | 
					e550e261f0 | ||
| 
						 | 
					46054c03fe | ||
| 
						 | 
					db07b24342 | ||
| 
						 | 
					cb81e81985 | ||
| 
						 | 
					b62e1e920b | ||
| 
						 | 
					01d9fa1719 | ||
| 
						 | 
					6846508631 | ||
| 
						 | 
					0488451c3d | ||
| 
						 | 
					7c3292af81 | ||
| 
						 | 
					3d2ba637e5 | ||
| 
						 | 
					db72b57ca4 | ||
| 
						 | 
					020157a9ae | ||
| 
						 | 
					d99cb2d7d1 | ||
| 
						 | 
					298261c4af | ||
| 
						 | 
					3c674a556d | ||
| 
						 | 
					f85fb49f49 | ||
| 
						 | 
					92084a56c6 | ||
| 
						 | 
					53f97c9841 | ||
| 
						 | 
					2770eca1bf | ||
| 
						 | 
					2945971ba9 | ||
| 
						 | 
					0a39ef60bd | ||
| 
						 | 
					e1faf1351e | ||
| 
						 | 
					7333451eac | ||
| 
						 | 
					c178db127c | ||
| 
						 | 
					9747af22e8 | ||
| 
						 | 
					ef9b7e22c6 | ||
| 
						 | 
					fd27c470b0 | ||
| 
						 | 
					c187209159 | ||
| 
						 | 
					a2e92207c5 | ||
| 
						 | 
					4f5ad93f00 | ||
| 
						 | 
					b47c42877a | ||
| 
						 | 
					d1fc5e5d0f | ||
| 
						 | 
					c4ecd15c0a | ||
| 
						 | 
					91d7f3b673 | ||
| 
						 | 
					63e23c2039 | ||
| 
						 | 
					4d1594b1cf | ||
| 
						 | 
					0eb6912296 | ||
| 
						 | 
					c237a55951 | ||
| 
						 | 
					98d68c4007 | ||
| 
						 | 
					e8cec5dfc1 | ||
| 
						 | 
					9a27a3225b | ||
| 
						 | 
					d44cb54bd5 | ||
| 
						 | 
					d1f863e9ac | ||
| 
						 | 
					ccdbc9daf9 | ||
| 
						 | 
					1723179430 | ||
| 
						 | 
					8e0f5b457c | ||
| 
						 | 
					2fc2c237d3 | ||
| 
						 | 
					b99fb9a5cb | ||
| 
						 | 
					538fee8e54 | ||
| 
						 | 
					925fa4b6e4 | ||
| 
						 | 
					b179c7a933 | ||
| 
						 | 
					b25e116f08 | ||
| 
						 | 
					422c369b15 | ||
| 
						 | 
					d450683e2e | ||
| 
						 | 
					ad1aa156dc | ||
| 
						 | 
					aa012db099 | ||
| 
						 | 
					b08f60bfbd | ||
| 
						 | 
					a9b3cef253 | ||
| 
						 | 
					b43d1f5502 | ||
| 
						 | 
					de9112f6e6 | ||
| 
						 | 
					329b14d838 | ||
| 
						 | 
					7009324e7f | ||
| 
						 | 
					f4ae097722 | ||
| 
						 | 
					50be07e8ac | ||
| 
						 | 
					2dd054087c | ||
| 
						 | 
					7f6608cf7d | ||
| 
						 | 
					39e9d8156b | ||
| 
						 | 
					90acd19014 | ||
| 
						 | 
					9154ec784d | ||
| 
						 | 
					0b3ce52958 | ||
| 
						 | 
					adeed2b79d | ||
| 
						 | 
					5dda5903a8 | ||
| 
						 | 
					a7bc306b2d | ||
| 
						 | 
					7e59c2e5a6 | ||
| 
						 | 
					9670caa3fe | ||
| 
						 | 
					005d3e4fb0 | ||
| 
						 | 
					62a6bbab66 | ||
| 
						 | 
					40ba537dc2 | 
							
								
								
									
										8
									
								
								.github/workflows/avm.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/avm.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,8 +11,8 @@ jobs:
 | 
				
			|||||||
    - uses: billziss-gh/avm@v1
 | 
					    - uses: billziss-gh/avm@v1
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        files: |
 | 
					        files: |
 | 
				
			||||||
            https://github.com/winfsp/winfsp/releases/download/v1.6/winfsp-1.6.20027.msi
 | 
					 | 
				
			||||||
            https://github.com/winfsp/winfsp/releases/download/v1.7/winfsp-1.7.20172.msi
 | 
					 | 
				
			||||||
            https://github.com/winfsp/winfsp/releases/download/v1.8/winfsp-1.8.20304.msi
 | 
					 | 
				
			||||||
            https://github.com/winfsp/winfsp/releases/download/v1.9/winfsp-1.9.21096.msi
 | 
					 | 
				
			||||||
            https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
 | 
					            https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
 | 
				
			||||||
 | 
					            https://github.com/winfsp/winfsp/releases/download/v1.11/winfsp-1.11.22176.msi
 | 
				
			||||||
 | 
					            https://github.com/winfsp/winfsp/releases/download/v1.12/winfsp-1.12.22301.msi
 | 
				
			||||||
 | 
					            https://github.com/winfsp/winfsp/releases/download/v1.12.22339/winfsp-1.12.22339.msi
 | 
				
			||||||
 | 
					            https://github.com/winfsp/winfsp/releases/download/v2.0B2/winfsp-2.0.23033.msi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										46
									
								
								Changelog.md
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								Changelog.md
									
									
									
									
									
								
							@@ -1,6 +1,52 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v2.0B2 (2023 Beta2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This release is a major version change for WinFsp (from 1.x to 2.x). There are no backwards incompatible API changes in this release, but nevertheless enough things change that warrant a version change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The major new feature of this release is that it allows uninstallation and reinstallation of WinFsp **without reboot**. Going forward installers named `winfsp-2.x.y.msi` can be uninstalled and reinstalled without reboot. Furthermore a later version `winfsp-2.x.y.msi` installer can be used to upgrade over an earlier version `winfsp-2.x.y.msi` installer. However note that a `winfsp-2.x.y.msi` installer cannot be used to upgrade over a "legacy" `winfsp-1.x.y.msi` installer; you will still need to uninstall the "old" `winfsp-1.x.y.msi` installer, potentially reboot and then install the "new" `winfsp-2.x.y.msi` installer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Changes visible to file system developers are listed below:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- WinFsp executable files are now installed by default in the directory `C:\Program Files (x86)\WinFsp\SxS\sxs.<InstanceID>\bin`. The previous directory `C:\Program Files (x86)\WinFsp\bin` is now a junction that points to the above directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The WinFsp driver name is no longer `winfsp`, but rather a name such as `winfsp+<InstanceID>`. This means that managing the driver using the `sc.exe` utility is no longer as easy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The `fsptool` utility has been updated with new commands `lsdrv`, `load`, `unload` and `ver`. The `lsdrv`, `load` and `unload` commands can be used to manage the driver from the command line. This is rarely necessary, but may be useful for troubleshooting purposes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Prior to this release the WinFsp driver would never unmount a file system volume unless the user mode file system requested the unmount. From this release onward it is possible for the WinFsp driver to unmount a file system volume, without a user mode file system request. This is to allow for the driver to be unloaded.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    A new operation `DispatcherStopped` has been added to `FSP_FILE_SYSTEM_INTERFACE`, which is sent after the file system volume has been unmounted and the file system dispatcher has been stopped. This can happen because of a user mode file system request via `FspFileSystemStopDispatcher` or because of driver unload. The `DispatcherStopped` operation includes a `Normally` parameter, which is `TRUE` for normal file system shutdown via `FspFileSystemStopDispatcher` and `FALSE` otherwise.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Native file systems that use the `FspService` infrastructure can use the `FspFileSystemStopServiceIfNecessary` API to handle the `DispatcherStopped` operation (see the MEMFS and NTPTFS samples). FUSE file systems get this functionality for free. .NET file systems that use the `Service` class infrastructure also get this functionality for free.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- WinFsp now offers a .NET library that targets .NET Framework 3.5 (as before) and one that targets .NET Standard 2.0. This is due to work by @Noire001 in PR #451.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- FUSE now supports path components up to 255 characters long (previously it was 255 bytes). This is due to work by @zeho11 in PR #474.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - The FUSE passthrough file systems have been updated to support long paths. This is also due to work by @zeho11.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v2.0B1 (2023 Beta1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This release is a major version change for WinFsp (from 1.x to 2.x). There are no backwards incompatible API changes in this release, but nevertheless enough things change that warrant a version change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The major new feature of this release is that it allows uninstallation and reinstallation of WinFsp **without reboot**. Going forward installers named `winfsp-2.x.y.msi` can be uninstalled and reinstalled without reboot. Furthermore a later version `winfsp-2.x.y.msi` installer can be used to upgrade over an earlier version `winfsp-2.x.y.msi` installer. However note that a `winfsp-2.x.y.msi` installer cannot be used to upgrade over a "legacy" `winfsp-1.x.y.msi` installer; you will still need to uninstall the "old" `winfsp-1.x.y.msi` installer, potentially reboot and then install the "new" `winfsp-2.x.y.msi` installer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some changes that may be visible to file system developers are listed below:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- WinFsp executable files are now installed by default in the directory `C:\Program Files (x86)\WinFsp\SxS\sxs.<InstanceID>\bin`. The previous directory `C:\Program Files (x86)\WinFsp\bin` is now a junction that points to the above directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The WinFsp driver name is no longer `winfsp`, but rather a name such as `winfsp+<InstanceID>`. This means that managing the driver using the `sc.exe` utility is no longer as easy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The `fsptool` utility has been updated with new commands `lsdrv`, `load`, `unload` and `ver`. The `lsdrv`, `load` and `unload` commands can be used to manage the driver from the command line. This is rarely necessary, but may be useful for troubleshooting purposes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## v1.12.22339 (2022.2 Update1)
 | 
					## v1.12.22339 (2022.2 Update1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*Note: This release (`v1.12.22339`) is the same as the previous release (`v1.12`) except that: (1) the kernel-mode drivers are now digitally signed only with the Microsoft Attestation signature, and that: (2) no release assets are digitally signed with SHA-1. (This change was necessary to fix a problem in older versions of Windows such as Windows 7.)*
 | 
					*Note: This release (`v1.12.22339`) is the same as the previous release (`v1.12`) except that: (1) the kernel-mode drivers are now digitally signed only with the Microsoft Attestation signature, and that: (2) no release assets are digitally signed with SHA-1. (This change was necessary to fix a problem in older versions of Windows such as Windows 7.)*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,6 +66,7 @@ CONTRIBUTOR LIST
 | 
				
			|||||||
|Gal Hammer (Red Hat, https://www.redhat.com)                   |ghammer at redhat.com
 | 
					|Gal Hammer (Red Hat, https://www.redhat.com)                   |ghammer at redhat.com
 | 
				
			||||||
|John Oberschelp                                                |john at oberschelp.net
 | 
					|John Oberschelp                                                |john at oberschelp.net
 | 
				
			||||||
|John Tyner                                                     |jtyner at gmail.com
 | 
					|John Tyner                                                     |jtyner at gmail.com
 | 
				
			||||||
 | 
					|Konstantinos Karakostas                                        |noiredev at protonmail.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
 | 
					|Ronny Chan                                                     |ronny at ronnychan.ca
 | 
				
			||||||
@@ -73,4 +74,5 @@ CONTRIBUTOR LIST
 | 
				
			|||||||
|Santiago Ganis                                                 |sganis at gmail.com
 | 
					|Santiago Ganis                                                 |sganis at gmail.com
 | 
				
			||||||
|Tobias Urlaub                                                  |saibotu at outlook.de
 | 
					|Tobias Urlaub                                                  |saibotu at outlook.de
 | 
				
			||||||
|Victor Gao                                                     |victgm at outlook.com
 | 
					|Victor Gao                                                     |victgm at outlook.com
 | 
				
			||||||
 | 
					|Zeho Huang                                                     |zeho11 at protonmail.com
 | 
				
			||||||
|===
 | 
					|===
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,6 +51,11 @@ install:
 | 
				
			|||||||
      $targets.Save("C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets")
 | 
					      $targets.Save("C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets")
 | 
				
			||||||
      Add-AppveyorMessage "Hack to make WDK 1903 work on VS2015"
 | 
					      Add-AppveyorMessage "Hack to make WDK 1903 work on VS2015"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					# Install .NET SDK on VS2015 image
 | 
				
			||||||
 | 
					- ps: |
 | 
				
			||||||
 | 
					    if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") {
 | 
				
			||||||
 | 
					        & ([scriptblock]::Create((New-Object System.Net.WebClient).DownloadString('https://dot.net/v1/dotnet-install.ps1'))) -InstallDir "C:\dotnet"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
# Submodules
 | 
					# Submodules
 | 
				
			||||||
- git submodule update --init --recursive
 | 
					- git submodule update --init --recursive
 | 
				
			||||||
# Kernel and user mode dumps
 | 
					# Kernel and user mode dumps
 | 
				
			||||||
@@ -76,6 +81,9 @@ build_script:
 | 
				
			|||||||
# remove ARM64 project configurations to build in VS2015/VS2017
 | 
					# remove ARM64 project configurations to build in VS2015/VS2017
 | 
				
			||||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" tools\gensrc\remove-build-arm64.bat
 | 
					- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" tools\gensrc\remove-build-arm64.bat
 | 
				
			||||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" tools\gensrc\remove-build-arm64.bat
 | 
					- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" tools\gensrc\remove-build-arm64.bat
 | 
				
			||||||
 | 
					# remove .NET library from solution for VS2015 and use the .NET SDK instead
 | 
				
			||||||
 | 
					- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" tools\gensrc\remove-build-dotnet.bat build\VStudio
 | 
				
			||||||
 | 
					- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set PATH=C:\dotnet;%PATH%
 | 
				
			||||||
# build winfsp
 | 
					# build winfsp
 | 
				
			||||||
- tools\build.bat %CONFIGURATION%
 | 
					- tools\build.bat %CONFIGURATION%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,10 @@
 | 
				
			|||||||
        <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</MyProductVersion>
 | 
					        <MyProductVersion>2023 RC1</MyProductVersion>
 | 
				
			||||||
        <MyProductStage>Gold</MyProductStage>
 | 
					        <MyProductStage>RC</MyProductStage>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert>
 | 
					        <MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert>
 | 
				
			||||||
        <MyCertIssuer>DigiCert</MyCertIssuer>
 | 
					        <MyCertIssuer>DigiCert</MyCertIssuer>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,29 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<Project>
 | 
				
			||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <BaseIntermediateOutputPath>$(SolutionDir)build\$(MSBuildProjectName).build\</BaseIntermediateOutputPath>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
 | 
				
			||||||
  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
 | 
					  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
 | 
				
			||||||
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
 | 
					 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
					    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
				
			||||||
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
					    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
				
			||||||
    <ProjectGuid>{94580219-CC8D-4FE5-A3BE-437B0B3481E1}</ProjectGuid>
 | 
					 | 
				
			||||||
    <OutputType>Library</OutputType>
 | 
					    <OutputType>Library</OutputType>
 | 
				
			||||||
    <ProjectName>winfsp.net</ProjectName>
 | 
					    <ProjectName>winfsp.net</ProjectName>
 | 
				
			||||||
    <RootNamespace>Fsp</RootNamespace>
 | 
					    <RootNamespace>Fsp</RootNamespace>
 | 
				
			||||||
    <AssemblyName>$(MyProductFileName)-msil</AssemblyName>
 | 
					    <AssemblyName>$(MyProductFileName)-msil</AssemblyName>
 | 
				
			||||||
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
 | 
					    <TargetFrameworks>netstandard2.0;net35</TargetFrameworks>
 | 
				
			||||||
    <FileAlignment>512</FileAlignment>
 | 
					    <FileAlignment>512</FileAlignment>
 | 
				
			||||||
    <TargetFrameworkProfile />
 | 
					    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
 | 
				
			||||||
 | 
					    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
 | 
				
			||||||
 | 
					    <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
					  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
				
			||||||
    <DebugSymbols>true</DebugSymbols>
 | 
					    <DebugSymbols>true</DebugSymbols>
 | 
				
			||||||
    <DebugType>full</DebugType>
 | 
					    <DebugType>full</DebugType>
 | 
				
			||||||
    <Optimize>false</Optimize>
 | 
					    <Optimize>false</Optimize>
 | 
				
			||||||
    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
					    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
				
			||||||
    <BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
 | 
					 | 
				
			||||||
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
					    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
				
			||||||
    <DefineConstants>DEBUG;TRACE</DefineConstants>
 | 
					    <DefineConstants>DEBUG;TRACE</DefineConstants>
 | 
				
			||||||
    <ErrorReport>prompt</ErrorReport>
 | 
					    <ErrorReport>prompt</ErrorReport>
 | 
				
			||||||
@@ -32,7 +36,6 @@
 | 
				
			|||||||
    <DebugType>pdbonly</DebugType>
 | 
					    <DebugType>pdbonly</DebugType>
 | 
				
			||||||
    <Optimize>true</Optimize>
 | 
					    <Optimize>true</Optimize>
 | 
				
			||||||
    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
					    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
				
			||||||
    <BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
 | 
					 | 
				
			||||||
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
					    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
				
			||||||
    <DefineConstants>TRACE</DefineConstants>
 | 
					    <DefineConstants>TRACE</DefineConstants>
 | 
				
			||||||
    <ErrorReport>prompt</ErrorReport>
 | 
					    <ErrorReport>prompt</ErrorReport>
 | 
				
			||||||
@@ -47,9 +50,6 @@
 | 
				
			|||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
 | 
					    <AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <Reference Include="System" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
 | 
					    <Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
 | 
				
			||||||
      <Link>FileSystemBase+Const.cs</Link>
 | 
					      <Link>FileSystemBase+Const.cs</Link>
 | 
				
			||||||
@@ -70,29 +70,28 @@
 | 
				
			|||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <None Include="winfsp.net.snk" />
 | 
					    <None Include="winfsp.net.snk" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
					  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
 | 
				
			||||||
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
 | 
					    <PackageReference Include="Microsoft.Win32.Registry">
 | 
				
			||||||
       Other similar extension points exist, see Microsoft.Common.targets.
 | 
					      <Version>5.0.0</Version>
 | 
				
			||||||
  <Target Name="AfterBuild">
 | 
					    </PackageReference>
 | 
				
			||||||
  </Target>
 | 
					    <PackageReference Include="System.IO.FileSystem.AccessControl">
 | 
				
			||||||
  -->
 | 
					      <Version>5.0.0</Version>
 | 
				
			||||||
  <Target Name="BeforeBuild">
 | 
					    </PackageReference>
 | 
				
			||||||
    <ItemGroup>
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="using System.Reflection%3b" />
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="[assembly: AssemblyProduct("$(MyProductName)")]" />
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="[assembly: AssemblyTitle("$(MyDescription)")]" />
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="[assembly: AssemblyCompany("$(MyCompanyName)")]" />
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="[assembly: AssemblyCopyright("$(MyCopyright)")]" />
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="[assembly: AssemblyVersion("$(MyAssemblyVersion)")]" />
 | 
					 | 
				
			||||||
      <AssemblyInfo Include="[assembly: AssemblyFileVersion("$(MyVersion)")]" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
    <MakeDir Directories="$(IntermediateOutputPath)" />
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <WriteLinesToFile File="$(IntermediateOutputPath)AssemblyInfo.cs" Lines="@(AssemblyInfo)" Overwrite="true" />
 | 
					    <AssemblyName>$(MyProductFileName)-msil</AssemblyName>
 | 
				
			||||||
    <ItemGroup>
 | 
					    <AssemblyTitle>$(MyDescription)</AssemblyTitle>
 | 
				
			||||||
      <Compile Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
 | 
					    <Product>$(MyProductName)</Product>
 | 
				
			||||||
      <FileWrites Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
 | 
					    <Copyright>$(MyCopyright)</Copyright>
 | 
				
			||||||
    </ItemGroup>
 | 
					    <AssemblyVersion>$(MyAssemblyVersion)</AssemblyVersion>
 | 
				
			||||||
  </Target>
 | 
					    <FileVersion>$(MyVersion)</FileVersion>
 | 
				
			||||||
 | 
					    <!-- NuGet metadata -->
 | 
				
			||||||
 | 
					    <PackageId>$(MyProductFileName).net</PackageId>
 | 
				
			||||||
 | 
					    <Version>$(MyVersion)</Version>
 | 
				
			||||||
 | 
					    <Description>$(MyDescription)</Description>
 | 
				
			||||||
 | 
					    <Authors>$(MyCopyright)</Authors>
 | 
				
			||||||
 | 
					    <Company>$(MyCompanyName)</Company>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <PostBuildEvent>exit /b 0
 | 
					    <PostBuildEvent>exit /b 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,4 +109,5 @@ for /f "delims=" %25%25l in ($(ProjectDir)winfsp.net.policy.config) do (
 | 
				
			|||||||
"$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.0A\Bin\al.exe" /product:"$(MyProductName)" /title:"$(MyDescription)" /company:"$(MyCompanyName)" /copyright:"$(MyCopyright)" /version:"$(MyAssemblyPolicyVersion)" /fileversion:"$(MyVersion)" /link:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config /out:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).dll /keyfile:$(ProjectDir)$(ProjectName).snk
 | 
					"$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.0A\Bin\al.exe" /product:"$(MyProductName)" /title:"$(MyDescription)" /company:"$(MyCompanyName)" /copyright:"$(MyCopyright)" /version:"$(MyAssemblyPolicyVersion)" /fileversion:"$(MyVersion)" /link:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).config /out:$(OutDir)policy.$(MyAssemblyPolicyVersion).$(TargetName).dll /keyfile:$(ProjectDir)$(ProjectName).snk
 | 
				
			||||||
</PostBuildEvent>
 | 
					</PostBuildEvent>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
@@ -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:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,7 @@
 | 
				
			|||||||
EXPORTS
 | 
					EXPORTS
 | 
				
			||||||
 | 
					    InstanceID
 | 
				
			||||||
    ServiceRunning
 | 
					    ServiceRunning
 | 
				
			||||||
 | 
					    DeferredAction
 | 
				
			||||||
 | 
					    InstallSymlinks
 | 
				
			||||||
 | 
					    InstallJunctions
 | 
				
			||||||
 | 
					    RemoveFiles
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,30 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<Project>
 | 
				
			||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <BaseIntermediateOutputPath>$(SolutionDir)build\$(MSBuildProjectName).build\</BaseIntermediateOutputPath>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
 | 
				
			||||||
  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
 | 
					  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
 | 
				
			||||||
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
 | 
					 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
					    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
				
			||||||
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
					    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
				
			||||||
    <ProjectGuid>{4920E350-D496-4652-AE98-6C4208AEC1D8}</ProjectGuid>
 | 
					 | 
				
			||||||
    <OutputType>Exe</OutputType>
 | 
					    <OutputType>Exe</OutputType>
 | 
				
			||||||
    <ProjectName>memfs-dotnet</ProjectName>
 | 
					    <ProjectName>memfs-dotnet</ProjectName>
 | 
				
			||||||
    <AppDesignerFolder>Properties</AppDesignerFolder>
 | 
					 | 
				
			||||||
    <RootNamespace>memfs</RootNamespace>
 | 
					    <RootNamespace>memfs</RootNamespace>
 | 
				
			||||||
    <AssemblyName>memfs-dotnet-msil</AssemblyName>
 | 
					    <AssemblyName>memfs-dotnet-msil</AssemblyName>
 | 
				
			||||||
    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
 | 
					    <TargetFramework>net452</TargetFramework>
 | 
				
			||||||
    <FileAlignment>512</FileAlignment>
 | 
					    <FileAlignment>512</FileAlignment>
 | 
				
			||||||
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
 | 
					    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
 | 
				
			||||||
 | 
					    <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
					  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
				
			||||||
    <PlatformTarget>AnyCPU</PlatformTarget>
 | 
					    <PlatformTarget>AnyCPU</PlatformTarget>
 | 
				
			||||||
    <DebugSymbols>true</DebugSymbols>
 | 
					    <DebugSymbols>true</DebugSymbols>
 | 
				
			||||||
    <DebugType>full</DebugType>
 | 
					    <DebugType>full</DebugType>
 | 
				
			||||||
    <Optimize>false</Optimize>
 | 
					    <Optimize>false</Optimize>
 | 
				
			||||||
    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
					    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
				
			||||||
    <BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
 | 
					 | 
				
			||||||
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
					    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
				
			||||||
    <DefineConstants>DEBUG;TRACE</DefineConstants>
 | 
					    <DefineConstants>DEBUG;TRACE</DefineConstants>
 | 
				
			||||||
    <ErrorReport>prompt</ErrorReport>
 | 
					    <ErrorReport>prompt</ErrorReport>
 | 
				
			||||||
@@ -33,32 +36,16 @@
 | 
				
			|||||||
    <DebugType>pdbonly</DebugType>
 | 
					    <DebugType>pdbonly</DebugType>
 | 
				
			||||||
    <Optimize>true</Optimize>
 | 
					    <Optimize>true</Optimize>
 | 
				
			||||||
    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
					    <OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
 | 
				
			||||||
    <BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
 | 
					 | 
				
			||||||
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
					    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
 | 
				
			||||||
    <DefineConstants>TRACE</DefineConstants>
 | 
					    <DefineConstants>TRACE</DefineConstants>
 | 
				
			||||||
    <ErrorReport>prompt</ErrorReport>
 | 
					    <ErrorReport>prompt</ErrorReport>
 | 
				
			||||||
    <WarningLevel>4</WarningLevel>
 | 
					    <WarningLevel>4</WarningLevel>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <Reference Include="System" />
 | 
					    <ProjectReference Include="..\dotnet\winfsp.net.csproj" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <Compile Include="..\..\..\tst\memfs-dotnet\Program.cs">
 | 
					    <Compile Include="..\..\..\tst\memfs-dotnet\Program.cs" />
 | 
				
			||||||
      <Link>Program.cs</Link>
 | 
					 | 
				
			||||||
    </Compile>
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
 | 
				
			||||||
    <ProjectReference Include="..\dotnet\winfsp.net.csproj">
 | 
					 | 
				
			||||||
      <Project>{94580219-cc8d-4fe5-a3be-437b0b3481e1}</Project>
 | 
					 | 
				
			||||||
      <Name>winfsp.net</Name>
 | 
					 | 
				
			||||||
    </ProjectReference>
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
					 | 
				
			||||||
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
 | 
					 | 
				
			||||||
       Other similar extension points exist, see Microsoft.Common.targets.
 | 
					 | 
				
			||||||
  <Target Name="BeforeBuild">
 | 
					 | 
				
			||||||
  </Target>
 | 
					 | 
				
			||||||
  <Target Name="AfterBuild">
 | 
					 | 
				
			||||||
  </Target>
 | 
					 | 
				
			||||||
  -->
 | 
					 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
@@ -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" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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" />
 | 
				
			||||||
@@ -290,6 +291,9 @@
 | 
				
			|||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">set DriverFile=$(TargetFileName)
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">set DriverFile=$(TargetFileName)
 | 
				
			||||||
set Provider="$(MyCompanyName)"
 | 
					set Provider="$(MyCompanyName)"
 | 
				
			||||||
set CatalogFile=driver-$(MyProductFileArch).cat
 | 
					set CatalogFile=driver-$(MyProductFileArch).cat
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setlocal EnableDelayedExpansion
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
					if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
				
			||||||
@@ -303,6 +307,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
 | 
				
			|||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">set DriverFile=$(TargetFileName)
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">set DriverFile=$(TargetFileName)
 | 
				
			||||||
set Provider="$(MyCompanyName)"
 | 
					set Provider="$(MyCompanyName)"
 | 
				
			||||||
set CatalogFile=driver-$(MyProductFileArch).cat
 | 
					set CatalogFile=driver-$(MyProductFileArch).cat
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setlocal EnableDelayedExpansion
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
					if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
				
			||||||
@@ -316,6 +323,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
 | 
				
			|||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">set DriverFile=$(TargetFileName)
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">set DriverFile=$(TargetFileName)
 | 
				
			||||||
set Provider="$(MyCompanyName)"
 | 
					set Provider="$(MyCompanyName)"
 | 
				
			||||||
set CatalogFile=driver-$(MyProductFileArch).cat
 | 
					set CatalogFile=driver-$(MyProductFileArch).cat
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setlocal EnableDelayedExpansion
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
					if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
				
			||||||
@@ -328,6 +338,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
 | 
				
			|||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">set DriverFile=$(TargetFileName)
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">set DriverFile=$(TargetFileName)
 | 
				
			||||||
set Provider="$(MyCompanyName)"
 | 
					set Provider="$(MyCompanyName)"
 | 
				
			||||||
set CatalogFile=driver-$(MyProductFileArch).cat
 | 
					set CatalogFile=driver-$(MyProductFileArch).cat
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setlocal EnableDelayedExpansion
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
					if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
				
			||||||
@@ -342,6 +355,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
 | 
				
			|||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">set DriverFile=$(TargetFileName)
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">set DriverFile=$(TargetFileName)
 | 
				
			||||||
set Provider="$(MyCompanyName)"
 | 
					set Provider="$(MyCompanyName)"
 | 
				
			||||||
set CatalogFile=driver-$(MyProductFileArch).cat
 | 
					set CatalogFile=driver-$(MyProductFileArch).cat
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setlocal EnableDelayedExpansion
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
					if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
				
			||||||
@@ -354,6 +370,9 @@ stampinf -d * -v $(MyVersion) -f $(OutDir)driver-$(MyProductFileArch).inf</Comma
 | 
				
			|||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">set DriverFile=$(TargetFileName)
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">set DriverFile=$(TargetFileName)
 | 
				
			||||||
set Provider="$(MyCompanyName)"
 | 
					set Provider="$(MyCompanyName)"
 | 
				
			||||||
set CatalogFile=driver-$(MyProductFileArch).cat
 | 
					set CatalogFile=driver-$(MyProductFileArch).cat
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="a64" set ArchDecoration=ntarm64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x64" set ArchDecoration=ntamd64
 | 
				
			||||||
 | 
					if "$(MyProductFileArch)"=="x86" set ArchDecoration=ntx86
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setlocal EnableDelayedExpansion
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
					if exist $(OutDir)driver-$(MyProductFileArch).inf del $(OutDir)driver-$(MyProductFileArch).inf
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1047,11 +1047,49 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    NTSTATUS (*Obsolete0)(VOID);
 | 
					    NTSTATUS (*Obsolete0)(VOID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Inform the file system that its dispatcher has been stopped.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Prior to WinFsp v2.0 the FSD would never unmount a file system volume unless
 | 
				
			||||||
 | 
					     * the user mode file system requested the unmount. Since WinFsp v2.0 it is possible
 | 
				
			||||||
 | 
					     * for the FSD to unmount a file system volume without an explicit user mode file system
 | 
				
			||||||
 | 
					     * request. For example, this happens when the FSD is being uninstalled.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * A user mode file system can use this operation to determine when its dispatcher
 | 
				
			||||||
 | 
					     * has been stopped. The Normally parameter can be used to determine why the dispatcher
 | 
				
			||||||
 | 
					     * was stopped: it is TRUE when the file system is being stopped via
 | 
				
			||||||
 | 
					     * FspFileSystemStopDispatcher and FALSE otherwise.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * When the file system receives a request with Normally == TRUE it need not take any
 | 
				
			||||||
 | 
					     * extra steps. This case is the same as for pre-v2.0 versions: since the file system
 | 
				
			||||||
 | 
					     * stopped the dispatcher via FspFileSystemStopDispatcher, it will likely exit its
 | 
				
			||||||
 | 
					     * process soon.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * When the file system receives a request with Normally == FALSE it may need to take
 | 
				
			||||||
 | 
					     * extra steps to exit its process as this is not done by default.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * A file system that uses the FspService infrastructure may use the
 | 
				
			||||||
 | 
					     * FspFileSystemStopServiceIfNecessary API to correctly handle all cases.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This operation is the last one that a file system will receive.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param FileSystem
 | 
				
			||||||
 | 
					     *     The file system on which this request is posted.
 | 
				
			||||||
 | 
					     * @param Normally
 | 
				
			||||||
 | 
					     *     TRUE if the file system is being stopped via FspFileSystemStopDispatcher.
 | 
				
			||||||
 | 
					     *     FALSE if the file system is being stopped because of another reason such
 | 
				
			||||||
 | 
					     *     as driver unload/uninstall.
 | 
				
			||||||
 | 
					     * @see
 | 
				
			||||||
 | 
					     *     FspFileSystemStopServiceIfNecessary
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    VOID (*DispatcherStopped)(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			||||||
 | 
					        BOOLEAN Normally);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * This ensures that this interface will always contain 64 function pointers.
 | 
					     * 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 +1112,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)) ||
 | 
				
			||||||
@@ -1108,7 +1147,7 @@ FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
 | 
				
			|||||||
 * @param VolumeParams
 | 
					 * @param VolumeParams
 | 
				
			||||||
 *     Volume parameters for the newly created file system.
 | 
					 *     Volume parameters for the newly created file system.
 | 
				
			||||||
 * @param Interface
 | 
					 * @param Interface
 | 
				
			||||||
 *     A pointer to the actual operations that actually implement this user mode file system.
 | 
					 *     A pointer to the operations that implement this user mode file system.
 | 
				
			||||||
 * @param PFileSystem [out]
 | 
					 * @param PFileSystem [out]
 | 
				
			||||||
 *     Pointer that will receive the file system object created on successful return from this
 | 
					 *     Pointer that will receive the file system object created on successful return from this
 | 
				
			||||||
 *     call.
 | 
					 *     call.
 | 
				
			||||||
@@ -1746,6 +1785,23 @@ UINT32 FspFileSystemGetEaPackedSize(PFILE_FULL_EA_INFORMATION SingleEa)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
 | 
					FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
 | 
				
			||||||
    PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
 | 
					    PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Stop a file system service, if any.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a helper for implementing the DispatcherStopped operation, but only for file systems
 | 
				
			||||||
 | 
					 * that use the FspService infrastructure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param FileSystem
 | 
				
			||||||
 | 
					 *     The file system object.
 | 
				
			||||||
 | 
					 * @param Normally
 | 
				
			||||||
 | 
					 *     TRUE if the file system is being stopped via FspFileSystemStopDispatcher.
 | 
				
			||||||
 | 
					 *     FALSE if the file system is being stopped because of another reason such
 | 
				
			||||||
 | 
					 *     as driver unload/uninstall.
 | 
				
			||||||
 | 
					 * @see
 | 
				
			||||||
 | 
					 *     DispatcherStopped
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					FSP_API VOID FspFileSystemStopServiceIfNecessary(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			||||||
 | 
					    BOOLEAN Normally);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Directory buffering
 | 
					 * Directory buffering
 | 
				
			||||||
@@ -2043,6 +2099,8 @@ FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service);
 | 
				
			|||||||
 * to connect the service process to the Service Control Manager. If the Service Control Manager is
 | 
					 * to connect the service process to the Service Control Manager. If the Service Control Manager is
 | 
				
			||||||
 * not available (and console mode is allowed) it will enter console mode.
 | 
					 * not available (and console mode is allowed) it will enter console mode.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * This function should be called once per process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @param Service
 | 
					 * @param Service
 | 
				
			||||||
 *     The service object.
 | 
					 *     The service object.
 | 
				
			||||||
 * @return
 | 
					 * @return
 | 
				
			||||||
@@ -2120,6 +2178,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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								src/dll/fs.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/dll/fs.c
									
									
									
									
									
								
							@@ -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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -391,6 +406,11 @@ FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG
 | 
				
			|||||||
    if (0 == FileSystem->DispatcherThread)
 | 
					    if (0 == FileSystem->DispatcherThread)
 | 
				
			||||||
        return FspNtStatusFromWin32(GetLastError());
 | 
					        return FspNtStatusFromWin32(GetLastError());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(FSP_CFG_REJECT_EARLY_IRP)
 | 
				
			||||||
 | 
					    FspFsctlTransact(FileSystem->VolumeHandle, 0, 0, 0, 0, FALSE);
 | 
				
			||||||
 | 
					        /* send a Transact0 to inform the FSD that the dispatcher is _almost_ ready */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return STATUS_SUCCESS;
 | 
					    return STATUS_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -399,6 +419,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 +432,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,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										384
									
								
								src/dll/fsctl.c
									
									
									
									
									
								
							
							
						
						
									
										384
									
								
								src/dll/fsctl.c
									
									
									
									
									
								
							@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1883,3 +1883,12 @@ FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    return FspFileSystemAddXxxInfo(NotifyInfo, Buffer, Length, PBytesTransferred);
 | 
					    return FspFileSystemAddXxxInfo(NotifyInfo, Buffer, Length, PBytesTransferred);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FSP_API VOID FspFileSystemStopServiceIfNecessary(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			||||||
 | 
					    BOOLEAN Normally)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* NOTE: .NET calls us with a zero FileSystem pointer! */
 | 
				
			||||||
 | 
					    if (Normally)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    FspServiceStopLoop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1939,7 +1939,7 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SizeA = lstrlenA(name);
 | 
					    SizeA = lstrlenA(name);
 | 
				
			||||||
    if (SizeA > 255)
 | 
					    if (SizeA > 255 * 4)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
 | 
					        fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
 | 
				
			||||||
            "too long");
 | 
					            "too long");
 | 
				
			||||||
@@ -1949,6 +1949,13 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
 | 
				
			|||||||
    SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255);
 | 
					    SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255);
 | 
				
			||||||
    if (0 == SizeW)
 | 
					    if (0 == SizeW)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
 | 
				
			||||||
 | 
					                "too long");
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
 | 
					        fsp_fuse_intf_LogBadDirInfo(filedesc->PosixPath, name,
 | 
				
			||||||
            "MultiByteToWideChar failed");
 | 
					            "MultiByteToWideChar failed");
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
@@ -1991,7 +1998,7 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			|||||||
    NTSTATUS Result;
 | 
					    NTSTATUS Result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SizeA = lstrlenA(filedesc->PosixPath);
 | 
					    SizeA = lstrlenA(filedesc->PosixPath);
 | 
				
			||||||
    PosixPath = MemAlloc(SizeA + 1 + 255 + 1);
 | 
					    PosixPath = MemAlloc(SizeA + 1 + 255 * 4 + 1);
 | 
				
			||||||
    if (0 == PosixPath)
 | 
					    if (0 == PosixPath)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Result = STATUS_INSUFFICIENT_RESOURCES;
 | 
					        Result = STATUS_INSUFFICIENT_RESOURCES;
 | 
				
			||||||
@@ -2040,7 +2047,7 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			|||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                PosixPathEnd = 0;
 | 
					                PosixPathEnd = 0;
 | 
				
			||||||
                SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
 | 
					                SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255 * 4, 0, 0);
 | 
				
			||||||
                if (0 == SizeA)
 | 
					                if (0 == SizeA)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    /* this should never happen because we just converted using MultiByteToWideChar */
 | 
					                    /* this should never happen because we just converted using MultiByteToWideChar */
 | 
				
			||||||
@@ -2628,6 +2635,17 @@ static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			|||||||
        &Uid, &Gid, &Mode, FileInfo);
 | 
					        &Uid, &Gid, &Mode, FileInfo);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VOID fsp_fuse_intf_DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			||||||
 | 
					    BOOLEAN Normally)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (Normally)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct fuse *f = FileSystem->UserContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fsp_fuse_exit(f->env, f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
 | 
					FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    fsp_fuse_intf_GetVolumeInfo,
 | 
					    fsp_fuse_intf_GetVolumeInfo,
 | 
				
			||||||
@@ -2661,6 +2679,8 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
 | 
				
			|||||||
    fsp_fuse_intf_Overwrite,
 | 
					    fsp_fuse_intf_Overwrite,
 | 
				
			||||||
    fsp_fuse_intf_GetEa,
 | 
					    fsp_fuse_intf_GetEa,
 | 
				
			||||||
    fsp_fuse_intf_SetEa,
 | 
					    fsp_fuse_intf_SetEa,
 | 
				
			||||||
 | 
					    0,
 | 
				
			||||||
 | 
					    fsp_fuse_intf_DispatcherStopped,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,6 +110,7 @@ NTSTATUS FspGetModuleFileName(
 | 
				
			|||||||
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
 | 
					VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
 | 
				
			||||||
    PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
 | 
					    PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VOID FspServiceStopLoop(VOID);
 | 
				
			||||||
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
 | 
					BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
 | 
					static inline ULONG FspPathSuffixIndex(PWSTR FileName)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,8 @@ enum
 | 
				
			|||||||
    GetStatus_WaitHint                  = 0x4000,
 | 
					    GetStatus_WaitHint                  = 0x4000,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SRWLOCK FspServiceLoopLock = SRWLOCK_INIT;
 | 
				
			||||||
 | 
					static SRWLOCK FspServiceTableLock = SRWLOCK_INIT;
 | 
				
			||||||
static SERVICE_TABLE_ENTRYW *FspServiceTable;
 | 
					static SERVICE_TABLE_ENTRYW *FspServiceTable;
 | 
				
			||||||
static HANDLE FspServiceConsoleModeEvent;
 | 
					static HANDLE FspServiceConsoleModeEvent;
 | 
				
			||||||
static UINT32 FspServiceConsoleCtrlHandlerDisabled;
 | 
					static UINT32 FspServiceConsoleCtrlHandlerDisabled;
 | 
				
			||||||
@@ -220,6 +222,14 @@ FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
 | 
					FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * FspServiceLoop can only be called once per process, because of StartServiceCtrlDispatcherW
 | 
				
			||||||
 | 
					     * (which returns ERROR_SERVICE_ALREADY_RUNNING if called more than once). Unfortunately this
 | 
				
			||||||
 | 
					     * limitation was never documented and there may be users of FspServiceLoop out there that call
 | 
				
			||||||
 | 
					     * it more than once per process.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    AcquireSRWLockExclusive(&FspServiceLoopLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NTSTATUS Result;
 | 
					    NTSTATUS Result;
 | 
				
			||||||
    SERVICE_TABLE_ENTRYW ServiceTable[2];
 | 
					    SERVICE_TABLE_ENTRYW ServiceTable[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -236,7 +246,9 @@ FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
 | 
				
			|||||||
    ServiceTable[0].lpServiceProc = FspServiceEntry;
 | 
					    ServiceTable[0].lpServiceProc = FspServiceEntry;
 | 
				
			||||||
    ServiceTable[1].lpServiceName = 0;
 | 
					    ServiceTable[1].lpServiceName = 0;
 | 
				
			||||||
    ServiceTable[1].lpServiceProc = 0;
 | 
					    ServiceTable[1].lpServiceProc = 0;
 | 
				
			||||||
 | 
					    AcquireSRWLockExclusive(&FspServiceTableLock);
 | 
				
			||||||
    FspServiceTable = ServiceTable;
 | 
					    FspServiceTable = ServiceTable;
 | 
				
			||||||
 | 
					    ReleaseSRWLockExclusive(&FspServiceTableLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!StartServiceCtrlDispatcherW(ServiceTable))
 | 
					    if (!StartServiceCtrlDispatcherW(ServiceTable))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -331,11 +343,42 @@ FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service)
 | 
				
			|||||||
    Result = STATUS_SUCCESS;
 | 
					    Result = STATUS_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
 | 
					    AcquireSRWLockExclusive(&FspServiceTableLock);
 | 
				
			||||||
    FspServiceTable = 0;
 | 
					    FspServiceTable = 0;
 | 
				
			||||||
 | 
					    ReleaseSRWLockExclusive(&FspServiceTableLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ReleaseSRWLockExclusive(&FspServiceLoopLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Result;
 | 
					    return Result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DWORD WINAPI FspServiceStopLoopThread(PVOID Context);
 | 
				
			||||||
 | 
					VOID FspServiceStopLoop(VOID)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BOOLEAN HasService;
 | 
				
			||||||
 | 
					    HANDLE Thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    AcquireSRWLockShared(&FspServiceTableLock);
 | 
				
			||||||
 | 
					    HasService = 0 != FspServiceFromTable();
 | 
				
			||||||
 | 
					    ReleaseSRWLockShared(&FspServiceTableLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (HasService)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Thread = CreateThread(0, 0, FspServiceStopLoopThread, 0, 0, 0);
 | 
				
			||||||
 | 
					        if (0 != Thread)
 | 
				
			||||||
 | 
					            CloseHandle(Thread);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static DWORD WINAPI FspServiceStopLoopThread(PVOID Context)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    AcquireSRWLockShared(&FspServiceTableLock);
 | 
				
			||||||
 | 
					    FSP_SERVICE *Service = FspServiceFromTable();
 | 
				
			||||||
 | 
					    if (0 != Service)
 | 
				
			||||||
 | 
					        FspServiceStop(Service);
 | 
				
			||||||
 | 
					    ReleaseSRWLockShared(&FspServiceTableLock);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FSP_API VOID FspServiceStop(FSP_SERVICE *Service)
 | 
					FSP_API VOID FspServiceStop(FSP_SERVICE *Service)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SERVICE_STATUS ServiceStatus;
 | 
					    SERVICE_STATUS ServiceStatus;
 | 
				
			||||||
@@ -393,6 +436,7 @@ static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv)
 | 
				
			|||||||
    FSP_SERVICE *Service;
 | 
					    FSP_SERVICE *Service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Service = FspServiceFromTable();
 | 
					    Service = FspServiceFromTable();
 | 
				
			||||||
 | 
					        /* we are subordinate to FspServiceLoop; no need to protect this access with FspServiceTableLock */
 | 
				
			||||||
    if (0 == Service)
 | 
					    if (0 == Service)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        FspServiceLog(EVENTLOG_ERROR_TYPE,
 | 
					        FspServiceLog(EVENTLOG_ERROR_TYPE,
 | 
				
			||||||
@@ -501,6 +545,7 @@ static DWORD WINAPI FspServiceConsoleModeThread(PVOID Context)
 | 
				
			|||||||
        ;
 | 
					        ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Service = FspServiceFromTable();
 | 
					    Service = FspServiceFromTable();
 | 
				
			||||||
 | 
					        /* we are subordinate to FspServiceLoop; no need to protect this access with FspServiceTableLock */
 | 
				
			||||||
    if (0 == Service)
 | 
					    if (0 == Service)
 | 
				
			||||||
        FspServiceLog(EVENTLOG_ERROR_TYPE,
 | 
					        FspServiceLog(EVENTLOG_ERROR_TYPE,
 | 
				
			||||||
            L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
 | 
					            L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										214
									
								
								src/dll/sxs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/dll/sxs.c
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1188,6 +1188,39 @@ namespace Fsp
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return STATUS_INVALID_DEVICE_REQUEST;
 | 
					            return STATUS_INVALID_DEVICE_REQUEST;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Inform the file system that its dispatcher has been stopped.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <remarks>
 | 
				
			||||||
 | 
					        /// <para>
 | 
				
			||||||
 | 
					        /// Prior to WinFsp v2.0 the FSD would never unmount a file system volume unless
 | 
				
			||||||
 | 
					        /// the user mode file system requested the unmount. Since WinFsp v2.0 it is possible
 | 
				
			||||||
 | 
					        /// for the FSD to unmount a file system volume without an explicit user mode file system
 | 
				
			||||||
 | 
					        /// request. For example, this happens when the FSD is being uninstalled.
 | 
				
			||||||
 | 
					        /// </para><para>
 | 
				
			||||||
 | 
					        /// A user mode file system can use this operation to determine when its dispatcher
 | 
				
			||||||
 | 
					        /// has been stopped. The Normally parameter can be used to determine why the dispatcher
 | 
				
			||||||
 | 
					        /// was stopped: it is TRUE when the file system is being stopped normally (i.e. via the
 | 
				
			||||||
 | 
					        /// native FspFileSystemStopDispatcher) and FALSE otherwise.
 | 
				
			||||||
 | 
					        /// </para><para>
 | 
				
			||||||
 | 
					        /// A file system that uses the Service class infrastructure may use the
 | 
				
			||||||
 | 
					        /// StopServiceIfNecessary method to correctly handle all cases. The base implementation
 | 
				
			||||||
 | 
					        /// of this method calls the StopServiceIfNecessary method.
 | 
				
			||||||
 | 
					        /// </para><para>
 | 
				
			||||||
 | 
					        /// This operation is the last one that a file system will receive.
 | 
				
			||||||
 | 
					        /// </para>
 | 
				
			||||||
 | 
					        /// </remarks>
 | 
				
			||||||
 | 
					        /// <param name="Normally">
 | 
				
			||||||
 | 
					        /// TRUE if the file system is being stopped via the native FspFileSystemStopDispatcher.
 | 
				
			||||||
 | 
					        /// FALSE if the file system is being stopped because of another reason such
 | 
				
			||||||
 | 
					        /// as driver unload/uninstall.
 | 
				
			||||||
 | 
					        /// </param>
 | 
				
			||||||
 | 
					        /// <seealso cref="StopServiceIfNecessary"/>
 | 
				
			||||||
 | 
					        public virtual void DispatcherStopped(
 | 
				
			||||||
 | 
					            Boolean Normally)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            StopServiceIfNecessary(Normally);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* helpers */
 | 
					        /* helpers */
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@@ -1483,6 +1516,10 @@ namespace Fsp
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return FullEaInformation.PackedSize(EaName, EaValue, NeedEa);
 | 
					            return FullEaInformation.PackedSize(EaName, EaValue, NeedEa);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        public void StopServiceIfNecessary(Boolean Normally)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Api.FspFileSystemStopServiceIfNecessary(IntPtr.Zero, Normally);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1426,6 +1426,21 @@ namespace Fsp
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private static void DispatcherStopped(
 | 
				
			||||||
 | 
					            IntPtr FileSystemPtr,
 | 
				
			||||||
 | 
					            Boolean Normally)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                FileSystem.DispatcherStopped(Normally);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ExceptionHandler(FileSystem, ex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static FileSystemHost()
 | 
					        static FileSystemHost()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _FileSystemInterface.GetVolumeInfo = GetVolumeInfo;
 | 
					            _FileSystemInterface.GetVolumeInfo = GetVolumeInfo;
 | 
				
			||||||
@@ -1456,6 +1471,7 @@ namespace Fsp
 | 
				
			|||||||
            _FileSystemInterface.SetDelete = SetDelete;
 | 
					            _FileSystemInterface.SetDelete = SetDelete;
 | 
				
			||||||
            _FileSystemInterface.GetEa = GetEa;
 | 
					            _FileSystemInterface.GetEa = GetEa;
 | 
				
			||||||
            _FileSystemInterface.SetEa = SetEa;
 | 
					            _FileSystemInterface.SetEa = SetEa;
 | 
				
			||||||
 | 
					            _FileSystemInterface.DispatcherStopped = DispatcherStopped;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
 | 
					            _FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
 | 
				
			||||||
            /* Marshal.AllocHGlobal does not zero memory; we must do it ourselves! */
 | 
					            /* Marshal.AllocHGlobal does not zero memory; we must do it ourselves! */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -745,6 +745,10 @@ namespace Fsp.Interop
 | 
				
			|||||||
                out FileInfo FileInfo);
 | 
					                out FileInfo FileInfo);
 | 
				
			||||||
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | 
					            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | 
				
			||||||
            internal delegate Int32 Obsolete0();
 | 
					            internal delegate Int32 Obsolete0();
 | 
				
			||||||
 | 
					            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | 
				
			||||||
 | 
					            internal delegate void DispatcherStopped(
 | 
				
			||||||
 | 
					                IntPtr FileSystem,
 | 
				
			||||||
 | 
					                [MarshalAs(UnmanagedType.U1)] Boolean Normally);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal static int Size = IntPtr.Size * 64;
 | 
					        internal static int Size = IntPtr.Size * 64;
 | 
				
			||||||
@@ -781,6 +785,7 @@ namespace Fsp.Interop
 | 
				
			|||||||
        internal Proto.GetEa GetEa;
 | 
					        internal Proto.GetEa GetEa;
 | 
				
			||||||
        internal Proto.SetEa SetEa;
 | 
					        internal Proto.SetEa SetEa;
 | 
				
			||||||
        internal Proto.Obsolete0 Obsolete0;
 | 
					        internal Proto.Obsolete0 Obsolete0;
 | 
				
			||||||
 | 
					        internal Proto.DispatcherStopped DispatcherStopped;
 | 
				
			||||||
        /* NTSTATUS (*Reserved[33])(); */
 | 
					        /* NTSTATUS (*Reserved[33])(); */
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -907,6 +912,10 @@ namespace Fsp.Interop
 | 
				
			|||||||
                UInt32 Length,
 | 
					                UInt32 Length,
 | 
				
			||||||
                out UInt32 PBytesTransferred);
 | 
					                out UInt32 PBytesTransferred);
 | 
				
			||||||
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | 
					            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | 
				
			||||||
 | 
					            internal delegate void FspFileSystemStopServiceIfNecessary(
 | 
				
			||||||
 | 
					                IntPtr FileSystem,
 | 
				
			||||||
 | 
					                [MarshalAs(UnmanagedType.U1)] Boolean Normally);
 | 
				
			||||||
 | 
					            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | 
				
			||||||
            [return: MarshalAs(UnmanagedType.U1)]
 | 
					            [return: MarshalAs(UnmanagedType.U1)]
 | 
				
			||||||
            internal delegate Boolean FspFileSystemAcquireDirectoryBuffer(
 | 
					            internal delegate Boolean FspFileSystemAcquireDirectoryBuffer(
 | 
				
			||||||
                ref IntPtr PDirBuffer,
 | 
					                ref IntPtr PDirBuffer,
 | 
				
			||||||
@@ -1048,6 +1057,7 @@ namespace Fsp.Interop
 | 
				
			|||||||
        internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo;
 | 
					        internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo;
 | 
				
			||||||
        internal static Proto.FspFileSystemAddEa _FspFileSystemAddEa;
 | 
					        internal static Proto.FspFileSystemAddEa _FspFileSystemAddEa;
 | 
				
			||||||
        internal static Proto.FspFileSystemAddNotifyInfo _FspFileSystemAddNotifyInfo;
 | 
					        internal static Proto.FspFileSystemAddNotifyInfo _FspFileSystemAddNotifyInfo;
 | 
				
			||||||
 | 
					        internal static Proto.FspFileSystemStopServiceIfNecessary FspFileSystemStopServiceIfNecessary;
 | 
				
			||||||
        internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer;
 | 
					        internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer;
 | 
				
			||||||
        internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer;
 | 
					        internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer;
 | 
				
			||||||
        internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer;
 | 
					        internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer;
 | 
				
			||||||
@@ -1506,6 +1516,7 @@ namespace Fsp.Interop
 | 
				
			|||||||
            _FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
 | 
					            _FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
 | 
				
			||||||
            _FspFileSystemAddEa = GetEntryPoint<Proto.FspFileSystemAddEa>(Module);
 | 
					            _FspFileSystemAddEa = GetEntryPoint<Proto.FspFileSystemAddEa>(Module);
 | 
				
			||||||
            _FspFileSystemAddNotifyInfo = GetEntryPoint<Proto.FspFileSystemAddNotifyInfo>(Module);
 | 
					            _FspFileSystemAddNotifyInfo = GetEntryPoint<Proto.FspFileSystemAddNotifyInfo>(Module);
 | 
				
			||||||
 | 
					            FspFileSystemStopServiceIfNecessary = GetEntryPoint<Proto.FspFileSystemStopServiceIfNecessary>(Module);
 | 
				
			||||||
            FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
 | 
					            FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
 | 
				
			||||||
            FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
 | 
					            FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
 | 
				
			||||||
            FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);
 | 
					            FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -154,8 +154,16 @@ NTSTATUS FspReleaseForModWrite(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    FSP_FILE_NODE *FileNode = FileObject->FsContext;
 | 
					    FSP_FILE_NODE *FileNode = FileObject->FsContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * In some rare cases and under load the mapped page writer's TopLevelIrp
 | 
				
			||||||
 | 
					     * may be trashed by some outside component (observed on Windows 10 1909).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PIRP TopLevelIrp = IoGetTopLevelIrp();
 | 
				
			||||||
 | 
					    IoSetTopLevelIrp((PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FspFileNodeRelease(FileNode, Full);
 | 
					    FspFileNodeRelease(FileNode, Full);
 | 
				
			||||||
    ASSERT((PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP == IoGetTopLevelIrp());
 | 
					
 | 
				
			||||||
 | 
					    IoSetTopLevelIrp(TopLevelIrp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FSP_LEAVE("FileObject=%p", FileObject);
 | 
					    FSP_LEAVE("FileObject=%p", FileObject);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -205,6 +205,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
 | 
				
			|||||||
                    ASSERT(sizeof(UINT64) == DirectoryMarker->Length);
 | 
					                    ASSERT(sizeof(UINT64) == DirectoryMarker->Length);
 | 
				
			||||||
                    DirectoryMarkerFound = DirectoryNextOffset == *(PUINT64)DirectoryMarker->Buffer;
 | 
					                    DirectoryMarkerFound = DirectoryNextOffset == *(PUINT64)DirectoryMarker->Buffer;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
 | 
					            /* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										208
									
								
								src/sys/driver.c
									
									
									
									
									
								
							
							
						
						
									
										208
									
								
								src/sys/driver.c
									
									
									
									
									
								
							@@ -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);
 | 
				
			||||||
@@ -176,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);
 | 
				
			||||||
@@ -206,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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -214,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);
 | 
				
			||||||
@@ -261,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]);
 | 
				
			||||||
@@ -281,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);
 | 
				
			||||||
@@ -297,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);
 | 
				
			||||||
@@ -318,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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,23 +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);
 | 
					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)
 | 
				
			||||||
@@ -1182,8 +1197,8 @@ typedef struct
 | 
				
			|||||||
    KSPIN_LOCK SpinLock;
 | 
					    KSPIN_LOCK SpinLock;
 | 
				
			||||||
    LONG RefCount;
 | 
					    LONG RefCount;
 | 
				
			||||||
    UINT32 Kind;
 | 
					    UINT32 Kind;
 | 
				
			||||||
    /* IoTimer emulation */
 | 
					    FSP_DEVICE_TIMER DeviceTimer;       /* IoTimer emulation */
 | 
				
			||||||
    FSP_DEVICE_TIMER DeviceTimer;
 | 
					    LONG DidIoDeleteDevice;
 | 
				
			||||||
} 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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ Provider = !Provider!
 | 
				
			|||||||
[DestinationDirs]
 | 
					[DestinationDirs]
 | 
				
			||||||
DefaultDestDir = 12
 | 
					DefaultDestDir = 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[DefaultInstall]
 | 
					[DefaultInstall.!ArchDecoration!]
 | 
				
			||||||
CopyFiles = Driver.CopyFiles
 | 
					CopyFiles = Driver.CopyFiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Driver.CopyFiles]
 | 
					[Driver.CopyFiles]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,8 @@ static NTSTATUS FspFsvolQueryBasicInformation(PFILE_OBJECT FileObject,
 | 
				
			|||||||
static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
 | 
					static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
 | 
				
			||||||
    PVOID *PBuffer, PVOID BufferEnd,
 | 
					    PVOID *PBuffer, PVOID BufferEnd,
 | 
				
			||||||
    const FSP_FSCTL_FILE_INFO *FileInfo);
 | 
					    const FSP_FSCTL_FILE_INFO *FileInfo);
 | 
				
			||||||
 | 
					static NTSTATUS FspFsvolQueryIdInformation(PFILE_OBJECT FileObject,
 | 
				
			||||||
 | 
					    PVOID *PBuffer, PVOID BufferEnd);
 | 
				
			||||||
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
 | 
					static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
 | 
				
			||||||
    PVOID *PBuffer, PVOID BufferEnd);
 | 
					    PVOID *PBuffer, PVOID BufferEnd);
 | 
				
			||||||
static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
 | 
					static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
 | 
				
			||||||
@@ -106,6 +108,7 @@ FAST_IO_QUERY_OPEN FspFastIoQueryOpen;
 | 
				
			|||||||
#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
 | 
				
			||||||
#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
 | 
				
			||||||
#pragma alloc_text(PAGE, FspFsvolQueryEaInformation)
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryEaInformation)
 | 
				
			||||||
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryIdInformation)
 | 
				
			||||||
#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
 | 
				
			||||||
#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
 | 
				
			||||||
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
 | 
					#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
 | 
				
			||||||
@@ -288,6 +291,32 @@ static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
 | 
				
			|||||||
    return STATUS_SUCCESS;
 | 
					    return STATUS_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static NTSTATUS FspFsvolQueryIdInformation(PFILE_OBJECT FileObject,
 | 
				
			||||||
 | 
					    PVOID *PBuffer, PVOID BufferEnd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PAGED_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PFILE_ID_INFORMATION Info = (PFILE_ID_INFORMATION)*PBuffer;
 | 
				
			||||||
 | 
					    FSP_FILE_NODE *FileNode = FileObject->FsContext;
 | 
				
			||||||
 | 
					    PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
 | 
				
			||||||
 | 
					    FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
 | 
				
			||||||
 | 
					    union
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        UINT64 IndexNumber;
 | 
				
			||||||
 | 
					        FILE_ID_128 FileId;
 | 
				
			||||||
 | 
					    } FileIdBuf = { .IndexNumber = FileNode->IndexNumber };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((PVOID)(Info + 1) > BufferEnd)
 | 
				
			||||||
 | 
					        return STATUS_BUFFER_TOO_SMALL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Info->VolumeSerialNumber = FsvolDeviceExtension->VolumeParams.VolumeSerialNumber;
 | 
				
			||||||
 | 
					    Info->FileId = FileIdBuf.FileId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *PBuffer = (PVOID)(Info + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return STATUS_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
 | 
					static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
 | 
				
			||||||
    PVOID *PBuffer, PVOID BufferEnd)
 | 
					    PVOID *PBuffer, PVOID BufferEnd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -961,6 +990,10 @@ static NTSTATUS FspFsvolQueryInformation(
 | 
				
			|||||||
    case FileHardLinkInformation:
 | 
					    case FileHardLinkInformation:
 | 
				
			||||||
        Result = STATUS_NOT_SUPPORTED;  /* no hard link support */
 | 
					        Result = STATUS_NOT_SUPPORTED;  /* no hard link support */
 | 
				
			||||||
        return Result;
 | 
					        return Result;
 | 
				
			||||||
 | 
					    case FileIdInformation:
 | 
				
			||||||
 | 
					        Result = FspFsvolQueryIdInformation(FileObject, &Buffer, BufferEnd);
 | 
				
			||||||
 | 
					        Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
 | 
				
			||||||
 | 
					        return Result;
 | 
				
			||||||
    case FileInternalInformation:
 | 
					    case FileInternalInformation:
 | 
				
			||||||
        Result = FspFsvolQueryInternalInformation(FileObject, &Buffer, BufferEnd);
 | 
					        Result = FspFsvolQueryInternalInformation(FileObject, &Buffer, BufferEnd);
 | 
				
			||||||
        Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
 | 
					        Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -110,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
 | 
				
			||||||
@@ -125,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;
 | 
				
			||||||
@@ -191,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);
 | 
				
			||||||
@@ -198,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);
 | 
				
			||||||
@@ -205,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))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -239,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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -249,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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -257,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;
 | 
				
			||||||
@@ -329,8 +358,47 @@ VOID FspSiloFinalize(VOID)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    CALL(PsUnregisterSiloMonitor)(FspSiloMonitor);
 | 
					    CALL(PsUnregisterSiloMonitor)(FspSiloMonitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DBG
 | 
				
			||||||
 | 
					    FsRtlEnterFileSystem();
 | 
				
			||||||
 | 
					    ExAcquireFastMutexUnsafe(&FspSiloListMutex);
 | 
				
			||||||
 | 
					    ASSERT(IsListEmpty(&FspSiloList));
 | 
				
			||||||
 | 
					    ExReleaseFastMutexUnsafe(&FspSiloListMutex);
 | 
				
			||||||
 | 
					    FsRtlExitFileSystem();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FspSiloMonitor = 0;
 | 
					    FspSiloMonitor = 0;
 | 
				
			||||||
    FspSiloInitCallback = 0;
 | 
					    FspSiloInitCallback = 0;
 | 
				
			||||||
    FspSiloFiniCallback = 0;
 | 
					    FspSiloFiniCallback = 0;
 | 
				
			||||||
    FspSiloInitDone = FALSE;
 | 
					    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
									
								
							
							
						
						
									
										71
									
								
								src/sys/sxs.c
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,6 +27,7 @@ if X%~nx0==Xbuild-choco.bat (
 | 
				
			|||||||
set BuildArm64=yes
 | 
					set BuildArm64=yes
 | 
				
			||||||
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
 | 
					if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (
 | 
				
			||||||
    set BuildArm64=no
 | 
					    set BuildArm64=no
 | 
				
			||||||
 | 
					    set UseDotnetSdk=yes
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
 | 
					if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
 | 
				
			||||||
    set BuildArm64=no
 | 
					    set BuildArm64=no
 | 
				
			||||||
@@ -42,8 +43,11 @@ call "%~dp0vcvarsall.bat" x64
 | 
				
			|||||||
if not X%SignedPackage%==X (
 | 
					if not X%SignedPackage%==X (
 | 
				
			||||||
    if not exist "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi" (echo previous build not found >&2 & exit /b 1)
 | 
					    if not exist "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi" (echo previous build not found >&2 & exit /b 1)
 | 
				
			||||||
    if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
 | 
					    if not exist "%SignedPackage%" (echo signed package not found >&2 & exit /b 1)
 | 
				
			||||||
 | 
					    set Version=
 | 
				
			||||||
 | 
					    for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do set Version=%%~nf
 | 
				
			||||||
 | 
					    set Version=!Version:%MyProductFileName%-=!
 | 
				
			||||||
    del "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi"
 | 
					    del "%~dp0..\build\VStudio\build\%Configuration%\%MyProductFileName%-*.msi"
 | 
				
			||||||
    if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.*.nupkg"
 | 
					    if exist "%~dp0..\build\VStudio\build\%Configuration%\winfsp.!Version!.nupkg" del "%~dp0..\build\VStudio\build\%Configuration%\winfsp.!Version!.nupkg"
 | 
				
			||||||
    for /R "%SignedPackage%" %%f in (*.sys) do (
 | 
					    for /R "%SignedPackage%" %%f in (*.sys) do (
 | 
				
			||||||
        copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
 | 
					        copy "%%f" "%~dp0..\build\VStudio\build\%Configuration%" >nul
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -70,6 +74,13 @@ if X%SignedPackage%==X (
 | 
				
			|||||||
        if errorlevel 1 goto fail
 | 
					        if errorlevel 1 goto fail
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if X%UseDotnetSdk%==Xyes (
 | 
				
			||||||
 | 
					        dotnet build ./dotnet/winfsp.net.csproj -c "%Configuration%" -p:Platform=AnyCPU -p:SolutionDir="%cd%"\
 | 
				
			||||||
 | 
					        if errorlevel 1 goto fail
 | 
				
			||||||
 | 
					        dotnet build ./testing/memfs-dotnet.csproj -c "%Configuration%" -p:Platform=AnyCPU -p:SolutionDir="%cd%"\
 | 
				
			||||||
 | 
					        if errorlevel 1 goto fail
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pushd build\%Configuration%
 | 
					    pushd build\%Configuration%
 | 
				
			||||||
    set signfiles=^
 | 
					    set signfiles=^
 | 
				
			||||||
        %MyProductFileName%-a64.sys %MyProductFileName%-x64.sys %MyProductFileName%-x86.sys^
 | 
					        %MyProductFileName%-a64.sys %MyProductFileName%-x64.sys %MyProductFileName%-x86.sys^
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ 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
 | 
					        docker-run.bat
 | 
				
			||||||
    ) do (
 | 
					    ) do (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								tools/gensrc/remove-build-dotnet.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								tools/gensrc/remove-build-dotnet.bat
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					@echo off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setlocal
 | 
				
			||||||
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if "%1"=="" (
 | 
				
			||||||
 | 
					    cd %~dp0..\..
 | 
				
			||||||
 | 
					) else (
 | 
				
			||||||
 | 
					    cd "%1"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if exist winfsp.sln (
 | 
				
			||||||
 | 
					    powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0remove-sln-project.ps1' -Path '%cd%\winfsp.sln' -Match '*dotnet*'
 | 
				
			||||||
 | 
					) else (
 | 
				
			||||||
 | 
					    echo winfsp.sln not found in %cd%
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										12
									
								
								tools/gensrc/remove-sln-project.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tools/gensrc/remove-sln-project.ps1
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					param (
 | 
				
			||||||
 | 
					    [Parameter(Mandatory)][string]$Path,
 | 
				
			||||||
 | 
					    [Parameter(Mandatory)][string]$Match
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Removing projects that match $($Match) from $($Path)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Get-Content $Path -Delimiter 'EndProject' |
 | 
				
			||||||
 | 
					  Where-Object {$_ -notlike $Match} |
 | 
				
			||||||
 | 
					  Set-Content "$($Path).new"
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					 Move-Item -Path "$($Path).new" -Destination $Path -Force
 | 
				
			||||||
@@ -68,6 +68,27 @@ function Get-ReleaseInfo ($Tag) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Get-HwapiCredentials {
 | 
				
			||||||
 | 
					    $Credentials = (& "$ProjectRoot\tools\wincred.ps1" get "Hardware Dashboard API")
 | 
				
			||||||
 | 
					    if ($Credentials) {
 | 
				
			||||||
 | 
					        try { $Credentials = ConvertFrom-Json $Credentials[1] } catch {;}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if ($Credentials -and $Credentials.TenantId -and $Credentials.ClientId -and $Credentials.ClientId) {
 | 
				
			||||||
 | 
					        return $Credentials
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Start-Sdcm {
 | 
				
			||||||
 | 
					    Start-Job -ArgumentList $args -ScriptBlock {
 | 
				
			||||||
 | 
					        $env:SDCM_CREDS_TENANTID = $using:HwapiCredentials.TenantId
 | 
				
			||||||
 | 
					        $env:SDCM_CREDS_CLIENTID = $using:HwapiCredentials.ClientId
 | 
				
			||||||
 | 
					        $env:SDCM_CREDS_KEY = $using:HwapiCredentials.Key
 | 
				
			||||||
 | 
					        $env:SDCM_CREDS_URL = "https://manage.devcenter.microsoft.com"
 | 
				
			||||||
 | 
					        $env:SDCM_CREDS_URLPREFIX = "v2.0/my"
 | 
				
			||||||
 | 
					        & "$using:ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -creds envonly @args
 | 
				
			||||||
 | 
					    } | Receive-Job -Wait -AutoRemoveJob
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Get-FileVersion ($FileName) {
 | 
					function Get-FileVersion ($FileName) {
 | 
				
			||||||
    return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
 | 
					    return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -96,6 +117,12 @@ function Check-Prerequisites {
 | 
				
			|||||||
        exit 1
 | 
					        exit 1
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # check scdm.exe
 | 
				
			||||||
 | 
					    if (!(Get-Command "$ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
 | 
					        Write-Stderr "error: cannot find sdcm.exe"
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # check gh.exe
 | 
					    # check gh.exe
 | 
				
			||||||
    if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
 | 
					    if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
        Write-Stderr "error: cannot find gh.exe"
 | 
					        Write-Stderr "error: cannot find gh.exe"
 | 
				
			||||||
@@ -137,6 +164,17 @@ function Check-Prerequisites {
 | 
				
			|||||||
        exit 1
 | 
					        exit 1
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # check hardware dashboard api credentials
 | 
				
			||||||
 | 
					    $script:HwapiCredentials = Get-HwapiCredentials
 | 
				
			||||||
 | 
					    if (!$script:HwapiCredentials) {
 | 
				
			||||||
 | 
					        Write-Stderr "error: cannot get Hardware Dashboard API credentials"
 | 
				
			||||||
 | 
					        Write-Stderr '    The expected format of the credentials is as follows:'
 | 
				
			||||||
 | 
					        Write-Stderr '    TargetName: Hardware Dashboard API'
 | 
				
			||||||
 | 
					        Write-Stderr '    UserName: Credentials'
 | 
				
			||||||
 | 
					        Write-Stderr '    Password: {"TenantId":"TENANTID","ClientId":"CLIENTID","Key":"KEY"}'
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ($State -contains $Name) {
 | 
					    if ($State -contains $Name) {
 | 
				
			||||||
        if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
 | 
					        if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
 | 
				
			||||||
            Write-Stderr "error: invalid state for tag $Tag"
 | 
					            Write-Stderr "error: invalid state for tag $Tag"
 | 
				
			||||||
@@ -149,6 +187,12 @@ function Check-Prerequisites {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Check-Assets {
 | 
					function Check-Assets {
 | 
				
			||||||
 | 
					    # check driver.cab
 | 
				
			||||||
 | 
					    if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\driver.cab" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
 | 
					        Write-Stderr "error: cannot find driver.cab"
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # check winfsp.msi
 | 
					    # check winfsp.msi
 | 
				
			||||||
    if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
 | 
					    if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
        Write-Stderr "error: cannot find winfsp*.msi"
 | 
					        Write-Stderr "error: cannot find winfsp*.msi"
 | 
				
			||||||
@@ -161,9 +205,15 @@ function Check-Assets {
 | 
				
			|||||||
        exit 1
 | 
					        exit 1
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # check winfsp.net.nupkg
 | 
				
			||||||
 | 
					    if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp.net.*.nupkg" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
 | 
					        Write-Stderr "error: cannot find winfsp.net.*.nupkg"
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # check winfsp.nupkg
 | 
					    # check winfsp.nupkg
 | 
				
			||||||
    if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.nupkg" -ErrorAction SilentlyContinue)) {
 | 
					    if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp.*.nupkg" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
        Write-Stderr "error: cannot find winfsp*.nupkg"
 | 
					        Write-Stderr "error: cannot find winfsp.*.nupkg"
 | 
				
			||||||
        exit 1
 | 
					        exit 1
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,8 +236,215 @@ function Build-AssetsPhase1 {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        Write-Stdout @"
 | 
					        Write-Stdout @"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Upload file driver.cab to Microsoft Partner Center for attestation signing.
 | 
					Assets have been built but are not properly signed.
 | 
				
			||||||
When the file has been signed, download and extract to ~\Downloads\drivers
 | 
					Signable assets are ready for submission to the hardware dashboard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Submit-AssetsToHwapi {
 | 
				
			||||||
 | 
					    Task -ScriptBlock {
 | 
				
			||||||
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
 | 
				
			||||||
 | 
					        $MsiName = Split-Path -Leaf $MsiFile
 | 
				
			||||||
 | 
					        if ($MsiName -match "winfsp-(.+)\.msi") {
 | 
				
			||||||
 | 
					            $Version = $matches[1]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!$Version) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot determine version for winfsp.msi"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $DocRequestedSignatures = @()
 | 
				
			||||||
 | 
					        $Documentation = Invoke-WebRequest -Uri "https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
 | 
				
			||||||
 | 
					        $Documentation = $Documentation.Content
 | 
				
			||||||
 | 
					        $List = $false
 | 
				
			||||||
 | 
					        foreach ($Line in $Documentation -Split "`n") {
 | 
				
			||||||
 | 
					            if ($Line -match "^### List of Operating System Codes") {
 | 
				
			||||||
 | 
					                $List = $true
 | 
				
			||||||
 | 
					            } elseif ($Line -match "^###") {
 | 
				
			||||||
 | 
					                $List = $false
 | 
				
			||||||
 | 
					            } elseif ($List -and $Line -cmatch "\| *(WINDOWS_v100_[^| ]+) *\|") {
 | 
				
			||||||
 | 
					                $DocRequestedSignatures += $matches[1]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if ($DocRequestedSignatures.length -lt 32) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot determine signatures to request"
 | 
				
			||||||
 | 
					            Write-Stderr '    Does the document at the URL below still contain a "List of Operating System Codes":'
 | 
				
			||||||
 | 
					            Write-Stderr "    https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # start with the base signatures and add any new ones found in the docs
 | 
				
			||||||
 | 
					        $RequestedSignatures = @(
 | 
				
			||||||
 | 
					            "WINDOWS_v100_TH2_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_TH2_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_RS1_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_RS1_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_RS2_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_RS2_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_RS3_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_RS3_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_RS3_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_RS4_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_RS4_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_RS4_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_RS5_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_RS5_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_RS5_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_19H1_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_19H1_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_19H1_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_VB_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_VB_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_VB_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_CO_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_CO_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_X64_NI_FULL"
 | 
				
			||||||
 | 
					            "WINDOWS_v100_ARM64_NI_FULL"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        foreach ($Signature in $DocRequestedSignatures) {
 | 
				
			||||||
 | 
					            if ($RequestedSignatures -contains $Signature) {
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($Signature.Contains("_SERVER_")) {
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($Signature -eq "WINDOWS_v100_TH1_FULL") {
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($Signature -eq "WINDOWS_v100_X64_TH1_FULL") {
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $RequestedSignatures += $Signature
 | 
				
			||||||
 | 
					            Write-Stdout "New doc signature: $Signature"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $CreateProduct = @{
 | 
				
			||||||
 | 
					            createType = "product"
 | 
				
			||||||
 | 
					            createProduct = @{
 | 
				
			||||||
 | 
					                productName = "winfsp-$Version"
 | 
				
			||||||
 | 
					                testHarness = "attestation"
 | 
				
			||||||
 | 
					                deviceType = "internalExternal"
 | 
				
			||||||
 | 
					                requestedSignatures = $RequestedSignatures
 | 
				
			||||||
 | 
					                # deviceMetaDataIds = $null
 | 
				
			||||||
 | 
					                # firmwareVersion = "0"
 | 
				
			||||||
 | 
					                # isTestSign = $false
 | 
				
			||||||
 | 
					                # isFlightSign = $false
 | 
				
			||||||
 | 
					                # markettingNames = $null
 | 
				
			||||||
 | 
					                # selectedProductTypes = $null
 | 
				
			||||||
 | 
					                # additionalAttributes = $null
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $CreateSubmission = @{
 | 
				
			||||||
 | 
					            createType = "submission"
 | 
				
			||||||
 | 
					            createSubmission = @{
 | 
				
			||||||
 | 
					                name = "winfsp-$Version"
 | 
				
			||||||
 | 
					                type = "initial"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        New-Item "$ProjectRoot\build\VStudio\build\Release\hwapi" -Type Directory -ErrorAction SilentlyContinue >$null
 | 
				
			||||||
 | 
					        ConvertTo-Json $CreateProduct | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json"
 | 
				
			||||||
 | 
					        ConvertTo-Json $CreateSubmission | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json" | Tee-Object -Variable Output
 | 
				
			||||||
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot create product on hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (-not ([string]$Output -match "--- Product: (\d+)")) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot get product id from hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $ProductId = $matches[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json" -productid $ProductId  | Tee-Object -Variable Output
 | 
				
			||||||
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot create submission on hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (-not ([string]$Output -match "---- Submission: (\d+)")) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot get submission id from hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $SubmissionId = $matches[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId" -Value $ProductId
 | 
				
			||||||
 | 
					        Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId" -Value $SubmissionId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Write-Stdout @"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Product submission has been prepared on hardware dashboard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Upload-AssetsToHwapi {
 | 
				
			||||||
 | 
					    Task -ScriptBlock {
 | 
				
			||||||
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
 | 
				
			||||||
 | 
					        $SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Start-Sdcm -upload "$ProjectRoot\build\VStudio\build\Release\driver.cab" -productid $ProductId -submissionid $SubmissionId
 | 
				
			||||||
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot upload driver.cab to hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Start-Sdcm -commit -productid $ProductId -submissionid $SubmissionId
 | 
				
			||||||
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot commit submission to hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Write-Stdout @"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Signable assets have been uploaded to the hardware dashboard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Download-AssetsFromHwapi {
 | 
				
			||||||
 | 
					    Task -ScriptBlock {
 | 
				
			||||||
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
 | 
				
			||||||
 | 
					        $SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Remove-Item -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue
 | 
				
			||||||
 | 
					        Remove-Item -Recurse -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Start-Sdcm -download "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -productid $ProductId -submissionid $SubmissionId
 | 
				
			||||||
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot download signed drivers from hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot download signed drivers from hardware dashboard"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ExpandError = ""
 | 
				
			||||||
 | 
					        Expand-Archive "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -DestinationPath "$ProjectRoot\build\VStudio\build\Release\hwapi" -ErrorVariable ExpandError
 | 
				
			||||||
 | 
					        if ($ExpandError) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot expand signed drivers archive"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot expand signed drivers archive"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Write-Stdout @"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Signable assets have been downloaded and can be used to complete the build.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@
 | 
					"@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -198,16 +455,16 @@ function Build-AssetsPhase2 {
 | 
				
			|||||||
        Check-Assets
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # check signed drivers folder
 | 
					        # check signed drivers folder
 | 
				
			||||||
        if (!(Test-Path ~\Downloads\drivers -ErrorAction SilentlyContinue)) {
 | 
					        if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
 | 
				
			||||||
            Write-Stderr "error: cannot find ~\Downloads\drivers"
 | 
					            Write-Stderr "error: cannot find hwapi\drivers"
 | 
				
			||||||
            exit 1
 | 
					            exit 1
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $SignedPackage = Resolve-Path ~\Downloads\drivers
 | 
					        $SignedPackage = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys"
 | 
					        $VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys"
 | 
				
			||||||
        if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) {
 | 
					        if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) {
 | 
				
			||||||
            Write-Stderr "error: incompatible versions in ~\Downloads\drivers"
 | 
					            Write-Stderr "error: incompatible versions in hwapi\drivers"
 | 
				
			||||||
            exit 1
 | 
					            exit 1
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -231,10 +488,6 @@ function Make-GitHubRelease {
 | 
				
			|||||||
    Task -ScriptBlock {
 | 
					    Task -ScriptBlock {
 | 
				
			||||||
        Check-Assets
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi") -match "\\winfsp-(.+)\.msi") {
 | 
					 | 
				
			||||||
            $Version = $matches[1]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $DownloadColor = "blue"
 | 
					        $DownloadColor = "blue"
 | 
				
			||||||
        $PrereleaseOpt = ""
 | 
					        $PrereleaseOpt = ""
 | 
				
			||||||
        if ($ReleaseInfo.Prerelease) {
 | 
					        if ($ReleaseInfo.Prerelease) {
 | 
				
			||||||
@@ -242,16 +495,34 @@ function Make-GitHubRelease {
 | 
				
			|||||||
            $PrereleaseOpt = "-p"
 | 
					            $PrereleaseOpt = "-p"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $ReleaseNotes = @"
 | 
					        $MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
 | 
				
			||||||
[](https://github.com/billziss-gh/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
 | 
					        $ZipFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip"
 | 
				
			||||||
 | 
					        $MsiName = Split-Path -Leaf $MsiFile
 | 
				
			||||||
 | 
					        $ZipName = Split-Path -Leaf $ZipFile
 | 
				
			||||||
 | 
					        $MsiHash = (Get-FileHash -Algorithm SHA256 $MsiFile).Hash
 | 
				
			||||||
 | 
					        $ZipHash = (Get-FileHash -Algorithm SHA256 $ZipFile).Hash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[VirusTotal Scan Results]()
 | 
					        if ($MsiName -match "winfsp-(.+)\.msi") {
 | 
				
			||||||
 | 
					            $Version = $matches[1]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ReleaseNotes = @"
 | 
				
			||||||
 | 
					[](https://github.com/winfsp/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion)
 | 
					## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion)
 | 
				
			||||||
$($ReleaseInfo.Text -join "`n")
 | 
					$($ReleaseInfo.Text -join "`n")
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					<summary>
 | 
				
			||||||
 | 
					<b>BUILD HASHES (SHA256)</b>
 | 
				
			||||||
 | 
					<p/>
 | 
				
			||||||
 | 
					</summary>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- **``$MsiName``**: $MsiHash
 | 
				
			||||||
 | 
					- **``$ZipName``**: $ZipHash
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
"@
 | 
					"@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gh release create $ReleaseInfo.Tag --draft --title "WinFsp $($ReleaseInfo.ProductVersion)" --notes "$ReleaseNotes" $PrereleaseOpt (Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi") (Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip")
 | 
					        gh release create $ReleaseInfo.Tag --draft --title "WinFsp $($ReleaseInfo.ProductVersion)" --notes "$ReleaseNotes" $PrereleaseOpt $MsiFile $ZipFile
 | 
				
			||||||
        if ($LastExitCode -ne 0) {
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
            Write-Stderr "error: cannot create GitHub release"
 | 
					            Write-Stderr "error: cannot create GitHub release"
 | 
				
			||||||
            exit 1
 | 
					            exit 1
 | 
				
			||||||
@@ -305,12 +576,32 @@ Push the winfsp.sym repository to GitHub.
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Make-NugetRelease {
 | 
				
			||||||
 | 
					    Task -ScriptBlock {
 | 
				
			||||||
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Push-Location "$ProjectRoot\build\VStudio\build\Release"
 | 
				
			||||||
 | 
					        nuget push (Resolve-Path winfsp.net.[0-9]*.nupkg) -Source https://api.nuget.org/v3/index.json
 | 
				
			||||||
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
 | 
					            Write-Stderr "error: cannot push to Nuget"
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Pop-Location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Write-Stdout @"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Nuget release for $($ReleaseInfo.Tag) has been pushed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Make-ChocoRelease {
 | 
					function Make-ChocoRelease {
 | 
				
			||||||
    Task -ScriptBlock {
 | 
					    Task -ScriptBlock {
 | 
				
			||||||
        Check-Assets
 | 
					        Check-Assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Push-Location "$ProjectRoot\build\VStudio\build\Release"
 | 
					        Push-Location "$ProjectRoot\build\VStudio\build\Release"
 | 
				
			||||||
        choco push
 | 
					        choco push (Resolve-Path winfsp.[0-9]*.nupkg)
 | 
				
			||||||
        if ($LastExitCode -ne 0) {
 | 
					        if ($LastExitCode -ne 0) {
 | 
				
			||||||
            Write-Stderr "error: cannot push to Chocolatey"
 | 
					            Write-Stderr "error: cannot push to Chocolatey"
 | 
				
			||||||
            exit 1
 | 
					            exit 1
 | 
				
			||||||
@@ -335,7 +626,12 @@ Check-Prerequisites
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Workflow tasks
 | 
					# Workflow tasks
 | 
				
			||||||
Build-AssetsPhase1
 | 
					Build-AssetsPhase1
 | 
				
			||||||
 | 
					Submit-AssetsToHwapi
 | 
				
			||||||
 | 
					Upload-AssetsToHwapi
 | 
				
			||||||
 | 
					Download-AssetsFromHwapi
 | 
				
			||||||
Build-AssetsPhase2
 | 
					Build-AssetsPhase2
 | 
				
			||||||
Make-GitHubRelease
 | 
					Make-GitHubRelease
 | 
				
			||||||
Upload-Symbols
 | 
					Upload-Symbols
 | 
				
			||||||
 | 
					Make-NugetRelease
 | 
				
			||||||
Make-ChocoRelease
 | 
					Make-ChocoRelease
 | 
				
			||||||
 | 
					Write-Stdout "ALL COMPLETE"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								tools/sxsident.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tools/sxsident.bat
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					@echo off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setlocal
 | 
				
			||||||
 | 
					setlocal EnableDelayedExpansion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set SxsDir=
 | 
				
			||||||
 | 
					set RegKey="HKLM\SOFTWARE\WinFsp"
 | 
				
			||||||
 | 
					set RegVal="SxsDir"
 | 
				
			||||||
 | 
					reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1
 | 
				
			||||||
 | 
					if !ERRORLEVEL! equ 0 (
 | 
				
			||||||
 | 
					    for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do (
 | 
				
			||||||
 | 
					        set SxsDir=%%j
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					if defined SxsDir (
 | 
				
			||||||
 | 
					    set SxsDir=!SxsDir:*SxS\sxs.=!
 | 
				
			||||||
 | 
					    if !SxsDir:~-1!==\ set SxsDir=!SxsDir:~0,-1!
 | 
				
			||||||
 | 
					    echo !SxsDir!
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit /b 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:fail
 | 
				
			||||||
 | 
					exit /b 1
 | 
				
			||||||
							
								
								
									
										124
									
								
								tools/wincred.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								tools/wincred.ps1
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
				
			|||||||
 | 
					Start-Job -ArgumentList $args -ScriptBlock {
 | 
				
			||||||
 | 
					param (
 | 
				
			||||||
 | 
					    [ValidateSet("get", "set", "del")]
 | 
				
			||||||
 | 
					    [string]$Command
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Add-Type -TypeDefinition @"
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					namespace Win32
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class Api
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static String[] CredRead(
 | 
				
			||||||
 | 
					            String TargetName)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            String[] Result = null;
 | 
				
			||||||
 | 
					            IntPtr CredentialPtr;
 | 
				
			||||||
 | 
					            if (CredReadW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0, out CredentialPtr))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                CREDENTIALW Credential = Marshal.PtrToStructure<CREDENTIALW>(CredentialPtr);
 | 
				
			||||||
 | 
					                Result = new String[2]{
 | 
				
			||||||
 | 
					                    Credential.UserName,
 | 
				
			||||||
 | 
					                    Marshal.PtrToStringUni(
 | 
				
			||||||
 | 
					                        Credential.CredentialBlob, (int)Credential.CredentialBlobSize / 2)
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                CredFree(CredentialPtr);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return Result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static Boolean CredWrite(
 | 
				
			||||||
 | 
					            String TargetName,
 | 
				
			||||||
 | 
					            String UserName,
 | 
				
			||||||
 | 
					            String Password)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CREDENTIALW Credential = new CREDENTIALW{
 | 
				
			||||||
 | 
					                Type = 1/*CRED_TYPE_GENERIC*/,
 | 
				
			||||||
 | 
					                Persist = 2/*CRED_PERSIST_LOCAL_MACHINE*/,
 | 
				
			||||||
 | 
					                TargetName = TargetName,
 | 
				
			||||||
 | 
					                UserName = UserName,
 | 
				
			||||||
 | 
					                CredentialBlobSize = (UInt32)Password.Length * 2,
 | 
				
			||||||
 | 
					                CredentialBlob = Marshal.StringToCoTaskMemUni(Password),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            Boolean Result = CredWriteW(ref Credential, 0);
 | 
				
			||||||
 | 
					            Marshal.FreeCoTaskMem(Credential.CredentialBlob);
 | 
				
			||||||
 | 
					            return Result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static Boolean CredDelete(
 | 
				
			||||||
 | 
					            String TargetName)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return CredDeleteW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
 | 
				
			||||||
 | 
					        [return: MarshalAs(UnmanagedType.U1)]
 | 
				
			||||||
 | 
					        private static extern Boolean CredReadW(
 | 
				
			||||||
 | 
					            String TargetName,
 | 
				
			||||||
 | 
					            UInt32 Type,
 | 
				
			||||||
 | 
					            UInt32 Flags,
 | 
				
			||||||
 | 
					            out IntPtr Credential);
 | 
				
			||||||
 | 
					        [DllImport("advapi32.dll")]
 | 
				
			||||||
 | 
					        private static extern void CredFree(
 | 
				
			||||||
 | 
					            IntPtr Buffer);
 | 
				
			||||||
 | 
					        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
 | 
				
			||||||
 | 
					        [return: MarshalAs(UnmanagedType.U1)]
 | 
				
			||||||
 | 
					        private static extern Boolean CredWriteW(
 | 
				
			||||||
 | 
					            ref CREDENTIALW Credential,
 | 
				
			||||||
 | 
					            UInt32 Flags);
 | 
				
			||||||
 | 
					        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
 | 
				
			||||||
 | 
					        [return: MarshalAs(UnmanagedType.U1)]
 | 
				
			||||||
 | 
					        private static extern Boolean CredDeleteW(
 | 
				
			||||||
 | 
					            String TargetName,
 | 
				
			||||||
 | 
					            UInt32 Type,
 | 
				
			||||||
 | 
					            UInt32 Flags);
 | 
				
			||||||
 | 
					        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 | 
				
			||||||
 | 
					        private struct CREDENTIALW
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public UInt32 Flags;
 | 
				
			||||||
 | 
					            public UInt32 Type;
 | 
				
			||||||
 | 
					            public String TargetName;
 | 
				
			||||||
 | 
					            public String Comment;
 | 
				
			||||||
 | 
					            public UInt64 LastWritten;
 | 
				
			||||||
 | 
					            public UInt32 CredentialBlobSize;
 | 
				
			||||||
 | 
					            public IntPtr CredentialBlob;
 | 
				
			||||||
 | 
					            public UInt32 Persist;
 | 
				
			||||||
 | 
					            public UInt32 AttributeCount;
 | 
				
			||||||
 | 
					            public IntPtr Attributes;
 | 
				
			||||||
 | 
					            public String TargetAlias;
 | 
				
			||||||
 | 
					            public String UserName;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					"@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Get-WindowsCredential {
 | 
				
			||||||
 | 
					    param (
 | 
				
			||||||
 | 
					        [Parameter(Mandatory)][string]$TargetName
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    return [Win32.Api]::CredRead($TargetName)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Set-WindowsCredential {
 | 
				
			||||||
 | 
					    param (
 | 
				
			||||||
 | 
					        [Parameter(Mandatory)][string]$TargetName,
 | 
				
			||||||
 | 
					        [Parameter(Mandatory)][string]$UserName,
 | 
				
			||||||
 | 
					        [Parameter(Mandatory)][string]$Password
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    return [Win32.Api]::CredWrite($TargetName, $UserName, $Password)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Delete-WindowsCredential {
 | 
				
			||||||
 | 
					    param (
 | 
				
			||||||
 | 
					        [Parameter(Mandatory)][string]$TargetName
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    return [Win32.Api]::CredDelete($TargetName)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$Function = @{
 | 
				
			||||||
 | 
					    "get" = "Get-WindowsCredential"
 | 
				
			||||||
 | 
					    "set" = "Set-WindowsCredential"
 | 
				
			||||||
 | 
					    "del" = "Delete-WindowsCredential"
 | 
				
			||||||
 | 
					}[$Command]
 | 
				
			||||||
 | 
					& $Function @args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} | Receive-Job -Wait -AutoRemoveJob
 | 
				
			||||||
@@ -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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FspFileSystemStopServiceIfNecessary(FileSystem, 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
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@ enum
 | 
				
			|||||||
    MemfsCaseInsensitive                = 0x80000000,
 | 
					    MemfsCaseInsensitive                = 0x80000000,
 | 
				
			||||||
    MemfsFlushAndPurgeOnCleanup         = 0x40000000,
 | 
					    MemfsFlushAndPurgeOnCleanup         = 0x40000000,
 | 
				
			||||||
    MemfsLegacyUnlinkRename             = 0x20000000,
 | 
					    MemfsLegacyUnlinkRename             = 0x20000000,
 | 
				
			||||||
 | 
					    MemfsNoSlowio                       = 0x10000000,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
 | 
					#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1143,6 +1143,12 @@ exit:
 | 
				
			|||||||
    return Result;
 | 
					    return Result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VOID DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
 | 
				
			||||||
 | 
					    BOOLEAN Normally)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FspFileSystemStopServiceIfNecessary(FileSystem, Normally);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
 | 
					static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    .GetVolumeInfo = GetVolumeInfo,
 | 
					    .GetVolumeInfo = GetVolumeInfo,
 | 
				
			||||||
@@ -1171,6 +1177,7 @@ static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
 | 
				
			|||||||
    .GetStreamInfo = GetStreamInfo,
 | 
					    .GetStreamInfo = GetStreamInfo,
 | 
				
			||||||
    .GetEa = GetEa,
 | 
					    .GetEa = GetEa,
 | 
				
			||||||
    .SetEa = SetEa,
 | 
					    .SetEa = SetEa,
 | 
				
			||||||
 | 
					    .DispatcherStopped = DispatcherStopped,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NTSTATUS PtfsCreate(
 | 
					NTSTATUS PtfsCreate(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@
 | 
				
			|||||||
#define fi_setdirp(fi, dirp)            (fi_setfh(fi, dirp, fi_dirbit))
 | 
					#define fi_setdirp(fi, dirp)            (fi_setfh(fi, dirp, fi_dirbit))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ptfs_impl_fullpath(n)           \
 | 
					#define ptfs_impl_fullpath(n)           \
 | 
				
			||||||
    char full ## n[PATH_MAX];           \
 | 
					    char full ## n[PATH_MAX * 4];       \
 | 
				
			||||||
    if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
 | 
					    if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
 | 
				
			||||||
        return -ENAMETOOLONG;           \
 | 
					        return -ENAMETOOLONG;           \
 | 
				
			||||||
    n = full ## n
 | 
					    n = full ## n
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,15 +129,50 @@ char *realpath(const char *path, char *resolved)
 | 
				
			|||||||
        result = resolved;
 | 
					        result = resolved;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int err = 0;
 | 
					    int err = 0;
 | 
				
			||||||
    DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    WCHAR ResultBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    PWSTR ResultBufBgn = &ResultBuf[6];
 | 
				
			||||||
 | 
					    if (0 == MultiByteToWideChar(CP_UTF8, 0, path, -1, PathBuf, PATH_MAX))
 | 
				
			||||||
 | 
					        err = GetLastError();
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DWORD len = GetFullPathNameW(PathBuf, PATH_MAX - 6, ResultBufBgn, 0);
 | 
				
			||||||
        if (0 == len)
 | 
					        if (0 == len)
 | 
				
			||||||
            err = GetLastError();
 | 
					            err = GetLastError();
 | 
				
			||||||
    else if (PATH_MAX < len)
 | 
					        else if (PATH_MAX - 6 < len)
 | 
				
			||||||
            err = ERROR_INVALID_PARAMETER;
 | 
					            err = ERROR_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (0 == WideCharToMultiByte(CP_UTF8, 0, ResultBufBgn, -1, result, PATH_MAX, 0, 0))
 | 
				
			||||||
 | 
					                err = GetLastError();
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (L'\\' == ResultBufBgn[0] && L'\\' == ResultBufBgn[1])
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ResultBufBgn = ResultBuf;
 | 
				
			||||||
 | 
					                    ResultBufBgn[0] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[1] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[2] = L'?';
 | 
				
			||||||
 | 
					                    ResultBufBgn[3] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[4] = L'U';
 | 
				
			||||||
 | 
					                    ResultBufBgn[5] = L'N';
 | 
				
			||||||
 | 
					                    ResultBufBgn[6] = L'C';
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ResultBufBgn = &ResultBuf[2];
 | 
				
			||||||
 | 
					                    ResultBufBgn[0] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[1] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[2] = L'?';
 | 
				
			||||||
 | 
					                    ResultBufBgn[3] = L'\\';
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (0 == err)
 | 
					    if (0 == err)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        HANDLE h = CreateFileA(result,
 | 
					        HANDLE h = CreateFileW(ResultBufBgn,
 | 
				
			||||||
            FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					            FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
            0,
 | 
					            0,
 | 
				
			||||||
            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -155,13 +190,71 @@ char *realpath(const char *path, char *resolved)
 | 
				
			|||||||
        errno = maperror(err);
 | 
					        errno = maperror(err);
 | 
				
			||||||
        result = 0;
 | 
					        result = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int uncpath(const char *path, WCHAR *buf, int nchar)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PWSTR BufP = 0;
 | 
				
			||||||
 | 
					    if ('\\' == path[0] && '\\' == path[1])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (8 < nchar &&
 | 
				
			||||||
 | 
					            0 < MultiByteToWideChar(CP_UTF8, 0, &path[2], -1, &buf[8], nchar - 8))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            BufP = &buf[8];
 | 
				
			||||||
 | 
					            buf[0] = L'\\';
 | 
				
			||||||
 | 
					            buf[1] = L'\\';
 | 
				
			||||||
 | 
					            buf[2] = L'?';
 | 
				
			||||||
 | 
					            buf[3] = L'\\';
 | 
				
			||||||
 | 
					            buf[4] = L'U';
 | 
				
			||||||
 | 
					            buf[5] = L'N';
 | 
				
			||||||
 | 
					            buf[6] = L'C';
 | 
				
			||||||
 | 
					            buf[7] = L'\\';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (4 < nchar &&
 | 
				
			||||||
 | 
					            0 < MultiByteToWideChar(CP_UTF8, 0, path, -1, &buf[4], nchar - 4))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            BufP = &buf[4];
 | 
				
			||||||
 | 
					            buf[0] = L'\\';
 | 
				
			||||||
 | 
					            buf[1] = L'\\';
 | 
				
			||||||
 | 
					            buf[2] = L'?';
 | 
				
			||||||
 | 
					            buf[3] = L'\\';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (0 == BufP)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (0 < nchar)
 | 
				
			||||||
 | 
					            buf[0] = 0;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PWSTR P = BufP;
 | 
				
			||||||
 | 
					    while (*BufP)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (L'/' == *BufP || L'\\' == *BufP)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (L'/' == BufP[1] || L'\\' == BufP[1])
 | 
				
			||||||
 | 
					                BufP++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (L'/' == *BufP)
 | 
				
			||||||
 | 
					            *P = L'\\';
 | 
				
			||||||
 | 
					        else if (P != BufP)
 | 
				
			||||||
 | 
					            *P = *BufP;
 | 
				
			||||||
 | 
					        BufP++;
 | 
				
			||||||
 | 
					        P++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (P != BufP)
 | 
				
			||||||
 | 
					        *P = 0;
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int statvfs(const char *path, struct fuse_statvfs *stbuf)
 | 
					int statvfs(const char *path, struct fuse_statvfs *stbuf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char root[PATH_MAX];
 | 
					    WCHAR root[PATH_MAX];
 | 
				
			||||||
    DWORD
 | 
					    DWORD
 | 
				
			||||||
        VolumeSerialNumber,
 | 
					        VolumeSerialNumber,
 | 
				
			||||||
        MaxComponentLength,
 | 
					        MaxComponentLength,
 | 
				
			||||||
@@ -170,9 +263,11 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
 | 
				
			|||||||
        NumberOfFreeClusters,
 | 
					        NumberOfFreeClusters,
 | 
				
			||||||
        TotalNumberOfClusters;
 | 
					        TotalNumberOfClusters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!GetVolumePathNameA(path, root, PATH_MAX) ||
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
        !GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
        !GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector,
 | 
					    if (!GetVolumePathNameW(PathBuf, root, PATH_MAX) ||
 | 
				
			||||||
 | 
					        !GetVolumeInformationW(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
 | 
				
			||||||
 | 
					        !GetDiskFreeSpaceW(root, &SectorsPerCluster, &BytesPerSector,
 | 
				
			||||||
            &NumberOfFreeClusters, &TotalNumberOfClusters))
 | 
					            &NumberOfFreeClusters, &TotalNumberOfClusters))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
@@ -201,7 +296,9 @@ int open(const char *path, int oflag, ...)
 | 
				
			|||||||
        CREATE_NEW :
 | 
					        CREATE_NEW :
 | 
				
			||||||
        cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
 | 
					        cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0/* default security */,
 | 
					        0/* default security */,
 | 
				
			||||||
        CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -325,7 +422,9 @@ int close(int fd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int getpath(const char *path, char *buf, size_t size)
 | 
					int getpath(const char *path, char *buf, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -341,7 +440,9 @@ int getpath(const char *path, char *buf, size_t size)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int lstat(const char *path, struct fuse_stat *stbuf)
 | 
					int lstat(const char *path, struct fuse_stat *stbuf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -375,7 +476,9 @@ int lchflags(const char *path, uint32_t flags)
 | 
				
			|||||||
    if (0 == FileAttributes)
 | 
					    if (0 == FileAttributes)
 | 
				
			||||||
        FileAttributes = FILE_ATTRIBUTE_NORMAL;
 | 
					        FileAttributes = FILE_ATTRIBUTE_NORMAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!SetFileAttributesA(path, FileAttributes))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!SetFileAttributesW(PathBuf, FileAttributes))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -384,7 +487,9 @@ int lchflags(const char *path, uint32_t flags)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int truncate(const char *path, fuse_off_t size)
 | 
					int truncate(const char *path, fuse_off_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -418,7 +523,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
 | 
				
			|||||||
    /* ignore dirfd and assume that it is always AT_FDCWD */
 | 
					    /* ignore dirfd and assume that it is always AT_FDCWD */
 | 
				
			||||||
    /* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
 | 
					    /* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -448,7 +555,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int setcrtime(const char *path, const struct fuse_timespec *tv)
 | 
					int setcrtime(const char *path, const struct fuse_timespec *tv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -468,7 +577,9 @@ int setcrtime(const char *path, const struct fuse_timespec *tv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int unlink(const char *path)
 | 
					int unlink(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!DeleteFileA(path))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!DeleteFileW(PathBuf))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -476,7 +587,11 @@ int unlink(const char *path)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int rename(const char *oldpath, const char *newpath)
 | 
					int rename(const char *oldpath, const char *newpath)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
 | 
					    WCHAR OldPathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    WCHAR NewPathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(oldpath, OldPathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    uncpath(newpath, NewPathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!MoveFileExW(OldPathBuf, NewPathBuf, MOVEFILE_REPLACE_EXISTING))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -484,7 +599,9 @@ int rename(const char *oldpath, const char *newpath)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
					static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -519,7 +636,9 @@ static int lgetea(const char *path,
 | 
				
			|||||||
    PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
 | 
					    PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
 | 
				
			||||||
    PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
					    PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -711,7 +830,9 @@ int lremovexattr(const char *path, const char *name)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mkdir(const char *path, fuse_mode_t mode)
 | 
					int mkdir(const char *path, fuse_mode_t mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!CreateDirectoryA(path, 0/* default security */))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!CreateDirectoryW(PathBuf, 0/* default security */))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -719,7 +840,9 @@ int mkdir(const char *path, fuse_mode_t mode)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int rmdir(const char *path)
 | 
					int rmdir(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!RemoveDirectoryA(path))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!RemoveDirectoryW(PathBuf))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -727,7 +850,9 @@ int rmdir(const char *path)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DIR *opendir(const char *path)
 | 
					DIR *opendir(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -772,18 +897,20 @@ void rewinddir(DIR *dirp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct dirent *readdir(DIR *dirp)
 | 
					struct dirent *readdir(DIR *dirp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    WIN32_FIND_DATAA FindData;
 | 
					    WIN32_FIND_DATAW FindData;
 | 
				
			||||||
    struct fuse_stat *stbuf = &dirp->de.d_stat;
 | 
					    struct fuse_stat *stbuf = &dirp->de.d_stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
					    if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        dirp->fh = FindFirstFileA(dirp->path, &FindData);
 | 
					        WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					        uncpath(dirp->path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					        dirp->fh = FindFirstFileW(PathBuf, &FindData);
 | 
				
			||||||
        if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
					        if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
				
			||||||
            return error0();
 | 
					            return error0();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (!FindNextFileA(dirp->fh, &FindData))
 | 
					        if (!FindNextFileW(dirp->fh, &FindData))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ERROR_NO_MORE_FILES == GetLastError())
 | 
					            if (ERROR_NO_MORE_FILES == GetLastError())
 | 
				
			||||||
                return 0;
 | 
					                return 0;
 | 
				
			||||||
@@ -804,7 +931,7 @@ struct dirent *readdir(DIR *dirp)
 | 
				
			|||||||
    stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
 | 
					    stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strcpy(dirp->de.d_name, FindData.cFileName);
 | 
					    WideCharToMultiByte(CP_UTF8, 0, FindData.cFileName, -1, dirp->de.d_name, 255 * 4, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return &dirp->de;
 | 
					    return &dirp->de;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ typedef struct _DIR DIR;
 | 
				
			|||||||
struct dirent
 | 
					struct dirent
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct fuse_stat d_stat;
 | 
					    struct fuse_stat d_stat;
 | 
				
			||||||
    char d_name[255];
 | 
					    char d_name[255 * 4];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *realpath(const char *path, char *resolved);
 | 
					char *realpath(const char *path, char *resolved);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@
 | 
				
			|||||||
#define fi_setdirp(fi, dirp)            (fi_setfh(fi, dirp, fi_dirbit))
 | 
					#define fi_setdirp(fi, dirp)            (fi_setfh(fi, dirp, fi_dirbit))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ptfs_impl_fullpath(n)           \
 | 
					#define ptfs_impl_fullpath(n)           \
 | 
				
			||||||
    char full ## n[PATH_MAX];           \
 | 
					    char full ## n[PATH_MAX * 4];           \
 | 
				
			||||||
    if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
 | 
					    if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
 | 
				
			||||||
        return -ENAMETOOLONG;           \
 | 
					        return -ENAMETOOLONG;           \
 | 
				
			||||||
    n = full ## n
 | 
					    n = full ## n
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,15 +129,50 @@ char *realpath(const char *path, char *resolved)
 | 
				
			|||||||
        result = resolved;
 | 
					        result = resolved;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int err = 0;
 | 
					    int err = 0;
 | 
				
			||||||
    DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    WCHAR ResultBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    PWSTR ResultBufBgn = &ResultBuf[6];
 | 
				
			||||||
 | 
					    if (0 == MultiByteToWideChar(CP_UTF8, 0, path, -1, PathBuf, PATH_MAX))
 | 
				
			||||||
 | 
					        err = GetLastError();
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DWORD len = GetFullPathNameW(PathBuf, PATH_MAX - 6, ResultBufBgn, 0);
 | 
				
			||||||
        if (0 == len)
 | 
					        if (0 == len)
 | 
				
			||||||
            err = GetLastError();
 | 
					            err = GetLastError();
 | 
				
			||||||
    else if (PATH_MAX < len)
 | 
					        else if (PATH_MAX - 6 < len)
 | 
				
			||||||
            err = ERROR_INVALID_PARAMETER;
 | 
					            err = ERROR_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (0 == WideCharToMultiByte(CP_UTF8, 0, ResultBufBgn, -1, result, PATH_MAX, 0, 0))
 | 
				
			||||||
 | 
					                err = GetLastError();
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (L'\\' == ResultBufBgn[0] && L'\\' == ResultBufBgn[1])
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ResultBufBgn = ResultBuf;
 | 
				
			||||||
 | 
					                    ResultBufBgn[0] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[1] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[2] = L'?';
 | 
				
			||||||
 | 
					                    ResultBufBgn[3] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[4] = L'U';
 | 
				
			||||||
 | 
					                    ResultBufBgn[5] = L'N';
 | 
				
			||||||
 | 
					                    ResultBufBgn[6] = L'C';
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ResultBufBgn = &ResultBuf[2];
 | 
				
			||||||
 | 
					                    ResultBufBgn[0] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[1] = L'\\';
 | 
				
			||||||
 | 
					                    ResultBufBgn[2] = L'?';
 | 
				
			||||||
 | 
					                    ResultBufBgn[3] = L'\\';
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (0 == err)
 | 
					    if (0 == err)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        HANDLE h = CreateFileA(result,
 | 
					        HANDLE h = CreateFileW(ResultBufBgn,
 | 
				
			||||||
            FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					            FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
            0,
 | 
					            0,
 | 
				
			||||||
            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -155,13 +190,71 @@ char *realpath(const char *path, char *resolved)
 | 
				
			|||||||
        errno = maperror(err);
 | 
					        errno = maperror(err);
 | 
				
			||||||
        result = 0;
 | 
					        result = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int uncpath(const char *path, WCHAR *buf, int nchar)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PWSTR BufP = 0;
 | 
				
			||||||
 | 
					    if ('\\' == path[0] && '\\' == path[1])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (8 < nchar &&
 | 
				
			||||||
 | 
					            0 < MultiByteToWideChar(CP_UTF8, 0, &path[2], -1, &buf[8], nchar - 8))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            BufP = &buf[8];
 | 
				
			||||||
 | 
					            buf[0] = L'\\';
 | 
				
			||||||
 | 
					            buf[1] = L'\\';
 | 
				
			||||||
 | 
					            buf[2] = L'?';
 | 
				
			||||||
 | 
					            buf[3] = L'\\';
 | 
				
			||||||
 | 
					            buf[4] = L'U';
 | 
				
			||||||
 | 
					            buf[5] = L'N';
 | 
				
			||||||
 | 
					            buf[6] = L'C';
 | 
				
			||||||
 | 
					            buf[7] = L'\\';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (4 < nchar &&
 | 
				
			||||||
 | 
					            0 < MultiByteToWideChar(CP_UTF8, 0, path, -1, &buf[4], nchar - 4))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            BufP = &buf[4];
 | 
				
			||||||
 | 
					            buf[0] = L'\\';
 | 
				
			||||||
 | 
					            buf[1] = L'\\';
 | 
				
			||||||
 | 
					            buf[2] = L'?';
 | 
				
			||||||
 | 
					            buf[3] = L'\\';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (0 == BufP)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (0 < nchar)
 | 
				
			||||||
 | 
					            buf[0] = 0;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PWSTR P = BufP;
 | 
				
			||||||
 | 
					    while (*BufP)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (L'/' == *BufP || L'\\' == *BufP)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (L'/' == BufP[1] || L'\\' == BufP[1])
 | 
				
			||||||
 | 
					                BufP++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (L'/' == *BufP)
 | 
				
			||||||
 | 
					            *P = L'\\';
 | 
				
			||||||
 | 
					        else if (P != BufP)
 | 
				
			||||||
 | 
					            *P = *BufP;
 | 
				
			||||||
 | 
					        BufP++;
 | 
				
			||||||
 | 
					        P++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (P != BufP)
 | 
				
			||||||
 | 
					        *P = 0;
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int statvfs(const char *path, struct fuse_statvfs *stbuf)
 | 
					int statvfs(const char *path, struct fuse_statvfs *stbuf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char root[PATH_MAX];
 | 
					    WCHAR root[PATH_MAX];
 | 
				
			||||||
    DWORD
 | 
					    DWORD
 | 
				
			||||||
        VolumeSerialNumber,
 | 
					        VolumeSerialNumber,
 | 
				
			||||||
        MaxComponentLength,
 | 
					        MaxComponentLength,
 | 
				
			||||||
@@ -170,9 +263,11 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
 | 
				
			|||||||
        NumberOfFreeClusters,
 | 
					        NumberOfFreeClusters,
 | 
				
			||||||
        TotalNumberOfClusters;
 | 
					        TotalNumberOfClusters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!GetVolumePathNameA(path, root, PATH_MAX) ||
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
        !GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
        !GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector,
 | 
					    if (!GetVolumePathNameW(PathBuf, root, PATH_MAX) ||
 | 
				
			||||||
 | 
					        !GetVolumeInformationW(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
 | 
				
			||||||
 | 
					        !GetDiskFreeSpaceW(root, &SectorsPerCluster, &BytesPerSector,
 | 
				
			||||||
            &NumberOfFreeClusters, &TotalNumberOfClusters))
 | 
					            &NumberOfFreeClusters, &TotalNumberOfClusters))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
@@ -201,7 +296,9 @@ int open(const char *path, int oflag, ...)
 | 
				
			|||||||
        CREATE_NEW :
 | 
					        CREATE_NEW :
 | 
				
			||||||
        cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
 | 
					        cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0/* default security */,
 | 
					        0/* default security */,
 | 
				
			||||||
        CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -305,7 +402,9 @@ int close(int fd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int lstat(const char *path, struct fuse_stat *stbuf)
 | 
					int lstat(const char *path, struct fuse_stat *stbuf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -339,7 +438,9 @@ int lchflags(const char *path, uint32_t flags)
 | 
				
			|||||||
    if (0 == FileAttributes)
 | 
					    if (0 == FileAttributes)
 | 
				
			||||||
        FileAttributes = FILE_ATTRIBUTE_NORMAL;
 | 
					        FileAttributes = FILE_ATTRIBUTE_NORMAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!SetFileAttributesA(path, FileAttributes))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!SetFileAttributesW(PathBuf, FileAttributes))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -348,7 +449,9 @@ int lchflags(const char *path, uint32_t flags)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int truncate(const char *path, fuse_off_t size)
 | 
					int truncate(const char *path, fuse_off_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -382,7 +485,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
 | 
				
			|||||||
    /* ignore dirfd and assume that it is always AT_FDCWD */
 | 
					    /* ignore dirfd and assume that it is always AT_FDCWD */
 | 
				
			||||||
    /* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
 | 
					    /* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -412,7 +517,9 @@ int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2],
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int setcrtime(const char *path, const struct fuse_timespec *tv)
 | 
					int setcrtime(const char *path, const struct fuse_timespec *tv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -432,7 +539,9 @@ int setcrtime(const char *path, const struct fuse_timespec *tv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int unlink(const char *path)
 | 
					int unlink(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!DeleteFileA(path))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!DeleteFileW(PathBuf))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -440,7 +549,11 @@ int unlink(const char *path)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int rename(const char *oldpath, const char *newpath)
 | 
					int rename(const char *oldpath, const char *newpath)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
 | 
					    WCHAR OldPathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    WCHAR NewPathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(oldpath, OldPathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    uncpath(newpath, NewPathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!MoveFileExW(OldPathBuf, NewPathBuf, MOVEFILE_REPLACE_EXISTING))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -448,7 +561,9 @@ int rename(const char *oldpath, const char *newpath)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
					static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -483,7 +598,9 @@ static int lgetea(const char *path,
 | 
				
			|||||||
    PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
 | 
					    PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
 | 
				
			||||||
    PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
					    PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -675,7 +792,9 @@ int lremovexattr(const char *path, const char *name)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mkdir(const char *path, fuse_mode_t mode)
 | 
					int mkdir(const char *path, fuse_mode_t mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!CreateDirectoryA(path, 0/* default security */))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!CreateDirectoryW(PathBuf, 0/* default security */))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -683,7 +802,9 @@ int mkdir(const char *path, fuse_mode_t mode)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int rmdir(const char *path)
 | 
					int rmdir(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!RemoveDirectoryA(path))
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    if (!RemoveDirectoryW(PathBuf))
 | 
				
			||||||
        return error();
 | 
					        return error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -691,7 +812,9 @@ int rmdir(const char *path)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DIR *opendir(const char *path)
 | 
					DIR *opendir(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HANDLE h = CreateFileA(path,
 | 
					    WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					    uncpath(path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					    HANDLE h = CreateFileW(PathBuf,
 | 
				
			||||||
        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
					        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
				
			||||||
@@ -736,18 +859,20 @@ void rewinddir(DIR *dirp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct dirent *readdir(DIR *dirp)
 | 
					struct dirent *readdir(DIR *dirp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    WIN32_FIND_DATAA FindData;
 | 
					    WIN32_FIND_DATAW FindData;
 | 
				
			||||||
    struct fuse_stat *stbuf = &dirp->de.d_stat;
 | 
					    struct fuse_stat *stbuf = &dirp->de.d_stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
					    if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        dirp->fh = FindFirstFileA(dirp->path, &FindData);
 | 
					        WCHAR PathBuf[PATH_MAX];
 | 
				
			||||||
 | 
					        uncpath(dirp->path, PathBuf, PATH_MAX);
 | 
				
			||||||
 | 
					        dirp->fh = FindFirstFileW(PathBuf, &FindData);
 | 
				
			||||||
        if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
					        if (INVALID_HANDLE_VALUE == dirp->fh)
 | 
				
			||||||
            return error0();
 | 
					            return error0();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (!FindNextFileA(dirp->fh, &FindData))
 | 
					        if (!FindNextFileW(dirp->fh, &FindData))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ERROR_NO_MORE_FILES == GetLastError())
 | 
					            if (ERROR_NO_MORE_FILES == GetLastError())
 | 
				
			||||||
                return 0;
 | 
					                return 0;
 | 
				
			||||||
@@ -768,7 +893,7 @@ struct dirent *readdir(DIR *dirp)
 | 
				
			|||||||
    stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
 | 
					    stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strcpy(dirp->de.d_name, FindData.cFileName);
 | 
					    WideCharToMultiByte(CP_UTF8, 0, FindData.cFileName, -1, dirp->de.d_name, 255 * 4, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return &dirp->de;
 | 
					    return &dirp->de;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ typedef struct _DIR DIR;
 | 
				
			|||||||
struct dirent
 | 
					struct dirent
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct fuse_stat d_stat;
 | 
					    struct fuse_stat d_stat;
 | 
				
			||||||
    char d_name[255];
 | 
					    char d_name[255 * 4];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *realpath(const char *path, char *resolved);
 | 
					char *realpath(const char *path, char *resolved);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1287,6 +1287,38 @@ void create_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
 | 
				
			|||||||
    ASSERT(INVALID_HANDLE_VALUE == Handle);
 | 
					    ASSERT(INVALID_HANDLE_VALUE == Handle);
 | 
				
			||||||
    ASSERT(ERROR_INVALID_NAME == GetLastError());
 | 
					    ASSERT(ERROR_INVALID_NAME == GetLastError());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
 | 
				
			||||||
 | 
					        *P = (P - FilePathBgn) % 10 + 0x3041;
 | 
				
			||||||
 | 
					    *P = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(FilePath,
 | 
				
			||||||
 | 
					        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | 
				
			||||||
 | 
					        CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | 
				
			||||||
 | 
					    ASSERT(INVALID_HANDLE_VALUE != Handle);
 | 
				
			||||||
 | 
					    Success = CloseHandle(Handle);
 | 
				
			||||||
 | 
					    ASSERT(Success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
 | 
				
			||||||
 | 
					        *P = (P - FilePathBgn) % 10 + 0x3041;
 | 
				
			||||||
 | 
					    *P = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(FilePath,
 | 
				
			||||||
 | 
					        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | 
				
			||||||
 | 
					        CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | 
				
			||||||
 | 
					    ASSERT(INVALID_HANDLE_VALUE != Handle);
 | 
				
			||||||
 | 
					    Success = CloseHandle(Handle);
 | 
				
			||||||
 | 
					    ASSERT(Success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
 | 
				
			||||||
 | 
					        *P = (P - FilePathBgn) % 10 + 0x3041;
 | 
				
			||||||
 | 
					    *P = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(FilePath,
 | 
				
			||||||
 | 
					        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | 
				
			||||||
 | 
					        CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | 
				
			||||||
 | 
					    ASSERT(INVALID_HANDLE_VALUE == Handle);
 | 
				
			||||||
 | 
					    ASSERT(ERROR_INVALID_NAME == GetLastError());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memfs_stop(memfs);
 | 
					    memfs_stop(memfs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,52 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "winfsp-tests.h"
 | 
					#include "winfsp-tests.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _FILE_FULL_DIR_INFORMATION
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ULONG NextEntryOffset;
 | 
				
			||||||
 | 
					    ULONG FileIndex;
 | 
				
			||||||
 | 
					    LARGE_INTEGER CreationTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER LastAccessTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER LastWriteTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER ChangeTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER EndOfFile;
 | 
				
			||||||
 | 
					    LARGE_INTEGER AllocationSize;
 | 
				
			||||||
 | 
					    ULONG FileAttributes;
 | 
				
			||||||
 | 
					    ULONG FileNameLength;
 | 
				
			||||||
 | 
					    ULONG EaSize;
 | 
				
			||||||
 | 
					    WCHAR FileName[1];
 | 
				
			||||||
 | 
					} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _FILE_DIRECTORY_INFORMATION
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ULONG NextEntryOffset;
 | 
				
			||||||
 | 
					    ULONG FileIndex;
 | 
				
			||||||
 | 
					    LARGE_INTEGER CreationTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER LastAccessTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER LastWriteTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER ChangeTime;
 | 
				
			||||||
 | 
					    LARGE_INTEGER EndOfFile;
 | 
				
			||||||
 | 
					    LARGE_INTEGER AllocationSize;
 | 
				
			||||||
 | 
					    ULONG FileAttributes;
 | 
				
			||||||
 | 
					    ULONG FileNameLength;
 | 
				
			||||||
 | 
					    WCHAR FileName[1];
 | 
				
			||||||
 | 
					} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NTSTATUS
 | 
				
			||||||
 | 
					NTAPI
 | 
				
			||||||
 | 
					NtQueryDirectoryFile (
 | 
				
			||||||
 | 
					    HANDLE FileHandle,
 | 
				
			||||||
 | 
					    HANDLE Event,
 | 
				
			||||||
 | 
					    PIO_APC_ROUTINE ApcRoutine,
 | 
				
			||||||
 | 
					    PVOID ApcContext,
 | 
				
			||||||
 | 
					    PIO_STATUS_BLOCK IoStatusBlock,
 | 
				
			||||||
 | 
					    PVOID FileInformation,
 | 
				
			||||||
 | 
					    ULONG Length,
 | 
				
			||||||
 | 
					    FILE_INFORMATION_CLASS FileInformationClass,
 | 
				
			||||||
 | 
					    BOOLEAN ReturnSingleEntry,
 | 
				
			||||||
 | 
					    PUNICODE_STRING FileName,
 | 
				
			||||||
 | 
					    BOOLEAN RestartScan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
 | 
					static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
					    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
				
			||||||
@@ -269,6 +315,212 @@ void querydir_test(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline size_t hash_chars(const wchar_t *s, size_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* djb2: see http://www.cse.yorku.ca/~oz/hash.html */
 | 
				
			||||||
 | 
					    size_t h = 5381;
 | 
				
			||||||
 | 
					    for (const wchar_t *t = s + length; t > s; ++s)
 | 
				
			||||||
 | 
					        h = 33 * h + *s;
 | 
				
			||||||
 | 
					    return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static NTSTATUS querydir_nodup_dotest_thread_loop(void *FilePath)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NTSTATUS Result;
 | 
				
			||||||
 | 
					    void *Buffer = 0;
 | 
				
			||||||
 | 
					    HANDLE Handle = INVALID_HANDLE_VALUE;
 | 
				
			||||||
 | 
					    IO_STATUS_BLOCK IoStatus;
 | 
				
			||||||
 | 
					    size_t hash[64], hash_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Buffer = malloc(4096);
 | 
				
			||||||
 | 
					    if (0 == Buffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = STATUS_INSUFFICIENT_RESOURCES;
 | 
				
			||||||
 | 
					        goto exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(
 | 
				
			||||||
 | 
					        FilePath,
 | 
				
			||||||
 | 
					        FILE_LIST_DIRECTORY,
 | 
				
			||||||
 | 
					        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
 | 
					        0,
 | 
				
			||||||
 | 
					        OPEN_EXISTING,
 | 
				
			||||||
 | 
					        FILE_FLAG_BACKUP_SEMANTICS,
 | 
				
			||||||
 | 
					        0);
 | 
				
			||||||
 | 
					    if (INVALID_HANDLE_VALUE == Handle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = FspNtStatusFromWin32(GetLastError());
 | 
				
			||||||
 | 
					        goto exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = NtQueryDirectoryFile(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            0, 0, 0,
 | 
				
			||||||
 | 
					            &IoStatus,
 | 
				
			||||||
 | 
					            Buffer,
 | 
				
			||||||
 | 
					            4096,
 | 
				
			||||||
 | 
					            2/*FileFullDirectoryInformation*/,
 | 
				
			||||||
 | 
					            FALSE,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            FALSE);
 | 
				
			||||||
 | 
					        if (STATUS_NO_MORE_FILES == Result)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        if (!NT_SUCCESS(Result))
 | 
				
			||||||
 | 
					            goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (FILE_FULL_DIR_INFORMATION *DirInfo = Buffer;;
 | 
				
			||||||
 | 
					            DirInfo = (PVOID)((PUINT8)DirInfo + DirInfo->NextEntryOffset))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            size_t h = hash_chars(DirInfo->FileName, DirInfo->FileNameLength / sizeof(WCHAR));
 | 
				
			||||||
 | 
					            for (size_t i = 0; hash_count > i; i++)
 | 
				
			||||||
 | 
					                if (hash[i] == h)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    WCHAR FileName[256];
 | 
				
			||||||
 | 
					                    memcpy(FileName, DirInfo->FileName, DirInfo->FileNameLength);
 | 
				
			||||||
 | 
					                    FileName[DirInfo->FileNameLength / sizeof(WCHAR)] = L'\0';
 | 
				
			||||||
 | 
					                    FspDebugLog(__FUNCTION__ ": duplicate \"%S\"\n", FileName);
 | 
				
			||||||
 | 
					                    Result = STATUS_UNSUCCESSFUL;
 | 
				
			||||||
 | 
					                    goto exit;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            if (sizeof hash / sizeof hash[0] > hash_count)
 | 
				
			||||||
 | 
					                hash[hash_count++] = h;
 | 
				
			||||||
 | 
					            if (0 == DirInfo->NextEntryOffset)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Result = STATUS_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
					    if (INVALID_HANDLE_VALUE != Handle)
 | 
				
			||||||
 | 
					        CloseHandle(Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(Buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static unsigned __stdcall querydir_nodup_dotest_thread(void *FilePath)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NTSTATUS Result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; 5000 > i; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = querydir_nodup_dotest_thread_loop(FilePath);
 | 
				
			||||||
 | 
					        if (!NT_SUCCESS(Result))
 | 
				
			||||||
 | 
					            goto exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Result = STATUS_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
					    return Result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void querydir_nodup_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static WCHAR *FileNames[] =
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        L"Extensions.cs",
 | 
				
			||||||
 | 
					        L"JsonSchema.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaBuilder.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaConstants.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaException.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaGenerator.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaModel.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaModelBuilder.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaNode.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaNodeCollection.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaResolver.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaType.cs",
 | 
				
			||||||
 | 
					        L"JsonSchemaWriter.cs",
 | 
				
			||||||
 | 
					        L"UndefinedSchemaIdHandling.cs",
 | 
				
			||||||
 | 
					        L"ValidationEventArgs.cs",
 | 
				
			||||||
 | 
					        L"ValidationEventHandler.cs",
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    HANDLE Handle;
 | 
				
			||||||
 | 
					    BOOL Success;
 | 
				
			||||||
 | 
					    WCHAR FilePath[MAX_PATH];
 | 
				
			||||||
 | 
					    HANDLE Threads[2];
 | 
				
			||||||
 | 
					    DWORD ExitCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
 | 
				
			||||||
 | 
					        Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
 | 
				
			||||||
 | 
					    Success = CreateDirectoryW(FilePath, 0);
 | 
				
			||||||
 | 
					    ASSERT(Success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; sizeof FileNames / sizeof FileNames[0] > i; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\%s",
 | 
				
			||||||
 | 
					            Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), FileNames[i]);
 | 
				
			||||||
 | 
					        Handle = CreateFileW(FilePath, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 | 
				
			||||||
 | 
					        ASSERT(INVALID_HANDLE_VALUE != Handle);
 | 
				
			||||||
 | 
					        Success = CloseHandle(Handle);
 | 
				
			||||||
 | 
					        ASSERT(Success);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
 | 
				
			||||||
 | 
					        Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
 | 
				
			||||||
 | 
					    for (size_t i = 0; sizeof Threads / sizeof Threads[0] > i; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Threads[i] = (HANDLE)_beginthreadex(0, 0, querydir_nodup_dotest_thread, FilePath, 0, 0);
 | 
				
			||||||
 | 
					        ASSERT(0 != Threads[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (size_t i = 0; sizeof Threads / sizeof Threads[0] > i; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        WaitForSingleObject(Threads[i], INFINITE);
 | 
				
			||||||
 | 
					        GetExitCodeThread(Threads[i], &ExitCode);
 | 
				
			||||||
 | 
					        CloseHandle(Threads[i]);
 | 
				
			||||||
 | 
					        ASSERT(0 == ExitCode);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; sizeof FileNames / sizeof FileNames[0] > i; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\%s",
 | 
				
			||||||
 | 
					            Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), FileNames[i]);
 | 
				
			||||||
 | 
					        Success = DeleteFileW(FilePath);
 | 
				
			||||||
 | 
					        ASSERT(Success);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
 | 
				
			||||||
 | 
					        Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
 | 
				
			||||||
 | 
					    Success = RemoveDirectoryW(FilePath);
 | 
				
			||||||
 | 
					    ASSERT(Success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memfs_stop(memfs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void querydir_nodup_test(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Test GitHub issue #475. Credit for the investigation and reproduction
 | 
				
			||||||
 | 
					     * of this issue goes to GitHub user @hach-que.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (NtfsTests)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        WCHAR DirBuf[MAX_PATH];
 | 
				
			||||||
 | 
					        GetTestDirectory(DirBuf);
 | 
				
			||||||
 | 
					        querydir_nodup_dotest(-1, DirBuf, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (WinFspDiskTests)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        querydir_nodup_dotest(MemfsDisk | MemfsNoSlowio, 0, 0);
 | 
				
			||||||
 | 
					        querydir_nodup_dotest(MemfsDisk | MemfsNoSlowio, 0, 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    if (WinFspNetTests)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        querydir_nodup_dotest(MemfsNet | MemfsNoSlowio, L"\\\\memfs\\share", 0);
 | 
				
			||||||
 | 
					        querydir_nodup_dotest(MemfsNet | MemfsNoSlowio, L"\\\\memfs\\share", 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
 | 
					static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
					    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
				
			||||||
@@ -368,36 +620,6 @@ void querydir_expire_cache_test(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _FILE_DIRECTORY_INFORMATION {
 | 
					 | 
				
			||||||
    ULONG NextEntryOffset;
 | 
					 | 
				
			||||||
    ULONG FileIndex;
 | 
					 | 
				
			||||||
    LARGE_INTEGER CreationTime;
 | 
					 | 
				
			||||||
    LARGE_INTEGER LastAccessTime;
 | 
					 | 
				
			||||||
    LARGE_INTEGER LastWriteTime;
 | 
					 | 
				
			||||||
    LARGE_INTEGER ChangeTime;
 | 
					 | 
				
			||||||
    LARGE_INTEGER EndOfFile;
 | 
					 | 
				
			||||||
    LARGE_INTEGER AllocationSize;
 | 
					 | 
				
			||||||
    ULONG FileAttributes;
 | 
					 | 
				
			||||||
    ULONG FileNameLength;
 | 
					 | 
				
			||||||
    WCHAR FileName[1];
 | 
					 | 
				
			||||||
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
NTSTATUS
 | 
					 | 
				
			||||||
NTAPI
 | 
					 | 
				
			||||||
NtQueryDirectoryFile (
 | 
					 | 
				
			||||||
    _In_ HANDLE FileHandle,
 | 
					 | 
				
			||||||
    _In_opt_ HANDLE Event,
 | 
					 | 
				
			||||||
    _In_opt_ PIO_APC_ROUTINE ApcRoutine,
 | 
					 | 
				
			||||||
    _In_opt_ PVOID ApcContext,
 | 
					 | 
				
			||||||
    _Out_ PIO_STATUS_BLOCK IoStatusBlock,
 | 
					 | 
				
			||||||
    _Out_writes_bytes_(Length) PVOID FileInformation,
 | 
					 | 
				
			||||||
    _In_ ULONG Length,
 | 
					 | 
				
			||||||
    _In_ FILE_INFORMATION_CLASS FileInformationClass,
 | 
					 | 
				
			||||||
    _In_ BOOLEAN ReturnSingleEntry,
 | 
					 | 
				
			||||||
    _In_opt_ PUNICODE_STRING FileName,
 | 
					 | 
				
			||||||
    _In_ BOOLEAN RestartScan
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void querydir_buffer_overflow_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
 | 
					static void querydir_buffer_overflow_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
					    void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | 
				
			||||||
@@ -576,6 +798,40 @@ static void querydir_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
 | 
				
			|||||||
    ASSERT(INVALID_HANDLE_VALUE == Handle);
 | 
					    ASSERT(INVALID_HANDLE_VALUE == Handle);
 | 
				
			||||||
    ASSERT(ERROR_INVALID_NAME == GetLastError());
 | 
					    ASSERT(ERROR_INVALID_NAME == GetLastError());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
 | 
				
			||||||
 | 
					        *P = (P - FilePathBgn) % 10 + 0x3041;
 | 
				
			||||||
 | 
					    *P = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(FilePath,
 | 
				
			||||||
 | 
					        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | 
				
			||||||
 | 
					        CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | 
				
			||||||
 | 
					    ASSERT(INVALID_HANDLE_VALUE != Handle);
 | 
				
			||||||
 | 
					    querydir_namelen_exists(FilePath);
 | 
				
			||||||
 | 
					    Success = CloseHandle(Handle);
 | 
				
			||||||
 | 
					    ASSERT(Success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
 | 
				
			||||||
 | 
					        *P = (P - FilePathBgn) % 10 + 0x3041;
 | 
				
			||||||
 | 
					    *P = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(FilePath,
 | 
				
			||||||
 | 
					        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | 
				
			||||||
 | 
					        CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | 
				
			||||||
 | 
					    ASSERT(INVALID_HANDLE_VALUE != Handle);
 | 
				
			||||||
 | 
					    querydir_namelen_exists(FilePath);
 | 
				
			||||||
 | 
					    Success = CloseHandle(Handle);
 | 
				
			||||||
 | 
					    ASSERT(Success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
 | 
				
			||||||
 | 
					        *P = (P - FilePathBgn) % 10 + 0x3041;
 | 
				
			||||||
 | 
					    *P = L'\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Handle = CreateFileW(FilePath,
 | 
				
			||||||
 | 
					        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | 
				
			||||||
 | 
					        CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | 
				
			||||||
 | 
					    ASSERT(INVALID_HANDLE_VALUE == Handle);
 | 
				
			||||||
 | 
					    ASSERT(ERROR_INVALID_NAME == GetLastError());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memfs_stop(memfs);
 | 
					    memfs_stop(memfs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -732,6 +988,7 @@ void dirnotify_test(void)
 | 
				
			|||||||
void dirctl_tests(void)
 | 
					void dirctl_tests(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    TEST(querydir_test);
 | 
					    TEST(querydir_test);
 | 
				
			||||||
 | 
					    TEST_OPT(querydir_nodup_test);
 | 
				
			||||||
    if (!OptShareName)
 | 
					    if (!OptShareName)
 | 
				
			||||||
        TEST_OPT(querydir_single_test);
 | 
					        TEST_OPT(querydir_single_test);
 | 
				
			||||||
    TEST(querydir_expire_cache_test);
 | 
					    TEST(querydir_expire_cache_test);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -273,6 +273,28 @@ void getfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
 | 
				
			|||||||
    ASSERT(0 == FileInfo.nFileSizeLow && 0 == FileInfo.nFileSizeHigh);
 | 
					    ASSERT(0 == FileInfo.nFileSizeLow && 0 == FileInfo.nFileSizeHigh);
 | 
				
			||||||
    ASSERT(1 == FileInfo.nNumberOfLinks);
 | 
					    ASSERT(1 == FileInfo.nNumberOfLinks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (-1 != Flags)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* WinFsp file systems respond to FileIdInformation queries with the IndexNumber zero-extended */
 | 
				
			||||||
 | 
					        struct
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            /* FILE_ID_INFO is missing from old version of SDK that we are still using */
 | 
				
			||||||
 | 
					            ULONGLONG VolumeSerialNumber;
 | 
				
			||||||
 | 
					            UINT8 FileId[16];
 | 
				
			||||||
 | 
					        } IdInfo;
 | 
				
			||||||
 | 
					        union
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            UINT64 IndexNumber;
 | 
				
			||||||
 | 
					            UINT8 FileId[16];
 | 
				
			||||||
 | 
					        } ExpectedFileId = { 0 };
 | 
				
			||||||
 | 
					        Success = GetFileInformationByHandleEx(Handle, 0x12/*FileIdInfo*/, &IdInfo, sizeof IdInfo);
 | 
				
			||||||
 | 
					        if (Success)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ExpectedFileId.IndexNumber = ((UINT64)FileInfo.nFileIndexHigh << 32) | (UINT64)FileInfo.nFileIndexLow;
 | 
				
			||||||
 | 
					            ASSERT(0 == memcmp(&ExpectedFileId.FileId, &IdInfo.FileId, sizeof IdInfo.FileId));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CloseHandle(Handle);
 | 
					    CloseHandle(Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memfs_stop(memfs);
 | 
					    memfs_stop(memfs);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								tst/winfsp-tests/loadun-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tst/winfsp-tests/loadun-test.c
									
									
									
									
									
										Normal 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -48,9 +48,9 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
 | 
				
			|||||||
        FileInfoTimeout,
 | 
					        FileInfoTimeout,
 | 
				
			||||||
        1024,
 | 
					        1024,
 | 
				
			||||||
        1024 * 1024,
 | 
					        1024 * 1024,
 | 
				
			||||||
        50, /*SlowioMaxDelay*/
 | 
					        (Flags & MemfsNoSlowio) ? 0 : 50, /*SlowioMaxDelay*/
 | 
				
			||||||
        10, /*SlowioPercentDelay*/
 | 
					        (Flags & MemfsNoSlowio) ? 0 : 10, /*SlowioPercentDelay*/
 | 
				
			||||||
        5,  /*SlowioRarefyDelay*/
 | 
					        (Flags & MemfsNoSlowio) ? 0 : 5,  /*SlowioRarefyDelay*/
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        MemfsNet == Flags ? L"\\memfs\\share" : 0,
 | 
					        MemfsNet == Flags ? L"\\memfs\\share" : 0,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -221,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);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user