Compare commits

..

44 Commits

Author SHA1 Message Date
52e6aa97b5 build: sys: pacify hardware center validation
Infverif /k no longer likes "undecorated" [DefaultInstall] sections and
instead it wants them "architecture decorated". For example,
[DefaultInstall.ntarm64]. So play along to have our driver signed.

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

For this reason remove an assertion that could trigger in debug builds.
2023-01-09 15:30:42 +00:00
69cc1820e1 tst: passthrough-fuse3: fix UNC path mount 2022-12-19 09:22:43 +08:00
c06141c8c8 tst: passthrough-fuse: fix UNC path mount 2022-12-19 09:22:16 +08:00
760c2acded Merge pull request #476 from zeho11/patch-1
dll: fuse: correct error handling when name exceeds limit
2022-12-16 22:29:37 +00:00
671efe625a Update 2022-12-15 20:49:01 +09:00
a59b32b1ee tst: winfsp-tests: add multibyte checks to querydir_namelen_test 2022-12-15 19:17:22 +09:00
22d81846df tst: passthrough-fuse3: multibyte support 2022-12-15 19:16:19 +09:00
8c9b8362b4 tst: passthrough-fuse: multibyte support 2022-12-15 19:14:44 +09:00
e92eb023fe Merge branch 'release/1.12' 2022-12-12 11:53:20 +00:00
e550e261f0 dll: fuse: correct error handling when name exceeds limit
Related to b62e1e920b
2022-12-12 12:08:48 +09:00
46054c03fe Merge pull request #474 from zeho11/patch-1
dll: fuse: change name limit to 255 chars
2022-12-08 16:02:38 +00:00
db07b24342 Update 2022-12-08 18:02:19 +09:00
cb81e81985 Update fuse_intf.c 2022-12-07 15:17:59 +09:00
b62e1e920b dll: fuse: change name limit to 255 chars
Fixes #191
Fixes #455
2022-12-07 14:39:36 +09:00
c61679a35d tools: build.bat: make cab file from unsigned drivers 2022-12-05 13:06:18 +00:00
619e41a18e changelog: update for v1.12.22335 2022-12-01 11:09:58 +00:00
80fa156e7b tools: build.bat: remove SHA1 signatures 2022-12-01 10:59:48 +00:00
01d9fa1719 Merge branch 'pvt-dotnetcore' 2022-11-30 10:06:42 +00:00
6846508631 tools: build.bat,make-release.ps1: accommodate winfsp.net.nupkg 2022-11-29 21:13:13 +00:00
0488451c3d build: fix dotnet output paths 2022-11-29 15:49:09 +00:00
7c3292af81 tools: build.bat: dotnet build 2022-11-29 12:53:33 +00:00
3d2ba637e5 build: minimize changes in .csproj files 2022-11-28 16:52:21 +00:00
db72b57ca4 build: dotnet: remove Directory.Build.props 2022-11-28 14:04:51 +00:00
020157a9ae Merge branch 'dotnetcore' of https://github.com/Noire001/winfsp into Noire001-dotnetcore 2022-11-28 12:13:50 +00:00
d99cb2d7d1 build: dotnet: set PlatformTarget to AnyCPU 2022-11-23 22:47:50 +02:00
298261c4af tools: make-release.ps1: add build hashes 2022-11-23 16:21:08 +00:00
3c674a556d tools: make-release.ps1: update download link 2022-11-23 15:18:25 +00:00
92084a56c6 build: dotnet: add missing NuGet properties 2022-11-20 20:05:10 +02:00
53f97c9841 build: dotnet: revert optional changes/deletions 2022-11-20 19:39:06 +02:00
2770eca1bf tools: use dotnet build in VS2015 CI 2022-11-20 15:10:50 +02:00
2945971ba9 build: memfs-dotnet: migrate to .NET SDK 2022-11-19 21:01:44 +02:00
0a39ef60bd Update Contributors.asciidoc 2022-11-19 21:01:44 +02:00
e1faf1351e build: dotnet: generate NuGet package on build 2022-11-19 21:01:44 +02:00
7333451eac build: installer: update assembly location 2022-11-19 21:01:24 +02:00
c178db127c build: dotnet: migrate to .NET SDK 2022-11-19 20:57:50 +02:00
e1b2e77df0 build: version: 2022.2 2022-10-18 12:19:36 +01:00
32 changed files with 826 additions and 149 deletions

View File

@ -1,6 +1,35 @@
# 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) ## 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. 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.
@ -18,6 +47,23 @@ Some changes that may be visible to file system developers are listed below:
- 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 - The WinFsp symbols directory has been removed. If you are looking for WinFsp symbols you can find them at https://github.com/winfsp/winfsp.sym
## v1.12.22339 (2022.2 Update1)
*Note: This release (`v1.12.22339`) is the same as the previous release (`v1.12`) except that: (1) the kernel-mode drivers are now digitally signed only with the Microsoft Attestation signature, and that: (2) no release assets are digitally signed with SHA-1. (This change was necessary to fix a problem in older versions of Windows such as Windows 7.)*
- [NEW] WinFsp now supports mounting as directory using the Mount Manager. Use the syntax `\\.\C:\Path\To\Mount\Directory`.
- [NEW] A new registry setting `MountUseMountmgrFromFSD` has been added. See [WinFsp Registry Settings](https://github.com/winfsp/winfsp/wiki/WinFsp-Registry-Settings) for details.
- [FIX] A problem with Windows containers has been fixed. (GitHub issue #438.)
- [FIX] File systems can now be mounted as directories on ARM64. (GitHub issue #448.)
- [FIX] The passthrough file system now reports correct `IndexNumber`. (GitHub issue #325.)
- [BUILD] Product configuration for the relative paths to the File System Driver, Network Provider and EventLog is now possible via the file `build.version.props` located in `build\VStudio`.
## v1.12 (2022.2) ## v1.12 (2022.2)
- [NEW] WinFsp now supports mounting as directory using the Mount Manager. Use the syntax `\\.\C:\Path\To\Mount\Directory`. - [NEW] WinFsp now supports mounting as directory using the Mount Manager. Use the syntax `\\.\C:\Path\To\Mount\Directory`.

View File

@ -66,6 +66,7 @@ CONTRIBUTOR LIST
|Gal Hammer (Red Hat, https://www.redhat.com) |ghammer at redhat.com |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
|=== |===

View File

@ -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%

View File

@ -20,7 +20,7 @@
<MyCanonicalVersion>2.0</MyCanonicalVersion> <MyCanonicalVersion>2.0</MyCanonicalVersion>
<MyProductVersion>2023 Beta1</MyProductVersion> <MyProductVersion>2023 Beta2</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Beta</MyProductStage>
<MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert> <MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert>

View File

@ -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(&quot;$(MyProductName)&quot;)]" /> <AssemblyName>$(MyProductFileName)-msil</AssemblyName>
<AssemblyInfo Include="[assembly: AssemblyTitle(&quot;$(MyDescription)&quot;)]" /> <AssemblyTitle>$(MyDescription)</AssemblyTitle>
<AssemblyInfo Include="[assembly: AssemblyCompany(&quot;$(MyCompanyName)&quot;)]" /> <Product>$(MyProductName)</Product>
<AssemblyInfo Include="[assembly: AssemblyCopyright(&quot;$(MyCopyright)&quot;)]" /> <Copyright>$(MyCopyright)</Copyright>
<AssemblyInfo Include="[assembly: AssemblyVersion(&quot;$(MyAssemblyVersion)&quot;)]" /> <AssemblyVersion>$(MyAssemblyVersion)</AssemblyVersion>
<AssemblyInfo Include="[assembly: AssemblyFileVersion(&quot;$(MyVersion)&quot;)]" /> <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>

View File

@ -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>

View File

@ -291,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
@ -304,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
@ -317,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
@ -329,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
@ -343,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
@ -355,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

View File

@ -1047,6 +1047,41 @@ 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, VOID (*DispatcherStopped)(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally); BOOLEAN Normally);
@ -1112,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.
@ -1750,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
@ -2047,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

View File

@ -406,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;
} }

View File

@ -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();
}

View File

@ -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,
}; };
/* /*

View File

@ -110,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)

View File

@ -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");

View File

@ -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);
}
} }
} }

View File

@ -1426,6 +1426,21 @@ namespace Fsp
} }
} }
private static void DispatcherStopped(
IntPtr FileSystemPtr,
Boolean Normally)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
{
FileSystem.DispatcherStopped(Normally);
}
catch (Exception ex)
{
ExceptionHandler(FileSystem, ex);
}
}
static FileSystemHost() 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! */

View File

@ -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);

View File

@ -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);
} }

View File

@ -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]

View File

@ -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^
@ -78,13 +89,19 @@ if X%SignedPackage%==X (
launchctl-a64.exe launchctl-x64.exe launchctl-x86.exe^ launchctl-a64.exe launchctl-x64.exe launchctl-x86.exe^
fsptool-a64.exe fsptool-x64.exe fsptool-x86.exe^ fsptool-a64.exe fsptool-x64.exe fsptool-x86.exe^
memfs-a64.exe memfs-x64.exe memfs-x86.exe memfs-dotnet-msil.exe memfs-a64.exe memfs-x64.exe memfs-x86.exe memfs-dotnet-msil.exe
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com !signfiles! signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 !signfiles!
if errorlevel 1 set /a signfail=signfail+1
signtool sign /as /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 !signfiles!
if errorlevel 1 set /a signfail=signfail+1 if errorlevel 1 set /a signfail=signfail+1
popd popd
pushd build\%Configuration% pushd build\%Configuration%
mkdir unsigned
for %%f in (!signfiles!) do (
copy "%%f" unsigned >nul
)
pushd unsigned
signtool remove /q /s !signfiles!
if errorlevel 1 set /a signfail=signfail+1
popd
echo .OPTION EXPLICIT >driver.ddf echo .OPTION EXPLICIT >driver.ddf
echo .Set CabinetFileCountThreshold=0 >>driver.ddf echo .Set CabinetFileCountThreshold=0 >>driver.ddf
echo .Set FolderFileCountThreshold=0 >>driver.ddf echo .Set FolderFileCountThreshold=0 >>driver.ddf
@ -99,13 +116,13 @@ if X%SignedPackage%==X (
echo .Set DiskDirectory1=. >>driver.ddf echo .Set DiskDirectory1=. >>driver.ddf
echo .Set DestinationDir=a64 >>driver.ddf echo .Set DestinationDir=a64 >>driver.ddf
echo driver-a64.inf >>driver.ddf echo driver-a64.inf >>driver.ddf
echo %MyProductFileName%-a64.sys >>driver.ddf echo unsigned\%MyProductFileName%-a64.sys >>driver.ddf
echo .Set DestinationDir=x64 >>driver.ddf echo .Set DestinationDir=x64 >>driver.ddf
echo driver-x64.inf >>driver.ddf echo driver-x64.inf >>driver.ddf
echo %MyProductFileName%-x64.sys >>driver.ddf echo unsigned\%MyProductFileName%-x64.sys >>driver.ddf
echo .Set DestinationDir=x86 >>driver.ddf echo .Set DestinationDir=x86 >>driver.ddf
echo driver-x86.inf >>driver.ddf echo driver-x86.inf >>driver.ddf
echo %MyProductFileName%-x86.sys >>driver.ddf echo unsigned\%MyProductFileName%-x86.sys >>driver.ddf
makecab /F driver.ddf makecab /F driver.ddf
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 driver.cab signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 driver.cab
if errorlevel 1 set /a signfail=signfail+1 if errorlevel 1 set /a signfail=signfail+1
@ -116,10 +133,8 @@ devenv winfsp.sln /build "Installer.%Configuration%|x86"
if errorlevel 1 goto fail if errorlevel 1 goto fail
for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do ( for %%f in (build\%Configuration%\%MyProductFileName%-*.msi) do (
signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha1 /t http://timestamp.digicert.com /d %MsiName% %%f signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
if errorlevel 1 set /a signfail=signfail+1 if errorlevel 1 set /a signfail=signfail+1
REM signtool sign /ac %CrossCert% /i %Issuer% /n %Subject% /fd sha256 /tr http://timestamp.digicert.com /td sha256 /d %MsiName% %%f
REM if errorlevel 1 set /a signfail=signfail+1
) )
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed. if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.

View File

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

View File

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

View File

@ -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"
[![Download WinFsp](https://img.shields.io/badge/-Download%20WinFsp-$DownloadColor.svg?style=for-the-badge&labelColor=grey&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0ODAgNDgwIj48cGF0aCBkPSJNMzg3LjAwMiAyMDEuMDAxQzM3Mi45OTggMTMyLjAwMiAzMTIuOTk4IDgwIDI0MCA4MGMtNTcuOTk4IDAtMTA3Ljk5OCAzMi45OTgtMTMyLjk5OCA4MS4wMDFDNDcuMDAyIDE2Ny4wMDIgMCAyMTcuOTk4IDAgMjgwYzAgNjUuOTk2IDUzLjk5OSAxMjAgMTIwIDEyMGgyNjBjNTUgMCAxMDAtNDUgMTAwLTEwMCAwLTUyLjk5OC00MC45OTYtOTYuMDAxLTkyLjk5OC05OC45OTl6TTIwOCAyNTJ2LTc2aDY0djc2aDY4TDI0MCAzNTIgMTQwIDI1Mmg2OHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://github.com/billziss-gh/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi) $ZipFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip"
$MsiName = Split-Path -Leaf $MsiFile
$ZipName = Split-Path -Leaf $ZipFile
$MsiHash = (Get-FileHash -Algorithm SHA256 $MsiFile).Hash
$ZipHash = (Get-FileHash -Algorithm SHA256 $ZipFile).Hash
[VirusTotal Scan Results]() if ($MsiName -match "winfsp-(.+)\.msi") {
$Version = $matches[1]
}
$ReleaseNotes = @"
[![Download WinFsp](https://img.shields.io/badge/-Download%20WinFsp-$DownloadColor.svg?style=for-the-badge&labelColor=grey&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0ODAgNDgwIj48cGF0aCBkPSJNMzg3LjAwMiAyMDEuMDAxQzM3Mi45OTggMTMyLjAwMiAzMTIuOTk4IDgwIDI0MCA4MGMtNTcuOTk4IDAtMTA3Ljk5OCAzMi45OTgtMTMyLjk5OCA4MS4wMDFDNDcuMDAyIDE2Ny4wMDIgMCAyMTcuOTk4IDAgMjgwYzAgNjUuOTk2IDUzLjk5OSAxMjAgMTIwIDEyMGgyNjBjNTUgMCAxMDAtNDUgMTAwLTEwMCAwLTUyLjk5OC00MC45OTYtOTYuMDAxLTkyLjk5OC05OC45OTl6TTIwOCAyNTJ2LTc2aDY0djc2aDY4TDI0MCAzNTIgMTQwIDI1Mmg2OHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://github.com/winfsp/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion) ## 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

View File

@ -2275,10 +2275,10 @@ static NTSTATUS SetEa(FSP_FILE_SYSTEM *FileSystem,
#endif #endif
#if defined(MEMFS_DISPATCHER_STOPPED) #if defined(MEMFS_DISPATCHER_STOPPED)
static void DispatcherStopped(FSP_FILE_SYSTEM *FileSystem, static VOID DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
BOOLEAN Normally) BOOLEAN Normally)
{ {
//FspDebugLog(__FUNCTION__ ": Normally=%d\n", Normally); FspFileSystemStopServiceIfNecessary(FileSystem, Normally);
} }
#endif #endif

View File

@ -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(

View File

@ -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

View File

@ -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;
} }

View File

@ -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);

View File

@ -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

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);
} }

View File

@ -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);
} }