mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 17:32:57 -05:00
Compare commits
49 Commits
v2.0B1
...
pvt-idinfo
Author | SHA1 | Date | |
---|---|---|---|
82f84f5bf7 | |||
97c075e744 | |||
874a223bcc | |||
901a98e118 | |||
0ab4300738 | |||
52e6aa97b5 | |||
a7d82d5f8d | |||
3aadaee511 | |||
da3a8aa229 | |||
1f0fd4c280 | |||
6da92f0b54 | |||
4f5f1dd350 | |||
ba5d52e9a5 | |||
d626fb9563 | |||
69cc1820e1 | |||
c06141c8c8 | |||
760c2acded | |||
671efe625a | |||
a59b32b1ee | |||
22d81846df | |||
8c9b8362b4 | |||
e92eb023fe | |||
e550e261f0 | |||
46054c03fe | |||
db07b24342 | |||
cb81e81985 | |||
b62e1e920b | |||
c61679a35d | |||
619e41a18e | |||
80fa156e7b | |||
01d9fa1719 | |||
6846508631 | |||
0488451c3d | |||
7c3292af81 | |||
3d2ba637e5 | |||
db72b57ca4 | |||
020157a9ae | |||
d99cb2d7d1 | |||
298261c4af | |||
3c674a556d | |||
92084a56c6 | |||
53f97c9841 | |||
2770eca1bf | |||
2945971ba9 | |||
0a39ef60bd | |||
e1faf1351e | |||
7333451eac | |||
c178db127c | |||
e1b2e77df0 |
8
.github/workflows/avm.yml
vendored
8
.github/workflows/avm.yml
vendored
@ -11,8 +11,8 @@ jobs:
|
|||||||
- uses: billziss-gh/avm@v1
|
- uses: billziss-gh/avm@v1
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
https://github.com/winfsp/winfsp/releases/download/v1.6/winfsp-1.6.20027.msi
|
|
||||||
https://github.com/winfsp/winfsp/releases/download/v1.7/winfsp-1.7.20172.msi
|
|
||||||
https://github.com/winfsp/winfsp/releases/download/v1.8/winfsp-1.8.20304.msi
|
|
||||||
https://github.com/winfsp/winfsp/releases/download/v1.9/winfsp-1.9.21096.msi
|
|
||||||
https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
|
https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
|
||||||
|
https://github.com/winfsp/winfsp/releases/download/v1.11/winfsp-1.11.22176.msi
|
||||||
|
https://github.com/winfsp/winfsp/releases/download/v1.12/winfsp-1.12.22301.msi
|
||||||
|
https://github.com/winfsp/winfsp/releases/download/v1.12.22339/winfsp-1.12.22339.msi
|
||||||
|
https://github.com/winfsp/winfsp/releases/download/v2.0B2/winfsp-2.0.23033.msi
|
||||||
|
46
Changelog.md
46
Changelog.md
@ -1,6 +1,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`.
|
||||||
|
@ -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%
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
<MyCanonicalVersion>2.0</MyCanonicalVersion>
|
<MyCanonicalVersion>2.0</MyCanonicalVersion>
|
||||||
|
|
||||||
<MyProductVersion>2023 Beta1</MyProductVersion>
|
<MyProductVersion>2023 RC1</MyProductVersion>
|
||||||
<MyProductStage>Beta</MyProductStage>
|
<MyProductStage>RC</MyProductStage>
|
||||||
|
|
||||||
<MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert>
|
<MyCrossCert>DigiCertGlobalG3CodeSigningECCSHA3842021CA1.cer</MyCrossCert>
|
||||||
<MyCertIssuer>DigiCert</MyCertIssuer>
|
<MyCertIssuer>DigiCert</MyCertIssuer>
|
||||||
|
@ -1,25 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project>
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<PropertyGroup>
|
||||||
|
<BaseIntermediateOutputPath>$(SolutionDir)build\$(MSBuildProjectName).build\</BaseIntermediateOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
|
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.common.props))/build.common.props" />
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>{94580219-CC8D-4FE5-A3BE-437B0B3481E1}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<ProjectName>winfsp.net</ProjectName>
|
<ProjectName>winfsp.net</ProjectName>
|
||||||
<RootNamespace>Fsp</RootNamespace>
|
<RootNamespace>Fsp</RootNamespace>
|
||||||
<AssemblyName>$(MyProductFileName)-msil</AssemblyName>
|
<AssemblyName>$(MyProductFileName)-msil</AssemblyName>
|
||||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
<TargetFrameworks>netstandard2.0;net35</TargetFrameworks>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||||
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
|
||||||
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
@ -32,7 +36,6 @@
|
|||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
|
||||||
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
|
|
||||||
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
@ -47,9 +50,6 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>winfsp.net.snk</AssemblyOriginatorKeyFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
|
<Compile Include="..\..\..\src\dotnet\FileSystemBase+Const.cs">
|
||||||
<Link>FileSystemBase+Const.cs</Link>
|
<Link>FileSystemBase+Const.cs</Link>
|
||||||
@ -70,29 +70,28 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="winfsp.net.snk" />
|
<None Include="winfsp.net.snk" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<PackageReference Include="Microsoft.Win32.Registry">
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
<Version>5.0.0</Version>
|
||||||
<Target Name="AfterBuild">
|
</PackageReference>
|
||||||
</Target>
|
<PackageReference Include="System.IO.FileSystem.AccessControl">
|
||||||
-->
|
<Version>5.0.0</Version>
|
||||||
<Target Name="BeforeBuild">
|
</PackageReference>
|
||||||
<ItemGroup>
|
</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>
|
@ -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>
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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)
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -205,6 +205,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
ASSERT(sizeof(UINT64) == DirectoryMarker->Length);
|
ASSERT(sizeof(UINT64) == DirectoryMarker->Length);
|
||||||
DirectoryMarkerFound = DirectoryNextOffset == *(PUINT64)DirectoryMarker->Buffer;
|
DirectoryMarkerFound = DirectoryNextOffset == *(PUINT64)DirectoryMarker->Buffer;
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
||||||
|
@ -8,7 +8,7 @@ Provider = !Provider!
|
|||||||
[DestinationDirs]
|
[DestinationDirs]
|
||||||
DefaultDestDir = 12
|
DefaultDestDir = 12
|
||||||
|
|
||||||
[DefaultInstall]
|
[DefaultInstall.!ArchDecoration!]
|
||||||
CopyFiles = Driver.CopyFiles
|
CopyFiles = Driver.CopyFiles
|
||||||
|
|
||||||
[Driver.CopyFiles]
|
[Driver.CopyFiles]
|
||||||
|
@ -33,6 +33,8 @@ static NTSTATUS FspFsvolQueryBasicInformation(PFILE_OBJECT FileObject,
|
|||||||
static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
|
||||||
PVOID *PBuffer, PVOID BufferEnd,
|
PVOID *PBuffer, PVOID BufferEnd,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo);
|
const FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
|
static NTSTATUS FspFsvolQueryIdInformation(PFILE_OBJECT FileObject,
|
||||||
|
PVOID *PBuffer, PVOID BufferEnd);
|
||||||
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
||||||
PVOID *PBuffer, PVOID BufferEnd);
|
PVOID *PBuffer, PVOID BufferEnd);
|
||||||
static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryNameInformation(PFILE_OBJECT FileObject,
|
||||||
@ -106,6 +108,7 @@ FAST_IO_QUERY_OPEN FspFastIoQueryOpen;
|
|||||||
#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryAttributeTagInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryBasicInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryEaInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryEaInformation)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolQueryIdInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryInternalInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryNameInformation)
|
||||||
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
|
#pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation)
|
||||||
@ -288,6 +291,32 @@ static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolQueryIdInformation(PFILE_OBJECT FileObject,
|
||||||
|
PVOID *PBuffer, PVOID BufferEnd)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
PFILE_ID_INFORMATION Info = (PFILE_ID_INFORMATION)*PBuffer;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
|
union
|
||||||
|
{
|
||||||
|
UINT64 IndexNumber;
|
||||||
|
FILE_ID_128 FileId;
|
||||||
|
} FileIdBuf = { .IndexNumber = FileNode->IndexNumber };
|
||||||
|
|
||||||
|
if ((PVOID)(Info + 1) > BufferEnd)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
Info->VolumeSerialNumber = FsvolDeviceExtension->VolumeParams.VolumeSerialNumber;
|
||||||
|
Info->FileId = FileIdBuf.FileId;
|
||||||
|
|
||||||
|
*PBuffer = (PVOID)(Info + 1);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
static NTSTATUS FspFsvolQueryInternalInformation(PFILE_OBJECT FileObject,
|
||||||
PVOID *PBuffer, PVOID BufferEnd)
|
PVOID *PBuffer, PVOID BufferEnd)
|
||||||
{
|
{
|
||||||
@ -961,6 +990,10 @@ static NTSTATUS FspFsvolQueryInformation(
|
|||||||
case FileHardLinkInformation:
|
case FileHardLinkInformation:
|
||||||
Result = STATUS_NOT_SUPPORTED; /* no hard link support */
|
Result = STATUS_NOT_SUPPORTED; /* no hard link support */
|
||||||
return Result;
|
return Result;
|
||||||
|
case FileIdInformation:
|
||||||
|
Result = FspFsvolQueryIdInformation(FileObject, &Buffer, BufferEnd);
|
||||||
|
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
|
||||||
|
return Result;
|
||||||
case FileInternalInformation:
|
case FileInternalInformation:
|
||||||
Result = FspFsvolQueryInternalInformation(FileObject, &Buffer, BufferEnd);
|
Result = FspFsvolQueryInternalInformation(FileObject, &Buffer, BufferEnd);
|
||||||
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
|
Irp->IoStatus.Information = (UINT_PTR)((PUINT8)Buffer - (PUINT8)Irp->AssociatedIrp.SystemBuffer);
|
||||||
|
@ -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.
|
||||||
|
17
tools/gensrc/remove-build-dotnet.bat
Normal file
17
tools/gensrc/remove-build-dotnet.bat
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
setlocal EnableDelayedExpansion
|
||||||
|
|
||||||
|
if "%1"=="" (
|
||||||
|
cd %~dp0..\..
|
||||||
|
) else (
|
||||||
|
cd "%1"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if exist winfsp.sln (
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0remove-sln-project.ps1' -Path '%cd%\winfsp.sln' -Match '*dotnet*'
|
||||||
|
) else (
|
||||||
|
echo winfsp.sln not found in %cd%
|
||||||
|
)
|
12
tools/gensrc/remove-sln-project.ps1
Normal file
12
tools/gensrc/remove-sln-project.ps1
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
param (
|
||||||
|
[Parameter(Mandatory)][string]$Path,
|
||||||
|
[Parameter(Mandatory)][string]$Match
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "Removing projects that match $($Match) from $($Path)"
|
||||||
|
|
||||||
|
Get-Content $Path -Delimiter 'EndProject' |
|
||||||
|
Where-Object {$_ -notlike $Match} |
|
||||||
|
Set-Content "$($Path).new"
|
||||||
|
|
||||||
|
Move-Item -Path "$($Path).new" -Destination $Path -Force
|
@ -68,6 +68,27 @@ function Get-ReleaseInfo ($Tag) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-HwapiCredentials {
|
||||||
|
$Credentials = (& "$ProjectRoot\tools\wincred.ps1" get "Hardware Dashboard API")
|
||||||
|
if ($Credentials) {
|
||||||
|
try { $Credentials = ConvertFrom-Json $Credentials[1] } catch {;}
|
||||||
|
}
|
||||||
|
if ($Credentials -and $Credentials.TenantId -and $Credentials.ClientId -and $Credentials.ClientId) {
|
||||||
|
return $Credentials
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Start-Sdcm {
|
||||||
|
Start-Job -ArgumentList $args -ScriptBlock {
|
||||||
|
$env:SDCM_CREDS_TENANTID = $using:HwapiCredentials.TenantId
|
||||||
|
$env:SDCM_CREDS_CLIENTID = $using:HwapiCredentials.ClientId
|
||||||
|
$env:SDCM_CREDS_KEY = $using:HwapiCredentials.Key
|
||||||
|
$env:SDCM_CREDS_URL = "https://manage.devcenter.microsoft.com"
|
||||||
|
$env:SDCM_CREDS_URLPREFIX = "v2.0/my"
|
||||||
|
& "$using:ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -creds envonly @args
|
||||||
|
} | Receive-Job -Wait -AutoRemoveJob
|
||||||
|
}
|
||||||
|
|
||||||
function Get-FileVersion ($FileName) {
|
function Get-FileVersion ($FileName) {
|
||||||
return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
|
return [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FileName).FileVersion
|
||||||
}
|
}
|
||||||
@ -96,6 +117,12 @@ function Check-Prerequisites {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# check scdm.exe
|
||||||
|
if (!(Get-Command "$ProjectRoot\..\winfsp.sdcm\SurfaceDevCenterManager\bin\Debug\sdcm.exe" -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Stderr "error: cannot find sdcm.exe"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# check gh.exe
|
# check gh.exe
|
||||||
if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
|
if (!(Get-Command "gh.exe" -ErrorAction SilentlyContinue)) {
|
||||||
Write-Stderr "error: cannot find gh.exe"
|
Write-Stderr "error: cannot find gh.exe"
|
||||||
@ -137,6 +164,17 @@ function Check-Prerequisites {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# check hardware dashboard api credentials
|
||||||
|
$script:HwapiCredentials = Get-HwapiCredentials
|
||||||
|
if (!$script:HwapiCredentials) {
|
||||||
|
Write-Stderr "error: cannot get Hardware Dashboard API credentials"
|
||||||
|
Write-Stderr ' The expected format of the credentials is as follows:'
|
||||||
|
Write-Stderr ' TargetName: Hardware Dashboard API'
|
||||||
|
Write-Stderr ' UserName: Credentials'
|
||||||
|
Write-Stderr ' Password: {"TenantId":"TENANTID","ClientId":"CLIENTID","Key":"KEY"}'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
if ($State -contains $Name) {
|
if ($State -contains $Name) {
|
||||||
if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
|
if (!($State -contains "$Tag-$CommitCount-g$Commit")) {
|
||||||
Write-Stderr "error: invalid state for tag $Tag"
|
Write-Stderr "error: invalid state for tag $Tag"
|
||||||
@ -149,6 +187,12 @@ function Check-Prerequisites {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Check-Assets {
|
function Check-Assets {
|
||||||
|
# check driver.cab
|
||||||
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\driver.cab" -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Stderr "error: cannot find driver.cab"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# check winfsp.msi
|
# check winfsp.msi
|
||||||
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi" -ErrorAction SilentlyContinue)) {
|
||||||
Write-Stderr "error: cannot find winfsp*.msi"
|
Write-Stderr "error: cannot find winfsp*.msi"
|
||||||
@ -161,9 +205,15 @@ function Check-Assets {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# check winfsp.net.nupkg
|
||||||
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp.net.*.nupkg" -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Stderr "error: cannot find winfsp.net.*.nupkg"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# check winfsp.nupkg
|
# check winfsp.nupkg
|
||||||
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.nupkg" -ErrorAction SilentlyContinue)) {
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\winfsp.*.nupkg" -ErrorAction SilentlyContinue)) {
|
||||||
Write-Stderr "error: cannot find winfsp*.nupkg"
|
Write-Stderr "error: cannot find winfsp.*.nupkg"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,8 +236,215 @@ function Build-AssetsPhase1 {
|
|||||||
|
|
||||||
Write-Stdout @"
|
Write-Stdout @"
|
||||||
|
|
||||||
Upload file driver.cab to Microsoft Partner Center for attestation signing.
|
Assets have been built but are not properly signed.
|
||||||
When the file has been signed, download and extract to ~\Downloads\drivers
|
Signable assets are ready for submission to the hardware dashboard.
|
||||||
|
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Submit-AssetsToHwapi {
|
||||||
|
Task -ScriptBlock {
|
||||||
|
Check-Assets
|
||||||
|
|
||||||
|
$MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
|
||||||
|
$MsiName = Split-Path -Leaf $MsiFile
|
||||||
|
if ($MsiName -match "winfsp-(.+)\.msi") {
|
||||||
|
$Version = $matches[1]
|
||||||
|
}
|
||||||
|
if (!$Version) {
|
||||||
|
Write-Stderr "error: cannot determine version for winfsp.msi"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$DocRequestedSignatures = @()
|
||||||
|
$Documentation = Invoke-WebRequest -Uri "https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
|
||||||
|
$Documentation = $Documentation.Content
|
||||||
|
$List = $false
|
||||||
|
foreach ($Line in $Documentation -Split "`n") {
|
||||||
|
if ($Line -match "^### List of Operating System Codes") {
|
||||||
|
$List = $true
|
||||||
|
} elseif ($Line -match "^###") {
|
||||||
|
$List = $false
|
||||||
|
} elseif ($List -and $Line -cmatch "\| *(WINDOWS_v100_[^| ]+) *\|") {
|
||||||
|
$DocRequestedSignatures += $matches[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($DocRequestedSignatures.length -lt 32) {
|
||||||
|
Write-Stderr "error: cannot determine signatures to request"
|
||||||
|
Write-Stderr ' Does the document at the URL below still contain a "List of Operating System Codes":'
|
||||||
|
Write-Stderr " https://raw.githubusercontent.com/MicrosoftDocs/windows-driver-docs/staging/windows-driver-docs-pr/dashboard/get-product-data.md"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# start with the base signatures and add any new ones found in the docs
|
||||||
|
$RequestedSignatures = @(
|
||||||
|
"WINDOWS_v100_TH2_FULL"
|
||||||
|
"WINDOWS_v100_X64_TH2_FULL"
|
||||||
|
"WINDOWS_v100_RS1_FULL"
|
||||||
|
"WINDOWS_v100_X64_RS1_FULL"
|
||||||
|
"WINDOWS_v100_RS2_FULL"
|
||||||
|
"WINDOWS_v100_X64_RS2_FULL"
|
||||||
|
"WINDOWS_v100_RS3_FULL"
|
||||||
|
"WINDOWS_v100_X64_RS3_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_RS3_FULL"
|
||||||
|
"WINDOWS_v100_RS4_FULL"
|
||||||
|
"WINDOWS_v100_X64_RS4_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_RS4_FULL"
|
||||||
|
"WINDOWS_v100_RS5_FULL"
|
||||||
|
"WINDOWS_v100_X64_RS5_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_RS5_FULL"
|
||||||
|
"WINDOWS_v100_19H1_FULL"
|
||||||
|
"WINDOWS_v100_X64_19H1_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_19H1_FULL"
|
||||||
|
"WINDOWS_v100_VB_FULL"
|
||||||
|
"WINDOWS_v100_X64_VB_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_VB_FULL"
|
||||||
|
"WINDOWS_v100_X64_CO_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_CO_FULL"
|
||||||
|
"WINDOWS_v100_X64_NI_FULL"
|
||||||
|
"WINDOWS_v100_ARM64_NI_FULL"
|
||||||
|
)
|
||||||
|
foreach ($Signature in $DocRequestedSignatures) {
|
||||||
|
if ($RequestedSignatures -contains $Signature) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ($Signature.Contains("_SERVER_")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ($Signature -eq "WINDOWS_v100_TH1_FULL") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ($Signature -eq "WINDOWS_v100_X64_TH1_FULL") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$RequestedSignatures += $Signature
|
||||||
|
Write-Stdout "New doc signature: $Signature"
|
||||||
|
}
|
||||||
|
|
||||||
|
$CreateProduct = @{
|
||||||
|
createType = "product"
|
||||||
|
createProduct = @{
|
||||||
|
productName = "winfsp-$Version"
|
||||||
|
testHarness = "attestation"
|
||||||
|
deviceType = "internalExternal"
|
||||||
|
requestedSignatures = $RequestedSignatures
|
||||||
|
# deviceMetaDataIds = $null
|
||||||
|
# firmwareVersion = "0"
|
||||||
|
# isTestSign = $false
|
||||||
|
# isFlightSign = $false
|
||||||
|
# markettingNames = $null
|
||||||
|
# selectedProductTypes = $null
|
||||||
|
# additionalAttributes = $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$CreateSubmission = @{
|
||||||
|
createType = "submission"
|
||||||
|
createSubmission = @{
|
||||||
|
name = "winfsp-$Version"
|
||||||
|
type = "initial"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
New-Item "$ProjectRoot\build\VStudio\build\Release\hwapi" -Type Directory -ErrorAction SilentlyContinue >$null
|
||||||
|
ConvertTo-Json $CreateProduct | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json"
|
||||||
|
ConvertTo-Json $CreateSubmission | Out-File -Encoding Ascii "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json"
|
||||||
|
|
||||||
|
Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateProduct.json" | Tee-Object -Variable Output
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
Write-Stderr "error: cannot create product on hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (-not ([string]$Output -match "--- Product: (\d+)")) {
|
||||||
|
Write-Stderr "error: cannot get product id from hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$ProductId = $matches[1]
|
||||||
|
|
||||||
|
Start-Sdcm -create "$ProjectRoot\build\VStudio\build\Release\hwapi\CreateSubmission.json" -productid $ProductId | Tee-Object -Variable Output
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
Write-Stderr "error: cannot create submission on hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (-not ([string]$Output -match "---- Submission: (\d+)")) {
|
||||||
|
Write-Stderr "error: cannot get submission id from hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$SubmissionId = $matches[1]
|
||||||
|
|
||||||
|
Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId" -Value $ProductId
|
||||||
|
Set-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId" -Value $SubmissionId
|
||||||
|
|
||||||
|
Write-Stdout @"
|
||||||
|
|
||||||
|
Product submission has been prepared on hardware dashboard.
|
||||||
|
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Upload-AssetsToHwapi {
|
||||||
|
Task -ScriptBlock {
|
||||||
|
Check-Assets
|
||||||
|
|
||||||
|
$ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
|
||||||
|
$SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
|
||||||
|
|
||||||
|
Start-Sdcm -upload "$ProjectRoot\build\VStudio\build\Release\driver.cab" -productid $ProductId -submissionid $SubmissionId
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
Write-Stderr "error: cannot upload driver.cab to hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Sdcm -commit -productid $ProductId -submissionid $SubmissionId
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
Write-Stderr "error: cannot commit submission to hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Stdout @"
|
||||||
|
|
||||||
|
Signable assets have been uploaded to the hardware dashboard.
|
||||||
|
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Download-AssetsFromHwapi {
|
||||||
|
Task -ScriptBlock {
|
||||||
|
Check-Assets
|
||||||
|
|
||||||
|
$ProductId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\ProductId"
|
||||||
|
$SubmissionId = Get-Content "$ProjectRoot\build\VStudio\build\Release\hwapi\SubmissionId"
|
||||||
|
|
||||||
|
Remove-Item -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Recurse -Force "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
Start-Sdcm -download "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -productid $ProductId -submissionid $SubmissionId
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
Write-Stderr "error: cannot download signed drivers from hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Stderr "error: cannot download signed drivers from hardware dashboard"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$ExpandError = ""
|
||||||
|
Expand-Archive "$ProjectRoot\build\VStudio\build\Release\hwapi\Signed-$SubmissionId.zip" -DestinationPath "$ProjectRoot\build\VStudio\build\Release\hwapi" -ErrorVariable ExpandError
|
||||||
|
if ($ExpandError) {
|
||||||
|
Write-Stderr "error: cannot expand signed drivers archive"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Stderr "error: cannot expand signed drivers archive"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Stdout @"
|
||||||
|
|
||||||
|
Signable assets have been downloaded and can be used to complete the build.
|
||||||
|
|
||||||
"@
|
"@
|
||||||
}
|
}
|
||||||
@ -198,16 +455,16 @@ function Build-AssetsPhase2 {
|
|||||||
Check-Assets
|
Check-Assets
|
||||||
|
|
||||||
# check signed drivers folder
|
# check signed drivers folder
|
||||||
if (!(Test-Path ~\Downloads\drivers -ErrorAction SilentlyContinue)) {
|
if (!(Test-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers" -ErrorAction SilentlyContinue)) {
|
||||||
Write-Stderr "error: cannot find ~\Downloads\drivers"
|
Write-Stderr "error: cannot find hwapi\drivers"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
$SignedPackage = Resolve-Path ~\Downloads\drivers
|
$SignedPackage = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\hwapi\drivers"
|
||||||
|
|
||||||
$VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys"
|
$VerX64 = Get-FileVersion "$ProjectRoot\build\VStudio\build\Release\winfsp-x64.sys"
|
||||||
if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) {
|
if ($VerX64 -ne (Get-FileVersion "$SignedPackage\x64\winfsp-x64.sys")) {
|
||||||
Write-Stderr "error: incompatible versions in ~\Downloads\drivers"
|
Write-Stderr "error: incompatible versions in hwapi\drivers"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +488,6 @@ function Make-GitHubRelease {
|
|||||||
Task -ScriptBlock {
|
Task -ScriptBlock {
|
||||||
Check-Assets
|
Check-Assets
|
||||||
|
|
||||||
if ((Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi") -match "\\winfsp-(.+)\.msi") {
|
|
||||||
$Version = $matches[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
$DownloadColor = "blue"
|
$DownloadColor = "blue"
|
||||||
$PrereleaseOpt = ""
|
$PrereleaseOpt = ""
|
||||||
if ($ReleaseInfo.Prerelease) {
|
if ($ReleaseInfo.Prerelease) {
|
||||||
@ -242,16 +495,34 @@ function Make-GitHubRelease {
|
|||||||
$PrereleaseOpt = "-p"
|
$PrereleaseOpt = "-p"
|
||||||
}
|
}
|
||||||
|
|
||||||
$ReleaseNotes = @"
|
$MsiFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi"
|
||||||
[](https://github.com/billziss-gh/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
|
$ZipFile = Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip"
|
||||||
|
$MsiName = Split-Path -Leaf $MsiFile
|
||||||
|
$ZipName = Split-Path -Leaf $ZipFile
|
||||||
|
$MsiHash = (Get-FileHash -Algorithm SHA256 $MsiFile).Hash
|
||||||
|
$ZipHash = (Get-FileHash -Algorithm SHA256 $ZipFile).Hash
|
||||||
|
|
||||||
[VirusTotal Scan Results]()
|
if ($MsiName -match "winfsp-(.+)\.msi") {
|
||||||
|
$Version = $matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
$ReleaseNotes = @"
|
||||||
|
[](https://github.com/winfsp/winfsp/releases/download/$($ReleaseInfo.Tag)/winfsp-$Version.msi)
|
||||||
|
|
||||||
## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion)
|
## CHANGES SINCE WINFSP $($ReleaseInfo.PreviousProductVersion)
|
||||||
$($ReleaseInfo.Text -join "`n")
|
$($ReleaseInfo.Text -join "`n")
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<b>BUILD HASHES (SHA256)</b>
|
||||||
|
<p/>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
- **``$MsiName``**: $MsiHash
|
||||||
|
- **``$ZipName``**: $ZipHash
|
||||||
|
</details>
|
||||||
"@
|
"@
|
||||||
|
|
||||||
gh release create $ReleaseInfo.Tag --draft --title "WinFsp $($ReleaseInfo.ProductVersion)" --notes "$ReleaseNotes" $PrereleaseOpt (Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp*.msi") (Resolve-Path "$ProjectRoot\build\VStudio\build\Release\winfsp-tests*.zip")
|
gh release create $ReleaseInfo.Tag --draft --title "WinFsp $($ReleaseInfo.ProductVersion)" --notes "$ReleaseNotes" $PrereleaseOpt $MsiFile $ZipFile
|
||||||
if ($LastExitCode -ne 0) {
|
if ($LastExitCode -ne 0) {
|
||||||
Write-Stderr "error: cannot create GitHub release"
|
Write-Stderr "error: cannot create GitHub release"
|
||||||
exit 1
|
exit 1
|
||||||
@ -305,12 +576,32 @@ Push the winfsp.sym repository to GitHub.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Make-NugetRelease {
|
||||||
|
Task -ScriptBlock {
|
||||||
|
Check-Assets
|
||||||
|
|
||||||
|
Push-Location "$ProjectRoot\build\VStudio\build\Release"
|
||||||
|
nuget push (Resolve-Path winfsp.net.[0-9]*.nupkg) -Source https://api.nuget.org/v3/index.json
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
Write-Stderr "error: cannot push to Nuget"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Pop-Location
|
||||||
|
|
||||||
|
Write-Stdout @"
|
||||||
|
|
||||||
|
Nuget release for $($ReleaseInfo.Tag) has been pushed.
|
||||||
|
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Make-ChocoRelease {
|
function Make-ChocoRelease {
|
||||||
Task -ScriptBlock {
|
Task -ScriptBlock {
|
||||||
Check-Assets
|
Check-Assets
|
||||||
|
|
||||||
Push-Location "$ProjectRoot\build\VStudio\build\Release"
|
Push-Location "$ProjectRoot\build\VStudio\build\Release"
|
||||||
choco push
|
choco push (Resolve-Path winfsp.[0-9]*.nupkg)
|
||||||
if ($LastExitCode -ne 0) {
|
if ($LastExitCode -ne 0) {
|
||||||
Write-Stderr "error: cannot push to Chocolatey"
|
Write-Stderr "error: cannot push to Chocolatey"
|
||||||
exit 1
|
exit 1
|
||||||
@ -335,7 +626,12 @@ Check-Prerequisites
|
|||||||
|
|
||||||
# Workflow tasks
|
# Workflow tasks
|
||||||
Build-AssetsPhase1
|
Build-AssetsPhase1
|
||||||
|
Submit-AssetsToHwapi
|
||||||
|
Upload-AssetsToHwapi
|
||||||
|
Download-AssetsFromHwapi
|
||||||
Build-AssetsPhase2
|
Build-AssetsPhase2
|
||||||
Make-GitHubRelease
|
Make-GitHubRelease
|
||||||
Upload-Symbols
|
Upload-Symbols
|
||||||
|
Make-NugetRelease
|
||||||
Make-ChocoRelease
|
Make-ChocoRelease
|
||||||
|
Write-Stdout "ALL COMPLETE"
|
||||||
|
124
tools/wincred.ps1
Normal file
124
tools/wincred.ps1
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
Start-Job -ArgumentList $args -ScriptBlock {
|
||||||
|
param (
|
||||||
|
[ValidateSet("get", "set", "del")]
|
||||||
|
[string]$Command
|
||||||
|
)
|
||||||
|
|
||||||
|
Add-Type -TypeDefinition @"
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
namespace Win32
|
||||||
|
{
|
||||||
|
public class Api
|
||||||
|
{
|
||||||
|
public static String[] CredRead(
|
||||||
|
String TargetName)
|
||||||
|
{
|
||||||
|
String[] Result = null;
|
||||||
|
IntPtr CredentialPtr;
|
||||||
|
if (CredReadW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0, out CredentialPtr))
|
||||||
|
{
|
||||||
|
CREDENTIALW Credential = Marshal.PtrToStructure<CREDENTIALW>(CredentialPtr);
|
||||||
|
Result = new String[2]{
|
||||||
|
Credential.UserName,
|
||||||
|
Marshal.PtrToStringUni(
|
||||||
|
Credential.CredentialBlob, (int)Credential.CredentialBlobSize / 2)
|
||||||
|
};
|
||||||
|
CredFree(CredentialPtr);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
public static Boolean CredWrite(
|
||||||
|
String TargetName,
|
||||||
|
String UserName,
|
||||||
|
String Password)
|
||||||
|
{
|
||||||
|
CREDENTIALW Credential = new CREDENTIALW{
|
||||||
|
Type = 1/*CRED_TYPE_GENERIC*/,
|
||||||
|
Persist = 2/*CRED_PERSIST_LOCAL_MACHINE*/,
|
||||||
|
TargetName = TargetName,
|
||||||
|
UserName = UserName,
|
||||||
|
CredentialBlobSize = (UInt32)Password.Length * 2,
|
||||||
|
CredentialBlob = Marshal.StringToCoTaskMemUni(Password),
|
||||||
|
};
|
||||||
|
Boolean Result = CredWriteW(ref Credential, 0);
|
||||||
|
Marshal.FreeCoTaskMem(Credential.CredentialBlob);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
public static Boolean CredDelete(
|
||||||
|
String TargetName)
|
||||||
|
{
|
||||||
|
return CredDeleteW(TargetName, 1/*CRED_TYPE_GENERIC*/, 0);
|
||||||
|
}
|
||||||
|
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
private static extern Boolean CredReadW(
|
||||||
|
String TargetName,
|
||||||
|
UInt32 Type,
|
||||||
|
UInt32 Flags,
|
||||||
|
out IntPtr Credential);
|
||||||
|
[DllImport("advapi32.dll")]
|
||||||
|
private static extern void CredFree(
|
||||||
|
IntPtr Buffer);
|
||||||
|
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
private static extern Boolean CredWriteW(
|
||||||
|
ref CREDENTIALW Credential,
|
||||||
|
UInt32 Flags);
|
||||||
|
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
private static extern Boolean CredDeleteW(
|
||||||
|
String TargetName,
|
||||||
|
UInt32 Type,
|
||||||
|
UInt32 Flags);
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
private struct CREDENTIALW
|
||||||
|
{
|
||||||
|
public UInt32 Flags;
|
||||||
|
public UInt32 Type;
|
||||||
|
public String TargetName;
|
||||||
|
public String Comment;
|
||||||
|
public UInt64 LastWritten;
|
||||||
|
public UInt32 CredentialBlobSize;
|
||||||
|
public IntPtr CredentialBlob;
|
||||||
|
public UInt32 Persist;
|
||||||
|
public UInt32 AttributeCount;
|
||||||
|
public IntPtr Attributes;
|
||||||
|
public String TargetAlias;
|
||||||
|
public String UserName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"@
|
||||||
|
|
||||||
|
function Get-WindowsCredential {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory)][string]$TargetName
|
||||||
|
)
|
||||||
|
return [Win32.Api]::CredRead($TargetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-WindowsCredential {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory)][string]$TargetName,
|
||||||
|
[Parameter(Mandatory)][string]$UserName,
|
||||||
|
[Parameter(Mandatory)][string]$Password
|
||||||
|
)
|
||||||
|
return [Win32.Api]::CredWrite($TargetName, $UserName, $Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Delete-WindowsCredential {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory)][string]$TargetName
|
||||||
|
)
|
||||||
|
return [Win32.Api]::CredDelete($TargetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
$Function = @{
|
||||||
|
"get" = "Get-WindowsCredential"
|
||||||
|
"set" = "Set-WindowsCredential"
|
||||||
|
"del" = "Delete-WindowsCredential"
|
||||||
|
}[$Command]
|
||||||
|
& $Function @args
|
||||||
|
|
||||||
|
} | Receive-Job -Wait -AutoRemoveJob
|
@ -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
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ enum
|
|||||||
MemfsCaseInsensitive = 0x80000000,
|
MemfsCaseInsensitive = 0x80000000,
|
||||||
MemfsFlushAndPurgeOnCleanup = 0x40000000,
|
MemfsFlushAndPurgeOnCleanup = 0x40000000,
|
||||||
MemfsLegacyUnlinkRename = 0x20000000,
|
MemfsLegacyUnlinkRename = 0x20000000,
|
||||||
|
MemfsNoSlowio = 0x10000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
|
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
|
||||||
|
@ -1143,6 +1143,12 @@ exit:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VOID DispatcherStopped(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
BOOLEAN Normally)
|
||||||
|
{
|
||||||
|
FspFileSystemStopServiceIfNecessary(FileSystem, Normally);
|
||||||
|
}
|
||||||
|
|
||||||
static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
|
static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
|
||||||
{
|
{
|
||||||
.GetVolumeInfo = GetVolumeInfo,
|
.GetVolumeInfo = GetVolumeInfo,
|
||||||
@ -1171,6 +1177,7 @@ static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
|
|||||||
.GetStreamInfo = GetStreamInfo,
|
.GetStreamInfo = GetStreamInfo,
|
||||||
.GetEa = GetEa,
|
.GetEa = GetEa,
|
||||||
.SetEa = SetEa,
|
.SetEa = SetEa,
|
||||||
|
.DispatcherStopped = DispatcherStopped,
|
||||||
};
|
};
|
||||||
|
|
||||||
NTSTATUS PtfsCreate(
|
NTSTATUS PtfsCreate(
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
|
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
|
||||||
|
|
||||||
#define ptfs_impl_fullpath(n) \
|
#define ptfs_impl_fullpath(n) \
|
||||||
char full ## n[PATH_MAX]; \
|
char full ## n[PATH_MAX * 4]; \
|
||||||
if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
|
if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
|
||||||
return -ENAMETOOLONG; \
|
return -ENAMETOOLONG; \
|
||||||
n = full ## n
|
n = full ## n
|
||||||
|
@ -129,15 +129,50 @@ char *realpath(const char *path, char *resolved)
|
|||||||
result = resolved;
|
result = resolved;
|
||||||
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
|
WCHAR PathBuf[PATH_MAX];
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,52 @@
|
|||||||
|
|
||||||
#include "winfsp-tests.h"
|
#include "winfsp-tests.h"
|
||||||
|
|
||||||
|
typedef struct _FILE_FULL_DIR_INFORMATION
|
||||||
|
{
|
||||||
|
ULONG NextEntryOffset;
|
||||||
|
ULONG FileIndex;
|
||||||
|
LARGE_INTEGER CreationTime;
|
||||||
|
LARGE_INTEGER LastAccessTime;
|
||||||
|
LARGE_INTEGER LastWriteTime;
|
||||||
|
LARGE_INTEGER ChangeTime;
|
||||||
|
LARGE_INTEGER EndOfFile;
|
||||||
|
LARGE_INTEGER AllocationSize;
|
||||||
|
ULONG FileAttributes;
|
||||||
|
ULONG FileNameLength;
|
||||||
|
ULONG EaSize;
|
||||||
|
WCHAR FileName[1];
|
||||||
|
} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _FILE_DIRECTORY_INFORMATION
|
||||||
|
{
|
||||||
|
ULONG NextEntryOffset;
|
||||||
|
ULONG FileIndex;
|
||||||
|
LARGE_INTEGER CreationTime;
|
||||||
|
LARGE_INTEGER LastAccessTime;
|
||||||
|
LARGE_INTEGER LastWriteTime;
|
||||||
|
LARGE_INTEGER ChangeTime;
|
||||||
|
LARGE_INTEGER EndOfFile;
|
||||||
|
LARGE_INTEGER AllocationSize;
|
||||||
|
ULONG FileAttributes;
|
||||||
|
ULONG FileNameLength;
|
||||||
|
WCHAR FileName[1];
|
||||||
|
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtQueryDirectoryFile (
|
||||||
|
HANDLE FileHandle,
|
||||||
|
HANDLE Event,
|
||||||
|
PIO_APC_ROUTINE ApcRoutine,
|
||||||
|
PVOID ApcContext,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
PVOID FileInformation,
|
||||||
|
ULONG Length,
|
||||||
|
FILE_INFORMATION_CLASS FileInformationClass,
|
||||||
|
BOOLEAN ReturnSingleEntry,
|
||||||
|
PUNICODE_STRING FileName,
|
||||||
|
BOOLEAN RestartScan);
|
||||||
|
|
||||||
static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
|
static void querydir_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
|
||||||
{
|
{
|
||||||
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||||
@ -269,6 +315,212 @@ void querydir_test(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline size_t hash_chars(const wchar_t *s, size_t length)
|
||||||
|
{
|
||||||
|
/* djb2: see http://www.cse.yorku.ca/~oz/hash.html */
|
||||||
|
size_t h = 5381;
|
||||||
|
for (const wchar_t *t = s + length; t > s; ++s)
|
||||||
|
h = 33 * h + *s;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
static NTSTATUS querydir_nodup_dotest_thread_loop(void *FilePath)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
void *Buffer = 0;
|
||||||
|
HANDLE Handle = INVALID_HANDLE_VALUE;
|
||||||
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
size_t hash[64], hash_count = 0;
|
||||||
|
|
||||||
|
Buffer = malloc(4096);
|
||||||
|
if (0 == Buffer)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle = CreateFileW(
|
||||||
|
FilePath,
|
||||||
|
FILE_LIST_DIRECTORY,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
0,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
|
0);
|
||||||
|
if (INVALID_HANDLE_VALUE == Handle)
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
Result = NtQueryDirectoryFile(
|
||||||
|
Handle,
|
||||||
|
0, 0, 0,
|
||||||
|
&IoStatus,
|
||||||
|
Buffer,
|
||||||
|
4096,
|
||||||
|
2/*FileFullDirectoryInformation*/,
|
||||||
|
FALSE,
|
||||||
|
0,
|
||||||
|
FALSE);
|
||||||
|
if (STATUS_NO_MORE_FILES == Result)
|
||||||
|
break;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
for (FILE_FULL_DIR_INFORMATION *DirInfo = Buffer;;
|
||||||
|
DirInfo = (PVOID)((PUINT8)DirInfo + DirInfo->NextEntryOffset))
|
||||||
|
{
|
||||||
|
size_t h = hash_chars(DirInfo->FileName, DirInfo->FileNameLength / sizeof(WCHAR));
|
||||||
|
for (size_t i = 0; hash_count > i; i++)
|
||||||
|
if (hash[i] == h)
|
||||||
|
{
|
||||||
|
WCHAR FileName[256];
|
||||||
|
memcpy(FileName, DirInfo->FileName, DirInfo->FileNameLength);
|
||||||
|
FileName[DirInfo->FileNameLength / sizeof(WCHAR)] = L'\0';
|
||||||
|
FspDebugLog(__FUNCTION__ ": duplicate \"%S\"\n", FileName);
|
||||||
|
Result = STATUS_UNSUCCESSFUL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (sizeof hash / sizeof hash[0] > hash_count)
|
||||||
|
hash[hash_count++] = h;
|
||||||
|
if (0 == DirInfo->NextEntryOffset)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (INVALID_HANDLE_VALUE != Handle)
|
||||||
|
CloseHandle(Handle);
|
||||||
|
|
||||||
|
free(Buffer);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
static unsigned __stdcall querydir_nodup_dotest_thread(void *FilePath)
|
||||||
|
{
|
||||||
|
FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
for (size_t i = 0; 5000 > i; i++)
|
||||||
|
{
|
||||||
|
Result = querydir_nodup_dotest_thread_loop(FilePath);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void querydir_nodup_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
||||||
|
{
|
||||||
|
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||||
|
|
||||||
|
static WCHAR *FileNames[] =
|
||||||
|
{
|
||||||
|
L"Extensions.cs",
|
||||||
|
L"JsonSchema.cs",
|
||||||
|
L"JsonSchemaBuilder.cs",
|
||||||
|
L"JsonSchemaConstants.cs",
|
||||||
|
L"JsonSchemaException.cs",
|
||||||
|
L"JsonSchemaGenerator.cs",
|
||||||
|
L"JsonSchemaModel.cs",
|
||||||
|
L"JsonSchemaModelBuilder.cs",
|
||||||
|
L"JsonSchemaNode.cs",
|
||||||
|
L"JsonSchemaNodeCollection.cs",
|
||||||
|
L"JsonSchemaResolver.cs",
|
||||||
|
L"JsonSchemaType.cs",
|
||||||
|
L"JsonSchemaWriter.cs",
|
||||||
|
L"UndefinedSchemaIdHandling.cs",
|
||||||
|
L"ValidationEventArgs.cs",
|
||||||
|
L"ValidationEventHandler.cs",
|
||||||
|
};
|
||||||
|
HANDLE Handle;
|
||||||
|
BOOL Success;
|
||||||
|
WCHAR FilePath[MAX_PATH];
|
||||||
|
HANDLE Threads[2];
|
||||||
|
DWORD ExitCode;
|
||||||
|
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
Success = CreateDirectoryW(FilePath, 0);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
for (size_t i = 0; sizeof FileNames / sizeof FileNames[0] > i; i++)
|
||||||
|
{
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\%s",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), FileNames[i]);
|
||||||
|
Handle = CreateFileW(FilePath, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||||
|
Success = CloseHandle(Handle);
|
||||||
|
ASSERT(Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
for (size_t i = 0; sizeof Threads / sizeof Threads[0] > i; i++)
|
||||||
|
{
|
||||||
|
Threads[i] = (HANDLE)_beginthreadex(0, 0, querydir_nodup_dotest_thread, FilePath, 0, 0);
|
||||||
|
ASSERT(0 != Threads[i]);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; sizeof Threads / sizeof Threads[0] > i; i++)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(Threads[i], INFINITE);
|
||||||
|
GetExitCodeThread(Threads[i], &ExitCode);
|
||||||
|
CloseHandle(Threads[i]);
|
||||||
|
ASSERT(0 == ExitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; sizeof FileNames / sizeof FileNames[0] > i; i++)
|
||||||
|
{
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\%s",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), FileNames[i]);
|
||||||
|
Success = DeleteFileW(FilePath);
|
||||||
|
ASSERT(Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
Success = RemoveDirectoryW(FilePath);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
memfs_stop(memfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void querydir_nodup_test(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Test GitHub issue #475. Credit for the investigation and reproduction
|
||||||
|
* of this issue goes to GitHub user @hach-que.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (NtfsTests)
|
||||||
|
{
|
||||||
|
WCHAR DirBuf[MAX_PATH];
|
||||||
|
GetTestDirectory(DirBuf);
|
||||||
|
querydir_nodup_dotest(-1, DirBuf, 0);
|
||||||
|
}
|
||||||
|
if (WinFspDiskTests)
|
||||||
|
{
|
||||||
|
querydir_nodup_dotest(MemfsDisk | MemfsNoSlowio, 0, 0);
|
||||||
|
querydir_nodup_dotest(MemfsDisk | MemfsNoSlowio, 0, 1000);
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
if (WinFspNetTests)
|
||||||
|
{
|
||||||
|
querydir_nodup_dotest(MemfsNet | MemfsNoSlowio, L"\\\\memfs\\share", 0);
|
||||||
|
querydir_nodup_dotest(MemfsNet | MemfsNoSlowio, L"\\\\memfs\\share", 1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
|
static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
|
||||||
{
|
{
|
||||||
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||||
@ -368,36 +620,6 @@ void querydir_expire_cache_test(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _FILE_DIRECTORY_INFORMATION {
|
|
||||||
ULONG NextEntryOffset;
|
|
||||||
ULONG FileIndex;
|
|
||||||
LARGE_INTEGER CreationTime;
|
|
||||||
LARGE_INTEGER LastAccessTime;
|
|
||||||
LARGE_INTEGER LastWriteTime;
|
|
||||||
LARGE_INTEGER ChangeTime;
|
|
||||||
LARGE_INTEGER EndOfFile;
|
|
||||||
LARGE_INTEGER AllocationSize;
|
|
||||||
ULONG FileAttributes;
|
|
||||||
ULONG FileNameLength;
|
|
||||||
WCHAR FileName[1];
|
|
||||||
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtQueryDirectoryFile (
|
|
||||||
_In_ HANDLE FileHandle,
|
|
||||||
_In_opt_ HANDLE Event,
|
|
||||||
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
|
|
||||||
_In_opt_ PVOID ApcContext,
|
|
||||||
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
|
|
||||||
_Out_writes_bytes_(Length) PVOID FileInformation,
|
|
||||||
_In_ ULONG Length,
|
|
||||||
_In_ FILE_INFORMATION_CLASS FileInformationClass,
|
|
||||||
_In_ BOOLEAN ReturnSingleEntry,
|
|
||||||
_In_opt_ PUNICODE_STRING FileName,
|
|
||||||
_In_ BOOLEAN RestartScan
|
|
||||||
);
|
|
||||||
|
|
||||||
static void querydir_buffer_overflow_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
|
static void querydir_buffer_overflow_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
|
||||||
{
|
{
|
||||||
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||||
@ -576,6 +798,40 @@ static void querydir_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
|
|||||||
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||||
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
||||||
|
|
||||||
|
for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
|
||||||
|
*P = (P - FilePathBgn) % 10 + 0x3041;
|
||||||
|
*P = L'\0';
|
||||||
|
|
||||||
|
Handle = CreateFileW(FilePath,
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||||
|
querydir_namelen_exists(FilePath);
|
||||||
|
Success = CloseHandle(Handle);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
|
||||||
|
*P = (P - FilePathBgn) % 10 + 0x3041;
|
||||||
|
*P = L'\0';
|
||||||
|
|
||||||
|
Handle = CreateFileW(FilePath,
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||||
|
querydir_namelen_exists(FilePath);
|
||||||
|
Success = CloseHandle(Handle);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
|
||||||
|
*P = (P - FilePathBgn) % 10 + 0x3041;
|
||||||
|
*P = L'\0';
|
||||||
|
|
||||||
|
Handle = CreateFileW(FilePath,
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||||
|
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
||||||
|
|
||||||
memfs_stop(memfs);
|
memfs_stop(memfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -732,6 +988,7 @@ void dirnotify_test(void)
|
|||||||
void dirctl_tests(void)
|
void dirctl_tests(void)
|
||||||
{
|
{
|
||||||
TEST(querydir_test);
|
TEST(querydir_test);
|
||||||
|
TEST_OPT(querydir_nodup_test);
|
||||||
if (!OptShareName)
|
if (!OptShareName)
|
||||||
TEST_OPT(querydir_single_test);
|
TEST_OPT(querydir_single_test);
|
||||||
TEST(querydir_expire_cache_test);
|
TEST(querydir_expire_cache_test);
|
||||||
|
@ -273,6 +273,28 @@ void getfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
|||||||
ASSERT(0 == FileInfo.nFileSizeLow && 0 == FileInfo.nFileSizeHigh);
|
ASSERT(0 == FileInfo.nFileSizeLow && 0 == FileInfo.nFileSizeHigh);
|
||||||
ASSERT(1 == FileInfo.nNumberOfLinks);
|
ASSERT(1 == FileInfo.nNumberOfLinks);
|
||||||
|
|
||||||
|
if (-1 != Flags)
|
||||||
|
{
|
||||||
|
/* WinFsp file systems respond to FileIdInformation queries with the IndexNumber zero-extended */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* FILE_ID_INFO is missing from old version of SDK that we are still using */
|
||||||
|
ULONGLONG VolumeSerialNumber;
|
||||||
|
UINT8 FileId[16];
|
||||||
|
} IdInfo;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
UINT64 IndexNumber;
|
||||||
|
UINT8 FileId[16];
|
||||||
|
} ExpectedFileId = { 0 };
|
||||||
|
Success = GetFileInformationByHandleEx(Handle, 0x12/*FileIdInfo*/, &IdInfo, sizeof IdInfo);
|
||||||
|
if (Success)
|
||||||
|
{
|
||||||
|
ExpectedFileId.IndexNumber = ((UINT64)FileInfo.nFileIndexHigh << 32) | (UINT64)FileInfo.nFileIndexLow;
|
||||||
|
ASSERT(0 == memcmp(&ExpectedFileId.FileId, &IdInfo.FileId, sizeof IdInfo.FileId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(Handle);
|
CloseHandle(Handle);
|
||||||
|
|
||||||
memfs_stop(memfs);
|
memfs_stop(memfs);
|
||||||
|
@ -48,9 +48,9 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
|
|||||||
FileInfoTimeout,
|
FileInfoTimeout,
|
||||||
1024,
|
1024,
|
||||||
1024 * 1024,
|
1024 * 1024,
|
||||||
50, /*SlowioMaxDelay*/
|
(Flags & MemfsNoSlowio) ? 0 : 50, /*SlowioMaxDelay*/
|
||||||
10, /*SlowioPercentDelay*/
|
(Flags & MemfsNoSlowio) ? 0 : 10, /*SlowioPercentDelay*/
|
||||||
5, /*SlowioRarefyDelay*/
|
(Flags & MemfsNoSlowio) ? 0 : 5, /*SlowioRarefyDelay*/
|
||||||
0,
|
0,
|
||||||
MemfsNet == Flags ? L"\\memfs\\share" : 0,
|
MemfsNet == Flags ? L"\\memfs\\share" : 0,
|
||||||
0,
|
0,
|
||||||
|
Reference in New Issue
Block a user