mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
95 Commits
v1.12.2233
...
v2.0B2
Author | SHA1 | Date | |
---|---|---|---|
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 |
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 Beta2</MyProductVersion>
|
||||||
<MyProductStage>Gold</MyProductStage>
|
<MyProductStage>Beta</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>
|
</ItemGroup>
|
||||||
<AssemblyInfo Include="using System.Reflection%3b" />
|
<PropertyGroup>
|
||||||
<AssemblyInfo Include="[assembly: AssemblyProduct("$(MyProductName)")]" />
|
<AssemblyName>$(MyProductFileName)-msil</AssemblyName>
|
||||||
<AssemblyInfo Include="[assembly: AssemblyTitle("$(MyDescription)")]" />
|
<AssemblyTitle>$(MyDescription)</AssemblyTitle>
|
||||||
<AssemblyInfo Include="[assembly: AssemblyCompany("$(MyCompanyName)")]" />
|
<Product>$(MyProductName)</Product>
|
||||||
<AssemblyInfo Include="[assembly: AssemblyCopyright("$(MyCopyright)")]" />
|
<Copyright>$(MyCopyright)</Copyright>
|
||||||
<AssemblyInfo Include="[assembly: AssemblyVersion("$(MyAssemblyVersion)")]" />
|
<AssemblyVersion>$(MyAssemblyVersion)</AssemblyVersion>
|
||||||
<AssemblyInfo Include="[assembly: AssemblyFileVersion("$(MyVersion)")]" />
|
<FileVersion>$(MyVersion)</FileVersion>
|
||||||
</ItemGroup>
|
<!-- NuGet metadata -->
|
||||||
<MakeDir Directories="$(IntermediateOutputPath)" />
|
<PackageId>$(MyProductFileName).net</PackageId>
|
||||||
<WriteLinesToFile File="$(IntermediateOutputPath)AssemblyInfo.cs" Lines="@(AssemblyInfo)" Overwrite="true" />
|
<Version>$(MyVersion)</Version>
|
||||||
<ItemGroup>
|
<Description>$(MyDescription)</Description>
|
||||||
<Compile Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
|
<Authors>$(MyCopyright)</Authors>
|
||||||
<FileWrites Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
|
<Company>$(MyCompanyName)</Company>
|
||||||
</ItemGroup>
|
</PropertyGroup>
|
||||||
</Target>
|
|
||||||
<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="BINDIR" Name="bin" />
|
<Directory Id="SXSBASEDIR" Name="SxS">
|
||||||
|
<Directory Id="SXSDIR" Name="DYNAMIC">
|
||||||
|
<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,
|
||||||
|
404
src/dll/fsctl.c
404
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,54 +789,40 @@ 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;
|
||||||
|
AccessEntries[1].Trustee.pMultipleTrustee = 0;
|
||||||
|
AccessEntries[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
||||||
|
AccessEntries[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||||||
|
AccessEntries[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
|
||||||
|
AccessEntries[1].Trustee.ptstrName = WorldSid;
|
||||||
|
|
||||||
|
/* create a new security descriptor with the new access */
|
||||||
|
LastError = BuildSecurityDescriptorW(0, 0, 2, AccessEntries, 0, 0, SecurityDescriptor,
|
||||||
|
&Size, &NewSecurityDescriptor);
|
||||||
|
if (0 != LastError)
|
||||||
{
|
{
|
||||||
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights);
|
Result = FspNtStatusFromWin32(LastError);
|
||||||
if (0 != LastError)
|
goto exit;
|
||||||
/*
|
|
||||||
* Apparently GetEffectiveRightsFromAclW can fail with ERROR_CIRCULAR_DEPENDENCY
|
|
||||||
* in some rare circumstances. Calling GetEffectiveRightsFromAclW is not essential
|
|
||||||
* in this instance. It is only done to check whether the "Everyone/World" SID
|
|
||||||
* already has the access required to start the FSD; if it does not have those
|
|
||||||
* rights already they are added. It is probably safe to just assume that the
|
|
||||||
* required rights are not there if GetEffectiveRightsFromAclW fails; the worst
|
|
||||||
* that can happen is that the rights get added twice (which is benign).
|
|
||||||
*
|
|
||||||
* See https://github.com/winfsp/winfsp/issues/62
|
|
||||||
*/
|
|
||||||
AccessRights = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do we have the required access rights? */
|
/* set the new service security descriptor DACL */
|
||||||
if (AccessEntry.grfAccessPermissions != (AccessRights & AccessEntry.grfAccessPermissions))
|
if (!SetServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
|
||||||
{
|
{
|
||||||
/* create a new security descriptor with the new access */
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor,
|
goto exit;
|
||||||
&Size, &NewSecurityDescriptor);
|
|
||||||
if (0 != LastError)
|
|
||||||
{
|
|
||||||
Result = FspNtStatusFromWin32(LastError);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the new service security descriptor DACL */
|
|
||||||
if (!SetServiceObjectSecurity(SvcHandle, DACL_SECURITY_INFORMATION, NewSecurityDescriptor))
|
|
||||||
{
|
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = 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,13 +218,17 @@ 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
|
|
||||||
|
|
||||||
IoDeleteDevice(DeviceObject);
|
VOID FspDeviceDoIoDeleteDevice(PDEVICE_OBJECT DeviceObject)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject);
|
||||||
|
|
||||||
|
if (0 == InterlockedCompareExchange(&DeviceExtension->DidIoDeleteDevice, 1, 0))
|
||||||
|
IoDeleteDevice(DeviceObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FspDeviceReference(PDEVICE_OBJECT DeviceObject)
|
BOOLEAN FspDeviceReference(PDEVICE_OBJECT 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;
|
||||||
|
222
src/sys/driver.c
222
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,13 +405,31 @@ 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);
|
||||||
|
|
||||||
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
|
if (Globals->InitDoneRegisterDisk)
|
||||||
|
{
|
||||||
|
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
|
||||||
|
Globals->InitDoneRegisterDisk = 0;
|
||||||
|
}
|
||||||
if (0 != Globals->MupHandle)
|
if (0 != Globals->MupHandle)
|
||||||
{
|
{
|
||||||
FsRtlDeregisterUncProvider(Globals->MupHandle);
|
FsRtlDeregisterUncProvider(Globals->MupHandle);
|
||||||
@ -332,26 +437,119 @@ static VOID FspDriverFinalizeDevices(VOID)
|
|||||||
}
|
}
|
||||||
if (0 != Globals->FsmupDeviceObject)
|
if (0 != Globals->FsmupDeviceObject)
|
||||||
{
|
{
|
||||||
FspDeviceDelete(Globals->FsmupDeviceObject);
|
if (DeleteDevices)
|
||||||
Globals->FsmupDeviceObject = 0;
|
{
|
||||||
|
FspDeviceDelete(Globals->FsmupDeviceObject);
|
||||||
|
ObDereferenceObject(Globals->FsmupDeviceObject);
|
||||||
|
Globals->FsmupDeviceObject = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FspDeviceDoIoDeleteDevice(Globals->FsmupDeviceObject);
|
||||||
|
}
|
||||||
|
if (Globals->InitDoneSymlinkNet)
|
||||||
|
{
|
||||||
|
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
|
||||||
|
IoDeleteSymbolicLink(&SymlinkName);
|
||||||
|
Globals->InitDoneSymlinkNet = 0;
|
||||||
}
|
}
|
||||||
if (0 != Globals->FsctlNetDeviceObject)
|
if (0 != Globals->FsctlNetDeviceObject)
|
||||||
{
|
{
|
||||||
FspDeviceDelete(Globals->FsctlNetDeviceObject);
|
if (DeleteDevices)
|
||||||
Globals->FsctlNetDeviceObject = 0;
|
{
|
||||||
|
FspDeviceDelete(Globals->FsctlNetDeviceObject);
|
||||||
|
ObDereferenceObject(Globals->FsctlNetDeviceObject);
|
||||||
|
Globals->FsctlNetDeviceObject = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FspDeviceDoIoDeleteDevice(Globals->FsctlNetDeviceObject);
|
||||||
|
}
|
||||||
|
if (Globals->InitDoneSymlinkDisk)
|
||||||
|
{
|
||||||
|
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
|
||||||
|
IoDeleteSymbolicLink(&SymlinkName);
|
||||||
|
Globals->InitDoneSymlinkDisk = 0;
|
||||||
}
|
}
|
||||||
if (0 != Globals->FsctlDiskDeviceObject)
|
if (0 != Globals->FsctlDiskDeviceObject)
|
||||||
{
|
{
|
||||||
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
|
if (DeleteDevices)
|
||||||
Globals->FsctlDiskDeviceObject = 0;
|
{
|
||||||
|
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
|
||||||
|
ObDereferenceObject(Globals->FsctlDiskDeviceObject);
|
||||||
|
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]
|
||||||
|
@ -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
|
@ -161,9 +161,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +237,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 +244,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 +325,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
|
||||||
@ -338,4 +378,5 @@ Build-AssetsPhase1
|
|||||||
Build-AssetsPhase2
|
Build-AssetsPhase2
|
||||||
Make-GitHubRelease
|
Make-GitHubRelease
|
||||||
Upload-Symbols
|
Upload-Symbols
|
||||||
|
Make-NugetRelease
|
||||||
Make-ChocoRelease
|
Make-ChocoRelease
|
||||||
|
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
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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];
|
||||||
if (0 == len)
|
WCHAR ResultBuf[PATH_MAX];
|
||||||
|
PWSTR ResultBufBgn = &ResultBuf[6];
|
||||||
|
if (0 == MultiByteToWideChar(CP_UTF8, 0, path, -1, PathBuf, PATH_MAX))
|
||||||
err = GetLastError();
|
err = GetLastError();
|
||||||
else if (PATH_MAX < len)
|
else
|
||||||
err = ERROR_INVALID_PARAMETER;
|
{
|
||||||
|
DWORD len = GetFullPathNameW(PathBuf, PATH_MAX - 6, ResultBufBgn, 0);
|
||||||
|
if (0 == len)
|
||||||
|
err = GetLastError();
|
||||||
|
else if (PATH_MAX - 6 < len)
|
||||||
|
err = ERROR_INVALID_PARAMETER;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (0 == WideCharToMultiByte(CP_UTF8, 0, ResultBufBgn, -1, result, PATH_MAX, 0, 0))
|
||||||
|
err = GetLastError();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (L'\\' == ResultBufBgn[0] && L'\\' == ResultBufBgn[1])
|
||||||
|
{
|
||||||
|
ResultBufBgn = ResultBuf;
|
||||||
|
ResultBufBgn[0] = L'\\';
|
||||||
|
ResultBufBgn[1] = L'\\';
|
||||||
|
ResultBufBgn[2] = L'?';
|
||||||
|
ResultBufBgn[3] = L'\\';
|
||||||
|
ResultBufBgn[4] = L'U';
|
||||||
|
ResultBufBgn[5] = L'N';
|
||||||
|
ResultBufBgn[6] = L'C';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResultBufBgn = &ResultBuf[2];
|
||||||
|
ResultBufBgn[0] = L'\\';
|
||||||
|
ResultBufBgn[1] = L'\\';
|
||||||
|
ResultBufBgn[2] = L'?';
|
||||||
|
ResultBufBgn[3] = L'\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (0 == err)
|
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];
|
||||||
if (0 == len)
|
WCHAR ResultBuf[PATH_MAX];
|
||||||
|
PWSTR ResultBufBgn = &ResultBuf[6];
|
||||||
|
if (0 == MultiByteToWideChar(CP_UTF8, 0, path, -1, PathBuf, PATH_MAX))
|
||||||
err = GetLastError();
|
err = GetLastError();
|
||||||
else if (PATH_MAX < len)
|
else
|
||||||
err = ERROR_INVALID_PARAMETER;
|
{
|
||||||
|
DWORD len = GetFullPathNameW(PathBuf, PATH_MAX - 6, ResultBufBgn, 0);
|
||||||
|
if (0 == len)
|
||||||
|
err = GetLastError();
|
||||||
|
else if (PATH_MAX - 6 < len)
|
||||||
|
err = ERROR_INVALID_PARAMETER;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (0 == WideCharToMultiByte(CP_UTF8, 0, ResultBufBgn, -1, result, PATH_MAX, 0, 0))
|
||||||
|
err = GetLastError();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (L'\\' == ResultBufBgn[0] && L'\\' == ResultBufBgn[1])
|
||||||
|
{
|
||||||
|
ResultBufBgn = ResultBuf;
|
||||||
|
ResultBufBgn[0] = L'\\';
|
||||||
|
ResultBufBgn[1] = L'\\';
|
||||||
|
ResultBufBgn[2] = L'?';
|
||||||
|
ResultBufBgn[3] = L'\\';
|
||||||
|
ResultBufBgn[4] = L'U';
|
||||||
|
ResultBufBgn[5] = L'N';
|
||||||
|
ResultBufBgn[6] = L'C';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResultBufBgn = &ResultBuf[2];
|
||||||
|
ResultBufBgn[0] = L'\\';
|
||||||
|
ResultBufBgn[1] = L'\\';
|
||||||
|
ResultBufBgn[2] = L'?';
|
||||||
|
ResultBufBgn[3] = L'\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (0 == err)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,6 +576,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -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