Compare commits

..

59 Commits

Author SHA1 Message Date
8320160d73 build: version.properties: update to v1.1B3 2017-05-22 13:49:59 -07:00
ce057b49b8 update Changelog 2017-05-22 13:30:16 -07:00
a60c989089 update Changelog 2017-05-22 21:25:44 +01:00
0f6371f0d8 tools: run-tests: add fsx and winfstest for memfs-dotnet 2017-05-17 21:07:37 -07:00
1a4bbbe09a cygfuse: fix tabs to spaces 2017-05-17 15:19:36 -07:00
4e891dc2a8 cygfuse: add fuse_exited 2017-05-17 15:13:05 -07:00
18a77d63c3 cygfuse: improve cygfuse initialization 2017-05-17 14:59:31 -07:00
4ea9c6e362 dll: fuse: added -o options for additional WinFsp-FUSE options 2017-05-17 12:11:45 -07:00
9d77c192a8 cygfuse: cygfuse_init_fail now prints message and exits 2017-05-17 10:58:04 -07:00
6d5401d911 cygfuse: add 32-bit package 2017-05-17 00:54:26 -07:00
330d6e79f8 opt: cygfuse: bump release number to 5 2017-05-17 00:05:41 -07:00
ed58b7a63c inc: fuse: fix missing-field-initializers warning 2017-05-16 23:41:02 -07:00
f6853114c1 dll: fuse: implement fuse_exited 2017-05-16 23:26:18 -07:00
8ec7285d32 doc: add rclone to known file systems 2017-05-15 15:12:26 -07:00
c183c0fe89 doc: add rar2fs to the known file systems 2017-05-13 16:37:26 -07:00
38ad8fd27d update README 2017-05-11 13:51:56 -07:00
de85070e73 tst: winfsp-tests: disable internal tests when running with --external 2017-05-11 11:17:57 -07:00
5b8ebd6e1d src: dotnet: minor documentation fixes 2017-05-11 10:38:12 -07:00
db530cb5e5 installer: add dotnet documentation 2017-05-10 23:32:43 -07:00
7cd4d4faab src: dotnet: add documentation 2017-05-10 23:11:42 -07:00
2560a513dc update changelog 2017-05-09 23:12:45 -07:00
1ee95be5d7 src: dotnet: FileSystemBase: GetStreamInfo: bug fix 2017-05-09 23:01:31 -07:00
bd7546559c tst: memfs-dotnet: Create: fix allocation size 2017-05-09 22:02:37 -07:00
d18a2c8b75 tst: memfs-dotnet: ReadDirectoryEntry: properly handle Marker 2017-05-09 17:49:43 -07:00
0ebae0adc1 src: dotnet: FileSystemHost.GetSecurityByName: handle STATUS_REPARSE 2017-05-09 16:58:16 -07:00
d70c49ccd0 tools: run-tests: add memfs-dotnet testing 2017-05-09 00:03:01 -07:00
5846939116 tools: run-tests: add memfs-dotnet testing 2017-05-08 23:11:45 -07:00
f124e74f01 installer: add memfs-dotnet 2017-05-08 22:56:06 -07:00
05abb93e4b tst: memfs-dotnet: fix stream_getstreaminfo_test 2017-05-08 22:17:17 -07:00
5839d46b7a tst: memfs-dotnet: fix stream_create_overwrite_test 2017-05-08 21:57:45 -07:00
bce0d63f7d tst: memfs-dotnet: fix read/write offset copy 2017-05-08 21:53:49 -07:00
14b9f5affc tst: memfs-dotnet: fix rename_caseins_test 2017-05-08 21:45:30 -07:00
035a430470 tst: dotnet: SetSecurity testing 2017-05-08 21:25:25 -07:00
0af9e46e76 src: dotnet: FileSystemBase.ModifySecurityDescriptor 2017-05-08 21:25:03 -07:00
c4530f1252 tst: memfs-dotnet: testing 2017-05-07 17:40:47 -07:00
9f78a17583 tst: memfs-dotnet: reparse points testing 2017-05-07 17:12:08 -07:00
eea0b1bc79 src: dotnet: GetReparseTag 2017-05-07 17:11:39 -07:00
8338a6e066 tst: memfs-dotnet: fix exceptions in SetFileSizeInternal 2017-05-07 16:29:28 -07:00
ddba49dbea tst: memfs-dotnet: remove unnecessary OpenNodeSet 2017-05-07 16:28:49 -07:00
a6ff8a87de tst: memfs-dotnet: ReadDirectory fixes 2017-05-07 15:45:01 -07:00
bf64bcf9ba dotnet: fix problems with FullContext and GCHandle 2017-05-07 15:13:22 -07:00
8c5d9bda20 tst: memfs-dotnet: testing 2017-05-06 23:40:46 -07:00
f1ac28b0aa dotnet: log exceptions 2017-05-06 23:39:58 -07:00
ff725f931d tst: memfs-dotnet: testing 2017-05-06 23:10:40 -07:00
31519ba416 dotnet: bug fixes 2017-05-06 17:01:55 -07:00
0bca8f851c tst: memfs-dotnet: remove dead code 2017-05-06 15:06:29 -07:00
acf175da60 tst: memfs-dotnet: WIP 2017-05-06 14:49:17 -07:00
23eac24c84 dotnet: FileSystemBase.GetStreamEntry 2017-05-06 14:48:56 -07:00
0f9ef3bd51 tst: memfs-dotnet: WIP 2017-05-05 20:30:07 -07:00
2bdd54536e dotnet: reparse point WIP 2017-05-05 20:29:47 -07:00
060ebcca0d tst: memfs-dotnet: WIP 2017-05-05 18:24:17 -07:00
b38a89e485 dotnet: reparse point changes 2017-05-05 18:23:52 -07:00
b5bfeee027 dotnet: FileSystemHost: fixes 2017-05-05 16:15:29 -07:00
f36cacaf84 tst: memfs-dotnet: WIP 2017-05-05 14:47:48 -07:00
4278cec465 tst: memfs-dotnet: WIP 2017-05-05 12:08:32 -07:00
151627091b tst: memfs-dotnet: WIP 2017-05-04 23:00:53 -07:00
2ee3f02928 tst: memfs-dotnet: WIP 2017-05-04 21:56:46 -07:00
d77d3ccccf tools: version-info.bat: toggle executable bit 2017-05-04 15:19:11 -07:00
1e0c91658e doc: add cgofuse to known file systems 2017-04-28 14:52:05 -07:00
40 changed files with 2661 additions and 170 deletions

View File

@ -1,11 +1,14 @@
= Changelog
v1.1B3 (2017.1 B3)::
v1.1 (2017.1)::
v1.1B2 (2017.1 B2)::
v1.1B1 (2017.1 BETA)::
This release brings some major new components and improvements.
- A .NET layer that allows the creation of file systems in managed mode. This is contained in the new `winfsp-msil.dll`.
- A .NET layer that allows the creation of file systems in managed mode. This is contained in the new `winfsp-msil.dll`. The new .NET layer is being tested with the WinFsp test suites and Microsoft's ifstest.
- A simple C++ layer can be found in `inc/winfsp/winfsp.hpp`.
- FUSE for Cygwin is now included with the installer.
- FUSE now has a `-ovolname=VOLNAME` parameter that allows setting the volume label. Thanks @samkelly.

View File

@ -42,7 +42,8 @@ The project source code is organized as follows:
* src/launcher: Source code to the launcher service and the launchctl utility.
* src/sys: Source code to the WinFsp FSD.
* opt/cygfuse: Source code for the Cygwin FUSE package.
* tst/memfs: Source code to an example file system written in C++ (memfs).
* tst/memfs*: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet).
* tst/passthrough*: Source code to additional example file systems.
* tst/winfsp-tests: WinFsp test suite.
## Building and Running
@ -72,7 +73,7 @@ WinFsp is designed to run on Windows 7 and above. It has been tested on the foll
I am looking for help in the following areas:
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* If you are working with a language other than C/C++ (e.g. Delphi, Java, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues). Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart.
In all cases I can provide ideas and/or support.

View File

@ -3,3 +3,4 @@ build
*.suo
*.vcproj.*
*.vcxproj.user
*.csproj.user

View File

@ -25,6 +25,8 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>$(BaseIntermediateOutputPath)$(Configuration)\winfsp-msil.xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -36,6 +38,8 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>$(BaseIntermediateOutputPath)$(Configuration)\winfsp-msil.xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>

View File

@ -92,6 +92,9 @@
<Component Id="C.winfsp_msil.dll" Guid="0D8BA6AE-9F87-402B-AE1A-95B0AE3BE179">
<File Id="FILE.winfsp_msil.dll" Name="winfsp-msil.dll" KeyPath="yes" />
</Component>
<Component Id="C.winfsp_msil.xml" Guid="1657F707-C112-454C-91AE-0FDEBBF454AB">
<File Id="FILE.winfsp_msil.xml" Name="winfsp-msil.xml" KeyPath="yes" />
</Component>
<!--
<Component Id="C.winfsp_msil.dll.GAC" Guid="6469467D-8C90-4889-8138-4028F9DA6E85">
<File Id="FILE.winfsp_msil.dll.GAC" Name="winfsp-msil.dll" KeyPath="yes" Assembly=".net" />
@ -214,6 +217,32 @@
</RegistryKey>
</RegistryKey>
</Component>
<Component Id="C.memfs_dotnet_msil.exe">
<File Name="memfs-dotnet-msil.exe" KeyPath="yes" />
<RegistryKey
Root="HKLM"
Key="[P.LauncherRegistryKey]">
<RegistryKey
Key="memfs-dotnet">
<RegistryValue
Type="string"
Name="Executable"
Value="[BINDIR]memfs-dotnet-msil.exe" />
<RegistryValue
Type="string"
Name="CommandLine"
Value="-i -F NTFS -n 65536 -s 67108864 -u %1 -m %2" />
<RegistryValue
Type="string"
Name="Security"
Value="D:P(A;;RPWPLC;;;WD)" />
<RegistryValue
Type="integer"
Name="JobControl"
Value="1" />
</RegistryKey>
</RegistryKey>
</Component>
</DirectoryRef>
<DirectoryRef Id="INCDIR" FileSource="..\..\..\inc">
<Directory Id="INCDIR.winfsp" Name="winfsp">
@ -272,9 +301,16 @@
</DirectoryRef>
<DirectoryRef Id="OPTDIR">
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
<Component Id="C.fuse.tar.xz">
<File Name="fuse-2.8-4.tar.xz" KeyPath="yes" />
</Component>
<Directory Id="OPTDIR.cygfuse.x64" Name="x64">
<Component Id="C.fuse.tar.xz.x64">
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-5.tar.xz" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="OPTDIR.cygfuse.x86" Name="x86">
<Component Id="C.fuse.tar.xz.x86">
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-5.tar.xz" KeyPath="yes" />
</Component>
</Directory>
<Component Id="C.fuse.install.sh">
<File Name="install.sh" KeyPath="yes" />
</Component>
@ -295,6 +331,11 @@
<File Name="memfs-main.c" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.memfs_dotnet" Name="memfs-dotnet">
<Component Id="C.memfs_dotnet.Program.cs">
<File Id="FILE.memfs_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.passthrough" Name="passthrough">
<Component Id="C.passthrough.c">
<File Name="passthrough.c" KeyPath="yes" />
@ -351,7 +392,7 @@
</Directory>
<Directory Id="SMPDIR.passthrough_dotnet" Name="passthrough-dotnet">
<Component Id="C.passthrough_dotnet.Program.cs">
<File Name="Program.cs" KeyPath="yes" />
<File Id="FILE.passthrough_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_dotnet.sln">
<File Name="passthrough-dotnet.sln" KeyPath="yes" />
@ -426,7 +467,8 @@
<ComponentRef Id="C.fuse_x86.pc" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.opt.fuse">
<ComponentRef Id="C.fuse.tar.xz" />
<ComponentRef Id="C.fuse.tar.xz.x64" />
<ComponentRef Id="C.fuse.tar.xz.x86" />
<ComponentRef Id="C.fuse.install.sh" />
<ComponentRef Id="C.fuse.uninstall.sh" />
</ComponentGroup>
@ -467,12 +509,15 @@
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.net">
<ComponentRef Id="C.winfsp_msil.dll" />
<ComponentRef Id="C.winfsp_msil.xml" />
<!--
<ComponentRef Id="C.winfsp_msil.dll.GAC" />
<ComponentRef Id="C.policy.winfsp_msil.dll.GAC" />
-->
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.smp.net">
<ComponentRef Id="C.memfs_dotnet_msil.exe" />
<ComponentRef Id="C.memfs_dotnet.Program.cs" />
<ComponentRef Id="C.passthrough_dotnet.Program.cs" />
<ComponentRef Id="C.passthrough_dotnet.sln" />
<ComponentRef Id="C.passthrough_dotnet.csproj" />
@ -531,7 +576,7 @@
Id="F.Cygfuse"
Level="1000"
Title="FUSE for Cygwin"
Description="From a Cygwin prompt change to $InstallDir/opt/cygfuse and run install.sh."
Description="From a Cygwin prompt change to &lt;InstallDir&gt;/opt/cygfuse and run install.sh."
AllowAdvertise="no"
InstallDefault="local"
Absent="allow">

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4920E350-D496-4652-AE98-6C4208AEC1D8}</ProjectGuid>
<OutputType>Exe</OutputType>
<ProjectName>memfs-dotnet</ProjectName>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>memfs</RootNamespace>
<AssemblyName>memfs-dotnet-msil</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)build\$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)build\$(ProjectName).build\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\tst\memfs-dotnet\Program.cs">
<Link>Program.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\dotnet\winfsp.net.csproj">
<Project>{94580219-cc8d-4fe5-a3be-437b0b3481e1}</Project>
<Name>winfsp.net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -17,7 +17,7 @@
<MyCanonicalVersion>1.1</MyCanonicalVersion>
<MyProductVersion>2017.1 BETA</MyProductVersion>
<MyProductVersion>2017.1 B3</MyProductVersion>
<MyProductStage>Beta</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>

View File

@ -61,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winfsp.net", "dotnet\winfsp
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet", "dotnet", "{A998CEC4-4B34-43DC-8457-F7761228BA67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "memfs-dotnet", "testing\memfs-dotnet.csproj", "{4920E350-D496-4652-AE98-6C4208AEC1D8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -259,6 +261,30 @@ Global
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x64.Build.0 = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x86.ActiveCfg = Release|Any CPU
{94580219-CC8D-4FE5-A3BE-437B0B3481E1}.Release|x86.Build.0 = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x64.ActiveCfg = Debug|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Debug|x64.Build.0 = 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}.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.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.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.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.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.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.Build.0 = 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|x86.ActiveCfg = Release|Any CPU
{4920E350-D496-4652-AE98-6C4208AEC1D8}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -273,5 +299,6 @@ Global
{10757011-749D-4954-873B-AE38D8145472} = {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}
{4920E350-D496-4652-AE98-6C4208AEC1D8} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
EndGlobalSection
EndGlobal

View File

@ -5,12 +5,15 @@ This document contains a list of known file systems and file system libraries th
== File Systems
- https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives
- https://github.com/billziss-gh/redditfs[redditfs] - ls -l /r/programming
- https://github.com/netheril96/securefs[securefs] - Filesystem in userspace (FUSE) with transparent authenticated encryption
- https://github.com/billziss-gh/sshfs-win[sshfs-win] - SSHFS for Windows
== File System Libraries
- https://github.com/billziss-gh/cgofuse[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/ui4j/fuse-jna[fuse-jna] - No-nonsense, actually-working Java bindings to FUSE using JNA
- https://github.com/billziss-gh/fusepy[fusepy] - Simple ctypes bindings for FUSE

View File

@ -118,6 +118,8 @@ FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
FSP_FUSE_SYM(
@ -171,6 +173,13 @@ void fuse_exit(struct fuse *f),
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
int fuse_exited(struct fuse *f),
{
return FSP_FUSE_API_CALL(fsp_fuse_exited)
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
struct fuse_context *fuse_get_context(void),
{

View File

@ -178,6 +178,7 @@ struct fuse_flock
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \
{ 0 }, \
}
#else
#define FSP_FUSE_ENV_INIT \
@ -187,6 +188,7 @@ struct fuse_flock
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
0/*conv_to_win_path*/, \
{ 0 }, \
}
#endif
@ -229,6 +231,7 @@ struct fuse_flock
fsp_fuse_daemonize, \
fsp_fuse_set_signal_handlers, \
fsp_fuse_conv_to_win_path, \
{ 0 }, \
}
/*

View File

@ -18,3 +18,11 @@ cygport:
> opt/cygfuse/winfsp-work.tar.gz\
)
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package
dist: cygport
case $(shell uname -m) in \
x86_64)\
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x64 ;;\
*)\
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x86 ;;\
esac

View File

@ -17,22 +17,39 @@
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/cygwin.h>
static void *cygfuse_init_slow(int force);
static void *cygfuse_init_winfsp();
static void *cygfuse_init_fail();
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
static void *cygfuse_handle = 0;
static inline void cygfuse_init(int force)
static inline void *cygfuse_init_fast(void)
{
void *handle = cygfuse_handle;
__sync_synchronize(); /* memory barrier */
if (0 == handle)
handle = cygfuse_init_slow(0);
return handle;
}
static void *cygfuse_init_slow(int force)
{
void *handle;
pthread_mutex_lock(&cygfuse_mutex);
if (force || 0 == cygfuse_handle)
cygfuse_handle = cygfuse_init_winfsp();
handle = cygfuse_handle;
if (force || 0 == handle)
{
handle = cygfuse_init_winfsp();
__sync_synchronize(); /* memory barrier */
cygfuse_handle = handle;
}
pthread_mutex_unlock(&cygfuse_mutex);
return handle;
}
/*
@ -50,7 +67,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
return -1;
/* force reload of WinFsp DLL to workaround fork() problems */
cygfuse_init(1);
cygfuse_init_slow(1);
return 0;
}
@ -58,7 +75,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
#define FSP_FUSE_API static
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api)
#define FSP_FUSE_API_CALL(api) (cygfuse_init_fast(), pfn_ ## api)
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
#include <fuse_common.h>
#include <fuse.h>
@ -74,6 +91,7 @@ static inline int cygfuse_daemon(int nochdir, int noclose)
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
return cygfuse_init_fail();
static void *cygfuse_init_fail();
static void *cygfuse_init_winfsp()
{
void *h;
@ -125,6 +143,7 @@ static void *cygfuse_init_winfsp()
CYGFUSE_GET_API(h, fsp_fuse_loop);
CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
CYGFUSE_GET_API(h, fsp_fuse_exit);
CYGFUSE_GET_API(h, fsp_fuse_exited);
CYGFUSE_GET_API(h, fsp_fuse_get_context);
/* fuse_opt.h */
@ -141,6 +160,7 @@ static void *cygfuse_init_winfsp()
static void *cygfuse_init_fail()
{
abort();
fprintf(stderr, "cygfuse: initialization failed: " CYGFUSE_WINFSP_NAME " not found\n");
exit(1);
return 0;
}

Binary file not shown.

View File

@ -1 +1,8 @@
tar -C/ -xaf fuse-2.8-*.tar.xz
cd "$(dirname "$0")"
case $(uname -m) in
x86_64)
tar -C/ -xaf x64/fuse-2.8-*.tar.xz ;;
*)
tar -C/ -xaf x86/fuse-2.8-*.tar.xz ;;
esac
echo FUSE for Cygwin installed.

View File

@ -1 +1,8 @@
tar -taf fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f
cd "$(dirname "$0")"
case $(uname -m) in
x86_64)
tar -taf x64/fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f ;;
*)
tar -taf x86/fuse-2.8-*.tar.xz | sed -e '/\/$/d' -e 's/.*/\/&/' | xargs rm -f ;;
esac
echo FUSE for Cygwin uninstalled.

BIN
opt/cygfuse/dist/x64/fuse-2.8-5.tar.xz vendored Normal file

Binary file not shown.

BIN
opt/cygfuse/dist/x86/fuse-2.8-5.tar.xz vendored Normal file

Binary file not shown.

View File

@ -1,6 +1,6 @@
NAME="fuse"
VERSION=2.8
RELEASE=4
RELEASE=5
CATEGORY="Utils"
SUMMARY="WinFsp-FUSE compatibility layer"
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."

View File

@ -96,8 +96,11 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FUSE_OPT_KEY("UNC=", 'U'),
FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("VolumePrefix=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("FileSystemName=", 'F'),
FUSE_OPT_KEY("--FileSystemName=", 'F'),
FUSE_OPT_END,
@ -457,17 +460,26 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
default:
return 1;
case 'h':
/* Note: The limit on FspServiceLog messages is 1024 bytes. This is getting close. */
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " options:\n"
" -o DebugLog=FILE debug log file (deflt: stderr)\n"
" -o umask=MASK set file permissions (octal)\n"
" -o uid=N set file owner (-1 for mounting user id)\n"
" -o gid=N set file group (-1 for mounting user group)\n"
" -o rellinks interpret absolute symlinks as volume relative\n"
" -o volname=NAME set volume label\n"
" -o VolumePrefix=UNC set UNC prefix (\\Server\\Share)\n"
" -o FileSystemName=NAME set file system name\n"
" -o DebugLog=FILE debug log file (requires -d)\n"
"\n"
FSP_FUSE_LIBRARY_NAME " advanced options:\n"
" -o FileInfoTimeout=N metadata timeout (millis, -1 for data caching)\n"
" -o SectorSize=N sector size for Windows (512-4096, deflt: 4096)\n"
" -o SectorsPerAllocationUnit=N sectors per allocation unit (deflt: 1)\n"
" -o MaxComponentLength=N max file name component length (deflt: 255)\n"
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
" -o VolumeSerialNumber=N 32-bit wide\n"
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
" --FileSystemName=FSN Name of user mode file system\n");
" -o VolumeSerialNumber=N volume serial number (32-bit wide)\n"
);
opt_data->help = 1;
return 1;
case 'V':
@ -488,8 +500,12 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
0);
return 0;
case 'U':
if ('U' == arg[2])
if ('U' == arg[0])
arg += sizeof "UNC=" - 1;
else if ('U' == arg[2])
arg += sizeof "--UNC=" - 1;
else if ('V' == arg[0])
arg += sizeof "VolumePrefix=" - 1;
else if ('V' == arg[2])
arg += sizeof "--VolumePrefix=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
@ -501,6 +517,8 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
case 'F':
if ('f' == arg[0])
arg += sizeof "fstypename=" - 1;
else if ('F' == arg[0])
arg += sizeof "FileSystemName=" - 1;
else if ('F' == arg[2])
arg += sizeof "--FileSystemName=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
@ -687,6 +705,13 @@ FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
{
if (0 != f->Service)
FspServiceStop(f->Service);
f->exited = 1;
}
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
struct fuse *f)
{
return f->exited;
}
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)

View File

@ -50,6 +50,7 @@ struct fuse
PWSTR MountPoint;
FSP_FILE_SYSTEM *FileSystem;
FSP_SERVICE *Service; /* weak */
volatile int exited;
};
struct fsp_fuse_context_header

View File

@ -1,7 +1,7 @@
/**
* @file dotnet/FileSystemBase+Const.cs
/*
* dotnet/FileSystemBase+Const.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
* Copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.

View File

@ -1,7 +1,7 @@
/**
* @file dotnet/FileSystemBase.cs
/*
* dotnet/FileSystemBase.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
* Copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -24,6 +24,9 @@ using Fsp.Interop;
namespace Fsp
{
/// <summary>
/// Provides the base class that user mode file systems must inherit from.
/// </summary>
public partial class FileSystemBase
{
/* types */
@ -48,27 +51,73 @@ namespace Fsp
}
/* operations */
/// <summary>
/// Provides a means to customize the returned status code when an exception happens.
/// </summary>
/// <param name="ex"></param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 ExceptionHandler(Exception ex)
{
Api.FspDebugLog("%s\n", ex.ToString());
return STATUS_UNEXPECTED_IO_ERROR;
}
/// <summary>
/// Occurs just before the file system is mounted.
/// File systems may override this method to configure the file system host.
/// </summary>
/// <param name="Host">
/// The file system host that is mounting this file system.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Init(Object Host)
{
return STATUS_SUCCESS;
}
/// <summary>
/// Occurs just after the file system is mounted,
/// but prior to receiving any file system operation.
/// </summary>
/// <param name="Host">
/// The file system host that is mounting this file system.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Mounted(Object Host)
{
return STATUS_SUCCESS;
}
/// <summary>
/// Occurs just after the file system is unmounted.
/// No other file system operations will be received on this file system.
/// </summary>
/// <param name="Host">
/// The file system host that is mounting this file system.
/// </param>
public virtual void Unmounted(Object Host)
{
}
/// <summary>
/// Gets the volume information.
/// </summary>
/// <param name="VolumeInfo">
/// Receives the volume information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 GetVolumeInfo(
out VolumeInfo VolumeInfo)
{
VolumeInfo = default(VolumeInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Sets the volume label.
/// </summary>
/// <param name="VolumeLabel">
/// The new label for the volume.
/// </param>
/// <param name="VolumeInfo">
/// Receives the updated volume information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 SetVolumeLabel(
String VolumeLabel,
out VolumeInfo VolumeInfo)
@ -76,6 +125,27 @@ namespace Fsp
VolumeInfo = default(VolumeInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Gets file or directory attributes and security descriptor given a file name.
/// </summary>
/// <param name="FileName">
/// The name of the file or directory to get the attributes and security descriptor for.
/// </param>
/// <param name="FileAttributes">
/// Receives the file attributes on successful return.
/// If this call returns STATUS_REPARSE, the file system may place here the index of the
/// first reparse point within FileName.
/// </param>
/// <param name="SecurityDescriptor">
/// Receives the file security descriptor. If the SecurityDescriptor parameter is null
/// on input the file system should not fill this value.
/// </param>
/// <returns>
/// STATUS_SUCCESS, STATUS_REPARSE or error code.
/// STATUS_REPARSE should be returned by file systems that support reparse points when
/// they encounter a FileName that contains reparse points anywhere but the final path
/// component.
/// </returns>
public virtual Int32 GetSecurityByName(
String FileName,
out UInt32 FileAttributes/* or ReparsePointIndex */,
@ -84,6 +154,40 @@ namespace Fsp
FileAttributes = default(UInt32);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Creates a new file or directory.
/// </summary>
/// <param name="FileName">
/// The name of the file or directory to be created.
/// </param>
/// <param name="CreateOptions">
/// Create options for this request.
/// </param>
/// <param name="GrantedAccess">
/// Determines the specific access rights that have been granted for this request.
/// </param>
/// <param name="FileAttributes">
/// File attributes to apply to the newly created file or directory.
/// </param>
/// <param name="SecurityDescriptor">
/// Security descriptor to apply to the newly created file or directory.
/// </param>
/// <param name="AllocationSize">
/// Allocation size for the newly created file.
/// </param>
/// <param name="FileNode">
/// Receives the file node for the newly created file.
/// </param>
/// <param name="FileDesc">
/// Receives the file descriptor for the newly created file.
/// </param>
/// <param name="FileInfo">
/// Receives the file information for the newly created file.
/// </param>
/// <param name="NormalizedName">
/// Receives the normalized name for the newly created file.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Create(
String FileName,
UInt32 CreateOptions,
@ -102,6 +206,31 @@ namespace Fsp
NormalizedName = default(String);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Opens a file or directory.
/// </summary>
/// <param name="FileName">
/// The name of the file or directory to be opened.
/// </param>
/// <param name="CreateOptions">
/// Create options for this request.
/// </param>
/// <param name="GrantedAccess">
/// Determines the specific access rights that have been granted for this request.
/// </param>
/// <param name="FileNode">
/// Receives the file node for the newly opened file.
/// </param>
/// <param name="FileDesc">
/// Receives the file descriptor for the newly opened file.
/// </param>
/// <param name="FileInfo">
/// Receives the file information for the newly opened file.
/// </param>
/// <param name="NormalizedName">
/// Receives the normalized name for the newly opened file.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Open(
String FileName,
UInt32 CreateOptions,
@ -117,6 +246,29 @@ namespace Fsp
NormalizedName = default(String);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Overwrites a file.
/// </summary>
/// <param name="FileNode">
/// The file node for the file to be overwritten.
/// </param>
/// <param name="FileDesc">
/// The file descriptor for the file to be overwritten.
/// </param>
/// <param name="FileAttributes">
/// File attributes to apply to the overwritten file.
/// </param>
/// <param name="ReplaceFileAttributes">
/// When true the existing file attributes should be replaced with the new ones.
/// When false the existing file attributes should be merged (or'ed) with the new ones.
/// </param>
/// <param name="AllocationSize">
/// Allocation size for the overwritten file.
/// </param>
/// <param name="FileInfo">
/// Receives the updated file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Overwrite(
Object FileNode,
Object FileDesc,
@ -128,6 +280,64 @@ namespace Fsp
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Cleans up a file or directory.
/// </summary>
/// <remarks>
/// <para>
/// When CreateFile is used to open or create a file the kernel creates a kernel mode file
/// object (type FILE_OBJECT) and a handle for it, which it returns to user-mode. The handle may
/// be duplicated (using DuplicateHandle), but all duplicate handles always refer to the same
/// file object. When all handles for a particular file object get closed (using CloseHandle)
/// the system sends a Cleanup request to the file system.
/// </para><para>
/// There will be a Cleanup operation for every Create or Open operation posted to the user mode
/// file system. However the Cleanup operation is not the final close operation on a file.
/// The file system must be ready to receive additional operations until close time. This is true
/// even when the file is being deleted!
/// </para><para>
/// The Flags parameter contains information about the cleanup operation:
/// <list>
/// <item>CleanupDelete -
/// An important function of the Cleanup operation is to complete a delete operation. Deleting
/// a file or directory in Windows is a three-stage process where the file is first opened, then
/// tested to see if the delete can proceed and if the answer is positive the file is then
/// deleted during Cleanup.
/// When this flag is set, this is the last outstanding cleanup for this particular file node.
/// </item>
/// <item>CleanupSetAllocationSize -
/// The NTFS and FAT file systems reset a file's allocation size when they receive the last
/// outstanding cleanup for a particular file node. User mode file systems that implement
/// allocation size and wish to duplicate the NTFS and FAT behavior can use this flag.
/// </item>
/// <item>CleanupSetArchiveBit -
/// File systems that support the archive bit should set the file node's archive bit when this
/// flag is set.
/// </item>
/// <item>CleanupSetLastAccessTime, CleanupSetLastWriteTime, CleanupSetChangeTime -
/// File systems should set the corresponding file time when each one of these flags is set.
/// Note that updating the last access time is expensive and a file system may choose to not
/// implement it.
/// </item>
/// </list>
/// </para><para>
/// There is no way to report failure of this operation. This is a Windows limitation.
/// </para>
/// </remarks>
/// <param name="FileNode">
/// The file node of the file or directory to cleanup.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to cleanup.
/// </param>
/// <param name="FileName">
/// The name of the file or directory to cleanup. Sent only when a Delete is requested.
/// </param>
/// <param name="Flags">
/// These flags determine whether the file was modified and whether to delete the file.
/// </param>
/// <seealso cref="CanDelete"/>
/// <seealso cref="Close"/>
public virtual void Cleanup(
Object FileNode,
Object FileDesc,
@ -135,11 +345,42 @@ namespace Fsp
UInt32 Flags)
{
}
/// <summary>
/// Closes a file or directory.
/// </summary>
/// <param name="FileNode">
/// The file node of the file or directory to close.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to close.
/// </param>
public virtual void Close(
Object FileNode,
Object FileDesc)
{
}
/// <summary>
/// Reads a file.
/// </summary>
/// <param name="FileNode">
/// The file node of the file to read.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file to read.
/// </param>
/// <param name="Buffer">
/// Pointer to a buffer that receives the results of the read operation.
/// </param>
/// <param name="Offset">
/// Offset within the file to read from.
/// </param>
/// <param name="Length">
/// Length of data to read.
/// </param>
/// <param name="BytesTransferred">
/// Receives the actual number of bytes read.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Read(
Object FileNode,
Object FileDesc,
@ -151,6 +392,38 @@ namespace Fsp
BytesTransferred = default(UInt32);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Writes a file.
/// </summary>
/// <param name="FileNode">
/// The file node of the file to write.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file to write.
/// </param>
/// <param name="Buffer">
/// Pointer to a buffer that receives the results of the write operation.
/// </param>
/// <param name="Offset">
/// Offset within the file to write to.
/// </param>
/// <param name="Length">
/// Length of data to write.
/// </param>
/// <param name="WriteToEndOfFile">
/// When true the file system must write to the current end of file. In this case the Offset
/// parameter will contain the value -1.
/// </param>
/// <param name="ConstrainedIo">
/// When true the file system must not extend the file (i.e. change the file size).
/// </param>
/// <param name="BytesTransferred">
/// Receives the actual number of bytes written.
/// </param>
/// <param name="FileInfo">
/// Receives the updated file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Write(
Object FileNode,
Object FileDesc,
@ -166,6 +439,24 @@ namespace Fsp
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Flushes a file or volume.
/// </summary>
/// <remarks>
/// Note that the FSD will also flush all file/volume caches prior to invoking this operation.
/// </remarks>
/// <param name="FileNode">
/// The file node of the file to flush.
/// When this and the FileDesc parameter are null the whole volume is being flushed.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file to flush.
/// When this and the FileNode parameter are null the whole volume is being flushed.
/// </param>
/// <param name="FileInfo">
/// Receives the updated file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Flush(
Object FileNode,
Object FileDesc,
@ -174,6 +465,19 @@ namespace Fsp
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Gets file or directory information.
/// </summary>
/// <param name="FileNode">
/// The file node of the file to get information for.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file to get information for.
/// </param>
/// <param name="FileInfo">
/// Receives the file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 GetFileInfo(
Object FileNode,
Object FileDesc,
@ -182,6 +486,39 @@ namespace Fsp
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Sets file or directory basic information.
/// </summary>
/// <param name="FileNode">
/// The file node of the file to set information for.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file to set information for.
/// </param>
/// <param name="FileAttributes">
/// File attributes to apply to the file or directory.
/// If the value -1 is sent, the file attributes should not be changed.
/// </param>
/// <param name="CreationTime">
/// Creation time to apply to the file or directory.
/// If the value 0 is sent, the creation time should not be changed.
/// </param>
/// <param name="LastAccessTime">
/// Last access time to apply to the file or directory.
/// If the value 0 is sent, the last access time should not be changed.
/// </param>
/// <param name="LastWriteTime">
/// Last write time to apply to the file or directory.
/// If the value 0 is sent, the last write time should not be changed.
/// </param>
/// <param name="ChangeTime">
/// Change time to apply to the file or directory.
/// If the value 0 is sent, the change time should not be changed.
/// </param>
/// <param name="FileInfo">
/// Receives the updated file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 SetBasicInfo(
Object FileNode,
Object FileDesc,
@ -195,6 +532,52 @@ namespace Fsp
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Sets file/allocation size.
/// </summary>
/// <remarks>
/// <para>
/// This function is used to change a file's sizes. Windows file systems maintain two kinds
/// of sizes: the file size is where the End Of File (EOF) is, and the allocation size is the
/// actual size that a file takes up on the "disk".
/// </para><para>
/// The rules regarding file/allocation size are:
/// <list>
/// <item>
/// Allocation size must always be aligned to the allocation unit boundary. The allocation
/// unit is the product SectorSize * SectorsPerAllocationUnit. The FSD will always send
/// properly aligned allocation sizes when setting the allocation size.
/// </item>
/// <item>
/// Allocation size is always greater or equal to the file size.
/// </item>
/// <item>
/// A file size of more than the current allocation size will also extend the allocation
/// size to the next allocation unit boundary.
/// </item>
/// <item>
/// An allocation size of less than the current file size should also truncate the current
/// file size.
/// </item>
/// </list>
/// </para>
/// </remarks>
/// <param name="FileNode">
/// The file node of the file to set the file/allocation size for.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file to set the file/allocation size for.
/// </param>
/// <param name="NewSize">
/// New file/allocation size to apply to the file.
/// </param>
/// <param name="SetAllocationSize">
/// If true, then the allocation size is being set. if false, then the file size is being set.
/// </param>
/// <param name="FileInfo">
/// Receives the updated file information.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 SetFileSize(
Object FileNode,
Object FileDesc,
@ -205,6 +588,20 @@ namespace Fsp
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Determines whether a file or directory can be deleted.
/// </summary>
/// <param name="FileNode">
/// The file node of the file or directory to test for deletion.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to test for deletion.
/// </param>
/// <param name="FileName">
/// The name of the file or directory to test for deletion.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
/// <seealso cref="Cleanup"/>
public virtual Int32 CanDelete(
Object FileNode,
Object FileDesc,
@ -212,6 +609,37 @@ namespace Fsp
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Renames a file or directory.
/// </summary>
/// <remarks>
/// The kernel mode FSD provides certain guarantees prior to posting a rename operation:
/// <list>
/// <item>
/// A file cannot be renamed if a file with the same name exists and has open handles.
/// </item>
/// <item>
/// A directory cannot be renamed if it or any of its subdirectories contains a file that
/// has open handles.
/// </item>
/// </list>
/// </remarks>
/// <param name="FileNode">
/// The file node of the file or directory to be renamed.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to be renamed.
/// </param>
/// <param name="FileName">
/// The current name of the file or directory to rename.
/// </param>
/// <param name="NewFileName">
/// The new name for the file or directory.
/// </param>
/// <param name="ReplaceIfExists">
/// Whether to replace a file that already exists at NewFileName.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 Rename(
Object FileNode,
Object FileDesc,
@ -221,6 +649,19 @@ namespace Fsp
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Gets file or directory security descriptor.
/// </summary>
/// <param name="FileNode">
/// The file node of the file or directory to get the security descriptor for.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to get the security descriptor for.
/// </param>
/// <param name="SecurityDescriptor">
/// Receives the file security descriptor.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 GetSecurity(
Object FileNode,
Object FileDesc,
@ -228,6 +669,23 @@ namespace Fsp
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Sets file or directory security descriptor.
/// </summary>
/// <param name="FileNode">
/// The file node of the file or directory to set the security descriptor for.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to set the security descriptor for.
/// </param>
/// <param name="Sections">
/// Describes what parts of the file or directory security descriptor should be modified.
/// </param>
/// <param name="SecurityDescriptor">
/// Describes the modifications to apply to the file or directory security descriptor.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
/// <seealso cref="ModifySecurityDescriptor"/>
public virtual Int32 SetSecurity(
Object FileNode,
Object FileDesc,
@ -236,6 +694,10 @@ namespace Fsp
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Reads a directory.
/// </summary>
/// <seealso cref="ReadDirectoryEntry"/>
public virtual Int32 ReadDirectory(
Object FileNode,
Object FileDesc,
@ -248,6 +710,36 @@ namespace Fsp
return SeekableReadDirectory(FileNode, FileDesc, Pattern, Marker, Buffer, Length,
out BytesTransferred);
}
/// <summary>
/// Reads a directory entry.
/// </summary>
/// <param name="FileNode">
/// The file node of the directory to be read.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the directory to be read.
/// </param>
/// <param name="Pattern">
/// The pattern to match against files in this directory. Can be null. The file system
/// can choose to ignore this parameter as the FSD will always perform its own pattern
/// matching on the returned results.
/// </param>
/// <param name="Marker">
/// A file name that marks where in the directory to start reading. Files with names
/// that are greater than (not equal to) this marker (in the directory order determined
/// by the file system) should be returned. Can be null.
/// </param>
/// <param name="Context">
/// Can be used by the file system to track the ReadDirectory operation.
/// </param>
/// <param name="FileName">
/// Receives the file name for the directory entry.
/// </param>
/// <param name="FileInfo">
/// Receives the file information for the directory entry.
/// </param>
/// <returns>True if there are additional directory entries to return. False otherwise.</returns>
/// <seealso cref="ReadDirectory"/>
public virtual Boolean ReadDirectoryEntry(
Object FileNode,
Object FileDesc,
@ -261,13 +753,16 @@ namespace Fsp
FileInfo = default(FileInfo);
return false;
}
/// <summary>
/// Resolves reparse points.
/// </summary>
public virtual Int32 ResolveReparsePoints(
String FileName,
UInt32 ReparsePointIndex,
Boolean ResolveLastPathComponent,
out IoStatusBlock IoStatus,
IntPtr Buffer,
ref UIntPtr Size)
IntPtr PSize)
{
GCHandle Handle = GCHandle.Alloc(this, GCHandleType.Normal);
try
@ -281,49 +776,108 @@ namespace Fsp
ResolveLastPathComponent,
out IoStatus,
Buffer,
ref Size);
PSize);
}
finally
{
Handle.Free();
}
}
/// <summary>
/// Gets a reparse point given a file name.
/// </summary>
/// <param name="FileName">
/// The name of the file or directory to get the reparse point for.
/// </param>
/// <param name="IsDirectory">
/// Determines whether the passed file name is assumed to be a directory.
/// </param>
/// <param name="ReparseData">
/// Receives the reparse data for the file or directory.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 GetReparsePointByName(
String FileName,
Boolean IsDirectory,
IntPtr Buffer,
ref UIntPtr Size)
ref Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Gets a reparse point.
/// </summary>
/// <param name="FileNode">
/// The file node of the reparse point.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the reparse point.
/// </param>
/// <param name="FileName">
/// The file name of the reparse point.
/// </param>
/// <param name="ReparseData">
/// Receives the reparse data for the reparse point.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 GetReparsePoint(
Object FileNode,
Object FileDesc,
String FileName,
IntPtr Buffer,
out UIntPtr Size)
ref Byte[] ReparseData)
{
Size = default(UIntPtr);
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Sets a reparse point.
/// </summary>
/// <param name="FileNode">
/// The file node of the reparse point.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the reparse point.
/// </param>
/// <param name="FileName">
/// The file name of the reparse point.
/// </param>
/// <param name="ReparseData">
/// The new reparse data for the reparse point.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 SetReparsePoint(
Object FileNode,
Object FileDesc,
String FileName,
IntPtr Buffer,
UIntPtr Size)
Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Deletes a reparse point.
/// </summary>
/// <param name="FileNode">
/// The file node of the reparse point.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the reparse point.
/// </param>
/// <param name="FileName">
/// The file name of the reparse point.
/// </param>
/// <param name="ReparseData">
/// The reparse data for the reparse point.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public virtual Int32 DeleteReparsePoint(
Object FileNode,
Object FileDesc,
String FileName,
IntPtr Buffer,
UIntPtr Size)
Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/// <summary>
/// Gets named streams information.
/// </summary>
public virtual Int32 GetStreamInfo(
Object FileNode,
Object FileDesc,
@ -331,19 +885,108 @@ namespace Fsp
UInt32 Length,
out UInt32 BytesTransferred)
{
Object Context = null;
String StreamName;
StreamInfo StreamInfo = default(StreamInfo);
BytesTransferred = default(UInt32);
return STATUS_INVALID_DEVICE_REQUEST;
while (GetStreamEntry(FileNode, FileDesc, ref Context,
out StreamName, out StreamInfo.StreamSize, out StreamInfo.StreamAllocationSize))
{
StreamInfo.SetStreamNameBuf(StreamName);
if (!Api.FspFileSystemAddStreamInfo(ref StreamInfo, Buffer, Length,
out BytesTransferred))
return STATUS_SUCCESS;
}
Api.FspFileSystemEndStreamInfo(Buffer, Length, out BytesTransferred);
return STATUS_SUCCESS;
}
/// <summary>
/// Gets named streams information entry.
/// </summary>
/// <param name="FileNode">
/// The file node of the file or directory to get stream information for.
/// </param>
/// <param name="FileDesc">
/// The file descriptor of the file or directory to get stream information for.
/// </param>
/// <param name="Context">
/// Can be used by the file system to track the GetStreamInfo operation.
/// </param>
/// <param name="StreamName">
/// Receives the stream name for the stream entry.
/// </param>
/// <param name="StreamSize">
/// Receives the stream size for the stream entry.
/// </param>
/// <param name="StreamAllocationSize">
/// Receives the stream allocation size for the stream entry.
/// </param>
/// <returns>True if there are additional stream entries to return. False otherwise.</returns>
public virtual Boolean GetStreamEntry(
Object FileNode,
Object FileDesc,
ref Object Context,
out String StreamName,
out UInt64 StreamSize,
out UInt64 StreamAllocationSize)
{
StreamName = default(String);
StreamSize = default(UInt64);
StreamAllocationSize = default(UInt64);
return false;
}
/* helpers */
/// <summary>
/// Converts a Win32 error code to a Windows kernel status code.
/// </summary>
public static Int32 NtStatusFromWin32(UInt32 Error)
{
return Api.FspNtStatusFromWin32(Error);
}
/// <summary>
/// Converts a Windows kernel status code to a Win32 error code.
/// </summary>
public static UInt32 Win32FromNtStatus(Int32 Status)
{
return Api.FspWin32FromNtStatus(Status);
}
/// <summary>
/// Modifies a security descriptor.
/// </summary>
/// <remarks>
/// This is a helper for implementing the SetSecurity operation.
/// </remarks>
/// <param name="SecurityDescriptor">
/// The original security descriptor.
/// </param>
/// <param name="Sections">
/// Describes what parts of the file or directory security descriptor should be modified.
/// </param>
/// <param name="ModificationDescriptor">
/// Describes the modifications to apply to the file or directory security descriptor.
/// </param>
/// <returns>The modified security descriptor.</returns>
/// <seealso cref="SetSecurity"/>
public static byte[] ModifySecurityDescriptor(
Byte[] SecurityDescriptor,
AccessControlSections Sections,
Byte[] ModificationDescriptor)
{
UInt32 SecurityInformation = 0;
if (0 != (Sections & AccessControlSections.Owner))
SecurityInformation |= 1/*OWNER_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Group))
SecurityInformation |= 2/*GROUP_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Access))
SecurityInformation |= 4/*DACL_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Audit))
SecurityInformation |= 8/*SACL_SECURITY_INFORMATION*/;
return Api.ModifySecurityDescriptor(
SecurityDescriptor,
SecurityInformation,
ModificationDescriptor);
}
public Int32 SeekableReadDirectory(
Object FileNode,
Object FileDesc,
@ -363,8 +1006,9 @@ namespace Fsp
DirInfo.SetFileNameBuf(FileName);
if (!Api.FspFileSystemAddDirInfo(ref DirInfo, Buffer, Length,
out BytesTransferred))
break;
return STATUS_SUCCESS;
}
Api.FspFileSystemEndDirInfo(Buffer, Length, out BytesTransferred);
return STATUS_SUCCESS;
}
public Int32 BufferedReadDirectory(
@ -408,7 +1052,22 @@ namespace Fsp
Marker, Buffer, Length, out BytesTransferred);
return STATUS_SUCCESS;
}
public Int32 FindReparsePoint(
/// <summary>
/// Finds a reparse point in file name.
/// </summary>
/// <remarks>
/// This is a helper for implementing the GetSecurityByName operation in file systems
/// that support reparse points.
/// </remarks>
/// <param name="FileName">
/// The name of the file or directory.
/// </param>
/// <param name="ReparsePointIndex">
/// Receives the index of the first reparse point within FileName.
/// </param>
/// <returns>True if a reparse point was found, false otherwise.</returns>
/// <seealso cref="GetSecurityByName"/>
public Boolean FindReparsePoint(
String FileName,
out UInt32 ReparsePointIndex)
{
@ -427,22 +1086,62 @@ namespace Fsp
Handle.Free();
}
}
/// <summary>
/// Gets the reparse tag from reparse data.
/// </summary>
/// <param name="ReparseData">
/// The reparse data to extract the reparse tag from.
/// </param>
/// <returns>The reparse tag.</returns>
public static UInt32 GetReparseTag(
Byte[] ReparseData)
{
return BitConverter.ToUInt32(ReparseData, 0);
}
/// <summary>
/// Tests whether reparse data can be replaced.
/// </summary>
/// <remarks>
/// This is a helper for implementing the SetReparsePoint/DeleteReparsePoint operation
/// in file systems that support reparse points.
/// </remarks>
/// <param name="CurrentReparseData">
/// The current reparse data.
/// </param>
/// <param name="ReplaceReparseData">
/// The replacement reparse data.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
/// <seealso cref="SetReparsePoint"/>
/// <seealso cref="DeleteReparsePoint"/>
public static Int32 CanReplaceReparsePoint(
Byte[] CurrentReparseData,
Byte[] ReplaceReparseData)
{
return Api.FspFileSystemCanReplaceReparsePoint(CurrentReparseData, ReplaceReparseData);
}
private static Int32 GetReparsePointByName(
IntPtr FileSystem,
IntPtr Context,
String FileName,
Boolean IsDirectory,
IntPtr Buffer,
ref UIntPtr Size)
IntPtr PSize)
{
FileSystemBase self = (FileSystemBase)GCHandle.FromIntPtr(Context).Target;
try
{
return self.GetReparsePointByName(
Byte[] ReparseData;
Int32 Result;
ReparseData = null;
Result = self.GetReparsePointByName(
FileName,
IsDirectory,
Buffer,
ref Size);
ref ReparseData);
if (0 <= Result)
Result = Api.CopyReparsePoint(ReparseData, Buffer, PSize);
return Result;
}
catch (Exception ex)
{

View File

@ -1,7 +1,7 @@
/**
* @file dotnet/FileSystemHost.cs
/*
* dotnet/FileSystemHost.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
* Copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -24,9 +24,16 @@ using Fsp.Interop;
namespace Fsp
{
/// <summary>
/// Provides a means to host (mount) a file system.
/// </summary>
public class FileSystemHost : IDisposable
{
/* ctor/dtor */
/// <summary>
/// Creates an instance of the FileSystemHost class.
/// </summary>
/// <param name="FileSystem">The file system to host.</param>
public FileSystemHost(FileSystemBase FileSystem)
{
_VolumeParams.Flags = VolumeParams.UmFileContextIsFullContext;
@ -36,6 +43,9 @@ namespace Fsp
{
Dispose(false);
}
/// <summary>
/// Unmounts the file system and releases all associated resources.
/// </summary>
public void Dispose()
{
lock (this)
@ -56,73 +66,114 @@ namespace Fsp
{
ExceptionHandler(_FileSystem, ex);
}
Api.SetUserContext(_FileSystemPtr, null);
Api.DisposeUserContext(_FileSystemPtr);
Api.FspFileSystemDelete(_FileSystemPtr);
_FileSystemPtr = IntPtr.Zero;
}
}
/* properties */
/// <summary>
/// Gets or sets the sector size used by the file system.
/// </summary>
public UInt16 SectorSize
{
get { return _VolumeParams.SectorSize; }
set { _VolumeParams.SectorSize = value; }
}
/// <summary>
/// Gets or sets the sectors per allocation unit used by the file system.
/// </summary>
public UInt16 SectorsPerAllocationUnit
{
get { return _VolumeParams.SectorsPerAllocationUnit; }
set { _VolumeParams.SectorsPerAllocationUnit = value; }
}
/// <summary>
/// Gets or sets the maximum path component length used by the file system.
/// </summary>
public UInt16 MaxComponentLength
{
get { return _VolumeParams.MaxComponentLength; }
set { _VolumeParams.MaxComponentLength = value; }
}
/// <summary>
/// Gets or sets the volume creation time.
/// </summary>
public UInt64 VolumeCreationTime
{
get { return _VolumeParams.VolumeCreationTime; }
set { _VolumeParams.VolumeCreationTime = value; }
}
/// <summary>
/// Gets or sets the volume serial number.
/// </summary>
public UInt32 VolumeSerialNumber
{
get { return _VolumeParams.VolumeSerialNumber; }
set { _VolumeParams.VolumeSerialNumber = value; }
}
/// <summary>
/// Gets or sets the file information timeout.
/// </summary>
public UInt32 FileInfoTimeout
{
get { return _VolumeParams.FileInfoTimeout; }
set { _VolumeParams.FileInfoTimeout = value; }
}
/// <summary>
/// Gets or sets a value that determines whether the file system is case sensitive.
/// </summary>
public Boolean CaseSensitiveSearch
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.CaseSensitiveSearch); }
set { _VolumeParams.Flags |= (value ? VolumeParams.CaseSensitiveSearch : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether a case insensitive file system
/// preserves case in file names.
/// </summary>
public Boolean CasePreservedNames
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.CasePreservedNames); }
set { _VolumeParams.Flags |= (value ? VolumeParams.CasePreservedNames : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether file names support unicode characters.
/// </summary>
public Boolean UnicodeOnDisk
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.UnicodeOnDisk); }
set { _VolumeParams.Flags |= (value ? VolumeParams.UnicodeOnDisk : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether the file system supports ACL security.
/// </summary>
public Boolean PersistentAcls
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.PersistentAcls); }
set { _VolumeParams.Flags |= (value ? VolumeParams.PersistentAcls : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether the file system supports reparse points.
/// </summary>
public Boolean ReparsePoints
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.ReparsePoints); }
set { _VolumeParams.Flags |= (value ? VolumeParams.ReparsePoints : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether the file system allows creation of
/// symbolic links without additional privileges.
/// </summary>
public Boolean ReparsePointsAccessCheck
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.ReparsePointsAccessCheck); }
set { _VolumeParams.Flags |= (value ? VolumeParams.ReparsePointsAccessCheck : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether the file system supports named streams.
/// </summary>
public Boolean NamedStreams
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.NamedStreams); }
@ -138,11 +189,17 @@ namespace Fsp
get { return 0 != (_VolumeParams.Flags & VolumeParams.PassQueryDirectoryPattern); }
set { _VolumeParams.Flags |= (value ? VolumeParams.PassQueryDirectoryPattern : 0); }
}
/// <summary>
/// Gets or sets the prefix for a network file system.
/// </summary>
public String Prefix
{
get { return _VolumeParams.GetPrefix(); }
set { _VolumeParams.SetPrefix(value); }
}
/// <summary>
/// Gets or sets the file system name.
/// </summary>
public String FileSystemName
{
get { return _VolumeParams.GetFileSystemName(); }
@ -150,12 +207,42 @@ namespace Fsp
}
/* control */
/// <summary>
/// Checks whether mounting a file system is possible.
/// </summary>
/// <param name="MountPoint">
/// The mount point for the new file system. A value of null means that
/// the file system should use the next available drive letter counting
/// downwards from Z: as its mount point.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public Int32 Preflight(String MountPoint)
{
return Api.FspFileSystemPreflight(
_VolumeParams.IsPrefixEmpty() ? "WinFsp.Disk" : "WinFsp.Net",
MountPoint);
}
/// <summary>
/// Mounts a file system.
/// </summary>
/// <param name="MountPoint">
/// The mount point for the new file system. A value of null means that
/// the file system should use the next available drive letter counting
/// downwards from Z: as its mount point.
/// </param>
/// <param name="SecurityDescriptor">
/// Security descriptor to use if mounting on (newly created) directory.
/// A value of null means the directory should be created with default
/// security.
/// </param>
/// <param name="Synchronized">
/// If true file system operations are synchronized using an exclusive lock.
/// </param>
/// <param name="DebugLog">
/// A value of 0 disables all debug logging.
/// A value of -1 enables all debug logging.
/// </param>
/// <returns></returns>
public Int32 Mount(String MountPoint,
Byte[] SecurityDescriptor = null,
Boolean Synchronized = false,
@ -210,16 +297,23 @@ namespace Fsp
}
if (0 > Result)
{
Api.SetUserContext(_FileSystemPtr, null);
Api.DisposeUserContext(_FileSystemPtr);
Api.FspFileSystemDelete(_FileSystemPtr);
_FileSystemPtr = IntPtr.Zero;
}
return Result;
}
/// <summary>
/// Unmounts the file system and releases all associated resources.
/// </summary>
public void Unmount()
{
Dispose();
}
/// <summary>
/// Gets the file system mount point.
/// </summary>
/// <returns>The file system mount point.</returns>
public String MountPoint()
{
return IntPtr.Zero != _FileSystemPtr ?
@ -229,17 +323,28 @@ namespace Fsp
{
return _FileSystemPtr;
}
/// <summary>
/// Gets the hosted file system.
/// </summary>
/// <returns>The hosted file system.</returns>
public FileSystemBase FileSystem()
{
return _FileSystem;
}
/// <summary>
/// Sets the debug log file to use when debug logging is enabled.
/// </summary>
/// <param name="FileName">
/// The debug log file name. A value of "-" means standard error output.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
public static Int32 SetDebugLogFile(String FileName)
{
return Api.SetDebugLogFile(FileName);
}
/* FSP_FILE_SYSTEM_INTERFACE */
private static Byte[] SecurityDescriptorNotNull = new Byte[0];
private static Byte[] ByteBufferNotNull = new Byte[0];
private static Int32 ExceptionHandler(
FileSystemBase FileSystem,
Exception ex)
@ -301,12 +406,12 @@ namespace Fsp
Byte[] SecurityDescriptorBytes = null;
Int32 Result;
if (IntPtr.Zero != PSecurityDescriptorSize)
SecurityDescriptorBytes = SecurityDescriptorNotNull;
SecurityDescriptorBytes = ByteBufferNotNull;
Result = FileSystem.GetSecurityByName(
FileName,
out FileAttributes,
ref SecurityDescriptorBytes);
if (0 <= Result)
if (0 <= Result && 260/*STATUS_REPARSE*/ != Result)
{
if (IntPtr.Zero != PFileAttributes)
Marshal.WriteInt32(PFileAttributes, (Int32)FileAttributes);
@ -457,7 +562,7 @@ namespace Fsp
FileSystem.Close(
FileNode,
FileDesc);
Api.SetFullContext(ref FullContext, null, null);
Api.DisposeFullContext(ref FullContext);
}
catch (Exception ex)
{
@ -680,13 +785,15 @@ namespace Fsp
Byte[] SecurityDescriptorBytes;
Int32 Result;
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
SecurityDescriptorBytes = SecurityDescriptorNotNull;
SecurityDescriptorBytes = ByteBufferNotNull;
Result = FileSystem.GetSecurity(
FileNode,
FileDesc,
ref SecurityDescriptorBytes);
return Api.CopySecurityDescriptor(SecurityDescriptorBytes,
SecurityDescriptor, PSecurityDescriptorSize);
if (0 <= Result)
Result = Api.CopySecurityDescriptor(SecurityDescriptorBytes,
SecurityDescriptor, PSecurityDescriptorSize);
return Result;
}
catch (Exception ex)
{
@ -761,7 +868,7 @@ namespace Fsp
Boolean ResolveLastPathComponent,
out IoStatusBlock PIoStatus,
IntPtr Buffer,
ref UIntPtr PSize)
IntPtr PSize)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
@ -772,7 +879,7 @@ namespace Fsp
ResolveLastPathComponent,
out PIoStatus,
Buffer,
ref PSize);
PSize);
}
catch (Exception ex)
{
@ -785,23 +892,27 @@ namespace Fsp
ref FullContext FullContext,
String FileName,
IntPtr Buffer,
out UIntPtr PSize)
IntPtr PSize)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
{
Byte[] ReparseData;
Object FileNode, FileDesc;
Int32 Result;
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
return FileSystem.GetReparsePoint(
ReparseData = null;
Result = FileSystem.GetReparsePoint(
FileNode,
FileDesc,
FileName,
Buffer,
out PSize);
ref ReparseData);
if (0 <= Result)
Result = Api.CopyReparsePoint(ReparseData, Buffer, PSize);
return Result;
}
catch (Exception ex)
{
PSize = default(UIntPtr);
return ExceptionHandler(FileSystem, ex);
}
}
@ -821,8 +932,7 @@ namespace Fsp
FileNode,
FileDesc,
FileName,
Buffer,
Size);
Api.MakeReparsePoint(Buffer, Size));
}
catch (Exception ex)
{
@ -845,8 +955,7 @@ namespace Fsp
FileNode,
FileDesc,
FileName,
Buffer,
Size);
Api.MakeReparsePoint(Buffer, Size));
}
catch (Exception ex)
{
@ -913,8 +1022,8 @@ namespace Fsp
private static FileSystemInterface _FileSystemInterface;
private static IntPtr _FileSystemInterfacePtr;
private VolumeParams _VolumeParams;
private IntPtr _FileSystemPtr;
private FileSystemBase _FileSystem;
private IntPtr _FileSystemPtr;
}
}

View File

@ -1,7 +1,7 @@
/**
* @file dotnet/Interop.cs
/*
* dotnet/Interop.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
* Copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -102,16 +102,28 @@ namespace Fsp.Interop
}
}
/// <summary>
/// Contains volume information about a file system.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct VolumeInfo
{
internal const int VolumeLabelSize = 32;
/// <summary>
/// Total size of volume in bytes.
/// </summary>
public UInt64 TotalSize;
/// <summary>
/// Free size of volume in bytes.
/// </summary>
public UInt64 FreeSize;
internal UInt16 VolumeLabelLength;
internal unsafe fixed UInt16 VolumeLabel[VolumeLabelSize];
/// <summary>
/// Sets the volume label.
/// </summary>
public unsafe void SetVolumeLabel(String Value)
{
fixed (UInt16 *P = VolumeLabel)
@ -121,23 +133,59 @@ namespace Fsp.Interop
Size = VolumeLabelSize;
for (int I = 0; Size > I; I++)
P[I] = Value[I];
VolumeLabelLength = (UInt16)Size;
VolumeLabelLength = (UInt16)(Size * 2);
}
}
}
/// <summary>
/// Contains metadata information about a file or directory.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct FileInfo
{
/// <summary>
/// The file or directory attributes.
/// </summary>
public UInt32 FileAttributes;
/// <summary>
/// The reparse tag of the file or directory.
/// This value is 0 if the file or directory is not a reparse point.
/// </summary>
public UInt32 ReparseTag;
/// <summary>
/// The allocation size of the file.
/// </summary>
public UInt64 AllocationSize;
/// <summary>
/// The file size of the file (end of file).
/// </summary>
public UInt64 FileSize;
/// <summary>
/// The time that the file or directory was created.
/// </summary>
public UInt64 CreationTime;
/// <summary>
/// The time that the file or directory was last accessed.
/// </summary>
public UInt64 LastAccessTime;
/// <summary>
/// The time that the file or direcotry was last modified.
/// </summary>
public UInt64 LastWriteTime;
/// <summary>
/// The time that the file or directory metadata was last modified.
/// </summary>
public UInt64 ChangeTime;
/// <summary>
/// A unique identifier that is associated with the file or directory.
/// Not all file systems support this value.
/// </summary>
public UInt64 IndexNumber;
/// <summary>
/// The number of hard links.
/// Not currently implemented. Set to 0.
/// </summary>
public UInt32 HardLinks;
}
@ -156,7 +204,7 @@ namespace Fsp.Interop
Size = NormalizedNameSize;
for (int I = 0; Size > I; I++)
P[I] = Value[I];
NormalizedNameSize = (UInt16)Size;
NormalizedNameSize = (UInt16)(Size * 2);
}
}
@ -164,7 +212,8 @@ namespace Fsp.Interop
internal struct DirInfo
{
internal const int FileNameBufSize = 255;
internal static int FileNameBufOffset = (int)Marshal.OffsetOf(typeof(DirInfo), "FileNameBuf");
internal static int FileNameBufOffset =
(int)Marshal.OffsetOf(typeof(DirInfo), "FileNameBuf");
internal UInt16 Size;
internal FileInfo FileInfo;
@ -172,7 +221,7 @@ namespace Fsp.Interop
//internal unsafe fixed UInt16 FileNameBuf[];
internal unsafe fixed UInt16 FileNameBuf[FileNameBufSize];
public unsafe void SetFileNameBuf(String Value)
internal unsafe void SetFileNameBuf(String Value)
{
fixed (UInt16 *P = FileNameBuf)
{
@ -189,10 +238,28 @@ namespace Fsp.Interop
[StructLayout(LayoutKind.Sequential)]
internal struct StreamInfo
{
internal const int StreamNameBufSize = 255;
internal static int StreamNameBufOffset =
(int)Marshal.OffsetOf(typeof(StreamInfo), "StreamNameBuf");
internal UInt16 Size;
internal UInt64 StreamSize;
internal UInt64 StreamAllocationSize;
//internal unsafe fixed UInt16 StreamNameBuf[];
internal unsafe fixed UInt16 StreamNameBuf[StreamNameBufSize];
internal unsafe void SetStreamNameBuf(String Value)
{
fixed (UInt16 *P = StreamNameBuf)
{
int Size = null != Value ? Value.Length : 0;
if (Size > StreamNameBufSize)
Size = StreamNameBufSize;
for (int I = 0; Size > I; I++)
P[I] = Value[I];
this.Size = (UInt16)(StreamNameBufOffset + Size * 2);
}
}
}
[StructLayout(LayoutKind.Sequential)]
@ -354,14 +421,14 @@ namespace Fsp.Interop
[MarshalAs(UnmanagedType.U1)] Boolean ResolveLastPathComponent,
out IoStatusBlock PIoStatus,
IntPtr Buffer,
ref UIntPtr PSize);
IntPtr PSize);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 GetReparsePoint(
IntPtr FileSystem,
ref FullContext FullContext,
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
IntPtr Buffer,
out UIntPtr PSize);
IntPtr PSize);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 SetReparsePoint(
IntPtr FileSystem,
@ -471,7 +538,8 @@ namespace Fsp.Interop
UInt32 Length,
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 FspFileSystemFindReparsePoint(
[return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemFindReparsePoint(
IntPtr FileSystem,
GetReparsePointByName GetReparsePointByName,
IntPtr Context,
@ -487,7 +555,7 @@ namespace Fsp.Interop
[MarshalAs(UnmanagedType.U1)] Boolean ResolveLastPathComponent,
out IoStatusBlock PIoStatus,
IntPtr Buffer,
ref UIntPtr PSize);
IntPtr PSize);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 FspFileSystemCanReplaceReparsePoint(
IntPtr CurrentReparseData,
@ -526,6 +594,16 @@ namespace Fsp.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void FspFileSystemDeleteDirectoryBuffer(
ref IntPtr PDirBuffer);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 FspSetSecurityDescriptor(
IntPtr InputDescriptor,
UInt32 SecurityInformation,
IntPtr ModificationDescriptor,
out IntPtr PSecurityDescriptor);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void FspDeleteSecurityDescriptor(
IntPtr SecurityDescriptor,
IntPtr CreateFunc);
/* Service */
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@ -575,6 +653,10 @@ namespace Fsp.Interop
internal delegate UInt32 FspWin32FromNtStatus(
Int32 Status);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void FspDebugLog(
[MarshalAs(UnmanagedType.LPStr)] String Format,
[MarshalAs(UnmanagedType.LPStr)] String Message);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void FspDebugLogSetHandle(
IntPtr Handle);
@ -586,7 +668,7 @@ namespace Fsp.Interop
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
[MarshalAs(UnmanagedType.U1)] Boolean IsDirectory,
IntPtr Buffer,
ref UIntPtr PSize);
IntPtr PSize);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 ServiceStart(
IntPtr Service,
@ -619,13 +701,16 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemAddDirInfo _FspFileSystemAddDirInfo;
internal static Proto.FspFileSystemFindReparsePoint FspFileSystemFindReparsePoint;
internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints;
internal static Proto.FspFileSystemCanReplaceReparsePoint FspFileSystemCanReplaceReparsePoint;
internal static Proto.FspFileSystemAddStreamInfo FspFileSystemAddStreamInfo;
internal static Proto.FspFileSystemCanReplaceReparsePoint _FspFileSystemCanReplaceReparsePoint;
internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo;
internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer;
internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer;
internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer;
internal static Proto.FspFileSystemReadDirectoryBuffer FspFileSystemReadDirectoryBuffer;
internal static Proto.FspFileSystemDeleteDirectoryBuffer FspFileSystemDeleteDirectoryBuffer;
internal static Proto.FspSetSecurityDescriptor FspSetSecurityDescriptor;
internal static IntPtr _FspSetSecurityDescriptorPtr;
internal static Proto.FspDeleteSecurityDescriptor FspDeleteSecurityDescriptor;
internal static Proto.FspServiceCreate FspServiceCreate;
internal static Proto.FspServiceDelete FspServiceDelete;
internal static Proto.FspServiceAllowConsoleMode FspServiceAllowConsoleMode;
@ -638,6 +723,7 @@ namespace Fsp.Interop
internal static Proto.FspVersion FspVersion;
internal static Proto.FspNtStatusFromWin32 FspNtStatusFromWin32;
internal static Proto.FspWin32FromNtStatus FspWin32FromNtStatus;
internal static Proto.FspDebugLog FspDebugLog;
internal static Proto.FspDebugLogSetHandle FspDebugLogSetHandle;
internal static unsafe Int32 FspFileSystemSetMountPointEx(
@ -662,6 +748,29 @@ namespace Fsp.Interop
fixed (DirInfo *P = &DirInfo)
return _FspFileSystemAddDirInfo((IntPtr)P, Buffer, Length, out PBytesTransferred);
}
internal static unsafe Boolean FspFileSystemEndDirInfo(
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
return _FspFileSystemAddDirInfo(IntPtr.Zero, Buffer, Length, out PBytesTransferred);
}
internal static unsafe Boolean FspFileSystemAddStreamInfo(
ref StreamInfo StreamInfo,
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
fixed (StreamInfo *P = &StreamInfo)
return _FspFileSystemAddStreamInfo((IntPtr)P, Buffer, Length, out PBytesTransferred);
}
internal static unsafe Boolean FspFileSystemEndStreamInfo(
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
return _FspFileSystemAddStreamInfo(IntPtr.Zero, Buffer, Length, out PBytesTransferred);
}
internal unsafe static Object GetUserContext(
IntPtr NativePtr)
@ -673,61 +782,61 @@ namespace Fsp.Interop
IntPtr NativePtr,
Object Obj)
{
if (null != Obj)
Debug.Assert(IntPtr.Zero == *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)));
GCHandle Handle = GCHandle.Alloc(Obj, GCHandleType.Weak);
*(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)) = (IntPtr)Handle;
}
internal unsafe static void DisposeUserContext(
IntPtr NativePtr)
{
IntPtr UserContext = *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr));
Debug.Assert(IntPtr.Zero != UserContext);
if (IntPtr.Zero != UserContext)
{
Debug.Assert(IntPtr.Zero == *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)));
GCHandle Handle = GCHandle.Alloc(Obj, GCHandleType.Weak);
*(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)) = (IntPtr)Handle;
}
else
{
IntPtr UserContext = *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr));
if (IntPtr.Zero != UserContext)
{
GCHandle.FromIntPtr(UserContext).Free();
*(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)) = IntPtr.Zero;
}
GCHandle.FromIntPtr(UserContext).Free();
*(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)) = IntPtr.Zero;
}
}
private class FullContextHolder
{
public Object FileNode;
public Object FileDesc;
}
internal static void GetFullContext(ref FullContext FullContext,
out Object FileNode, out Object FileDesc)
{
FileNode = 0 != FullContext.UserContext ?
GCHandle.FromIntPtr((IntPtr)FullContext.UserContext).Target : null;
FileDesc = 0 != FullContext.UserContext2 ?
GCHandle.FromIntPtr((IntPtr)FullContext.UserContext2).Target : null;
FullContextHolder Holder = 0 != FullContext.UserContext2 ?
(FullContextHolder)GCHandle.FromIntPtr((IntPtr)FullContext.UserContext2).Target :
null;
if (null != Holder)
{
FileNode = Holder.FileNode;
FileDesc = Holder.FileDesc;
}
else
{
FileNode = null;
FileDesc = null;
}
}
internal static void SetFullContext(ref FullContext FullContext,
Object FileNode, Object FileDesc)
{
if (null != FileNode)
Debug.Assert(0 == FullContext.UserContext && 0 == FullContext.UserContext2);
FullContextHolder Holder = new FullContextHolder();
Holder.FileNode = FileNode;
Holder.FileDesc = FileDesc;
GCHandle Handle = GCHandle.Alloc(Holder, GCHandleType.Normal);
FullContext.UserContext2 = (UInt64)(IntPtr)Handle;
}
internal static void DisposeFullContext(ref FullContext FullContext)
{
Debug.Assert(0 == FullContext.UserContext && 0 != FullContext.UserContext2);
if (0 != FullContext.UserContext2)
{
Debug.Assert(0 == FullContext.UserContext);
GCHandle Handle = GCHandle.Alloc(FileNode, GCHandleType.Normal);
FullContext.UserContext = (UInt64)(IntPtr)Handle;
}
else
{
if (0 != FullContext.UserContext)
{
GCHandle.FromIntPtr((IntPtr)FullContext.UserContext).Free();
FullContext.UserContext = 0;
}
}
if (null != FileDesc)
{
Debug.Assert(0 == FullContext.UserContext2);
GCHandle Handle = GCHandle.Alloc(FileDesc, GCHandleType.Normal);
FullContext.UserContext2 = (UInt64)(IntPtr)Handle;
}
else
{
if (0 != FullContext.UserContext2)
{
GCHandle.FromIntPtr((IntPtr)FullContext.UserContext2).Free();
FullContext.UserContext2 = 0;
}
GCHandle.FromIntPtr((IntPtr)FullContext.UserContext2).Free();
FullContext.UserContext2 = 0;
}
}
@ -768,6 +877,67 @@ namespace Fsp.Interop
else
return null;
}
internal unsafe static byte[] ModifySecurityDescriptor(
Byte[] SecurityDescriptorBytes,
UInt32 SecurityInformation,
Byte[] ModificationDescriptorBytes)
{
fixed (Byte *S = SecurityDescriptorBytes)
fixed (Byte *M = ModificationDescriptorBytes)
{
IntPtr SecurityDescriptor;
Int32 Result = FspSetSecurityDescriptor(
(IntPtr)S, SecurityInformation, (IntPtr)M, out SecurityDescriptor);
if (0 > Result)
return null;
SecurityDescriptorBytes = MakeSecurityDescriptor(SecurityDescriptor);
FspDeleteSecurityDescriptor(SecurityDescriptor, _FspSetSecurityDescriptorPtr);
return SecurityDescriptorBytes;
}
}
internal unsafe static Int32 CopyReparsePoint(
Byte[] ReparseData,
IntPtr Buffer,
IntPtr PSize)
{
if (IntPtr.Zero != Buffer)
{
if (null != ReparseData)
{
if (ReparseData.Length > (int)*(UIntPtr *)PSize)
return unchecked((Int32)0xc0000023)/*STATUS_BUFFER_TOO_SMALL*/;
*(UIntPtr *)PSize = (UIntPtr)ReparseData.Length;
Marshal.Copy(ReparseData, 0, Buffer, ReparseData.Length);
}
else
*(UIntPtr *)PSize = UIntPtr.Zero;
}
return 0/*STATUS_SUCCESS*/;
}
internal static Byte[] MakeReparsePoint(
IntPtr Buffer,
UIntPtr Size)
{
if (IntPtr.Zero != Buffer)
{
Byte[] ReparseData = new Byte[(int)Size];
Marshal.Copy(Buffer, ReparseData, 0, ReparseData.Length);
return ReparseData;
}
else
return null;
}
internal unsafe static Int32 FspFileSystemCanReplaceReparsePoint(
Byte[] CurrentReparseData,
Byte[] ReplaceReparseData)
{
fixed (Byte *C = CurrentReparseData)
fixed (Byte *R = ReplaceReparseData)
return _FspFileSystemCanReplaceReparsePoint(
(IntPtr)C, (UIntPtr)CurrentReparseData.Length,
(IntPtr)R, (UIntPtr)ReplaceReparseData.Length);
}
internal static Int32 SetDebugLogFile(String FileName)
{
@ -812,17 +982,17 @@ namespace Fsp.Interop
}
return Module;
}
private static IntPtr GetEntryPointPtr(IntPtr Module, String Name)
{
IntPtr Proc = GetProcAddress(Module, Name);
if (IntPtr.Zero == Proc)
throw new EntryPointNotFoundException("cannot get entry point " + Name);
return Proc;
}
private static T GetEntryPoint<T>(IntPtr Module)
{
try
{
return (T)(object)Marshal.GetDelegateForFunctionPointer(
GetProcAddress(Module, typeof(T).Name), typeof(T));
}
catch (ArgumentNullException)
{
throw new EntryPointNotFoundException("cannot get entry point " + typeof(T).Name);
}
return (T)(object)Marshal.GetDelegateForFunctionPointer(
GetEntryPointPtr(Module, typeof(T).Name), typeof(T));
}
private static void LoadProto(IntPtr Module)
{
@ -840,13 +1010,16 @@ namespace Fsp.Interop
_FspFileSystemAddDirInfo = GetEntryPoint<Proto.FspFileSystemAddDirInfo>(Module);
FspFileSystemFindReparsePoint = GetEntryPoint<Proto.FspFileSystemFindReparsePoint>(Module);
FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module);
FspFileSystemCanReplaceReparsePoint = GetEntryPoint<Proto.FspFileSystemCanReplaceReparsePoint>(Module);
FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
_FspFileSystemCanReplaceReparsePoint = GetEntryPoint<Proto.FspFileSystemCanReplaceReparsePoint>(Module);
_FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);
FspFileSystemReadDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReadDirectoryBuffer>(Module);
FspFileSystemDeleteDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemDeleteDirectoryBuffer>(Module);
FspSetSecurityDescriptor = GetEntryPoint<Proto.FspSetSecurityDescriptor>(Module);
_FspSetSecurityDescriptorPtr = GetEntryPointPtr(Module, "FspSetSecurityDescriptor");
FspDeleteSecurityDescriptor = GetEntryPoint<Proto.FspDeleteSecurityDescriptor>(Module);
FspServiceCreate = GetEntryPoint<Proto.FspServiceCreate>(Module);
FspServiceDelete = GetEntryPoint<Proto.FspServiceDelete>(Module);
FspServiceAllowConsoleMode = GetEntryPoint<Proto.FspServiceAllowConsoleMode>(Module);
@ -859,6 +1032,7 @@ namespace Fsp.Interop
FspVersion = GetEntryPoint<Proto.FspVersion>(Module);
FspNtStatusFromWin32 = GetEntryPoint<Proto.FspNtStatusFromWin32>(Module);
FspWin32FromNtStatus = GetEntryPoint<Proto.FspWin32FromNtStatus>(Module);
FspDebugLog = GetEntryPoint<Proto.FspDebugLog>(Module);
FspDebugLogSetHandle = GetEntryPoint<Proto.FspDebugLogSetHandle>(Module);
}
private static void CheckVersion()

View File

@ -1,7 +1,7 @@
/**
* @file dotnet/Service.cs
/*
* dotnet/Service.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
* Copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
@ -16,13 +16,16 @@
*/
using System;
using System.Runtime.InteropServices;
using Fsp.Interop;
namespace Fsp
{
/// <summary>
/// Provides the base class for a process that can be run as a service,
/// command line application or under the control of the WinFsp launcher.
/// </summary>
public class Service
{
/* const */
@ -31,25 +34,33 @@ namespace Fsp
public const UInt32 EVENTLOG_INFORMATION_TYPE = 0x0004;
/* ctor/dtor */
/// <summary>
/// Creates an instance of the Service class.
/// </summary>
/// <param name="ServiceName">The name of the service.</param>
public Service(String ServiceName)
{
Api.FspServiceCreate(ServiceName, _OnStart, _OnStop, null, out _Service);
if (IntPtr.Zero != _Service)
Api.SetUserContext(_Service, this);
Api.FspServiceCreate(ServiceName, _OnStart, _OnStop, null, out _ServicePtr);
if (IntPtr.Zero != _ServicePtr)
Api.SetUserContext(_ServicePtr, this);
}
~Service()
{
if (IntPtr.Zero != _Service)
if (IntPtr.Zero != _ServicePtr)
{
Api.SetUserContext(_Service, null);
Api.FspServiceDelete(_Service);
Api.DisposeUserContext(_ServicePtr);
Api.FspServiceDelete(_ServicePtr);
}
}
/* control */
/// <summary>
/// Runs a service.
/// </summary>
/// <returns>Service process exit code.</returns>
public int Run()
{
if (IntPtr.Zero == _Service)
if (IntPtr.Zero == _ServicePtr)
{
const Int32 STATUS_INSUFFICIENT_RESOURCES = unchecked((Int32)0xc000009a);
Log(EVENTLOG_ERROR_TYPE,
@ -57,9 +68,9 @@ namespace Fsp
GetType().FullName, STATUS_INSUFFICIENT_RESOURCES));
return (int)Api.FspWin32FromNtStatus(STATUS_INSUFFICIENT_RESOURCES);
}
Api.FspServiceAllowConsoleMode(_Service);
Int32 Result = Api.FspServiceLoop(_Service);
int ExitCode = (int)Api.FspServiceGetExitCode(_Service);
Api.FspServiceAllowConsoleMode(_ServicePtr);
Int32 Result = Api.FspServiceLoop(_ServicePtr);
int ExitCode = (int)Api.FspServiceGetExitCode(_ServicePtr);
if (0 > Result)
{
Log(EVENTLOG_ERROR_TYPE,
@ -69,36 +80,42 @@ namespace Fsp
}
return ExitCode;
}
/// <summary>
/// Stops a running service.
/// </summary>
public void Stop()
{
if (IntPtr.Zero == _Service)
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
Api.FspServiceStop(_Service);
Api.FspServiceStop(_ServicePtr);
}
public void RequestTime(UInt32 Time)
{
if (IntPtr.Zero == _Service)
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
Api.FspServiceRequestTime(_Service, Time);
Api.FspServiceRequestTime(_ServicePtr, Time);
}
/// <summary>
/// Gets or sets the service process exit code.
/// </summary>
public int ExitCode
{
get
{
if (IntPtr.Zero == _Service)
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
return (int)Api.FspServiceGetExitCode(_Service);
return (int)Api.FspServiceGetExitCode(_ServicePtr);
}
set
{
if (IntPtr.Zero == _Service)
if (IntPtr.Zero == _ServicePtr)
throw new InvalidOperationException();
Api.FspServiceSetExitCode(_Service, (UInt32)value);
Api.FspServiceSetExitCode(_ServicePtr, (UInt32)value);
}
}
public IntPtr ServiceHandle
{
get { return _Service; }
get { return _ServicePtr; }
}
public static void Log(UInt32 Type, String Message)
{
@ -106,13 +123,25 @@ namespace Fsp
}
/* start/stop */
/// <summary>
/// Provides a means to customize the returned status code when an exception happens.
/// </summary>
/// <param name="ex"></param>
/// <returns>STATUS_SUCCESS or error code.</returns>
protected virtual Int32 ExceptionHandler(Exception ex)
{
return unchecked((Int32)0xE0434f4D)/*STATUS_CLR_EXCEPTION*/;
}
/// <summary>
/// Occurs when the service starts.
/// </summary>
/// <param name="Args">Command line arguments passed to the service.</param>
protected virtual void OnStart(String[] Args)
{
}
/// <summary>
/// Occurs when the service stops.
/// </summary>
protected virtual void OnStop()
{
}
@ -152,7 +181,7 @@ namespace Fsp
private static Api.Proto.ServiceStart _OnStart = OnStart;
private static Api.Proto.ServiceStop _OnStop = OnStop;
private IntPtr _Service;
private IntPtr _ServicePtr;
}
}

View File

@ -17,12 +17,16 @@ launchctl-x64 start memfs64 testdsk "" M: >nul
launchctl-x64 start memfs64 testnet \memfs64\test N: >nul
launchctl-x64 start memfs32 testdsk "" O: >nul
launchctl-x64 start memfs32 testnet \memfs32\test P: >nul
launchctl-x64 start memfs-dotnet testdsk "" Q: >nul
launchctl-x64 start memfs-dotnet testnet \memfs-dotnet\test R: >nul
rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported"
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
cd M: >nul 2>nul || (echo === Unable to find drive M: >&2 & goto fail)
cd N: >nul 2>nul || (echo === Unable to find drive N: >&2 & goto fail)
cd O: >nul 2>nul || (echo === Unable to find drive O: >&2 & goto fail)
cd P: >nul 2>nul || (echo === Unable to find drive P: >&2 & goto fail)
cd Q: >nul 2>nul || (echo === Unable to find drive Q: >&2 & goto fail)
cd R: >nul 2>nul || (echo === Unable to find drive R: >&2 & goto fail)
set dfl_tests=^
winfsp-tests-x64 ^
@ -31,6 +35,7 @@ set dfl_tests=^
winfsp-tests-x64-mountpoint-dir ^
winfsp-tests-x64-no-traverse ^
winfsp-tests-x64-oplock ^
winfsp-tests-x64-external ^
winfsp-tests-x64-external-share ^
fsx-memfs-x64-disk ^
fsx-memfs-x64-net ^
@ -46,6 +51,7 @@ set dfl_tests=^
winfsp-tests-x86-mountpoint-dir ^
winfsp-tests-x86-no-traverse ^
winfsp-tests-x86-oplock ^
winfsp-tests-x86-external ^
winfsp-tests-x86-external-share ^
fsx-memfs-x86-disk ^
fsx-memfs-x86-net ^
@ -54,10 +60,17 @@ set dfl_tests=^
net-use-memfs-x86 ^
winfstest-memfs-x86-disk ^
winfstest-memfs-x86-net ^
fscrash-x86
fscrash-x86 ^
winfsp-tests-dotnet-external ^
winfsp-tests-dotnet-external-share ^
fsx-memfs-dotnet-disk ^
fsx-memfs-dotnet-net ^
winfstest-memfs-dotnet-disk ^
winfstest-memfs-dotnet-net
set opt_tests=^
ifstest-memfs-x64-disk ^
ifstest-memfs-x86-disk ^
ifstest-memfs-dotnet-disk ^
sample-passthrough-x64 ^
sample-passthrough-x86 ^
sample-passthrough-cpp-x64 ^
@ -121,6 +134,8 @@ launchctl-x64 stop memfs64 testdsk >nul
launchctl-x64 stop memfs64 testnet >nul
launchctl-x64 stop memfs32 testdsk >nul
launchctl-x64 stop memfs32 testnet >nul
launchctl-x64 stop memfs-dotnet testdsk >nul
launchctl-x64 stop memfs-dotnet testnet >nul
rem Cannot use timeout under cygwin/mintty: "Input redirection is not supported"
waitfor 7BF47D72F6664550B03248ECFE77C7DD /t 3 2>nul
@ -195,6 +210,12 @@ winfsp-tests-x86 --oplock=filter --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x64-external
M:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x64-external-share
M:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=M:\ --resilient ^
@ -242,6 +263,12 @@ net use L: /delete
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x86-external
O:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x86-external-share
O:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x86.exe" --external --share=winfsp-tests-share=O:\ --resilient ^
@ -351,6 +378,47 @@ fscrash-x86 --huge-alloc-size --cached >nul 2>&1
if !ERRORLEVEL! neq 1 goto fail
exit /b 0
:winfsp-tests-dotnet-external
Q:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-dotnet-external-share
Q:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-x64.exe" --external --share=winfsp-tests-share=Q:\ --resilient ^
-reparse_symlink*
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:fsx-memfs-dotnet-disk
Q:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:fsx-memfs-dotnet-net
R:
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -f foo -N 5000 test xxxxxx
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfstest-memfs-dotnet-disk
Q:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfstest-memfs-dotnet-net
R:
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:ifstest-memfs-x64-disk
call :__ifstest-memfs M: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail
@ -361,6 +429,11 @@ call :__ifstest-memfs O: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:ifstest-memfs-dotnet-disk
call :__ifstest-memfs Q: \Device\WinFsp.Disk C:
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:__ifstest-memfs
%1
set IfsTestDirectories=^

0
tools/version-info.bat Normal file → Executable file
View File

1156
tst/memfs-dotnet/Program.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -316,6 +316,9 @@ static void dirbuf_fill_test(void)
void dirbuf_tests(void)
{
if (OptExternal)
return;
TEST(dirbuf_empty_test);
TEST(dirbuf_dots_test);
TEST(dirbuf_fill_test);

View File

@ -31,5 +31,8 @@ void eventlog_test(void)
void eventlog_tests(void)
{
if (OptExternal)
return;
TEST_OPT(eventlog_test);
}

View File

@ -370,5 +370,8 @@ void fuse_opt_parse_test(void)
void fuse_opt_tests(void)
{
if (OptExternal)
return;
TEST(fuse_opt_parse_test);
}

View File

@ -102,5 +102,8 @@ void memfs_test(void)
void memfs_tests(void)
{
if (OptExternal)
return;
TEST(memfs_test);
}

View File

@ -336,7 +336,7 @@ void mount_preflight_test(void)
void mount_tests(void)
{
if (NtfsTests || OptOplock)
if (OptExternal || OptOplock)
return;
TEST_OPT(mount_invalid_test);

View File

@ -126,6 +126,9 @@ void path_suffix_test(void)
void path_tests(void)
{
if (OptExternal)
return;
TEST(path_prefix_test);
TEST(path_suffix_test);
}

View File

@ -265,6 +265,9 @@ void posix_map_path_test(void)
void posix_tests(void)
{
if (OptExternal)
return;
TEST(posix_map_sid_test);
TEST(posix_map_sd_test);
TEST(posix_map_path_test);

View File

@ -262,7 +262,7 @@ void timeout_transact_test(void)
void timeout_tests(void)
{
if (NtfsTests || OptOplock)
if (OptExternal || OptOplock)
return;
TEST_OPT(timeout_pending_test);

View File

@ -38,5 +38,8 @@ static void version_test(void)
void version_tests(void)
{
if (OptExternal)
return;
TEST(version_test);
}

View File

@ -28,6 +28,7 @@ int NtfsTests = 0;
int WinFspDiskTests = 1;
int WinFspNetTests = 1;
BOOLEAN OptExternal = FALSE;
BOOLEAN OptResilient = FALSE;
BOOLEAN OptCaseInsensitiveCmp = FALSE;
BOOLEAN OptCaseInsensitive = FALSE;
@ -211,6 +212,7 @@ int main(int argc, char *argv[])
{
if (0 == strcmp("--ntfs", a) || 0 == strcmp("--external", a))
{
OptExternal = TRUE;
NtfsTests = 1;
WinFspDiskTests = 0;
WinFspNetTests = 0;

View File

@ -149,6 +149,7 @@ extern int NtfsTests;
extern int WinFspDiskTests;
extern int WinFspNetTests;
extern BOOLEAN OptExternal;
extern BOOLEAN OptResilient;
extern BOOLEAN OptCaseInsensitiveCmp;
extern BOOLEAN OptCaseInsensitive;