mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
d824ba464d | |||
affca267c5 | |||
4b7684122b | |||
55eee2efdd | |||
f8a05eae95 | |||
9a4f04f46a | |||
98334208b9 | |||
aae0a5bc74 | |||
2438ece1cf | |||
487d2449fe | |||
6430b386da | |||
c70089a176 | |||
0dff9a4c07 | |||
86c0ffa942 | |||
5c613b2abd | |||
8a099f3faa | |||
1ac172d2f8 | |||
34546def3c | |||
3ede1a5c70 | |||
5194536ec3 | |||
c39bc81299 | |||
18bf6ca666 | |||
7eebdbd74e | |||
9a88791f61 | |||
6e578350f4 | |||
81afac9c3a | |||
10081e1a69 | |||
8e5c40bbbe | |||
7745bf4cdc | |||
c7a779fa98 | |||
3f90d60dc4 | |||
f73cbc0e37 | |||
c88a86f7c7 | |||
dbdbdf07cf | |||
6b2dcaef96 | |||
fcae6ce018 | |||
690d3e4c8e | |||
af37424ecc | |||
fd53e22f7e | |||
3df0fa02ba | |||
9484b50cbd | |||
14e6b402fe | |||
2227429d8e | |||
9deb9d5319 | |||
193d5f4e91 | |||
26485ffbd6 | |||
7302b4baea | |||
fc1586eb82 | |||
637f461a65 | |||
b35bf204db | |||
3073646f29 | |||
7f9f55de24 |
@ -1,6 +1,13 @@
|
|||||||
= Changelog
|
= Changelog
|
||||||
|
|
||||||
|
|
||||||
|
v1.2B1 (2017.2 B1)::
|
||||||
|
|
||||||
|
- New command line tool `fsptool` allows command line access to some WinFsp features.
|
||||||
|
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW("foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS.
|
||||||
|
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls.
|
||||||
|
|
||||||
|
|
||||||
v1.1 (2017.1)::
|
v1.1 (2017.1)::
|
||||||
|
|
||||||
This release brings some major new components and improvements.
|
This release brings some major new components and improvements.
|
||||||
|
@ -56,4 +56,5 @@ CONTRIBUTOR LIST
|
|||||||
|===
|
|===
|
||||||
|Bill Zissimopoulos |billziss at navimatics.com
|
|Bill Zissimopoulos |billziss at navimatics.com
|
||||||
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|
||||||
|
|Tobias Urlaub |saibotu at outlook.de
|
||||||
|===
|
|===
|
||||||
|
@ -158,6 +158,13 @@
|
|||||||
<File Name="launchctl-x86.exe" KeyPath="yes" />
|
<File Name="launchctl-x86.exe" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
|
|
||||||
|
<Component Id="C.fsptool_x64.exe" Guid="013FE508-097D-4433-9C60-717F5446E7F4">
|
||||||
|
<File Name="fsptool-x64.exe" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.fsptool_x86.exe" Guid="6C16DC2C-E12F-49FB-A665-3AF0475487AD">
|
||||||
|
<File Name="fsptool-x86.exe" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
|
||||||
<Component Id="C.diag.bat">
|
<Component Id="C.diag.bat">
|
||||||
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
|
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
@ -303,12 +310,12 @@
|
|||||||
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
|
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
|
||||||
<Directory Id="OPTDIR.cygfuse.x64" Name="x64">
|
<Directory Id="OPTDIR.cygfuse.x64" Name="x64">
|
||||||
<Component Id="C.fuse.tar.xz.x64">
|
<Component Id="C.fuse.tar.xz.x64">
|
||||||
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-5.tar.xz" KeyPath="yes" />
|
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-6.tar.xz" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory Id="OPTDIR.cygfuse.x86" Name="x86">
|
<Directory Id="OPTDIR.cygfuse.x86" Name="x86">
|
||||||
<Component Id="C.fuse.tar.xz.x86">
|
<Component Id="C.fuse.tar.xz.x86">
|
||||||
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-5.tar.xz" KeyPath="yes" />
|
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-6.tar.xz" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
</Directory>
|
</Directory>
|
||||||
<Component Id="C.fuse.install.sh">
|
<Component Id="C.fuse.install.sh">
|
||||||
@ -427,6 +434,12 @@
|
|||||||
<Component Id="C.launchctl_x86.pdb">
|
<Component Id="C.launchctl_x86.pdb">
|
||||||
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
|
<File Name="launchctl-x86.pdb" Source="..\build\$(var.Configuration)\launchctl-x86.public.pdb" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component Id="C.fsptool_x64.pdb">
|
||||||
|
<File Name="fsptool-x64.pdb" Source="..\build\$(var.Configuration)\fsptool-x64.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="C.fsptool_x86.pdb">
|
||||||
|
<File Name="fsptool-x86.pdb" Source="..\build\$(var.Configuration)\fsptool-x86.public.pdb" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
<Component Id="C.memfs_x64.pdb">
|
<Component Id="C.memfs_x64.pdb">
|
||||||
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
|
<File Name="memfs-x64.pdb" Source="..\build\$(var.Configuration)\memfs-x64.public.pdb" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
@ -448,6 +461,8 @@
|
|||||||
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
|
<ComponentRef Id="C.launcher_x86.exe.svcinst" />
|
||||||
<ComponentRef Id="C.launchctl_x64.exe" />
|
<ComponentRef Id="C.launchctl_x64.exe" />
|
||||||
<ComponentRef Id="C.launchctl_x86.exe" />
|
<ComponentRef Id="C.launchctl_x86.exe" />
|
||||||
|
<ComponentRef Id="C.fsptool_x64.exe" />
|
||||||
|
<ComponentRef Id="C.fsptool_x86.exe" />
|
||||||
<ComponentRef Id="C.diag.bat" />
|
<ComponentRef Id="C.diag.bat" />
|
||||||
<ComponentRef Id="C.fsreg.bat" />
|
<ComponentRef Id="C.fsreg.bat" />
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
@ -504,6 +519,8 @@
|
|||||||
<ComponentRef Id="C.launcher_x64.pdb" />
|
<ComponentRef Id="C.launcher_x64.pdb" />
|
||||||
<ComponentRef Id="C.launchctl_x64.pdb" />
|
<ComponentRef Id="C.launchctl_x64.pdb" />
|
||||||
<ComponentRef Id="C.launchctl_x86.pdb" />
|
<ComponentRef Id="C.launchctl_x86.pdb" />
|
||||||
|
<ComponentRef Id="C.fsptool_x64.pdb" />
|
||||||
|
<ComponentRef Id="C.fsptool_x86.pdb" />
|
||||||
<ComponentRef Id="C.memfs_x64.pdb" />
|
<ComponentRef Id="C.memfs_x64.pdb" />
|
||||||
<ComponentRef Id="C.memfs_x86.pdb" />
|
<ComponentRef Id="C.memfs_x86.pdb" />
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
|
193
build/VStudio/tools/fsptool.vcxproj
Normal file
193
build/VStudio/tools/fsptool.vcxproj
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\version.properties" />
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{1E997BEC-1642-4A5C-B252-852DA094E11E}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>fsptool</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\inc</AdditionalIncludeDirectories>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
|
<StripPrivateSymbols>$(OutDir)$(TargetName).public.pdb</StripPrivateSymbols>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\winfsp_dll.vcxproj">
|
||||||
|
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\fsptool\fsptool.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="..\..\..\src\fsptool\fsptool-version.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
23
build/VStudio/tools/fsptool.vcxproj.filters
Normal file
23
build/VStudio/tools/fsptool.vcxproj.filters
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Include">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\fsptool\fsptool.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="..\..\..\src\fsptool\fsptool-version.rc">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -20,7 +20,7 @@
|
|||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{73EAAEDA-557B-48D5-A137-328934720FB4}</ProjectGuid>
|
<ProjectGuid>{264A5D09-126F-4760-A3F1-4B3B95C925AA}</ProjectGuid>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>launchctl</RootNamespace>
|
<RootNamespace>launchctl</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
@ -20,7 +20,7 @@
|
|||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{A5EFD487-0140-4184-8C54-FFAEC2F85E35}</ProjectGuid>
|
<ProjectGuid>{6CDF9411-B852-4EAC-822D-8F930675F17B}</ProjectGuid>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>launcher</RootNamespace>
|
<RootNamespace>launcher</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
@ -7,7 +7,8 @@
|
|||||||
<!-- git revision -->
|
<!-- git revision -->
|
||||||
<MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot>
|
<MyGitRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .git/HEAD))</MyGitRoot>
|
||||||
<MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
|
<MyGitHead>$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/HEAD).Trim())</MyGitHead>
|
||||||
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: ))">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision>
|
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) And Exists('$(MyGitRoot)/.git/$(MyGitHead.Substring(5))')">$([System.IO.File]::ReadAllText($(MyGitRoot)/.git/$(MyGitHead.Substring(5))).Trim().Substring(0, 7))</MyGitRevision>
|
||||||
|
<MyGitRevision Condition="$(MyGitHead.StartsWith(ref: )) And !Exists('$(MyGitRoot)/.git/$(MyGitHead.Substring(5))')">$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText($(MyGitRoot)/.git/packed-refs)), '[0-9a-fA-F]{40,}.*$(MyGitHead.Substring(5))').Value.Substring(0, 7))</MyGitRevision>
|
||||||
<MyGitRevision Condition="!$(MyGitHead.StartsWith(ref: ))">$(MyGitHead.Substring(0, 7))</MyGitRevision>
|
<MyGitRevision Condition="!$(MyGitHead.StartsWith(ref: ))">$(MyGitHead.Substring(0, 7))</MyGitRevision>
|
||||||
|
|
||||||
<MyProductName>WinFsp</MyProductName>
|
<MyProductName>WinFsp</MyProductName>
|
||||||
@ -15,10 +16,10 @@
|
|||||||
<MyCompanyName>Navimatics Corporation</MyCompanyName>
|
<MyCompanyName>Navimatics Corporation</MyCompanyName>
|
||||||
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
|
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
|
||||||
|
|
||||||
<MyCanonicalVersion>1.1</MyCanonicalVersion>
|
<MyCanonicalVersion>1.2</MyCanonicalVersion>
|
||||||
|
|
||||||
<MyProductVersion>2017.1</MyProductVersion>
|
<MyProductVersion>2017.2 B1</MyProductVersion>
|
||||||
<MyProductStage>Gold</MyProductStage>
|
<MyProductStage>Beta</MyProductStage>
|
||||||
|
|
||||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||||
|
@ -32,19 +32,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "winfsp_msi", "installer\win
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomActions", "installer\CustomActions\CustomActions.vcxproj", "{95C223E6-B5F1-4FD0-9376-41CDBC824445}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "launcher", "launcher", "{FD28A504-431E-49B9-BB8C-DCA0E7019F66}"
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "launcher\launcher.vcxproj", "{A5EFD487-0140-4184-8C54-FFAEC2F85E35}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
|
||||||
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launchctl.vcxproj", "{73EAAEDA-557B-48D5-A137-328934720FB4}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
|
||||||
@ -63,6 +50,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet", "dotnet", "{A998CE
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{04A4762C-FAB9-4196-9AC8-0757F3E8AB79}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "tools\launcher.vcxproj", "{6CDF9411-B852-4EAC-822D-8F930675F17B}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "tools\launchctl.vcxproj", "{264A5D09-126F-4760-A3F1-4B3B95C925AA}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsptool", "tools\fsptool.vcxproj", "{1E997BEC-1642-4A5C-B252-852DA094E11E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -179,38 +174,6 @@ Global
|
|||||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|Any CPU.ActiveCfg = Release|Win32
|
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
|
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x64.ActiveCfg = Release|Win32
|
||||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
|
{95C223E6-B5F1-4FD0-9376-41CDBC824445}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Installer.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|Any CPU.ActiveCfg = Release|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x64.Build.0 = Release|x64
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35}.Release|x86.Build.0 = Release|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|Any CPU.ActiveCfg = Release|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|Any CPU.ActiveCfg = Release|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Installer.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|Any CPU.ActiveCfg = Release|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
|
|
||||||
{10757011-749D-4954-873B-AE38D8145472}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
|
{10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
|
||||||
@ -268,23 +231,65 @@ Global
|
|||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.Build.0 = Debug|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.ActiveCfg = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.ActiveCfg = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Installer.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.ActiveCfg = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.Build.0 = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.ActiveCfg = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU
|
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Debug|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x64.Build.0 = Release|x64
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Debug|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x64.Build.0 = Release|x64
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Debug|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Installer.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x64.Build.0 = Release|x64
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E}.Release|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -294,11 +299,12 @@ Global
|
|||||||
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
{AA7190E8-877F-4827-8CDD-E0D85F83C8C1} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||||
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
{D53AAC39-4C57-4CA5-A4F3-C2B24888C594} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
||||||
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
|
||||||
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
|
||||||
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
|
|
||||||
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||||
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||||
{94580219-CC8D-4FE5-A3BE-437B0B3481E1} = {A998CEC4-4B34-43DC-8457-F7761228BA67}
|
{94580219-CC8D-4FE5-A3BE-437B0B3481E1} = {A998CEC4-4B34-43DC-8457-F7761228BA67}
|
||||||
{4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
{4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
|
||||||
|
{6CDF9411-B852-4EAC-822D-8F930675F17B} = {04A4762C-FAB9-4196-9AC8-0757F3E8AB79}
|
||||||
|
{264A5D09-126F-4760-A3F1-4B3B95C925AA} = {04A4762C-FAB9-4196-9AC8-0757F3E8AB79}
|
||||||
|
{1E997BEC-1642-4A5C-B252-852DA094E11E} = {04A4762C-FAB9-4196-9AC8-0757F3E8AB79}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -17,6 +17,7 @@ The documentation available here discusses various aspects of WinFsp.
|
|||||||
|
|
||||||
- The [[Design|WinFsp-Design]] document describes the high-level design of WinFsp.
|
- The [[Design|WinFsp-Design]] document describes the high-level design of WinFsp.
|
||||||
- The [[IPC|WinFsp-as-an-IPC-Mechanism]] document offers insights into the WinFsp Inter-Process Communication mechanism.
|
- The [[IPC|WinFsp-as-an-IPC-Mechanism]] document offers insights into the WinFsp Inter-Process Communication mechanism.
|
||||||
|
- The [[Queued Events|Queued-Events]] document discusses a low-level synchronization primitive that is largely responsible for the excellent performance of the WinFsp IPC mechanism.
|
||||||
- The [[Service Architecture|WinFsp-Service-Architecture]] document discusses how to intergrate a file system into Windows as a service and the reasons to do so.
|
- The [[Service Architecture|WinFsp-Service-Architecture]] document discusses how to intergrate a file system into Windows as a service and the reasons to do so.
|
||||||
- The [[SSHFS Port Case Study|SSHFS-Port-Case-Study]] document chronicles the creation of the WinFsp-FUSE compatibility layer and the decisions that led to its design.
|
- The [[SSHFS Port Case Study|SSHFS-Port-Case-Study]] document chronicles the creation of the WinFsp-FUSE compatibility layer and the decisions that led to its design.
|
||||||
|
|
||||||
|
@ -13,8 +13,7 @@ This document contains a list of known file systems and file system libraries th
|
|||||||
|
|
||||||
== File System Libraries
|
== File System Libraries
|
||||||
|
|
||||||
- https://github.com/billziss-gh/cgofuse[cgofuse] - Cross-platform FUSE library for Go
|
- https://github.com/billziss-gh/cgofuse[Go: cgofuse] - Cross-platform FUSE library for Go
|
||||||
- https://github.com/DuroSoft/fuse-bindings[fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
|
- https://github.com/DuroSoft/fuse-bindings[Nodejs: fuse-bindings] - Fully maintained FUSE bindings for Node that aims to cover the entire FUSE api
|
||||||
- https://github.com/ui4j/fuse-jna[fuse-jna] - No-nonsense, actually-working Java bindings to FUSE using JNA
|
- https://github.com/SerCeMan/jnr-fuse[Java: jnr-fuse] - FUSE implementation in Java using Java Native Runtime (JNR)
|
||||||
- https://github.com/billziss-gh/fusepy[fusepy] - Simple ctypes bindings for FUSE
|
- https://github.com/billziss-gh/fusepy[Python: fusepy] - Simple ctypes bindings for FUSE
|
||||||
- https://github.com/yogendersolanki91/winfsp[WinFsp fork with .NET Layer] - by @yogendersolanki91
|
|
||||||
|
105
doc/Queued-Events.asciidoc
Normal file
105
doc/Queued-Events.asciidoc
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
= Queued Events - Windows kernel events with IOCP scheduling characteristics
|
||||||
|
|
||||||
|
In this article I am discussing _Queued Events_. _Queued Events_ are a Windows kernel synchronization mechanism that I invented for https://github.com/billziss-gh/winfsp[WinFsp - FUSE for Windows]. _Queued Events_ behave like kernel Synchronization Events (i.e. Win32 auto-reset events), but provide scheduling characteristics similar to those of I/O Completion Ports.
|
||||||
|
|
||||||
|
== The Problem
|
||||||
|
|
||||||
|
During the later stages of WinFsp development I decided to do some performance testing to understand its behavior and find opportunities for optimization. I found out that WinFsp performed very well in most tested scenarios, but there was one test that seemed to have bad performance for no particular reason.
|
||||||
|
|
||||||
|
I ended up profiling this issue using xperf (included in the https://docs.microsoft.com/en-us/windows-hardware/test/wpt/[Windows Performance Toolkit]), which allows for kernel-level profiling. I spent considerable time looking at the profiling results, but could identify no obvious issue with my code.
|
||||||
|
|
||||||
|
After a day or two of doing this and being stumped I finally had a lightbulb moment: what if the issue is not with my code, but with how the OS schedules threads? Sure enough I had xperf trace context switches and found that on good runs the OS would context switch my file system threads relatively rarely; on bad runs the OS would context switch my threads excessively.
|
||||||
|
|
||||||
|
After contemplating this issue I realized that this was happening because the OS was trying to schedule my threads in a "fair" manner. Windows in general tries to give every thread a chance to run. This can be counter-productive in server-like programs (such as file systems), where all server threads are equivalent and it is actually better to reuse the same thread (if possible) to avoid context switching and other negative effects.
|
||||||
|
|
||||||
|
== The Solution
|
||||||
|
|
||||||
|
One way of looking at WinFsp is as an IPC (Inter-Process Communication) mechanism. The Windows kernel packages file system operations (open, close, read, write) as IRP's (I/O Request Packets) which it sends to WinFsp. WinFsp places them in an _I/O Queue_; at a later time the threads in a user mode file system retrieve the IRP's from the _I/O Queue_ and service them.
|
||||||
|
|
||||||
|
The _I/O Queue_ had gone through multiple iterations, but at the time I was looking at this issue it was using Windows kernel Synchronization Event's (Win32 auto-reset events) for managing threads. The problem was that a wait on a Synchronization Event would be satisfied in a "fair" manner, thus resulting to excessive context switching and bad performance in some circumstances. I needed to find a way to convince Windows to schedule my threads in an "unfair" manner, giving preference to the same thread as much as possible.
|
||||||
|
|
||||||
|
I started considering different schemes where I would associate a different event per thread thus being able to wake up the "correct" thread myself and effectively writing my own mini-scheduler. Luckily I had another lightbulb moment: I/O completion ports already do this better than I would ever be able to!
|
||||||
|
|
||||||
|
The kernel portion of an I/O Completion Port is called a https://msdn.microsoft.com/en-us/library/windows/hardware/ff549547(v=vs.85).aspx[KQUEUE]. KQUEUE's are (unfortunately) not directly exposed to user mode, however they are at the core of the user mode I/O Completion Ports. KQUEUE's are the main reason I/O Completion Ports are so fast as they provide the following scheduling characteristics:
|
||||||
|
|
||||||
|
- They have a Last-In First-Out (LIFO) wait discipline.
|
||||||
|
- They limit the number of threads that can be satisfied concurrently.
|
||||||
|
|
||||||
|
I briefly considered the idea of building _I/O Queues_ directly on top of KQUEUE's, but soon dismissed this idea because _I/O Queues_ are not simple queues but provide additional services, such as IRP cancelation, IRP expiration, etc.
|
||||||
|
|
||||||
|
== Queued Events
|
||||||
|
|
||||||
|
In an ideal scenario I wanted to continue using my implementation of _I/O Queues_ which had undergone considerable testing and I knew it worked. But somehow I had to convince the Windows kernel to change the scheduling characteristics of Synchronization Events to mirror those of a KQUEUE.
|
||||||
|
|
||||||
|
Then I had lightbulb no 3: _Queued Events_ or how to make a queue behave like a Synchronization Event.
|
||||||
|
|
||||||
|
Here is how _Queued Events_ work. A _Queued Event_ consists of a KQUEUE and a spin lock. There is also a single dummy item that can be placed in the KQUEUE.
|
||||||
|
|
||||||
|
The KQUEUE is guaranteed to contain either 0 or 1 items. When the KQUEUE contains 0 items the _Queued Event_ is considered non-signaled. When the KQUEUE contains 1 items the _Queued Event_ is considered signaled.
|
||||||
|
|
||||||
|
ifdef::env-browser[]
|
||||||
|
[ditaa,file="Queued-Events/states.png"]
|
||||||
|
--
|
||||||
|
Non signaled Signaled
|
||||||
|
+---------------------------+ +---------------------------+
|
||||||
|
| Queued Event | | Queued Event |
|
||||||
|
+---------------------------+ +---------------------------+
|
||||||
|
| | | +---------+ |
|
||||||
|
| KQUEUE (empty) | | KQUEUE | DUMMY | |
|
||||||
|
| | | +---------+ |
|
||||||
|
+---------------------------+ +---------------------------+
|
||||||
|
--
|
||||||
|
endif::env-browser[]
|
||||||
|
ifndef::env-browser[image::Queued-Events/states.png[]]
|
||||||
|
|
||||||
|
To transition from the non-signaled to the signaled state, we acquire the spin lock and then insert the dummy item in the KQUEUE using https://msdn.microsoft.com/en-us/library/windows/hardware/ff549570(v=vs.85).aspx[KeInsertQueue]. To transition from the signaled to the non-signaled state, we simply (wait and) remove the dummy item from the KQUEUE using https://msdn.microsoft.com/en-us/library/windows/hardware/ff549605(v=vs.85).aspx[KeRemoveQueue] (without the use of the spin lock).
|
||||||
|
|
||||||
|
----
|
||||||
|
EventSet:
|
||||||
|
AcquireSpinLock
|
||||||
|
if (0 == KeReadState()) // if KQUEUE is empty
|
||||||
|
KeInsertQueue(DUMMY);
|
||||||
|
ReleaseSpinLock
|
||||||
|
|
||||||
|
EventWait:
|
||||||
|
KeRemoveQueue(); // (wait and) remove item
|
||||||
|
----
|
||||||
|
|
||||||
|
First notice that EventSet is serialized by the use of the spin lock. This guarantees that the dummy item can be only inserted ONCE in the KQUEUE and that the only possible signaled state transitions for EventSet are 0->1 and 1->1. This is how https://msdn.microsoft.com/en-us/library/windows/hardware/ff553253(v=vs.85).aspx[KeSetEvent] works for a Synchronization Event.
|
||||||
|
|
||||||
|
Second notice that EventWait is not protected by the spin lock, which means that it can happen at any time including concurrently with EventSet or another EventWait. Notice also that for EventWait the only possible transitions are 1->0 or 0->0 (0->block->0). This is how https://msdn.microsoft.com/en-us/library/windows/hardware/ff553350(v=vs.85).aspx[KeWaitForSingleObject] works for a Synchronization Event.
|
||||||
|
|
||||||
|
ifdef::env-browser[]
|
||||||
|
[ditaa,file="Queued-Events/transitions.png"]
|
||||||
|
--
|
||||||
|
Non signaled Signaled
|
||||||
|
+---------------------------+ +---------------------------+
|
||||||
|
| Queued Event | | Queued Event |
|
||||||
|
+---------------------------+ +---------------------------+
|
||||||
|
| | ---EventSet --> | +---------+ |
|
||||||
|
| KQUEUE (empty) | | KQUEUE | DUMMY | |
|
||||||
|
| | <--EventWait--- | +---------+ |
|
||||||
|
+---------------------------+ +---------------------------+
|
||||||
|
--
|
||||||
|
endif::env-browser[]
|
||||||
|
ifndef::env-browser[image::Queued-Events/transitions.png[]]
|
||||||
|
|
||||||
|
We now have to consider what happens when we have one EventSet concurrently with one or more EventWait's:
|
||||||
|
|
||||||
|
1. The EventWait(s) happen before https://msdn.microsoft.com/en-us/library/windows/hardware/ff549591(v=vs.85).aspx[KeReadState]. If the KQUEUE has an item one EventWait gets satisfied, otherwise it blocks. In this case KeReadState will read the KQUEUE's state as 0 and KeInsertQueue will insert the dummy item, which will unblock the EventWait.
|
||||||
|
2. The EventWait(s) happen after KeReadState, but before KeInsertQueue. If the dummy item was already in the KQUEUE the KeReadState test will fail and KeInsertQueue will not be executed, but EventWait will be satisfied immediately. If the dummy item was not in the KQUEUE the KeReadState will succeed and EventWait will momentarily block until KeInsertQueue releases it.
|
||||||
|
3. The EventWait(s) happen after KeInsertQueue. In this case the dummy item in is the KQUEUE already and one EventWait will be satisfied immediately.
|
||||||
|
|
||||||
|
NOTE: _Queued Events_ cannot cleanly support an EventClear operation. The obvious choice of using KeRemoveQueue with a 0 timeout is insufficient because it would associate the current thread with the KQUEUE and that is not desirable. KeRundownQueue cannot be used either because it disassociates all threads from the KQUEUE.
|
||||||
|
|
||||||
|
The complete implementation of _Queued Events_ within WinFsp can be found here: https://github.com/billziss-gh/winfsp/blob/v1.1/src/sys/driver.h#L655-L795
|
||||||
|
|
||||||
|
== Queued Events Scheduling Characteristics
|
||||||
|
|
||||||
|
Queued Events encapsulate KQUEUE's and therefore inherit their scheduling characteristics:
|
||||||
|
|
||||||
|
- They have a Last-In First-Out (LIFO) wait discipline.
|
||||||
|
- They limit the number of threads that can be satisfied concurrently.
|
||||||
|
|
||||||
|
These characteristics are desirable because they reduce the number of context switches thus speeding up the WinFsp IPC implementation. Performance testing immediately after the incorporation of _Queued Events_ into WinFsp showed significant performance improvements; profiling with xperf showed that context switches among file system threads were now a relatively rare event!
|
||||||
|
|
BIN
doc/Queued-Events/states.png
Normal file
BIN
doc/Queued-Events/states.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
doc/Queued-Events/transitions.png
Normal file
BIN
doc/Queued-Events/transitions.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
@ -178,6 +178,7 @@ struct fuse_flock
|
|||||||
fsp_fuse_daemonize, \
|
fsp_fuse_daemonize, \
|
||||||
fsp_fuse_set_signal_handlers, \
|
fsp_fuse_set_signal_handlers, \
|
||||||
0/*conv_to_win_path*/, \
|
0/*conv_to_win_path*/, \
|
||||||
|
0/*winpid_to_pid*/, \
|
||||||
{ 0 }, \
|
{ 0 }, \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -188,6 +189,7 @@ struct fuse_flock
|
|||||||
fsp_fuse_daemonize, \
|
fsp_fuse_daemonize, \
|
||||||
fsp_fuse_set_signal_handlers, \
|
fsp_fuse_set_signal_handlers, \
|
||||||
0/*conv_to_win_path*/, \
|
0/*conv_to_win_path*/, \
|
||||||
|
0/*winpid_to_pid*/, \
|
||||||
{ 0 }, \
|
{ 0 }, \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -231,6 +233,7 @@ struct fuse_flock
|
|||||||
fsp_fuse_daemonize, \
|
fsp_fuse_daemonize, \
|
||||||
fsp_fuse_set_signal_handlers, \
|
fsp_fuse_set_signal_handlers, \
|
||||||
fsp_fuse_conv_to_win_path, \
|
fsp_fuse_conv_to_win_path, \
|
||||||
|
fsp_fuse_winpid_to_pid, \
|
||||||
{ 0 }, \
|
{ 0 }, \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +254,8 @@ struct fsp_fuse_env
|
|||||||
int (*daemonize)(int);
|
int (*daemonize)(int);
|
||||||
int (*set_signal_handlers)(void *);
|
int (*set_signal_handlers)(void *);
|
||||||
char *(*conv_to_win_path)(const char *);
|
char *(*conv_to_win_path)(const char *);
|
||||||
void (*reserved[3])();
|
fuse_pid_t (*winpid_to_pid)(uint32_t);
|
||||||
|
void (*reserved[2])();
|
||||||
};
|
};
|
||||||
|
|
||||||
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
|
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
|
||||||
@ -362,6 +366,13 @@ static inline char *fsp_fuse_conv_to_win_path(const char *path)
|
|||||||
0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/,
|
0/*CCP_POSIX_TO_WIN_A*/ | 0x100/*CCP_RELATIVE*/,
|
||||||
path);
|
path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline fuse_pid_t fsp_fuse_winpid_to_pid(uint32_t winpid)
|
||||||
|
{
|
||||||
|
pid_t cygwin_winpid_to_pid(int winpid);
|
||||||
|
pid_t pid = cygwin_winpid_to_pid(winpid);
|
||||||
|
return -1 != pid ? pid : (fuse_pid_t)winpid;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,6 +78,9 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
|
|||||||
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
|
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
|
||||||
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
|
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
|
||||||
|
|
||||||
|
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((T) & 0xffffffff))
|
||||||
|
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff))
|
||||||
|
|
||||||
/* marshalling */
|
/* marshalling */
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
||||||
@ -149,7 +152,8 @@ typedef struct
|
|||||||
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
|
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
|
||||||
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
|
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
|
||||||
UINT32 AlwaysUseDoubleBuffering:1;
|
UINT32 AlwaysUseDoubleBuffering:1;
|
||||||
UINT32 KmReservedFlags:3;
|
UINT32 PassQueryDirectoryFileName:1; /* pass FileName during QueryDirectory (GetDirInfoByName) */
|
||||||
|
UINT32 KmReservedFlags:2;
|
||||||
/* user-mode flags */
|
/* user-mode flags */
|
||||||
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
|
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
|
||||||
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
|
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
|
||||||
@ -222,7 +226,7 @@ typedef struct
|
|||||||
UINT32 FileAttributes; /* file attributes for new files */
|
UINT32 FileAttributes; /* file attributes for new files */
|
||||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */
|
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */
|
||||||
UINT64 AllocationSize; /* initial allocation size */
|
UINT64 AllocationSize; /* initial allocation size */
|
||||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||||
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||||
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||||
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
|
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
|
||||||
@ -315,7 +319,7 @@ typedef struct
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||||
UINT64 AccessToken; /* request access token (HANDLE) */
|
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||||
} Rename;
|
} Rename;
|
||||||
} Info;
|
} Info;
|
||||||
} SetInformation;
|
} SetInformation;
|
||||||
@ -344,6 +348,7 @@ typedef struct
|
|||||||
FSP_FSCTL_TRANSACT_BUF Pattern;
|
FSP_FSCTL_TRANSACT_BUF Pattern;
|
||||||
FSP_FSCTL_TRANSACT_BUF Marker;
|
FSP_FSCTL_TRANSACT_BUF Marker;
|
||||||
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
|
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
|
||||||
|
UINT32 PatternIsFileName:1; /* Pattern does not contain wildcards */
|
||||||
} QueryDirectory;
|
} QueryDirectory;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -802,12 +802,32 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
PVOID FileContext, PVOID Buffer, ULONG Length,
|
PVOID FileContext, PVOID Buffer, ULONG Length,
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
|
/**
|
||||||
|
* Get directory information for a single file or directory within a parent directory.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param FileContext
|
||||||
|
* The file context of the parent directory.
|
||||||
|
* @param FileName
|
||||||
|
* The name of the file or directory to get information for. This name is relative
|
||||||
|
* to the parent directory and is a single path component.
|
||||||
|
* @param DirInfo [out]
|
||||||
|
* Pointer to a structure that will receive the directory information on successful
|
||||||
|
* return from this call. This information includes the file name, but also file
|
||||||
|
* attributes, file times, etc.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
*/
|
||||||
|
NTSTATUS (*GetDirInfoByName)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PVOID FileContext, PWSTR FileName,
|
||||||
|
FSP_FSCTL_DIR_INFO *DirInfo);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This ensures that this interface will always contain 64 function pointers.
|
* This ensures that this interface will always contain 64 function pointers.
|
||||||
* Please update when changing the interface as it is important for future compatibility.
|
* Please update when changing the interface as it is important for future compatibility.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Reserved[40])();
|
NTSTATUS (*Reserved[39])();
|
||||||
} FSP_FILE_SYSTEM_INTERFACE;
|
} FSP_FILE_SYSTEM_INTERFACE;
|
||||||
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||||
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||||
@ -1065,6 +1085,23 @@ BOOLEAN FspFileSystemIsOperationCaseSensitive(VOID)
|
|||||||
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive ||
|
FspFsctlTransactCreateKind == Request->Kind && Request->Req.Create.CaseSensitive ||
|
||||||
FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive;
|
FspFsctlTransactQueryDirectoryKind == Request->Kind && Request->Req.QueryDirectory.CaseSensitive;
|
||||||
}
|
}
|
||||||
|
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID);
|
||||||
|
static inline
|
||||||
|
UINT32 FspFileSystemOperationProcessId(VOID)
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
|
||||||
|
switch (Request->Kind)
|
||||||
|
{
|
||||||
|
case FspFsctlTransactCreateKind:
|
||||||
|
return FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken);
|
||||||
|
case FspFsctlTransactSetInformationKind:
|
||||||
|
if (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
|
||||||
|
return FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken);
|
||||||
|
/* fall through! */
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Operations
|
* Operations
|
||||||
|
BIN
opt/cygfuse/dist/x64/fuse-2.8-5.tar.xz
vendored
BIN
opt/cygfuse/dist/x64/fuse-2.8-5.tar.xz
vendored
Binary file not shown.
BIN
opt/cygfuse/dist/x64/fuse-2.8-6.tar.xz
vendored
Normal file
BIN
opt/cygfuse/dist/x64/fuse-2.8-6.tar.xz
vendored
Normal file
Binary file not shown.
BIN
opt/cygfuse/dist/x86/fuse-2.8-5.tar.xz
vendored
BIN
opt/cygfuse/dist/x86/fuse-2.8-5.tar.xz
vendored
Binary file not shown.
BIN
opt/cygfuse/dist/x86/fuse-2.8-6.tar.xz
vendored
Normal file
BIN
opt/cygfuse/dist/x86/fuse-2.8-6.tar.xz
vendored
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
NAME="fuse"
|
NAME="fuse"
|
||||||
VERSION=2.8
|
VERSION=2.8
|
||||||
RELEASE=5
|
RELEASE=6
|
||||||
CATEGORY="Utils"
|
CATEGORY="Utils"
|
||||||
SUMMARY="WinFsp-FUSE compatibility layer"
|
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||||
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||||
|
@ -302,7 +302,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
|
FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", "
|
||||||
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
"%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, "
|
||||||
"AllocationSize=%lx:%lx, "
|
"AllocationSize=%lx:%lx, "
|
||||||
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, "
|
"AccessToken=%p[PID=%lx], DesiredAccess=%lx, GrantedAccess=%lx, "
|
||||||
"ShareAccess=%lx\n",
|
"ShareAccess=%lx\n",
|
||||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||||
Request->Req.Create.UserMode ? 'U' : 'K',
|
Request->Req.Create.UserMode ? 'U' : 'K',
|
||||||
@ -319,7 +319,8 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
Sddl ? Sddl : "NULL",
|
Sddl ? Sddl : "NULL",
|
||||||
Sddl ? "\"" : "",
|
Sddl ? "\"" : "",
|
||||||
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize),
|
||||||
(PVOID)Request->Req.Create.AccessToken,
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken),
|
||||||
Request->Req.Create.DesiredAccess,
|
Request->Req.Create.DesiredAccess,
|
||||||
Request->Req.Create.GrantedAccess,
|
Request->Req.Create.GrantedAccess,
|
||||||
Request->Req.Create.ShareAccess);
|
Request->Req.Create.ShareAccess);
|
||||||
@ -459,7 +460,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
break;
|
break;
|
||||||
case 10/*FileRenameInformation*/:
|
case 10/*FileRenameInformation*/:
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
|
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
|
||||||
"NewFileName=\"%S\", AccessToken=%p\n",
|
"NewFileName=\"%S\", AccessToken=%p[PID=%lx]\n",
|
||||||
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
|
||||||
Request->FileName.Size ? "\"" : "",
|
Request->FileName.Size ? "\"" : "",
|
||||||
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
|
||||||
@ -468,7 +469,8 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
|
|||||||
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
Request->Req.SetInformation.UserContext, Request->Req.SetInformation.UserContext2,
|
||||||
UserContextBuf),
|
UserContextBuf),
|
||||||
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset),
|
||||||
(PVOID)Request->Req.SetInformation.Info.Rename.AccessToken);
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.SetInformation.Info.Rename.AccessToken),
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
|
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
|
||||||
|
@ -683,3 +683,8 @@ FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID)
|
|||||||
{
|
{
|
||||||
return FspFileSystemIsOperationCaseSensitive();
|
return FspFileSystemIsOperationCaseSensitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID)
|
||||||
|
{
|
||||||
|
return FspFileSystemOperationProcessId();
|
||||||
|
}
|
||||||
|
@ -1121,6 +1121,36 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFileSystemOpQueryDirectory_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PVOID FileContext, PWSTR FileName,
|
||||||
|
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
FSP_FSCTL_DIR_INFO V;
|
||||||
|
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)];
|
||||||
|
} DirInfoBuf;
|
||||||
|
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V;
|
||||||
|
|
||||||
|
/* The FSD will never send us a Marker that we need to worry about! */
|
||||||
|
|
||||||
|
memset(DirInfo, 0, sizeof *DirInfo);
|
||||||
|
Result = FileSystem->Interface->GetDirInfoByName(FileSystem, FileContext, FileName, DirInfo);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
if (FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
|
||||||
|
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||||
|
}
|
||||||
|
else if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
||||||
|
{
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
{
|
{
|
||||||
@ -1131,15 +1161,24 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
BytesTransferred = 0;
|
BytesTransferred = 0;
|
||||||
Result = FileSystem->Interface->ReadDirectory(FileSystem,
|
if (0 != FileSystem->Interface->GetDirInfoByName &&
|
||||||
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
|
0 != Request->Req.QueryDirectory.Pattern.Size && Request->Req.QueryDirectory.PatternIsFileName)
|
||||||
0 != Request->Req.QueryDirectory.Pattern.Size ?
|
Result = FspFileSystemOpQueryDirectory_GetDirInfoByName(FileSystem,
|
||||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0,
|
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
|
||||||
0 != Request->Req.QueryDirectory.Marker.Size ?
|
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset),
|
||||||
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : 0,
|
(PVOID)Request->Req.QueryDirectory.Address,
|
||||||
(PVOID)Request->Req.QueryDirectory.Address,
|
Request->Req.QueryDirectory.Length,
|
||||||
Request->Req.QueryDirectory.Length,
|
&BytesTransferred);
|
||||||
&BytesTransferred);
|
else
|
||||||
|
Result = FileSystem->Interface->ReadDirectory(FileSystem,
|
||||||
|
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
|
||||||
|
0 != Request->Req.QueryDirectory.Pattern.Size ?
|
||||||
|
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0,
|
||||||
|
0 != Request->Req.QueryDirectory.Marker.Size ?
|
||||||
|
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : 0,
|
||||||
|
(PVOID)Request->Req.QueryDirectory.Address,
|
||||||
|
Request->Req.QueryDirectory.Length,
|
||||||
|
&BytesTransferred);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
|
@ -283,6 +283,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
context->private_data = f->data;
|
context->private_data = f->data;
|
||||||
context->uid = -1;
|
context->uid = -1;
|
||||||
context->gid = -1;
|
context->gid = -1;
|
||||||
|
context->pid = -1;
|
||||||
|
|
||||||
memset(&conn, 0, sizeof conn);
|
memset(&conn, 0, sizeof conn);
|
||||||
conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */
|
conn.proto_major = 7; /* pretend that we are FUSE kernel protocol 7.12 */
|
||||||
@ -304,6 +305,14 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|||||||
context->private_data = f->data = f->ops.init(&conn);
|
context->private_data = f->data = f->ops.init(&conn);
|
||||||
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
|
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
|
||||||
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
|
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
|
||||||
|
if (!f->VolumeParams.CaseSensitiveSearch)
|
||||||
|
/*
|
||||||
|
* Disable GetDirInfoByName when file system is case-insensitive.
|
||||||
|
* The reason is that Windows always sends us queries with uppercase
|
||||||
|
* file names in GetDirInfoByName and we have no way in FUSE to normalize
|
||||||
|
* those file names when embedding them in FSP_FSCTL_DIR_INFO.
|
||||||
|
*/
|
||||||
|
f->VolumeParams.PassQueryDirectoryFileName = FALSE;
|
||||||
f->conn_want = conn.want;
|
f->conn_want = conn.want;
|
||||||
}
|
}
|
||||||
f->fsinit = TRUE;
|
f->fsinit = TRUE;
|
||||||
@ -602,12 +611,14 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
|||||||
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
|
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
|
||||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
||||||
opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
|
opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
|
||||||
|
opt_data.VolumeParams.CasePreservedNames = TRUE;
|
||||||
opt_data.VolumeParams.PersistentAcls = TRUE;
|
opt_data.VolumeParams.PersistentAcls = TRUE;
|
||||||
opt_data.VolumeParams.ReparsePoints = TRUE;
|
opt_data.VolumeParams.ReparsePoints = TRUE;
|
||||||
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
|
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
|
||||||
opt_data.VolumeParams.NamedStreams = FALSE;
|
opt_data.VolumeParams.NamedStreams = FALSE;
|
||||||
opt_data.VolumeParams.ReadOnlyVolume = FALSE;
|
opt_data.VolumeParams.ReadOnlyVolume = FALSE;
|
||||||
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
|
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
|
||||||
|
opt_data.VolumeParams.PassQueryDirectoryFileName = TRUE;
|
||||||
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||||
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||||
@ -737,7 +748,6 @@ FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr);
|
context = FSP_FUSE_CONTEXT_FROM_HDR(contexthdr);
|
||||||
context->pid = -1;
|
|
||||||
|
|
||||||
TlsSetValue(fsp_fuse_tlskey, context);
|
TlsSetValue(fsp_fuse_tlskey, context);
|
||||||
}
|
}
|
||||||
|
@ -112,10 +112,10 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
struct fuse_context *context;
|
struct fuse_context *context;
|
||||||
struct fsp_fuse_context_header *contexthdr;
|
struct fsp_fuse_context_header *contexthdr;
|
||||||
char *PosixPath = 0;
|
char *PosixPath = 0;
|
||||||
UINT32 Uid = -1, Gid = -1;
|
UINT32 Uid = -1, Gid = -1, Pid = -1;
|
||||||
PWSTR FileName = 0, Suffix;
|
PWSTR FileName = 0, Suffix;
|
||||||
WCHAR Root[2] = L"\\";
|
WCHAR Root[2] = L"\\";
|
||||||
HANDLE Token = 0;
|
UINT64 AccessToken = 0;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
if (FspFsctlTransactCreateKind == Request->Kind)
|
if (FspFsctlTransactCreateKind == Request->Kind)
|
||||||
@ -124,13 +124,13 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
|
FspPathSuffix((PWSTR)Request->Buffer, &FileName, &Suffix, Root);
|
||||||
else
|
else
|
||||||
FileName = (PWSTR)Request->Buffer;
|
FileName = (PWSTR)Request->Buffer;
|
||||||
Token = (HANDLE)Request->Req.Create.AccessToken;
|
AccessToken = Request->Req.Create.AccessToken;
|
||||||
}
|
}
|
||||||
else if (FspFsctlTransactSetInformationKind == Request->Kind &&
|
else if (FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||||
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
|
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
|
||||||
{
|
{
|
||||||
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
|
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
|
||||||
Token = (HANDLE)Request->Req.SetInformation.Info.Rename.AccessToken;
|
AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != FileName)
|
if (0 != FileName)
|
||||||
@ -142,11 +142,16 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != Token)
|
if (0 != AccessToken)
|
||||||
{
|
{
|
||||||
Result = fsp_fuse_get_token_uidgid(Token, TokenUser, &Uid, &Gid);
|
Result = fsp_fuse_get_token_uidgid(
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(AccessToken),
|
||||||
|
TokenUser,
|
||||||
|
&Uid, &Gid);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
Pid = FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(AccessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
context = fsp_fuse_get_context(f->env);
|
context = fsp_fuse_get_context(f->env);
|
||||||
@ -162,6 +167,7 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
context->private_data = f->data;
|
context->private_data = f->data;
|
||||||
context->uid = Uid;
|
context->uid = Uid;
|
||||||
context->gid = Gid;
|
context->gid = Gid;
|
||||||
|
context->pid = 0 != f->env->winpid_to_pid ? f->env->winpid_to_pid(Pid) : Pid;
|
||||||
|
|
||||||
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
|
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
|
||||||
contexthdr->PosixPath = PosixPath;
|
contexthdr->PosixPath = PosixPath;
|
||||||
@ -189,6 +195,7 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
context->private_data = 0;
|
context->private_data = 0;
|
||||||
context->uid = -1;
|
context->uid = -1;
|
||||||
context->gid = -1;
|
context->gid = -1;
|
||||||
|
context->pid = -1;
|
||||||
|
|
||||||
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
|
contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
|
||||||
if (0 != contexthdr->PosixPath)
|
if (0 != contexthdr->PosixPath)
|
||||||
@ -799,10 +806,9 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache
|
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
|
||||||
* WinFsp does not currently support disabling the cache manager
|
* NOTE: Originally WinFsp dit not support disabling the cache manager
|
||||||
* for an individual file although it should not be hard to add
|
* for an individual file. This is now possible and we should revisit.
|
||||||
* if required.
|
|
||||||
*
|
*
|
||||||
* Ignore fuse_file_info::nonseekable.
|
* Ignore fuse_file_info::nonseekable.
|
||||||
*/
|
*/
|
||||||
@ -1141,7 +1147,8 @@ static NTSTATUS fsp_fuse_intf_Write(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
|
AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
|
||||||
(UINT64)f->VolumeParams.SectorsPerAllocationUnit;
|
(UINT64)f->VolumeParams.SectorsPerAllocationUnit;
|
||||||
FileInfoBuf.FileSize = Offset + bytes;
|
if (Offset + bytes > FileInfoBuf.FileSize)
|
||||||
|
FileInfoBuf.FileSize = Offset + bytes;
|
||||||
FileInfoBuf.AllocationSize =
|
FileInfoBuf.AllocationSize =
|
||||||
(FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
(FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||||
|
|
||||||
@ -1749,6 +1756,63 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS fsp_fuse_intf_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PVOID FileNode, PWSTR FileName,
|
||||||
|
FSP_FSCTL_DIR_INFO *DirInfo)
|
||||||
|
{
|
||||||
|
struct fuse *f = FileSystem->UserContext;
|
||||||
|
struct fsp_fuse_file_desc *filedesc = FileNode;
|
||||||
|
char *PosixName = 0;
|
||||||
|
char PosixPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||||
|
int ParentLength, FSlashLength, PosixNameLength;
|
||||||
|
UINT32 Uid, Gid, Mode;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
Result = FspPosixMapWindowsToPosixPath(FileName, &PosixName);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_NOT_FOUND; //Result?
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParentLength = lstrlenA(filedesc->PosixPath);
|
||||||
|
FSlashLength = 1 < ParentLength;
|
||||||
|
PosixNameLength = lstrlenA(PosixName);
|
||||||
|
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX <= (ParentLength + FSlashLength + PosixNameLength) * sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_NOT_FOUND; //STATUS_OBJECT_NAME_INVALID?
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(PosixPath, filedesc->PosixPath, ParentLength);
|
||||||
|
memcpy(PosixPath + ParentLength, "/", FSlashLength);
|
||||||
|
memcpy(PosixPath + ParentLength + FSlashLength, PosixName, PosixNameLength + 1);
|
||||||
|
|
||||||
|
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
|
||||||
|
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_NOT_FOUND; //Result?
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FUSE does not do FileName normalization; so just return the FileName as given to us!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
|
||||||
|
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + lstrlenW(FileName) * sizeof(WCHAR));
|
||||||
|
memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO));
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != PosixName)
|
||||||
|
FspPosixDeletePath(PosixName);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
||||||
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
||||||
@ -2022,6 +2086,8 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
|||||||
fsp_fuse_intf_GetReparsePoint,
|
fsp_fuse_intf_GetReparsePoint,
|
||||||
fsp_fuse_intf_SetReparsePoint,
|
fsp_fuse_intf_SetReparsePoint,
|
||||||
fsp_fuse_intf_DeleteReparsePoint,
|
fsp_fuse_intf_DeleteReparsePoint,
|
||||||
|
0,
|
||||||
|
fsp_fuse_intf_GetDirInfoByName,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -172,8 +172,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
if (0 < SecurityDescriptorSize)
|
if (0 < SecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
|
if (AccessCheck(SecurityDescriptor,
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, &TraverseAccess, &AccessStatus))
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||||
|
FILE_TRAVERSE,
|
||||||
|
&FspFileGenericMapping,
|
||||||
|
PrivilegeSet, &PrivilegeSetLength,
|
||||||
|
&TraverseAccess, &AccessStatus))
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
else
|
else
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
@ -202,8 +206,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
if (0 == DesiredAccess)
|
if (0 == DesiredAccess)
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
else if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
else if (AccessCheck(SecurityDescriptor,
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||||
|
DesiredAccess,
|
||||||
|
&FspFileGenericMapping,
|
||||||
|
PrivilegeSet, &PrivilegeSetLength,
|
||||||
|
PGrantedAccess, &AccessStatus))
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
else
|
else
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
@ -244,8 +252,12 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
||||||
if (0 != DesiredAccess2)
|
if (0 != DesiredAccess2)
|
||||||
{
|
{
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
if (AccessCheck(SecurityDescriptor,
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||||
|
DesiredAccess2,
|
||||||
|
&FspFileGenericMapping,
|
||||||
|
PrivilegeSet, &PrivilegeSetLength,
|
||||||
|
PGrantedAccess, &AccessStatus))
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
else
|
else
|
||||||
/* any failure just becomes ACCESS DENIED at this point */
|
/* any failure just becomes ACCESS DENIED at this point */
|
||||||
@ -396,7 +408,7 @@ FSP_API NTSTATUS FspCreateSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
(PSECURITY_DESCRIPTOR)(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset) : 0,
|
(PSECURITY_DESCRIPTOR)(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset) : 0,
|
||||||
PSecurityDescriptor,
|
PSecurityDescriptor,
|
||||||
0 != (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE),
|
0 != (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE),
|
||||||
(HANDLE)Request->Req.Create.AccessToken,
|
FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(Request->Req.Create.AccessToken),
|
||||||
&FspFileGenericMapping))
|
&FspFileGenericMapping))
|
||||||
return FspNtStatusFromWin32(GetLastError());
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
|
@ -935,6 +935,37 @@ namespace Fsp
|
|||||||
StreamAllocationSize = default(UInt64);
|
StreamAllocationSize = default(UInt64);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets directory information for a single file or directory within a parent directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="FileNode">
|
||||||
|
/// The file node of the parent directory.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="FileDesc">
|
||||||
|
/// The file descriptor of the parent directory.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="FileName">
|
||||||
|
/// The name of the file or directory to get information for. This name is relative
|
||||||
|
/// to the parent directory and is a single path component.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="NormalizedName">
|
||||||
|
/// Receives the normalized name from the directory entry.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="FileInfo">
|
||||||
|
/// Receives the file information.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>STATUS_SUCCESS or error code.</returns>
|
||||||
|
public virtual Int32 GetDirInfoByName(
|
||||||
|
Object FileNode,
|
||||||
|
Object FileDesc,
|
||||||
|
String FileName,
|
||||||
|
out String NormalizedName,
|
||||||
|
out FileInfo FileInfo)
|
||||||
|
{
|
||||||
|
NormalizedName = default(String);
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
/* helpers */
|
/* helpers */
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -189,6 +189,11 @@ namespace Fsp
|
|||||||
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryPattern); }
|
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryPattern); }
|
||||||
set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryPattern : 0); }
|
set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryPattern : 0); }
|
||||||
}
|
}
|
||||||
|
public Boolean PassQueryDirectoryFileName
|
||||||
|
{
|
||||||
|
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryFileName); }
|
||||||
|
set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryFileName : 0); }
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the prefix for a network file system.
|
/// Gets or sets the prefix for a network file system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -987,6 +992,34 @@ namespace Fsp
|
|||||||
return ExceptionHandler(FileSystem, ex);
|
return ExceptionHandler(FileSystem, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static Int32 GetDirInfoByName(
|
||||||
|
IntPtr FileSystemPtr,
|
||||||
|
ref FullContext FullContext,
|
||||||
|
String FileName,
|
||||||
|
out DirInfo DirInfo)
|
||||||
|
{
|
||||||
|
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Object FileNode, FileDesc;
|
||||||
|
String NormalizedName;
|
||||||
|
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
|
||||||
|
DirInfo = default(DirInfo);
|
||||||
|
Int32 Result = FileSystem.GetDirInfoByName(
|
||||||
|
FileNode,
|
||||||
|
FileDesc,
|
||||||
|
FileName,
|
||||||
|
out NormalizedName,
|
||||||
|
out DirInfo.FileInfo);
|
||||||
|
DirInfo.SetFileNameBuf(NormalizedName);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
DirInfo = default(DirInfo);
|
||||||
|
return ExceptionHandler(FileSystem, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static FileSystemHost()
|
static FileSystemHost()
|
||||||
{
|
{
|
||||||
@ -1014,6 +1047,7 @@ namespace Fsp
|
|||||||
_FileSystemInterface.SetReparsePoint = SetReparsePoint;
|
_FileSystemInterface.SetReparsePoint = SetReparsePoint;
|
||||||
_FileSystemInterface.DeleteReparsePoint = DeleteReparsePoint;
|
_FileSystemInterface.DeleteReparsePoint = DeleteReparsePoint;
|
||||||
_FileSystemInterface.GetStreamInfo = GetStreamInfo;
|
_FileSystemInterface.GetStreamInfo = GetStreamInfo;
|
||||||
|
_FileSystemInterface.GetDirInfoByName = GetDirInfoByName;
|
||||||
|
|
||||||
_FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
|
_FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
|
||||||
Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false);
|
Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false);
|
||||||
|
@ -42,6 +42,7 @@ namespace Fsp.Interop
|
|||||||
internal const UInt32 PostCleanupWhenModifiedOnly = 0x00000400;
|
internal const UInt32 PostCleanupWhenModifiedOnly = 0x00000400;
|
||||||
internal const UInt32 PassQueryDirectoryPattern = 0x00000800;
|
internal const UInt32 PassQueryDirectoryPattern = 0x00000800;
|
||||||
internal const UInt32 AlwaysUseDoubleBuffering = 0x00001000;
|
internal const UInt32 AlwaysUseDoubleBuffering = 0x00001000;
|
||||||
|
internal const UInt32 PassQueryDirectoryFileName = 0x00002000;
|
||||||
internal const UInt32 UmFileContextIsUserContext2 = 0x00010000;
|
internal const UInt32 UmFileContextIsUserContext2 = 0x00010000;
|
||||||
internal const UInt32 UmFileContextIsFullContext = 0x00020000;
|
internal const UInt32 UmFileContextIsFullContext = 0x00020000;
|
||||||
internal const int PrefixSize = 192;
|
internal const int PrefixSize = 192;
|
||||||
@ -450,6 +451,12 @@ namespace Fsp.Interop
|
|||||||
IntPtr Buffer,
|
IntPtr Buffer,
|
||||||
UInt32 Length,
|
UInt32 Length,
|
||||||
out UInt32 PBytesTransferred);
|
out UInt32 PBytesTransferred);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
internal delegate Int32 GetDirInfoByName(
|
||||||
|
IntPtr FileSystem,
|
||||||
|
ref FullContext FullContext,
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
|
||||||
|
out DirInfo DirInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int Size = IntPtr.Size * 64;
|
internal static int Size = IntPtr.Size * 64;
|
||||||
@ -478,7 +485,8 @@ namespace Fsp.Interop
|
|||||||
internal Proto.SetReparsePoint SetReparsePoint;
|
internal Proto.SetReparsePoint SetReparsePoint;
|
||||||
internal Proto.DeleteReparsePoint DeleteReparsePoint;
|
internal Proto.DeleteReparsePoint DeleteReparsePoint;
|
||||||
internal Proto.GetStreamInfo GetStreamInfo;
|
internal Proto.GetStreamInfo GetStreamInfo;
|
||||||
/* NTSTATUS (*Reserved[40])(); */
|
internal Proto.GetDirInfoByName GetDirInfoByName;
|
||||||
|
/* NTSTATUS (*Reserved[39])(); */
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
|
37
src/fsptool/fsptool-version.rc
Normal file
37
src/fsptool/fsptool-version.rc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <winver.h>
|
||||||
|
|
||||||
|
#define STR(x) STR_(x)
|
||||||
|
#define STR_(x) #x
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION MyVersionWithCommas
|
||||||
|
PRODUCTVERSION MyVersionWithCommas
|
||||||
|
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS VS_FF_DEBUG
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0
|
||||||
|
#endif
|
||||||
|
FILEOS VOS_NT
|
||||||
|
FILETYPE VFT_APP
|
||||||
|
FILESUBTYPE 0
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", STR(MyCompanyName)
|
||||||
|
VALUE "FileDescription", STR(MyDescription)
|
||||||
|
VALUE "FileVersion", STR(MyFullVersion)
|
||||||
|
VALUE "InternalName", "fsptool.exe"
|
||||||
|
VALUE "LegalCopyright", STR(MyCopyright)
|
||||||
|
VALUE "OriginalFilename", "fsptool.exe"
|
||||||
|
VALUE "ProductName", STR(MyProductName)
|
||||||
|
VALUE "ProductVersion", STR(MyProductVersion)
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
602
src/fsptool/fsptool.c
Normal file
602
src/fsptool/fsptool.c
Normal file
@ -0,0 +1,602 @@
|
|||||||
|
/**
|
||||||
|
* @file fsptool/fsptool.c
|
||||||
|
*
|
||||||
|
* @copyright 2015-2017 Bill Zissimopoulos
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This file is part of WinFsp.
|
||||||
|
*
|
||||||
|
* You can redistribute it and/or modify it under the terms of the GNU
|
||||||
|
* General Public License version 3 as published by the Free Software
|
||||||
|
* Foundation.
|
||||||
|
*
|
||||||
|
* Licensees holding a valid commercial license may use this file in
|
||||||
|
* accordance with the commercial license agreement provided with the
|
||||||
|
* software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <winfsp/winfsp.h>
|
||||||
|
#include <shared/minimal.h>
|
||||||
|
#include <aclapi.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
|
||||||
|
#define PROGNAME "fsptool"
|
||||||
|
|
||||||
|
#define info(format, ...) printlog(GetStdHandle(STD_OUTPUT_HANDLE), format, __VA_ARGS__)
|
||||||
|
#define warn(format, ...) printlog(GetStdHandle(STD_ERROR_HANDLE), format, __VA_ARGS__)
|
||||||
|
#define fatal(ExitCode, format, ...) (warn(format, __VA_ARGS__), ExitProcess(ExitCode))
|
||||||
|
|
||||||
|
static void vprintlog(HANDLE h, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
/* wvsprintf is only safe with a 1024 byte buffer */
|
||||||
|
size_t len;
|
||||||
|
DWORD BytesTransferred;
|
||||||
|
|
||||||
|
wvsprintfA(buf, format, ap);
|
||||||
|
buf[sizeof buf - 1] = '\0';
|
||||||
|
|
||||||
|
len = lstrlenA(buf);
|
||||||
|
buf[len++] = '\n';
|
||||||
|
|
||||||
|
WriteFile(h, buf, (DWORD)len, &BytesTransferred, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printlog(HANDLE h, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vprintlog(h, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned wcstoint(const wchar_t *p, const wchar_t **endp, int base)
|
||||||
|
{
|
||||||
|
unsigned v;
|
||||||
|
int maxdig, maxalp;
|
||||||
|
|
||||||
|
maxdig = 10 < base ? '9' : (base - 1) + '0';
|
||||||
|
maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0;
|
||||||
|
|
||||||
|
for (v = 0; *p; p++)
|
||||||
|
{
|
||||||
|
int c = *p;
|
||||||
|
|
||||||
|
if ('0' <= c && c <= maxdig)
|
||||||
|
v = base * v + (c - '0');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c |= 0x20;
|
||||||
|
if ('a' <= c && c <= maxalp)
|
||||||
|
v = base * v + (c - 'a') + 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != endp)
|
||||||
|
*endp = (wchar_t *)p;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
fatal(ERROR_INVALID_PARAMETER,
|
||||||
|
"usage: %s COMMAND ARGS\n"
|
||||||
|
"\n"
|
||||||
|
"commands:\n"
|
||||||
|
" lsvol list file system devices (volumes)\n"
|
||||||
|
//" list list running file system processes\n"
|
||||||
|
//" kill kill file system process\n"
|
||||||
|
" id [NAME|SID|UID] print user id\n"
|
||||||
|
" perm [PATH|SDDL|UID:GID:MODE] print permissions\n",
|
||||||
|
PROGNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspToolGetVolumeList(PWSTR DeviceName,
|
||||||
|
PWCHAR *PVolumeListBuf, PSIZE_T PVolumeListSize)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
PWCHAR VolumeListBuf;
|
||||||
|
SIZE_T VolumeListSize;
|
||||||
|
|
||||||
|
*PVolumeListBuf = 0;
|
||||||
|
*PVolumeListSize = 0;
|
||||||
|
|
||||||
|
for (VolumeListSize = 1024;; VolumeListSize *= 2)
|
||||||
|
{
|
||||||
|
VolumeListBuf = MemAlloc(VolumeListSize);
|
||||||
|
if (0 == VolumeListBuf)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
Result = FspFsctlGetVolumeList(DeviceName,
|
||||||
|
VolumeListBuf, &VolumeListSize);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
*PVolumeListBuf = VolumeListBuf;
|
||||||
|
*PVolumeListSize = VolumeListSize;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemFree(VolumeListBuf);
|
||||||
|
|
||||||
|
if (STATUS_BUFFER_TOO_SMALL != Result)
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static WCHAR FspToolGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
|
||||||
|
{
|
||||||
|
WCHAR VolumeNameBuf[MAX_PATH];
|
||||||
|
WCHAR LocalNameBuf[3];
|
||||||
|
WCHAR Drive;
|
||||||
|
|
||||||
|
if (0 == *PLogicalDrives)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
LocalNameBuf[1] = L':';
|
||||||
|
LocalNameBuf[2] = L'\0';
|
||||||
|
|
||||||
|
for (Drive = 'Z'; 'A' <= Drive; Drive--)
|
||||||
|
if (0 != (*PLogicalDrives & (1 << (Drive - 'A'))))
|
||||||
|
{
|
||||||
|
LocalNameBuf[0] = Drive;
|
||||||
|
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
|
||||||
|
{
|
||||||
|
if (0 == invariant_wcscmp(VolumeNameBuf, VolumeName))
|
||||||
|
{
|
||||||
|
*PLogicalDrives &= ~(1 << (Drive - 'A'));
|
||||||
|
return Drive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspToolGetTokenInfo(HANDLE Token,
|
||||||
|
TOKEN_INFORMATION_CLASS TokenInformationClass, PVOID *PInfo)
|
||||||
|
{
|
||||||
|
PVOID Info = 0;
|
||||||
|
DWORD Size;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (GetTokenInformation(Token, TokenInformationClass, 0, 0, &Size))
|
||||||
|
{
|
||||||
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info = MemAlloc(Size);
|
||||||
|
if (0 == Info)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetTokenInformation(Token, TokenInformationClass, Info, Size, &Size))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PInfo = Info;
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
MemFree(Info);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspToolGetNameFromSid(PSID Sid, PWSTR *PName)
|
||||||
|
{
|
||||||
|
WCHAR Name[256], Domn[256];
|
||||||
|
DWORD NameSize, DomnSize;
|
||||||
|
SID_NAME_USE Use;
|
||||||
|
PWSTR P;
|
||||||
|
|
||||||
|
NameSize = sizeof Name / sizeof Name[0];
|
||||||
|
DomnSize = sizeof Domn / sizeof Domn[0];
|
||||||
|
if (!LookupAccountSidW(0, Sid, Name, &NameSize, Domn, &DomnSize, &Use))
|
||||||
|
{
|
||||||
|
Name[0] = L'\0';
|
||||||
|
Domn[0] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
NameSize = lstrlenW(Name);
|
||||||
|
DomnSize = lstrlenW(Domn);
|
||||||
|
|
||||||
|
P = *PName = MemAlloc((DomnSize + 1 + NameSize + 1) * sizeof(WCHAR));
|
||||||
|
if (0 == P)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
if (0 < DomnSize)
|
||||||
|
{
|
||||||
|
memcpy(P, Domn, DomnSize * sizeof(WCHAR));
|
||||||
|
P[DomnSize] = L'\\';
|
||||||
|
P += DomnSize + 1;
|
||||||
|
}
|
||||||
|
memcpy(P, Name, NameSize * sizeof(WCHAR));
|
||||||
|
P[NameSize] = L'\0';
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspToolGetSidFromName(PWSTR Name, PSID *PSid)
|
||||||
|
{
|
||||||
|
PSID Sid;
|
||||||
|
WCHAR Domn[256];
|
||||||
|
DWORD SidSize, DomnSize;
|
||||||
|
SID_NAME_USE Use;
|
||||||
|
|
||||||
|
SidSize = 0;
|
||||||
|
DomnSize = sizeof Domn / sizeof Domn[0];
|
||||||
|
if (LookupAccountNameW(0, Name, 0, &SidSize, Domn, &DomnSize, &Use))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||||
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
|
Sid = MemAlloc(SidSize);
|
||||||
|
if (0 == Sid)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
DomnSize = sizeof Domn / sizeof Domn[0];
|
||||||
|
if (!LookupAccountNameW(0, Name, Sid, &SidSize, Domn, &DomnSize, &Use))
|
||||||
|
{
|
||||||
|
MemFree(Sid);
|
||||||
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
*PSid = Sid;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS lsvol_dev(PWSTR DeviceName)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
PWCHAR VolumeListBuf, VolumeListBufEnd;
|
||||||
|
SIZE_T VolumeListSize;
|
||||||
|
DWORD LogicalDrives;
|
||||||
|
WCHAR Drive[3] = L"\0:";
|
||||||
|
|
||||||
|
Result = FspToolGetVolumeList(DeviceName, &VolumeListBuf, &VolumeListSize);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
VolumeListBufEnd = (PVOID)((PUINT8)VolumeListBuf + VolumeListSize);
|
||||||
|
|
||||||
|
LogicalDrives = GetLogicalDrives();
|
||||||
|
for (PWCHAR P = VolumeListBuf, VolumeName = P; VolumeListBufEnd > P; P++)
|
||||||
|
if (L'\0' == *P)
|
||||||
|
{
|
||||||
|
Drive[0] = FspToolGetDriveLetter(&LogicalDrives, VolumeName);
|
||||||
|
info("%-4S%S", Drive[0] ? Drive : L"", VolumeName);
|
||||||
|
VolumeName = P + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemFree(VolumeListBuf);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsvol(int argc, wchar_t **argv)
|
||||||
|
{
|
||||||
|
if (1 != argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
Result = lsvol_dev(L"" FSP_FSCTL_DISK_DEVICE_NAME);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return FspWin32FromNtStatus(Result);
|
||||||
|
|
||||||
|
Result = lsvol_dev(L"" FSP_FSCTL_NET_DEVICE_NAME);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return FspWin32FromNtStatus(Result);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS id_print_sid(const char *format, PSID Sid)
|
||||||
|
{
|
||||||
|
PWSTR Str = 0;
|
||||||
|
PWSTR Name = 0;
|
||||||
|
UINT32 Uid;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (!ConvertSidToStringSidW(Sid, &Str))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = FspToolGetNameFromSid(Sid, &Name);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
Result = FspPosixMapSidToUid(Sid, &Uid);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
info(format, Str, Name, Uid);
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
MemFree(Name);
|
||||||
|
LocalFree(Str);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS id_name(PWSTR Name)
|
||||||
|
{
|
||||||
|
PSID Sid = 0;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
Result = FspToolGetSidFromName(Name, &Sid);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
id_print_sid("%S(%S) (uid=%u)", Sid);
|
||||||
|
|
||||||
|
MemFree(Sid);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS id_sid(PWSTR SidStr)
|
||||||
|
{
|
||||||
|
PSID Sid = 0;
|
||||||
|
|
||||||
|
if (!ConvertStringSidToSid(SidStr, &Sid))
|
||||||
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
|
id_print_sid("%S(%S) (uid=%u)", Sid);
|
||||||
|
|
||||||
|
LocalFree(Sid);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS id_uid(PWSTR UidStr)
|
||||||
|
{
|
||||||
|
PSID Sid = 0;
|
||||||
|
UINT32 Uid;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
Uid = wcstoint(UidStr, &UidStr, 10);
|
||||||
|
if (L'\0' != *UidStr)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
Result = FspPosixMapUidToSid(Uid, &Sid);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
id_print_sid("%S(%S) (uid=%u)", Sid);
|
||||||
|
|
||||||
|
FspDeleteSid(Sid, FspPosixMapUidToSid);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS id_user(void)
|
||||||
|
{
|
||||||
|
HANDLE Token = 0;
|
||||||
|
TOKEN_USER *Uinfo = 0;
|
||||||
|
TOKEN_OWNER *Oinfo = 0;
|
||||||
|
TOKEN_PRIMARY_GROUP *Ginfo = 0;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = FspToolGetTokenInfo(Token, TokenUser, &Uinfo);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
Result = FspToolGetTokenInfo(Token, TokenOwner, &Oinfo);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
Result = FspToolGetTokenInfo(Token, TokenPrimaryGroup, &Ginfo);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
id_print_sid("User=%S(%S) (uid=%u)", Uinfo->User.Sid);
|
||||||
|
id_print_sid("Owner=%S(%S) (uid=%u)", Oinfo->Owner);
|
||||||
|
id_print_sid("Group=%S(%S) (gid=%u)", Ginfo->PrimaryGroup);
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
MemFree(Ginfo);
|
||||||
|
MemFree(Oinfo);
|
||||||
|
MemFree(Uinfo);
|
||||||
|
|
||||||
|
if (0 != Token)
|
||||||
|
CloseHandle(Token);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int id(int argc, wchar_t **argv)
|
||||||
|
{
|
||||||
|
if (2 < argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (2 == argc)
|
||||||
|
{
|
||||||
|
if (L'S' == argv[1][0] && L'-' == argv[1][1] && L'1' == argv[1][2] && L'-' == argv[1][3])
|
||||||
|
Result = id_sid(argv[1]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = id_uid(argv[1]);
|
||||||
|
if (STATUS_INVALID_PARAMETER == Result)
|
||||||
|
Result = id_name(argv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = id_user();
|
||||||
|
|
||||||
|
return FspWin32FromNtStatus(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS perm_print_sd(PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||||
|
{
|
||||||
|
UINT32 Uid, Gid, Mode;
|
||||||
|
PWSTR Sddl = 0;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
Result = FspPosixMapSecurityDescriptorToPermissions(SecurityDescriptor, &Uid, &Gid, &Mode);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
if (!ConvertSecurityDescriptorToStringSecurityDescriptorW(
|
||||||
|
SecurityDescriptor, SDDL_REVISION_1,
|
||||||
|
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||||
|
&Sddl, 0))
|
||||||
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
|
info("%S (perm=%u:%u:%d%d%d%d)",
|
||||||
|
Sddl, Uid, Gid, (Mode >> 9) & 7, (Mode >> 6) & 7, (Mode >> 3) & 7, Mode & 7);
|
||||||
|
|
||||||
|
LocalFree(Sddl);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS perm_path(PWSTR Path)
|
||||||
|
{
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
||||||
|
int ErrorCode;
|
||||||
|
|
||||||
|
ErrorCode = GetNamedSecurityInfoW(Path, SE_FILE_OBJECT,
|
||||||
|
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||||
|
0, 0, 0, 0, &SecurityDescriptor);
|
||||||
|
if (0 != ErrorCode)
|
||||||
|
return FspNtStatusFromWin32(ErrorCode);
|
||||||
|
|
||||||
|
perm_print_sd(SecurityDescriptor);
|
||||||
|
|
||||||
|
LocalFree(SecurityDescriptor);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS perm_sddl(PWSTR Sddl)
|
||||||
|
{
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
||||||
|
|
||||||
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||||
|
Sddl, SDDL_REVISION_1, &SecurityDescriptor, 0))
|
||||||
|
return FspNtStatusFromWin32(GetLastError());
|
||||||
|
|
||||||
|
perm_print_sd(SecurityDescriptor);
|
||||||
|
|
||||||
|
LocalFree(SecurityDescriptor);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS perm_mode(PWSTR PermStr)
|
||||||
|
{
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
|
||||||
|
UINT32 Uid, Gid, Mode;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
Uid = wcstoint(PermStr, &PermStr, 10);
|
||||||
|
if (L':' != *PermStr)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
Gid = wcstoint(PermStr + 1, &PermStr, 10);
|
||||||
|
if (L':' != *PermStr)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
Mode = wcstoint(PermStr + 1, &PermStr, 8);
|
||||||
|
if (L'\0' != *PermStr)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
Result = FspPosixMapPermissionsToSecurityDescriptor(Uid, Gid, Mode, &SecurityDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
perm_print_sd(SecurityDescriptor);
|
||||||
|
|
||||||
|
FspDeleteSecurityDescriptor(SecurityDescriptor,
|
||||||
|
FspPosixMapPermissionsToSecurityDescriptor);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int perm(int argc, wchar_t **argv)
|
||||||
|
{
|
||||||
|
if (2 != argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
PWSTR P;
|
||||||
|
|
||||||
|
for (P = argv[1]; *P; P++)
|
||||||
|
if (L'\\' == *P)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (L'\\' == *P)
|
||||||
|
Result = perm_path(argv[1]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = perm_mode(argv[1]);
|
||||||
|
if (STATUS_INVALID_PARAMETER == Result)
|
||||||
|
Result = perm_sddl(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FspWin32FromNtStatus(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wmain(int argc, wchar_t **argv)
|
||||||
|
{
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
if (0 == argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (0 == invariant_wcscmp(L"lsvol", argv[0]))
|
||||||
|
return lsvol(argc, argv);
|
||||||
|
else
|
||||||
|
if (0 == invariant_wcscmp(L"id", argv[0]))
|
||||||
|
return id(argc, argv);
|
||||||
|
else
|
||||||
|
if (0 == invariant_wcscmp(L"perm", argv[0]))
|
||||||
|
return perm(argc, argv);
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wmainCRTStartup(void)
|
||||||
|
{
|
||||||
|
DWORD Argc;
|
||||||
|
PWSTR *Argv;
|
||||||
|
|
||||||
|
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
|
||||||
|
if (0 == Argv)
|
||||||
|
ExitProcess(GetLastError());
|
||||||
|
|
||||||
|
ExitProcess(wmain(Argc, Argv));
|
||||||
|
}
|
@ -545,6 +545,7 @@ NTSTATUS FspFsvolCreatePrepare(
|
|||||||
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
||||||
HANDLE UserModeAccessToken;
|
HANDLE UserModeAccessToken;
|
||||||
PEPROCESS Process;
|
PEPROCESS Process;
|
||||||
|
HANDLE ProcessId;
|
||||||
FSP_FILE_NODE *FileNode;
|
FSP_FILE_NODE *FileNode;
|
||||||
FSP_FILE_DESC *FileDesc;
|
FSP_FILE_DESC *FileDesc;
|
||||||
PFILE_OBJECT FileObject;
|
PFILE_OBJECT FileObject;
|
||||||
@ -578,11 +579,15 @@ NTSTATUS FspFsvolCreatePrepare(
|
|||||||
/* get a pointer to the current process so that we can close the impersonation token later */
|
/* get a pointer to the current process so that we can close the impersonation token later */
|
||||||
Process = PsGetCurrentProcess();
|
Process = PsGetCurrentProcess();
|
||||||
ObReferenceObject(Process);
|
ObReferenceObject(Process);
|
||||||
|
ProcessId = PsGetProcessId(Process);
|
||||||
|
|
||||||
/* send the user-mode handle to the user-mode file system */
|
/* send the user-mode handle to the user-mode file system */
|
||||||
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
|
FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken;
|
||||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||||
Request->Req.Create.AccessToken = (UINT_PTR)UserModeAccessToken;
|
ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL);
|
||||||
|
ASSERT((UINT64)(UINT_PTR)ProcessId <= 0xffffffffULL);
|
||||||
|
Request->Req.Create.AccessToken =
|
||||||
|
((UINT64)(UINT_PTR)ProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1098,7 +1103,44 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
|
/*
|
||||||
|
* FspFileNodeTrySetFileInfoOnOpen sets the FileNode's metadata to values reported
|
||||||
|
* by the user mode file system. It does so only if the file is not already open; the
|
||||||
|
* reason is that there is a subtle race condition otherwise.
|
||||||
|
*
|
||||||
|
* Consider that a file is already open and (for example) being appended to. The appends
|
||||||
|
* appear as WRITE IRP's and they are all synchronized by acquiring the FileNode resources
|
||||||
|
* exclusive. Part of the WRITE protocol involves returning an updated FileInfo for the
|
||||||
|
* written FileNode, which the FSD uses to update its view of the file metadata.
|
||||||
|
*
|
||||||
|
* Now consider that a file OPEN comes in. Because the FSD does not know yet which FileNode
|
||||||
|
* will be opened it does not acquire any FileNode. [Note that while it is possible to
|
||||||
|
* uniquely identify a FileNode by FileName currently, this would no longer be the case
|
||||||
|
* when we implement hard links.] The FSD posts the OPEN request to the user mode file system.
|
||||||
|
* The user mode file system processes the OPEN request successfully and responds with the
|
||||||
|
* opened file and its FileInfo.
|
||||||
|
*
|
||||||
|
* Prior to the FSD processing the OPEN response additional WRITE IRP's come through the
|
||||||
|
* original file handle. These WRITE's update the FileSize as understood by the user mode
|
||||||
|
* file system and the corresponding FileInfo gets reported back to the FSD. Eventually the
|
||||||
|
* delayed OPEN response gets processed, which now clobbers the FileInfo as understood by
|
||||||
|
* the FSD.
|
||||||
|
*
|
||||||
|
* The problem here is that OPEN requests have no way of locking the FileNode while the OPEN
|
||||||
|
* request is in transit to the user mode file system. In all other cases the user mode file
|
||||||
|
* system and the FSD update their view of the file's metadata in an atomic fashion. Not so
|
||||||
|
* in the case of OPEN.
|
||||||
|
*
|
||||||
|
* While this is a subtle race condition it can nevertheless creates a real problem. For
|
||||||
|
* example, Explorer often opens files to get information about them and may inappropriately
|
||||||
|
* update the FSD view of the file size during WRITE's.
|
||||||
|
*
|
||||||
|
* FspFileNodeTrySetFileInfoOnOpen attempts to mitigate this problem by only updating the
|
||||||
|
* FileInfo if the file is not already open. This avoids placing stale information in the
|
||||||
|
* FileNode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FspFileNodeTrySetFileInfoOnOpen(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
|
||||||
FILE_CREATED == Response->IoStatus.Information);
|
FILE_CREATED == Response->IoStatus.Information);
|
||||||
|
|
||||||
if (FlushImage)
|
if (FlushImage)
|
||||||
|
@ -480,6 +480,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
PVOID DirInfoBuffer;
|
PVOID DirInfoBuffer;
|
||||||
ULONG DirInfoSize;
|
ULONG DirInfoSize;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
BOOLEAN PassQueryDirectoryPattern, PatternIsFileName;
|
||||||
BOOLEAN Success;
|
BOOLEAN Success;
|
||||||
|
|
||||||
ASSERT(FileNode == FileDesc->FileNode);
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
@ -556,6 +557,22 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
|
|
||||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||||
|
|
||||||
|
/* special handling when pattern is filename */
|
||||||
|
PatternIsFileName = FsvolDeviceExtension->VolumeParams.PassQueryDirectoryFileName &&
|
||||||
|
!FsRtlDoesNameContainWildCards(&FileDesc->DirectoryPattern);
|
||||||
|
PassQueryDirectoryPattern = PatternIsFileName ||
|
||||||
|
(FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
|
||||||
|
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer);
|
||||||
|
if (PatternIsFileName &&
|
||||||
|
0 != FileDesc->DirectoryMarker.Buffer &&
|
||||||
|
0 == FspFileNameCompare(&FileDesc->DirectoryPattern, &FileDesc->DirectoryMarker,
|
||||||
|
!FileDesc->CaseSensitive, 0))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return !FileDesc->DirectoryHasSuchFile ?
|
||||||
|
STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
/* buffer the user buffer! */
|
/* buffer the user buffer! */
|
||||||
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
||||||
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
||||||
@ -567,9 +584,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
|
|
||||||
/* create request */
|
/* create request */
|
||||||
Result = FspIopCreateRequestEx(Irp, 0,
|
Result = FspIopCreateRequestEx(Irp, 0,
|
||||||
(FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
|
(PassQueryDirectoryPattern ? FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0) +
|
||||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?
|
|
||||||
FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0) +
|
|
||||||
(FsvolDeviceExtension->VolumeParams.MaxComponentLength + 1) * sizeof(WCHAR),
|
(FsvolDeviceExtension->VolumeParams.MaxComponentLength + 1) * sizeof(WCHAR),
|
||||||
FspFsvolQueryDirectoryRequestFini, &Request);
|
FspFsvolQueryDirectoryRequestFini, &Request);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
@ -584,9 +599,9 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
Request->Req.QueryDirectory.Length = SystemBufferLength;
|
Request->Req.QueryDirectory.Length = SystemBufferLength;
|
||||||
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
|
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
|
||||||
|
|
||||||
if (FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
|
if (PassQueryDirectoryPattern)
|
||||||
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
|
|
||||||
{
|
{
|
||||||
|
Request->Req.QueryDirectory.PatternIsFileName = PatternIsFileName;
|
||||||
Request->Req.QueryDirectory.Pattern.Offset =
|
Request->Req.QueryDirectory.Pattern.Offset =
|
||||||
Request->FileName.Size;
|
Request->FileName.Size;
|
||||||
Request->Req.QueryDirectory.Pattern.Size =
|
Request->Req.QueryDirectory.Pattern.Size =
|
||||||
|
@ -1350,6 +1350,8 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
|
|||||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||||
|
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
|
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||||
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
||||||
|
@ -58,6 +58,8 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
|
|||||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||||
|
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
|
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||||
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
||||||
@ -129,6 +131,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
|||||||
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeGetFileInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
|
||||||
|
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfoOnOpen)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
|
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
|
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
|
||||||
@ -1660,6 +1663,43 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
|
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
BOOLEAN EarlyExit;
|
||||||
|
|
||||||
|
FspFsvolDeviceLockContextTable(FileNode->FsvolDeviceObject);
|
||||||
|
EarlyExit = 1 < FileNode->OpenCount;
|
||||||
|
FspFsvolDeviceUnlockContextTable(FileNode->FsvolDeviceObject);
|
||||||
|
|
||||||
|
if (EarlyExit)
|
||||||
|
{
|
||||||
|
if (TruncateOnClose)
|
||||||
|
{
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
|
UINT64 AllocationSize = FileInfo->AllocationSize > FileInfo->FileSize ?
|
||||||
|
FileInfo->AllocationSize : FileInfo->FileSize;
|
||||||
|
UINT64 AllocationUnit;
|
||||||
|
|
||||||
|
AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize *
|
||||||
|
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
|
||||||
|
AllocationSize = (AllocationSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||||
|
|
||||||
|
if ((UINT64)FileNode->Header.AllocationSize.QuadPart != AllocationSize ||
|
||||||
|
(UINT64)FileNode->Header.FileSize.QuadPart != FileInfo->FileSize)
|
||||||
|
FileNode->TruncateOnClose = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo, TruncateOnClose);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber)
|
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber)
|
||||||
{
|
{
|
||||||
|
@ -1573,6 +1573,7 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
|||||||
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
||||||
HANDLE UserModeAccessToken;
|
HANDLE UserModeAccessToken;
|
||||||
PEPROCESS Process;
|
PEPROCESS Process;
|
||||||
|
HANDLE ProcessId;
|
||||||
|
|
||||||
SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken);
|
SecuritySubjectContext = FspIopRequestContext(Request, RequestSubjectContextOrAccessToken);
|
||||||
|
|
||||||
@ -1604,11 +1605,15 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
|||||||
/* get a pointer to the current process so that we can close the impersonation token later */
|
/* get a pointer to the current process so that we can close the impersonation token later */
|
||||||
Process = PsGetCurrentProcess();
|
Process = PsGetCurrentProcess();
|
||||||
ObReferenceObject(Process);
|
ObReferenceObject(Process);
|
||||||
|
ProcessId = PsGetProcessId(Process);
|
||||||
|
|
||||||
/* send the user-mode handle to the user-mode file system */
|
/* send the user-mode handle to the user-mode file system */
|
||||||
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken;
|
FspIopRequestContext(Request, RequestSubjectContextOrAccessToken) = UserModeAccessToken;
|
||||||
FspIopRequestContext(Request, RequestProcess) = Process;
|
FspIopRequestContext(Request, RequestProcess) = Process;
|
||||||
Request->Req.SetInformation.Info.Rename.AccessToken = (UINT_PTR)UserModeAccessToken;
|
ASSERT((UINT64)(UINT_PTR)UserModeAccessToken <= 0xffffffffULL);
|
||||||
|
ASSERT((UINT64)(UINT_PTR)ProcessId <= 0xffffffffULL);
|
||||||
|
Request->Req.SetInformation.Info.Rename.AccessToken =
|
||||||
|
((UINT64)(UINT_PTR)ProcessId << 32) | (UINT64)(UINT_PTR)UserModeAccessToken;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,9 @@ set opt_tests=^
|
|||||||
sample-passthrough-x64 ^
|
sample-passthrough-x64 ^
|
||||||
sample-passthrough-x86 ^
|
sample-passthrough-x86 ^
|
||||||
sample-passthrough-fuse-x64 ^
|
sample-passthrough-fuse-x64 ^
|
||||||
|
sample-fsx-passthrough-fuse-x64 ^
|
||||||
sample-passthrough-fuse-x86 ^
|
sample-passthrough-fuse-x86 ^
|
||||||
|
sample-fsx-passthrough-fuse-x86 ^
|
||||||
sample-passthrough-dotnet
|
sample-passthrough-dotnet
|
||||||
|
|
||||||
set tests=
|
set tests=
|
||||||
@ -591,6 +593,16 @@ call :__run_sample_fuse_test passthrough-fuse x86 passthrough-fuse-x86 winfsp-te
|
|||||||
if !ERRORLEVEL! neq 0 goto fail
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
|
:sample-fsx-passthrough-fuse-x64
|
||||||
|
call :__run_sample_fsx_fuse_test passthrough-fuse x64 passthrough-fuse-x64 fsx
|
||||||
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
:sample-fsx-passthrough-fuse-x86
|
||||||
|
call :__run_sample_fsx_fuse_test passthrough-fuse x86 passthrough-fuse-x86 fsx
|
||||||
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
:__run_sample_test
|
:__run_sample_test
|
||||||
set RunSampleTestExit=0
|
set RunSampleTestExit=0
|
||||||
call %ProjRoot%\tools\build-sample %Configuration% %2 %1 "%TMP%\%1"
|
call %ProjRoot%\tools\build-sample %Configuration% %2 %1 "%TMP%\%1"
|
||||||
@ -645,6 +657,30 @@ call "%ProjRoot%\tools\fsreg" -u %1
|
|||||||
rmdir /s/q "%TMP%\%1"
|
rmdir /s/q "%TMP%\%1"
|
||||||
exit /b !RunSampleTestExit!
|
exit /b !RunSampleTestExit!
|
||||||
|
|
||||||
|
:__run_sample_fsx_fuse_test
|
||||||
|
set RunSampleTestExit=0
|
||||||
|
call %ProjRoot%\tools\build-sample %Configuration% %2 %1 "%TMP%\%1"
|
||||||
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
|
mkdir "%TMP%\%1\test"
|
||||||
|
call "%ProjRoot%\tools\fsreg" %1 "%TMP%\%1\build\%Configuration%\%3.exe" ^
|
||||||
|
"-ouid=11,gid=65792 --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)"
|
||||||
|
echo net use L: "\\%1\%TMP::=$%\%1\test"
|
||||||
|
net use L: "\\%1\%TMP::=$%\%1\test"
|
||||||
|
if !ERRORLEVEL! neq 0 goto fail
|
||||||
|
echo net use ^| findstr L:
|
||||||
|
net use | findstr L:
|
||||||
|
pushd >nul
|
||||||
|
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
|
||||||
|
L:
|
||||||
|
"%ProjRoot%\ext\test\fstools\src\fsx\%4.exe" -N 5000 test xxxxxx
|
||||||
|
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
|
||||||
|
popd
|
||||||
|
echo net use L: /delete
|
||||||
|
net use L: /delete
|
||||||
|
call "%ProjRoot%\tools\fsreg" -u %1
|
||||||
|
rmdir /s/q "%TMP%\%1"
|
||||||
|
exit /b !RunSampleTestExit!
|
||||||
|
|
||||||
:leak-test
|
:leak-test
|
||||||
for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^
|
for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^
|
||||||
/c:"Current Pool Allocations:" ^
|
/c:"Current Pool Allocations:" ^
|
||||||
|
@ -75,6 +75,41 @@ static void file_list_test(void)
|
|||||||
ASSERT(Success);
|
ASSERT(Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void file_list_single_test(void)
|
||||||
|
{
|
||||||
|
HANDLE Handle;
|
||||||
|
BOOL Success;
|
||||||
|
WCHAR FileName[MAX_PATH];
|
||||||
|
WIN32_FIND_DATAW FindData;
|
||||||
|
|
||||||
|
for (ULONG ListIndex = 0; OptListCount > ListIndex; ListIndex++)
|
||||||
|
for (ULONG Index = 0; OptFileCount > Index; Index++)
|
||||||
|
{
|
||||||
|
StringCbPrintfW(FileName, sizeof FileName, L"fsbench-file%lu", Index);
|
||||||
|
Handle = FindFirstFileW(FileName, &FindData);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
} while (FindNextFileW(Handle, &FindData));
|
||||||
|
Success = FindClose(Handle);
|
||||||
|
ASSERT(Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void file_list_none_test(void)
|
||||||
|
{
|
||||||
|
HANDLE Handle;
|
||||||
|
WCHAR FileName[MAX_PATH];
|
||||||
|
WIN32_FIND_DATAW FindData;
|
||||||
|
|
||||||
|
for (ULONG ListIndex = 0; OptListCount > ListIndex; ListIndex++)
|
||||||
|
for (ULONG Index = 0; OptFileCount > Index; Index++)
|
||||||
|
{
|
||||||
|
StringCbPrintfW(FileName, sizeof FileName, L"{5F849D7F-73AF-49AC-B7C3-657B36EAD5C4}");
|
||||||
|
Handle = FindFirstFileW(FileName, &FindData);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||||
|
ASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
static void file_delete_test(void)
|
static void file_delete_test(void)
|
||||||
{
|
{
|
||||||
BOOL Success;
|
BOOL Success;
|
||||||
@ -117,6 +152,8 @@ static void file_tests(void)
|
|||||||
TEST(file_open_test);
|
TEST(file_open_test);
|
||||||
TEST(file_overwrite_test);
|
TEST(file_overwrite_test);
|
||||||
TEST(file_list_test);
|
TEST(file_list_test);
|
||||||
|
TEST(file_list_single_test);
|
||||||
|
TEST(file_list_none_test);
|
||||||
TEST(file_delete_test);
|
TEST(file_delete_test);
|
||||||
TEST(file_mkdir_test);
|
TEST(file_mkdir_test);
|
||||||
TEST(file_rmdir_test);
|
TEST(file_rmdir_test);
|
||||||
|
@ -188,15 +188,21 @@ namespace memfs
|
|||||||
}
|
}
|
||||||
public IEnumerable<String> GetDescendantFileNames(FileNode FileNode)
|
public IEnumerable<String> GetDescendantFileNames(FileNode FileNode)
|
||||||
{
|
{
|
||||||
String MinName = "\\";
|
yield return FileNode.FileName;
|
||||||
String MaxName = "]";
|
String MinName = FileNode.FileName + ":";
|
||||||
|
String MaxName = FileNode.FileName + ";";
|
||||||
|
foreach (String Name in Set.GetViewBetween(MinName, MaxName))
|
||||||
|
if (Name.Length > MinName.Length)
|
||||||
|
yield return Name;
|
||||||
|
MinName = "\\";
|
||||||
|
MaxName = "]";
|
||||||
if ("\\" != FileNode.FileName)
|
if ("\\" != FileNode.FileName)
|
||||||
{
|
{
|
||||||
MinName = FileNode.FileName;
|
MinName = FileNode.FileName + "\\";
|
||||||
MaxName = FileNode.FileName + "]";
|
MaxName = FileNode.FileName + "]";
|
||||||
}
|
}
|
||||||
foreach (String Name in Set.GetViewBetween(MinName, MaxName))
|
foreach (String Name in Set.GetViewBetween(MinName, MaxName))
|
||||||
if (Name == MinName || Name.Length > MinName.Length)
|
if (Name.Length > MinName.Length)
|
||||||
yield return Name;
|
yield return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +254,7 @@ namespace memfs
|
|||||||
Host.ReparsePointsAccessCheck = false;
|
Host.ReparsePointsAccessCheck = false;
|
||||||
Host.NamedStreams = true;
|
Host.NamedStreams = true;
|
||||||
Host.PostCleanupWhenModifiedOnly = true;
|
Host.PostCleanupWhenModifiedOnly = true;
|
||||||
|
Host.PassQueryDirectoryFileName = true;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,6 +850,35 @@ namespace memfs
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override int GetDirInfoByName(
|
||||||
|
Object ParentNode0,
|
||||||
|
Object FileDesc,
|
||||||
|
String FileName,
|
||||||
|
out String NormalizedName,
|
||||||
|
out FileInfo FileInfo)
|
||||||
|
{
|
||||||
|
FileNode ParentNode = (FileNode)ParentNode0;
|
||||||
|
FileNode FileNode;
|
||||||
|
|
||||||
|
FileName =
|
||||||
|
ParentNode.FileName +
|
||||||
|
("\\" == ParentNode.FileName ? "" : "\\") +
|
||||||
|
Path.GetFileName(FileName);
|
||||||
|
|
||||||
|
FileNode = FileNodeMap.Get(FileName);
|
||||||
|
if (null == FileNode)
|
||||||
|
{
|
||||||
|
NormalizedName = default(String);
|
||||||
|
FileInfo = default(FileInfo);
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalizedName = Path.GetFileName(FileNode.FileName);
|
||||||
|
FileInfo = FileNode.FileInfo;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
public override Int32 GetReparsePointByName(
|
public override Int32 GetReparsePointByName(
|
||||||
String FileName,
|
String FileName,
|
||||||
Boolean IsDirectory,
|
Boolean IsDirectory,
|
||||||
|
@ -42,6 +42,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
|
|||||||
*/
|
*/
|
||||||
#define MEMFS_NAMED_STREAMS
|
#define MEMFS_NAMED_STREAMS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define the MEMFS_DIRINFO_BY_NAME macro to include GetDirInfoByName.
|
||||||
|
*/
|
||||||
|
#define MEMFS_DIRINFO_BY_NAME
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
||||||
* a check for the Write buffer to ensure that it is read-only.
|
* a check for the Write buffer to ensure that it is read-only.
|
||||||
@ -137,20 +142,85 @@ UINT64 MemfsGetSystemTime(VOID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int MemfsCompareString(PWSTR a, int alen, PWSTR b, int blen, BOOLEAN CaseInsensitive)
|
int MemfsFileNameCompare(PWSTR a0, int alen, PWSTR b0, int blen, BOOLEAN CaseInsensitive)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* HACKFIX GITHUB ISSUE #103
|
||||||
|
*
|
||||||
|
* MEMFS stores the whole file system in a single map. This was to keep the file system
|
||||||
|
* "simple", but in retrospect it was probably a bad decision as it creates multiple problems.
|
||||||
|
*
|
||||||
|
* One of these problems was what caused GitHub issue #103. A directory that had both "Firefox"
|
||||||
|
* and "Firefox64" subdirectories in it would cause directory listings of "Firefox" to fail,
|
||||||
|
* because "Firefox\\" (and "Firefox:") comes *after* "Firefox64" in case-sensitive or
|
||||||
|
* case-insensitive order!
|
||||||
|
*
|
||||||
|
* The hackfix is this: copy our input strings into temporary buffers and then translate ':' to
|
||||||
|
* '\x1' and '\\' to '\x2' so they always order the FileName map properly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
WCHAR a[MEMFS_MAX_PATH], b[MEMFS_MAX_PATH];
|
||||||
int len, res;
|
int len, res;
|
||||||
|
|
||||||
if (-1 == alen)
|
if (-1 == alen)
|
||||||
alen = (int)wcslen(a);
|
{
|
||||||
|
PWSTR p = a0, q = a;
|
||||||
|
for (; *p; p++, q++)
|
||||||
|
if (L':' == *p)
|
||||||
|
*q = L'\x1';
|
||||||
|
else if (L'\\' == *p)
|
||||||
|
*q = L'\x2';
|
||||||
|
else
|
||||||
|
*q = *p;
|
||||||
|
alen = (int)(p - a0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PWSTR p = a0, q = a;
|
||||||
|
for (PWSTR endp = p + alen; endp > p; p++, q++)
|
||||||
|
if (L':' == *p)
|
||||||
|
*q = L'\x1';
|
||||||
|
else if (L'\\' == *p)
|
||||||
|
*q = L'\x2';
|
||||||
|
else
|
||||||
|
*q = *p;
|
||||||
|
}
|
||||||
|
|
||||||
if (-1 == blen)
|
if (-1 == blen)
|
||||||
blen = (int)wcslen(b);
|
{
|
||||||
|
PWSTR p = b0, q = b;
|
||||||
|
for (; *p; p++, q++)
|
||||||
|
if (L':' == *p)
|
||||||
|
*q = L'\x1';
|
||||||
|
else if (L'\\' == *p)
|
||||||
|
*q = L'\x2';
|
||||||
|
else
|
||||||
|
*q = *p;
|
||||||
|
blen = (int)(p - b0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PWSTR p = b0, q = b;
|
||||||
|
for (PWSTR endp = p + blen; endp > p; p++, q++)
|
||||||
|
if (L':' == *p)
|
||||||
|
*q = L'\x1';
|
||||||
|
else if (L'\\' == *p)
|
||||||
|
*q = L'\x2';
|
||||||
|
else
|
||||||
|
*q = *p;
|
||||||
|
}
|
||||||
|
|
||||||
len = alen < blen ? alen : blen;
|
len = alen < blen ? alen : blen;
|
||||||
|
|
||||||
/* we should still be in the C locale */
|
|
||||||
if (CaseInsensitive)
|
if (CaseInsensitive)
|
||||||
res = _wcsnicmp(a, b, len);
|
{
|
||||||
|
/* better Unicode comparison when case-insensitive */
|
||||||
|
res = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, a, alen, b, blen);
|
||||||
|
if (0 != res)
|
||||||
|
res -= 2;
|
||||||
|
else
|
||||||
|
res = _wcsnicmp(a, b, len);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
res = wcsncmp(a, b, len);
|
res = wcsncmp(a, b, len);
|
||||||
|
|
||||||
@ -160,19 +230,13 @@ int MemfsCompareString(PWSTR a, int alen, PWSTR b, int blen, BOOLEAN CaseInsensi
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
|
||||||
int MemfsFileNameCompare(PWSTR a, PWSTR b, BOOLEAN CaseInsensitive)
|
|
||||||
{
|
|
||||||
return MemfsCompareString(a, -1, b, -1, CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
BOOLEAN MemfsFileNameHasPrefix(PWSTR a, PWSTR b, BOOLEAN CaseInsensitive)
|
BOOLEAN MemfsFileNameHasPrefix(PWSTR a, PWSTR b, BOOLEAN CaseInsensitive)
|
||||||
{
|
{
|
||||||
int alen = (int)wcslen(a);
|
int alen = (int)wcslen(a);
|
||||||
int blen = (int)wcslen(b);
|
int blen = (int)wcslen(b);
|
||||||
|
|
||||||
return alen >= blen && 0 == MemfsCompareString(a, blen, b, blen, CaseInsensitive) &&
|
return alen >= blen && 0 == MemfsFileNameCompare(a, blen, b, blen, CaseInsensitive) &&
|
||||||
(alen == blen || (1 == blen && L'\\' == b[0]) ||
|
(alen == blen || (1 == blen && L'\\' == b[0]) ||
|
||||||
#if defined(MEMFS_NAMED_STREAMS)
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
(L'\\' == a[blen] || L':' == a[blen]));
|
(L'\\' == a[blen] || L':' == a[blen]));
|
||||||
@ -205,7 +269,7 @@ struct MEMFS_FILE_NODE_LESS
|
|||||||
}
|
}
|
||||||
bool operator()(PWSTR a, PWSTR b) const
|
bool operator()(PWSTR a, PWSTR b) const
|
||||||
{
|
{
|
||||||
return 0 > MemfsFileNameCompare(a, b, CaseInsensitive);
|
return 0 > MemfsFileNameCompare(a, -1, b, -1, CaseInsensitive);
|
||||||
}
|
}
|
||||||
BOOLEAN CaseInsensitive;
|
BOOLEAN CaseInsensitive;
|
||||||
};
|
};
|
||||||
@ -446,7 +510,7 @@ BOOLEAN MemfsFileNodeMapHasChild(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMFS_FILE_NO
|
|||||||
continue;
|
continue;
|
||||||
#endif
|
#endif
|
||||||
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
||||||
Result = 0 == MemfsFileNameCompare(Remain, FileNode->FileName,
|
Result = 0 == MemfsFileNameCompare(Remain, -1, FileNode->FileName, -1,
|
||||||
MemfsFileNodeMapIsCaseInsensitive(FileNodeMap));
|
MemfsFileNodeMapIsCaseInsensitive(FileNodeMap));
|
||||||
FspPathCombine(iter->second->FileName, Suffix);
|
FspPathCombine(iter->second->FileName, Suffix);
|
||||||
break;
|
break;
|
||||||
@ -483,7 +547,7 @@ BOOLEAN MemfsFileNodeMapEnumerateChildren(MEMFS_FILE_NODE_MAP *FileNodeMap, MEMF
|
|||||||
MemfsFileNodeMapIsCaseInsensitive(FileNodeMap)))
|
MemfsFileNodeMapIsCaseInsensitive(FileNodeMap)))
|
||||||
break;
|
break;
|
||||||
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
FspPathSuffix(iter->second->FileName, &Remain, &Suffix, Root);
|
||||||
IsDirectoryChild = 0 == MemfsFileNameCompare(Remain, FileNode->FileName,
|
IsDirectoryChild = 0 == MemfsFileNameCompare(Remain, -1, FileNode->FileName, -1,
|
||||||
MemfsFileNodeMapIsCaseInsensitive(FileNodeMap));
|
MemfsFileNodeMapIsCaseInsensitive(FileNodeMap));
|
||||||
#if defined(MEMFS_NAMED_STREAMS)
|
#if defined(MEMFS_NAMED_STREAMS)
|
||||||
IsDirectoryChild = IsDirectoryChild && 0 == wcschr(Suffix, L':');
|
IsDirectoryChild = IsDirectoryChild && 0 == wcschr(Suffix, L':');
|
||||||
@ -726,7 +790,7 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
size_t RemainLength, BSlashLength, SuffixLength;
|
size_t RemainLength, BSlashLength, SuffixLength;
|
||||||
|
|
||||||
FspPathSuffix(FileName, &Remain, &Suffix, Root);
|
FspPathSuffix(FileName, &Remain, &Suffix, Root);
|
||||||
assert(0 == MemfsCompareString(Remain, -1, ParentNode->FileName, -1, TRUE));
|
assert(0 == MemfsFileNameCompare(Remain, -1, ParentNode->FileName, -1, TRUE));
|
||||||
FspPathCombine(FileName, Suffix);
|
FspPathCombine(FileName, Suffix);
|
||||||
|
|
||||||
RemainLength = wcslen(ParentNode->FileName);
|
RemainLength = wcslen(ParentNode->FileName);
|
||||||
@ -1350,6 +1414,8 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PVOID FileNode0, PWSTR Pattern, PWSTR Marker,
|
PVOID FileNode0, PWSTR Pattern, PWSTR Marker,
|
||||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
|
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
|
||||||
{
|
{
|
||||||
|
assert(0 == Pattern);
|
||||||
|
|
||||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
MEMFS_FILE_NODE *ParentNode;
|
MEMFS_FILE_NODE *ParentNode;
|
||||||
@ -1388,6 +1454,48 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MEMFS_DIRINFO_BY_NAME)
|
||||||
|
static NTSTATUS GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PVOID ParentNode0, PWSTR FileName,
|
||||||
|
FSP_FSCTL_DIR_INFO *DirInfo)
|
||||||
|
{
|
||||||
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
|
MEMFS_FILE_NODE *ParentNode = (MEMFS_FILE_NODE *)ParentNode0;
|
||||||
|
MEMFS_FILE_NODE *FileNode;
|
||||||
|
WCHAR FileNameBuf[MEMFS_MAX_PATH];
|
||||||
|
size_t ParentLength, BSlashLength, FileNameLength;
|
||||||
|
WCHAR Root[2] = L"\\";
|
||||||
|
PWSTR Remain, Suffix;
|
||||||
|
|
||||||
|
ParentLength = wcslen(ParentNode->FileName);
|
||||||
|
BSlashLength = 1 < ParentLength;
|
||||||
|
FileNameLength = wcslen(FileName);
|
||||||
|
if (MEMFS_MAX_PATH <= ParentLength + BSlashLength + FileNameLength)
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND; //STATUS_OBJECT_NAME_INVALID?
|
||||||
|
|
||||||
|
memcpy(FileNameBuf, ParentNode->FileName, ParentLength * sizeof(WCHAR));
|
||||||
|
memcpy(FileNameBuf + ParentLength, L"\\", BSlashLength * sizeof(WCHAR));
|
||||||
|
memcpy(FileNameBuf + ParentLength + BSlashLength, FileName, (FileNameLength + 1) * sizeof(WCHAR));
|
||||||
|
|
||||||
|
FileName = FileNameBuf;
|
||||||
|
|
||||||
|
FileNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, FileName);
|
||||||
|
if (0 == FileNode)
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
FspPathSuffix(FileNode->FileName, &Remain, &Suffix, Root);
|
||||||
|
FileName = Suffix;
|
||||||
|
FspPathCombine(FileNode->FileName, Suffix);
|
||||||
|
|
||||||
|
//memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
|
||||||
|
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(FileName) * sizeof(WCHAR));
|
||||||
|
DirInfo->FileInfo = FileNode->FileInfo;
|
||||||
|
memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO));
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(MEMFS_REPARSE_POINTS)
|
#if defined(MEMFS_REPARSE_POINTS)
|
||||||
static NTSTATUS ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent,
|
||||||
@ -1628,6 +1736,11 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
|||||||
#else
|
#else
|
||||||
0,
|
0,
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(MEMFS_DIRINFO_BY_NAME)
|
||||||
|
GetDirInfoByName,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1704,6 +1817,9 @@ NTSTATUS MemfsCreateFunnel(
|
|||||||
VolumeParams.NamedStreams = 1;
|
VolumeParams.NamedStreams = 1;
|
||||||
#endif
|
#endif
|
||||||
VolumeParams.PostCleanupWhenModifiedOnly = 1;
|
VolumeParams.PostCleanupWhenModifiedOnly = 1;
|
||||||
|
#if defined(MEMFS_DIRINFO_BY_NAME)
|
||||||
|
VolumeParams.PassQueryDirectoryFileName = 1;
|
||||||
|
#endif
|
||||||
if (0 != VolumePrefix)
|
if (0 != VolumePrefix)
|
||||||
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
|
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
|
||||||
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),
|
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),
|
||||||
|
@ -1082,6 +1082,57 @@ void create_namelen_test(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_FILE_SYSTEM_OPERATION *create_pid_CreateOp;
|
||||||
|
UINT32 create_pid_Pass, create_pid_Fail;
|
||||||
|
|
||||||
|
NTSTATUS create_pid_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
|
{
|
||||||
|
if (FspFileSystemOperationProcessId() == GetCurrentProcessId())
|
||||||
|
InterlockedIncrement(&create_pid_Pass);
|
||||||
|
else
|
||||||
|
InterlockedIncrement(&create_pid_Fail);
|
||||||
|
return create_pid_CreateOp(FileSystem, Request, Response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_pid_dotest(ULONG Flags, PWSTR Prefix)
|
||||||
|
{
|
||||||
|
create_pid_Pass = create_pid_Fail = 0;
|
||||||
|
|
||||||
|
void *memfs = memfs_start(Flags);
|
||||||
|
|
||||||
|
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
|
||||||
|
create_pid_CreateOp = FileSystem->Operations[FspFsctlTransactCreateKind];
|
||||||
|
FileSystem->Operations[FspFsctlTransactCreateKind] = create_pid_Create;
|
||||||
|
|
||||||
|
HANDLE Handle;
|
||||||
|
WCHAR FilePath[MAX_PATH];
|
||||||
|
|
||||||
|
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
|
||||||
|
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);
|
||||||
|
CloseHandle(Handle);
|
||||||
|
|
||||||
|
memfs_stop(memfs);
|
||||||
|
|
||||||
|
ASSERT(0 < create_pid_Pass && 0 == create_pid_Fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_pid_test(void)
|
||||||
|
{
|
||||||
|
if (NtfsTests)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (WinFspDiskTests)
|
||||||
|
create_pid_dotest(MemfsDisk, 0);
|
||||||
|
if (WinFspNetTests)
|
||||||
|
create_pid_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||||
|
}
|
||||||
|
|
||||||
void create_tests(void)
|
void create_tests(void)
|
||||||
{
|
{
|
||||||
TEST(create_test);
|
TEST(create_test);
|
||||||
@ -1096,4 +1147,6 @@ void create_tests(void)
|
|||||||
TEST(create_curdir_test);
|
TEST(create_curdir_test);
|
||||||
if (!OptShareName && !OptMountPoint)
|
if (!OptShareName && !OptMountPoint)
|
||||||
TEST(create_namelen_test);
|
TEST(create_namelen_test);
|
||||||
|
if (!NtfsTests)
|
||||||
|
TEST(create_pid_test);
|
||||||
}
|
}
|
||||||
|
@ -1512,6 +1512,78 @@ void rename_standby_test(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_FILE_SYSTEM_OPERATION *rename_pid_SetInformationOp;
|
||||||
|
UINT32 rename_pid_Pass, rename_pid_Fail;
|
||||||
|
|
||||||
|
NTSTATUS rename_pid_SetInformation(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
|
{
|
||||||
|
if (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
|
||||||
|
{
|
||||||
|
if (FspFileSystemOperationProcessId() == GetCurrentProcessId())
|
||||||
|
InterlockedIncrement(&rename_pid_Pass);
|
||||||
|
else
|
||||||
|
InterlockedIncrement(&rename_pid_Fail);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FspFileSystemOperationProcessId() == 0)
|
||||||
|
InterlockedIncrement(&rename_pid_Pass);
|
||||||
|
else
|
||||||
|
InterlockedIncrement(&rename_pid_Fail);
|
||||||
|
}
|
||||||
|
return rename_pid_SetInformationOp(FileSystem, Request, Response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rename_pid_dotest(ULONG Flags, PWSTR Prefix)
|
||||||
|
{
|
||||||
|
rename_pid_Pass = rename_pid_Fail = 0;
|
||||||
|
|
||||||
|
void *memfs = memfs_start(Flags);
|
||||||
|
|
||||||
|
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
|
||||||
|
rename_pid_SetInformationOp = FileSystem->Operations[FspFsctlTransactSetInformationKind];
|
||||||
|
FileSystem->Operations[FspFsctlTransactSetInformationKind] = rename_pid_SetInformation;
|
||||||
|
|
||||||
|
HANDLE Handle;
|
||||||
|
BOOL Success;
|
||||||
|
WCHAR File0Path[MAX_PATH];
|
||||||
|
WCHAR File1Path[MAX_PATH];
|
||||||
|
|
||||||
|
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\file0",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
|
||||||
|
StringCbPrintfW(File1Path, sizeof File1Path, L"%s%s\\file1",
|
||||||
|
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||||
|
|
||||||
|
Handle = CreateFileW(File0Path,
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||||
|
CloseHandle(Handle);
|
||||||
|
|
||||||
|
Success = MoveFileExW(File0Path, File1Path, MOVEFILE_REPLACE_EXISTING);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
Success = DeleteFileW(File1Path);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
memfs_stop(memfs);
|
||||||
|
|
||||||
|
ASSERT(0 < rename_pid_Pass && 0 == rename_pid_Fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rename_pid_test(void)
|
||||||
|
{
|
||||||
|
if (NtfsTests)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (WinFspDiskTests)
|
||||||
|
rename_pid_dotest(MemfsDisk, 0);
|
||||||
|
if (WinFspNetTests)
|
||||||
|
rename_pid_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||||
|
}
|
||||||
|
|
||||||
void getvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
void getvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
||||||
{
|
{
|
||||||
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||||
@ -1736,6 +1808,8 @@ void info_tests(void)
|
|||||||
if (!OptShareName)
|
if (!OptShareName)
|
||||||
TEST(rename_mmap_test);
|
TEST(rename_mmap_test);
|
||||||
TEST(rename_standby_test);
|
TEST(rename_standby_test);
|
||||||
|
if (!NtfsTests)
|
||||||
|
TEST(rename_pid_test);
|
||||||
TEST(getvolinfo_test);
|
TEST(getvolinfo_test);
|
||||||
TEST(setvolinfo_test);
|
TEST(setvolinfo_test);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user