Compare commits

..

90 Commits

Author SHA1 Message Date
9c4b73dac1 add FLOSS exception to License 2017-02-06 11:51:29 -08:00
9ecfc64178 doc: update tutorial 2017-02-04 15:22:42 -08:00
fbe46d8c81 doc: update tutorial 2017-02-04 14:56:01 -08:00
2a12ed490d tools: run-tests: run mountpoint-drive tests with --resilient 2017-02-03 18:50:39 -08:00
c6d9e68c3f Revert "tst: winfsp-tests: getfileinfo_dotest: CREATE_ALWAYS instead of CREATE_NEW"
This reverts commit dca3cb93f3.
2017-02-03 18:48:55 -08:00
bfc41127d0 sys: FspFsvolCreateSharingViolationOplock: fix problem with missed FspFsvolCreatePostClose 2017-02-03 18:08:11 -08:00
6e70500afc sys: FspFsvolCreateComplete: populate FileNode and FileDesc before name normalization 2017-02-03 17:36:16 -08:00
dca3cb93f3 tst: winfsp-tests: getfileinfo_dotest: CREATE_ALWAYS instead of CREATE_NEW 2017-02-02 22:12:49 -08:00
2f0061b4ba tools: run-tests: sample-passthrough-fuse 2017-02-02 21:44:36 -08:00
3fcef3b0fa tools: run-tests: sample-passthrough-fuse 2017-02-02 21:39:13 -08:00
6a0574e309 tools: run-tests: sample-passthrough-fuse 2017-02-02 17:51:08 -08:00
0c945b67f3 dll: fuse: use -ouid=-1,gid=-1 to specify user/group who mounted file system 2017-02-02 17:06:10 -08:00
25b3e111fa dll: fuse: fuse.pc file renamed to fuse.pc.in 2017-02-02 15:01:22 -08:00
09101129a3 tst: passthrough: EnableBackupRestorePrivileges: minor fix 2017-02-02 14:51:45 -08:00
3700b375a7 tst: passthrough-fuse: on Windows allow the --VolumePrefix option to specify path 2017-02-01 21:37:53 -08:00
22fccdb575 build: bump version to RC2 and files to installer 2017-02-01 16:10:13 -08:00
c4932f7c7e tools: run-tests: include passthrough-fuse sample test 2017-02-01 15:38:46 -08:00
303cadb55d tst: passthrough-fuse: update Makefile to link with CYGFUSE or WinFsp-FUSE 2017-02-01 15:30:51 -08:00
5617d09edc tst: passthrough-fuse:
- When building for Windows (rather than Cygwin or POSIX OS)
allow the syntax C$\Path as an alternative to C:\Path.
2017-02-01 13:35:13 -08:00
eefaad241d doc: update tutorial 2017-01-31 17:29:03 -08:00
11dce32baa doc: update tutorial 2017-01-31 17:21:55 -08:00
3b8396dc27 tst: passthrough: minor fix 2017-01-31 16:53:27 -08:00
da7082030a doc: update tutorial 2017-01-31 16:36:30 -08:00
7425eba8af inc: winfsp.h: FspLoad 2017-01-31 16:07:50 -08:00
acf6ce1008 inc: winfsp.h: FspLoad 2017-01-31 15:56:00 -08:00
06f6c192ed tst: passthrough, passthrough-fuse: WinFspLoad: eliminate RRF_SUBKEY_WOW6432KEY 2017-01-31 15:27:15 -08:00
b7a06c7046 tools: run-tests 2017-01-31 14:52:20 -08:00
edb675d2d4 tools: run-tests 2017-01-31 12:21:46 -08:00
9533815931 update Changelog 2017-01-31 12:19:54 -08:00
fe74fc4013 tools: run-tests: sample testing fix 2017-01-31 11:31:00 -08:00
5bd6c1a122 dll: np: NPAddConnection: check volume access and report success/failure 2017-01-31 11:29:24 -08:00
7b15d32c33 appveyor: sample testing 2017-01-30 23:33:50 -08:00
c186289672 tools: run-tests: sample-passthrough-fuse: add but keep disabled 2017-01-30 23:32:22 -08:00
ff649e05c5 tools: run-tests: sample-passthrough* 2017-01-30 23:10:34 -08:00
9a9d3cd4e8 installer: add passthrough-fuse and fsreg.bat 2017-01-30 16:23:45 -08:00
d1bb65a998 tst: winfsp-tests: add --share-prefix option:
- this accommodates network file systems that have mapped drives
2017-01-30 16:07:44 -08:00
178200fd63 doc: update tutorial 2017-01-30 15:32:48 -08:00
396d9d97d2 tst: passthrough: enable backup/restore privileges if able 2017-01-30 15:22:20 -08:00
1d35069aab doc: update tutorial 2017-01-30 14:41:33 -08:00
4421c82ce0 doc: update tutorial 2017-01-30 14:34:44 -08:00
36f0978971 dll: fuse: allow rename for filenames that differ only in case 2017-01-30 11:59:21 -08:00
dae4bad732 tst: passthrough-fuse: testing 2017-01-29 21:25:50 -08:00
75744571ff dll: debug: fix problem with debug logs under 32-bits 2017-01-29 21:23:44 -08:00
0494726f52 tst: passthrough-fuse: testing 2017-01-29 18:06:56 -08:00
a964ab1b73 dll: fuse: CanDelete bug fix 2017-01-29 17:38:13 -08:00
796010c9fe tst: passthrough-fuse: testing 2017-01-29 17:28:40 -08:00
dc343ecbe5 tst: passthrough-fuse: testing 2017-01-29 17:07:22 -08:00
706fa2cc07 tst: passthrough-fuse: fi_fd, fi_setfd, etc. macros 2017-01-29 16:45:21 -08:00
c0aaebd0a5 tst: passthrough-fuse: windows-posix layer: dirfd 2017-01-29 15:45:36 -08:00
9c2b4e5631 tst: passthrough-fuse: testing 2017-01-29 13:59:29 -08:00
206b85c278 tst: passthrough-fuse: testing 2017-01-29 13:48:29 -08:00
075d1821a2 tst: passthrough-fuse: windows-posix layer 2017-01-29 12:44:18 -08:00
c252382204 tst: passthrough-fuse: windows-posix layer 2017-01-29 12:34:28 -08:00
a91e5b01ab tst: passthrough-fuse: windows-posix layer 2017-01-29 10:29:37 -08:00
473914d45f tst: passthrough-fuse: initial checkin 2017-01-28 22:47:46 -08:00
e12e3630bb doc: update tutorial document 2017-01-28 12:40:42 -08:00
960c627924 tst: passthrough: reorg project 2017-01-28 12:34:10 -08:00
f97ef5704f dll: fuse: reimplement ReadDirectory 2017-01-28 11:49:57 -08:00
41605a3d5a doc: update tutorial 2017-01-27 15:40:04 -08:00
e4f0406c4f tools: fsreg
tst: passthrough: support passing passthrough directory using -u
2017-01-27 13:38:45 -08:00
b5bf84b618 installer: add passthrough sample 2017-01-27 11:10:20 -08:00
3c340345c0 tst: passthrough: PassQueryDirectoryPattern 2017-01-26 23:22:59 -08:00
63c23f382b inc: fsctl: PassQueryDirectoryPattern 2017-01-26 23:09:58 -08:00
de5ef0c81d tst: winfsp-tests: --case-insensitive-cmp 2017-01-26 22:58:49 -08:00
7288605f65 tst: passthrough: use FspFileSystem*DirectoryBuffer API's 2017-01-26 16:39:06 -08:00
55a7864173 dll: FspFileSystem*DirectoryBuffer API's 2017-01-26 16:30:33 -08:00
4fe72ab332 sys,dll: ReadDirectory: add Marker, remove Offset 2017-01-25 10:51:37 -08:00
76a2926116 sys,dll: ReadDirectory: add Marker, remove Offset 2017-01-24 20:20:02 -08:00
7843c73d34 sys,dll: ReadDirectory: add Marker, remove Offset 2017-01-24 18:10:13 -08:00
ebad86387c tst: passthrough: testing 2017-01-23 14:33:07 -08:00
5475c414b3 doc: tutorial: minor fixes 2017-01-23 11:23:19 -08:00
e3e111ab27 doc: add tutorial document 2017-01-23 10:52:26 -08:00
9cd6710438 tst: passthrough: minor fix 2017-01-22 16:47:50 -08:00
a5f8736b1e tst: passthrough: ReadDirectory improvements 2017-01-20 20:47:55 -08:00
2ced698256 tst: passthrough: testing 2017-01-20 17:46:43 -08:00
53a4bdc478 tst: passthrough file system: WIP 2017-01-20 13:16:11 -08:00
eea92e89ef tst: passthrough file system: WIP 2017-01-20 13:05:22 -08:00
d519145f61 tst: passthrough file system: WIP 2017-01-20 12:38:25 -08:00
2809f56217 tst: passthrough file system: WIP 2017-01-20 12:03:06 -08:00
8cb76783ad tst: passthrough file system: WIP 2017-01-20 11:07:39 -08:00
117ab9c3e4 tst: passthrough file system: WIP 2017-01-20 10:38:31 -08:00
61a001baf1 tst: passthrough file system: WIP 2017-01-20 00:28:18 -08:00
d0c700eb0f tst: passthrough file system: WIP 2017-01-20 00:13:54 -08:00
b774aea4f4 tst: passthrough file system: WIP 2017-01-19 23:58:36 -08:00
f8e4c1bbc4 tst: passthrough file system: WIP 2017-01-19 22:44:31 -08:00
3bbff30f14 tst: passthrough file system: skeleton 2017-01-19 17:09:02 -08:00
2fe4e18d9c dll: FspFileSystemPreflight 2017-01-16 18:48:05 -08:00
b65322c2ac dll: FspPathIsDrive: bug fix 2017-01-16 18:21:56 -08:00
7764663386 dll: FspFileSystemPreflight 2017-01-16 14:54:10 -08:00
c6ae62f301 Update README - add installer link 2017-01-09 15:34:17 -08:00
59 changed files with 5573 additions and 620 deletions

View File

@ -1,6 +1,16 @@
= Changelog
v1.0RC2::
This is the WinFsp 2017 Release Candidate 2. Some important changes included below:
- The `ReadDirectory` `FSP_FILE_SYSTEM_INTERFACE` operation has been changed. Extensive testing with multiple file systems has shown that `ReadDirectory` was hard to implement correctly. The new definition should make implementation easier for most file system. [See GitHub issue #34.]
- Some API's to facilitate `ReadDirectory` implementation have been added. Look for `FspFileSystem*DirectoryBuffer` symbols.
- The installer now (optionally) installs a sample file system called "passthrough". This is a simple file system that passes all operations to an underlying file system. There is also a tutorial for this file system (in the doc directory).
- The installer now (optionally) installs a sample file system called "passthrough-fuse". This file system performs the same function as the "passthrough" file system, but uses the FUSE compatibility layer. It builds and runs on both Windows and Cygwin.
v1.0RC1::
This is the WinFsp 2017 Release Candidate 1. It has been tested extensively in a variety of scenarios for stability and correct file system semantics. Some of the more important changes:

View File

@ -1,8 +1,35 @@
The WinFsp project is Copyright (C) Bill Zissimopoulos. It is licensed
under the terms of the GPLv3. The full text of this license follows
below. Commercial licensing options are also available: Please contact
under the terms of the GPLv3.
As a special exception to GPLv3, Bill Zissimopoulos grants additional
permissions to Free/Libre and Open Source Software ("FLOSS") without requiring
that such software is covered by the GPLv3.
1. Permission to link with a platform specific version of the WinFsp DLL
(currently winfsp-x64.dll or winfsp-x86.dll).
2. Permission to distribute unmodified binary releases of the WinFsp
installer (as released by the WinFsp project).
These permissions (and no other) are granted provided that the software:
1. Is distributed under a license that satisfies the Free Software
Definition Version 1.141 (https://www.gnu.org/philosophy/free-sw.en.html)
or the Open Source Definition Version 1.9 (https://opensource.org/osd).
2. Includes the copyright notice "WinFsp - Windows File System Proxy,
Copyright (C) Bill Zissimopoulos" and a link to the WinFsp repository in
its user-interface and any user-facing documentation.
3. Is not linked or distributed with proprietary (non-FLOSS) software.
[You cannot mix FLOSS and proprietary software while using WinFsp under
this special exception.]
Commercial licensing options are also available: Please contact
Bill Zissimopoulos <billziss at navimatics.com>.
The full text of the GPLv3 license follows below.
-----------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE

View File

@ -2,6 +2,11 @@
![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif)
<a href="https://github.com/billziss-gh/winfsp/releases/download/v1.0RC1/winfsp-1.0.17009.msi"><img src="http://www.secfs.net/winfsp/resources/Download-WinFsp.png" alt="Download WinFsp Installer" width="244" height="34"></a>
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
Some of the benefits of using WinFsp are listed below:
@ -9,7 +14,7 @@ Some of the benefits of using WinFsp are listed below:
* Very well-tested and stable. Read about its [Testing Strategy](doc/WinFsp-Testing.asciidoc).
* Very fast. Read about its [Performance](doc/WinFsp-Performance-Testing.asciidoc).
* Strives for compatibility with NTFS. Read about its [Compatibility](doc/NTFS-Compatibility.asciidoc ).
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/).
* Easy to understand but comprehensive API. Consult the [API Reference](http://www.secfs.net/winfsp/apiref/). There is also a simple [Tutorial](doc/WinFsp-Tutorial.asciidoc).
* FUSE compatibility layer for native Windows and Cygwin. See [fuse.h](inc/fuse/fuse.h).
* Signed drivers provided on every release.
* Available under the GPLv3.

View File

@ -29,6 +29,7 @@ test_script:
- if %TESTING%==Func tools\nmake-ext-test.bat %CONFIGURATION%
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION%
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% ifstest
- if %TESTING%==Func tools\run-tests.bat %CONFIGURATION% sample
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- if exist %SystemRoot%\memory.dmp exit 1

View File

@ -55,6 +55,9 @@
Value="[INSTALLDIR]"
KeyPath="yes" />
</Component>
<Component Id="C.License.txt">
<File Name="License.txt" Source="..\..\..\License.txt" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
<Component Id="C.winfsp_x64.sys">
@ -140,6 +143,9 @@
<Component Id="C.diag.bat">
<File Name="diag.bat" Source="..\..\..\tools\diag.bat" KeyPath="yes" />
</Component>
<Component Id="C.fsreg.bat">
<File Name="fsreg.bat" Source="..\..\..\tools\fsreg.bat" KeyPath="yes" />
</Component>
<Component Id="C.memfs_x64.exe">
<File Name="memfs-x64.exe" KeyPath="yes" />
@ -258,6 +264,46 @@
<File Name="memfs-main.c" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.passthrough" Name="passthrough">
<Component Id="C.passthrough.c">
<File Name="passthrough.c" KeyPath="yes" />
</Component>
<Component Id="C.passthrough.sln">
<File Name="passthrough.sln" KeyPath="yes" />
</Component>
<Component Id="C.passthrough.vcxproj">
<File Name="passthrough.vcxproj" KeyPath="yes" />
</Component>
<Component Id="C.passthrough.vcxproj.filters">
<File Name="passthrough.vcxproj.filters" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="SMPDIR.passthrough_fuse" Name="passthrough-fuse">
<Component Id="C.passthrough_fuse.c">
<File Name="passthrough-fuse.c" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.winposix.c">
<File Name="winposix.c" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.winposix.h">
<File Name="winposix.h" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.sln">
<File Name="passthrough-fuse.sln" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.vcxproj">
<File Name="passthrough-fuse.vcxproj" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.vcxproj.filters">
<File Name="passthrough-fuse.vcxproj.filters" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.Makefile">
<File Name="Makefile" KeyPath="yes" />
</Component>
<Component Id="C.passthrough_fuse.README.md">
<File Name="README.md" KeyPath="yes" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="SYMDIR">
<Component Id="C.winfsp_x64.sys.pdb">
@ -306,6 +352,7 @@
<ComponentRef Id="C.launchctl_x64.exe" />
<ComponentRef Id="C.launchctl_x86.exe" />
<ComponentRef Id="C.diag.bat" />
<ComponentRef Id="C.fsreg.bat" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.inc">
<ComponentRef Id="C.fsctl.h" />
@ -327,6 +374,18 @@
<ComponentRef Id="C.memfs.h" />
<ComponentRef Id="C.memfs.cpp" />
<ComponentRef Id="C.memfs_main.c" />
<ComponentRef Id="C.passthrough.c" />
<ComponentRef Id="C.passthrough.sln" />
<ComponentRef Id="C.passthrough.vcxproj" />
<ComponentRef Id="C.passthrough.vcxproj.filters" />
<ComponentRef Id="C.passthrough_fuse.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.c" />
<ComponentRef Id="C.passthrough_fuse.winposix.h" />
<ComponentRef Id="C.passthrough_fuse.sln" />
<ComponentRef Id="C.passthrough_fuse.vcxproj" />
<ComponentRef Id="C.passthrough_fuse.vcxproj.filters" />
<ComponentRef Id="C.passthrough_fuse.Makefile" />
<ComponentRef Id="C.passthrough_fuse.README.md" />
</ComponentGroup>
<ComponentGroup Id="C.WinFsp.sym">
<ComponentRef Id="C.winfsp_x64.sys.pdb" />
@ -352,6 +411,7 @@
InstallDefault="local"
Absent="disallow">
<ComponentRef Id="C.INSTALLDIR" />
<ComponentRef Id="C.License.txt" />
<Feature
Id="F.User"
Level="1"

View File

@ -182,6 +182,7 @@
</ClCompile>
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />

View File

@ -76,6 +76,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -17,7 +17,7 @@
<MyCanonicalVersion>1.0</MyCanonicalVersion>
<MyProductVersion>2017 RC1</MyProductVersion>
<MyProductVersion>2017 RC2</MyProductVersion>
<MyProductStage>RC</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>

View File

@ -31,6 +31,7 @@
<ClInclude Include="..\..\src\shared\minimal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dll\dirbuf.c" />
<ClCompile Include="..\..\src\dll\eventlog.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
@ -50,7 +51,7 @@
<ClCompile Include="..\..\src\dll\util.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo arch=$(PlatformTarget) &gt;$(OutDir)fuse-$(PlatformTarget).pc
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc &gt;nul</Command>

View File

@ -103,6 +103,9 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
<Filter>Source\fuse</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\dirbuf.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\library.def">
@ -118,7 +121,7 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc">
<CustomBuild Include="..\..\src\dll\fuse\fuse.pc.in">
<Filter>Source\fuse</Filter>
</CustomBuild>
</ItemGroup>

View File

@ -113,8 +113,8 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\sys\driver.inf.in">
<CustomBuild Include="..\..\src\sys\driver.inf.in">
<Filter>Source</Filter>
</None>
</CustomBuild>
</ItemGroup>
</Project>

1321
doc/WinFsp-Tutorial.asciidoc Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -147,7 +147,8 @@ typedef struct
UINT32 ReadOnlyVolume:1;
/* kernel-mode flags */
UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
UINT32 KmReservedFlags:5;
UINT32 PassQueryDirectoryPattern:1; /* pass Pattern during QueryDirectory operations */
UINT32 KmReservedFlags:4;
/* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */
@ -185,8 +186,7 @@ typedef struct
{
UINT16 Size;
FSP_FSCTL_FILE_INFO FileInfo;
UINT64 NextOffset;
UINT8 Padding[16];
UINT8 Padding[24];
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
WCHAR FileNameBuf[];
} FSP_FSCTL_DIR_INFO;
@ -339,9 +339,9 @@ typedef struct
UINT64 UserContext;
UINT64 UserContext2;
UINT64 Address;
UINT64 Offset;
UINT32 Length;
FSP_FSCTL_TRANSACT_BUF Pattern;
FSP_FSCTL_TRANSACT_BUF Marker;
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
} QueryDirectory;
struct

View File

@ -647,30 +647,18 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file system on which this request is posted.
* @param FileContext
* The file context of the directory to be read.
* @param Buffer
* Pointer to a buffer that will receive the results of the read operation.
* @param Offset
* Offset within the directory to read from. The kernel does not interpret this value
* which is used solely by the file system to locate directory entries. However the
* special value 0 indicates that the read should start from the first entries. The first
* two entries returned by ReadDirectory should always be the "." and ".." entries,
* except for the root directory which does not have these entries.
*
* This parameter is used by the WinFsp FSD to break directory listings into chunks.
* In this case all 64-bits of the Offset are valid. In some cases the Windows kernel
* (NTOS) may also use this parameter. In this case only the lower 32-bits of this
* parameter will be valid. This is an unfortunate limitation of Windows (for more
* information see the documentation for IRP_MJ_DIRECTORY_CONTROL and the flag
* SL_INDEX_SPECIFIED).
*
* In practice this means that you should only rely on the lower 32-bits of this value
* to be valid.
* @param Length
* Length of data to read.
* @param 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 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 Buffer
* Pointer to a buffer that will receive the results of the read operation.
* @param Length
* Length of data to read.
* @param PBytesTransferred [out]
* Pointer to a memory location that will receive the actual number of bytes read.
* @return
@ -680,9 +668,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* FspFileSystemAddDirInfo
*/
NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred);
PVOID FileContext, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/**
* Resolve reparse points.
*
@ -845,6 +832,20 @@ typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT
FSP_FSCTL_TRANSACT_REQ *Request;
FSP_FSCTL_TRANSACT_RSP *Response;
} FSP_FILE_SYSTEM_OPERATION_CONTEXT;
/**
* Check whether creating a file system object is possible.
*
* @param DevicePath
* The name of the control device for this file system. This must be either
* FSP_FSCTL_DISK_DEVICE_NAME or FSP_FSCTL_NET_DEVICE_NAME.
* @param 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.
* @return
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
PWSTR MountPoint);
/**
* Create a file system object.
*
@ -1292,6 +1293,19 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/*
* Directory buffering
*/
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
BOOLEAN Reset, PNTSTATUS PResult);
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult);
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer);
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer);
/*
* Security
*/
@ -1389,6 +1403,8 @@ NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPat
return FspPosixMapPosixToWindowsPathEx(PosixPath, PWindowsPath, TRUE);
}
FSP_API VOID FspPosixDeletePath(void *Path);
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
/*
* Path Handling
@ -1610,6 +1626,58 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PULONG PBytesTransferred, ULONG Timeout,
PSID Sid);
/*
* Delay load
*/
static inline
NTSTATUS FspLoad(PVOID *PModule)
{
#if defined(_WIN64)
#define FSP_DLLNAME "winfsp-x64.dll"
#else
#define FSP_DLLNAME "winfsp-x86.dll"
#endif
#define FSP_DLLPATH "bin\\" FSP_DLLNAME
WCHAR PathBuf[MAX_PATH];
DWORD Size;
HKEY RegKey;
LONG Result;
HMODULE Module;
if (0 != PModule)
*PModule = 0;
Module = LoadLibraryW(L"" FSP_DLLNAME);
if (0 == Module)
{
Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\WinFsp",
0, KEY_READ | KEY_WOW64_32KEY, &RegKey);
if (ERROR_SUCCESS == Result)
{
Size = sizeof PathBuf - sizeof L"" FSP_DLLPATH + sizeof(WCHAR);
Result = RegGetValueW(RegKey, 0, L"InstallDir",
RRF_RT_REG_SZ, 0, PathBuf, &Size);
RegCloseKey(RegKey);
}
if (ERROR_SUCCESS != Result)
return STATUS_OBJECT_NAME_NOT_FOUND;
RtlCopyMemory(PathBuf + (Size / sizeof(WCHAR) - 1), L"" FSP_DLLPATH, sizeof L"" FSP_DLLPATH);
Module = LoadLibraryW(PathBuf);
if (0 == Module)
return STATUS_DLL_NOT_FOUND;
}
if (0 != PModule)
*PModule = Module;
return STATUS_SUCCESS;
#undef FSP_DLLNAME
#undef FSP_DLLPATH
}
#ifdef __cplusplus
}
#endif

View File

@ -106,7 +106,7 @@ static const char *FspDebugLogDispositionString(UINT32 CreateOptions)
static const char *FspDebugLogUserContextString(UINT64 UserContext, UINT64 UserContext2, char *Buf)
{
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", UserContext, UserContext2);
wsprintfA(Buf, 0 == UserContext2 ? "%p" : "%p:%p", (PVOID)UserContext, (PVOID)UserContext2);
return Buf;
}
@ -269,13 +269,13 @@ static const char *FspDebugLogReparseDataString(PVOID ReparseData0, char *Buf)
static VOID FspDebugLogRequestVoid(FSP_FSCTL_TRANSACT_REQ *Request, const char *Name)
{
FspDebugLog("%S[TID=%04lx]: %p: >>%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Name);
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint, Name);
}
static VOID FspDebugLogResponseStatus(FSP_FSCTL_TRANSACT_RSP *Response, const char *Name)
{
FspDebugLog("%S[TID=%04lx]: %p: <<%s IoStatus=%lx[%ld]\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint, Name,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint, Name,
Response->IoStatus.Status, Response->IoStatus.Information);
}
@ -304,7 +304,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
"AllocationSize=%lx:%lx, "
"AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, "
"ShareAccess=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Create.UserMode ? 'U' : 'K',
Request->Req.Create.HasTraversePrivilege ? 'T' : '-',
Request->Req.Create.HasBackupPrivilege ? 'B' : '-',
@ -328,7 +328,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FspFsctlTransactOverwriteKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Overwrite%s %s%S%s%s, "
"FileAttributes=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Overwrite.Supersede ? " [Supersede]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -340,7 +340,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactCleanupKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Cleanup%s %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Cleanup.Delete ? " [Delete]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -351,7 +351,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactCloseKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Close %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -362,14 +362,14 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FspFsctlTransactReadKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Read %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.Read.UserContext, Request->Req.Read.UserContext2,
UserContextBuf),
Request->Req.Read.Address,
(PVOID)Request->Req.Read.Address,
MAKE_UINT32_PAIR(Request->Req.Read.Offset),
Request->Req.Read.Length,
Request->Req.Read.Key);
@ -377,7 +377,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FspFsctlTransactWriteKind:
FspDebugLog("%S[TID=%04lx]: %p: >>Write%s %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Key=%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->Req.Write.ConstrainedIo ? " [C]" : "",
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
@ -385,14 +385,14 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
FspDebugLogUserContextString(
Request->Req.Write.UserContext, Request->Req.Write.UserContext2,
UserContextBuf),
Request->Req.Write.Address,
(PVOID)Request->Req.Write.Address,
MAKE_UINT32_PAIR(Request->Req.Write.Offset),
Request->Req.Write.Length,
Request->Req.Write.Key);
break;
case FspFsctlTransactQueryInformationKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryInformation %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -406,7 +406,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 4/*FileBasicInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Basic] %s%S%s%s, "
"FileAttributes=%lx, CreationTime=%s, LastAccessTime=%s, LastWriteTime=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -424,7 +424,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 19/*FileAllocationInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Allocation] %s%S%s%s, "
"AllocationSize=%lx:%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -436,7 +436,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 20/*FileEndOfFileInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [EndOfFile] %s%S%s%s, "
"FileSize = %lx:%lx\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -448,7 +448,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 13/*FileDispositionInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Disposition] %s%S%s%s, "
"%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -460,7 +460,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 10/*FileRenameInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [Rename] %s%S%s%s, "
"NewFileName=\"%S\", AccessToken=%p\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -472,7 +472,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetInformation [INVALID] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -490,7 +490,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactFlushBuffersKind:
FspDebugLog("%S[TID=%04lx]: %p: >>FlushBuffers %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -507,39 +507,42 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case 2/*FileFsLabelInformation*/:
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [FsLabel] "
"Label=\"%S\"\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
(PWSTR)Request->Buffer);
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>SetVolumeInformation [INVALID]\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint);
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint);
break;
}
break;
case FspFsctlTransactQueryDirectoryKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, "
"Address=%p, Offset=%lx:%lx, Length=%ld, Pattern=%s%S%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
"Address=%p, Length=%ld, Pattern=%s%S%s, Marker=%s%S%s\n",
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
FspDebugLogUserContextString(
Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2,
UserContextBuf),
Request->Req.QueryDirectory.Address,
MAKE_UINT32_PAIR(Request->Req.QueryDirectory.Offset),
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Length,
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
Request->Req.QueryDirectory.Pattern.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL",
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "");
Request->Req.QueryDirectory.Pattern.Size ? "\"" : "",
Request->Req.QueryDirectory.Marker.Size ? "\"" : "",
Request->Req.QueryDirectory.Marker.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : L"NULL",
Request->Req.QueryDirectory.Marker.Size ? "\"" : "");
break;
case FspFsctlTransactFileSystemControlKind:
switch (Request->Req.FileSystemControl.FsControlCode)
{
case FSCTL_GET_REPARSE_POINT:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [FSCTL_GET_REPARSE_POINT] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -551,7 +554,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
case FSCTL_DELETE_REPARSE_POINT:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [%s] %s%S%s%s "
"ReparseData=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
FSCTL_SET_REPARSE_POINT == Request->Req.FileSystemControl.FsControlCode ?
"FSCTL_SET_REPARSE_POINT" : "FSCTL_DELETE_REPARSE_POINT",
Request->FileName.Size ? "\"" : "",
@ -565,7 +568,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
default:
FspDebugLog("%S[TID=%04lx]: %p: >>FileSystemControl [INVALID] %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -586,7 +589,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactQuerySecurityKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QuerySecurity %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -604,7 +607,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: >>SetSecurity %s%S%s%s, "
"SecurityInformation=%lx, Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -619,7 +622,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request)
break;
case FspFsctlTransactQueryStreamInformationKind:
FspDebugLog("%S[TID=%04lx]: %p: >>QueryStreamInformation %s%S%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Request->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Request->Hint,
Request->FileName.Size ? "\"" : "",
Request->FileName.Size ? (PWSTR)Request->Buffer : L"",
Request->FileName.Size ? "\", " : "",
@ -655,7 +658,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
if (0/*IO_REPARSE*/ == Response->IoStatus.Information)
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"Reparse.FileName=\"%s\"\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogWideCharBufferString(
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
@ -666,7 +669,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"Reparse.Data=\"%s\"\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogReparseDataString(
Response->Buffer + Response->Rsp.Create.Reparse.Buffer.Offset,
@ -675,7 +678,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Create IoStatus=%lx[%ld] "
"UserContext=%s, GrantedAccess=%lx, FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogUserContextString(
Response->Rsp.Create.Opened.UserContext, Response->Rsp.Create.Opened.UserContext2,
@ -689,7 +692,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Overwrite IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.Overwrite.FileInfo, InfoBuf));
break;
@ -708,7 +711,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<Write IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.Write.FileInfo, InfoBuf));
break;
@ -718,7 +721,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<QueryInformation IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.QueryInformation.FileInfo, InfoBuf));
break;
@ -728,7 +731,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<SetInformation IoStatus=%lx[%ld] "
"FileInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogFileInfoString(&Response->Rsp.SetInformation.FileInfo, InfoBuf));
break;
@ -747,7 +750,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<QueryVolumeInformation IoStatus=%lx[%ld] "
"VolumeInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogVolumeInfoString(&Response->Rsp.QueryVolumeInformation.VolumeInfo, InfoBuf));
break;
@ -757,7 +760,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<SetVolumeInformation IoStatus=%lx[%ld] "
"VolumeInfo=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogVolumeInfoString(&Response->Rsp.SetVolumeInformation.VolumeInfo, InfoBuf));
break;
@ -771,7 +774,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
else
FspDebugLog("%S[TID=%04lx]: %p: <<FileSystemControl IoStatus=%lx[%ld] "
"ReparseData=%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
FspDebugLogReparseDataString(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
InfoBuf));
@ -799,7 +802,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: <<QuerySecurity IoStatus=%lx[%ld] "
"Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",
@ -821,7 +824,7 @@ FSP_API VOID FspDebugLogResponse(FSP_FSCTL_TRANSACT_RSP *Response)
&Sddl, 0);
FspDebugLog("%S[TID=%04lx]: %p: <<SetSecurity IoStatus=%lx[%ld] "
"Security=%s%s%s\n",
FspDiagIdent(), GetCurrentThreadId(), Response->Hint,
FspDiagIdent(), GetCurrentThreadId(), (PVOID)Response->Hint,
Response->IoStatus.Status, Response->IoStatus.Information,
Sddl ? "\"" : "",
Sddl ? Sddl : "NULL",

404
src/dll/dirbuf.c Normal file
View File

@ -0,0 +1,404 @@
/**
* @file dll/dirbuf.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dll/library.h>
#define RETURN(R, B) \
do \
{ \
if (0 != PResult) \
*PResult = R; \
return B; \
} while (0,0)
typedef struct
{
SRWLOCK Lock;
ULONG Capacity, LoMark, HiMark;
PUINT8 Buffer;
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
static int FspFileSystemDirectoryBufferFileNameCmp(PWSTR a, int alen, PWSTR b, int blen)
{
int len, res;
if (-1 == alen)
alen = (int)lstrlenW(a);
if (-1 == blen)
blen = (int)lstrlenW(b);
len = alen < blen ? alen : blen;
/* order "." and ".." first */
switch (alen)
{
case 1:
if (L'.' == a[0])
a = L"\1";
break;
case 2:
if (L'.' == a[0] && L'.' == a[1])
a = L"\1\1";
break;
}
/* order "." and ".." first */
switch (blen)
{
case 1:
if (L'.' == b[0])
b = L"\1";
break;
case 2:
if (L'.' == b[0] && L'.' == b[1])
b = L"\1\1";
break;
}
res = invariant_wcsncmp(a, b, len);
if (0 == res)
res = alen - blen;
return res;
}
/*
* Binary search
* "I wish I had the standard library!"
*/
static BOOLEAN FspFileSystemSearchDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer,
PWSTR Marker, int MarkerLen, PULONG PIndexNum)
{
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
FSP_FSCTL_DIR_INFO *DirInfo;
int Lo = 0, Hi = Count - 1, Mi;
int CmpResult;
while (Lo <= Hi)
{
Mi = (unsigned)(Lo + Hi) >> 1;
DirInfo = (PVOID)(DirBuffer->Buffer + Index[Mi]);
CmpResult = FspFileSystemDirectoryBufferFileNameCmp(
DirInfo->FileNameBuf, (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR),
Marker, MarkerLen);
if (0 > CmpResult)
Lo = Mi + 1;
else if (0 < CmpResult)
Hi = Mi - 1;
else
{
*PIndexNum = Mi;
return TRUE;
}
}
*PIndexNum = Lo;
return FALSE;
}
/*
* Quick sort
* "I wish I had the standard library!"
*
* Based on Sedgewick's Algorithms in C++; multiple editions.
*
* Implements a non-recursive quicksort with tail-end recursion eliminated
* and median-of-three partitioning.
*/
#define less(a, b) FspFileSystemDirectoryBufferLess(Buffer, a, b)
#define exch(a, b) { ULONG t = a; a = b; b = t; }
#define compexch(a, b) if (less(b, a)) exch(a, b)
#define push(i) (stack[stackpos++] = (i))
#define pop() (stack[--stackpos])
static __forceinline
int FspFileSystemDirectoryBufferLess(PUINT8 Buffer, int a, int b)
{
FSP_FSCTL_DIR_INFO *DirInfoA = (FSP_FSCTL_DIR_INFO *)(Buffer + a);
FSP_FSCTL_DIR_INFO *DirInfoB = (FSP_FSCTL_DIR_INFO *)(Buffer + b);
return 0 > FspFileSystemDirectoryBufferFileNameCmp(
DirInfoA->FileNameBuf, (DirInfoA->Size - sizeof *DirInfoA) / sizeof(WCHAR),
DirInfoB->FileNameBuf, (DirInfoB->Size - sizeof *DirInfoB) / sizeof(WCHAR));
}
static __forceinline
int FspFileSystemPartitionDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
{
int i = l - 1, j = r;
ULONG v = Index[r];
for (;;)
{
while (less(Index[++i], v))
;
while (less(v, Index[--j]))
if (j == l)
break;
if (i >= j)
break;
exch(Index[i], Index[j]);
}
exch(Index[i], Index[r]);
return i;
}
static VOID FspFileSystemQSortDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
{
int stack[64], stackpos = 0;
int i;
for (;;)
{
while (r > l)
{
#if 0
exch(Index[(l + r) / 2], Index[r - 1]);
compexch(Index[l], Index[r - 1]);
compexch(Index[l], Index[r]);
compexch(Index[r - 1], Index[r]);
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l + 1, r - 1);
#else
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l, r);
#endif
if (i - l > r - i)
{
push(l); push(i - 1);
l = i + 1;
}
else
{
push(i + 1); push(r);
r = i - 1;
}
}
if (0 == stackpos)
break;
r = pop(); l = pop();
}
}
#undef push
#undef pop
#undef less
#undef compexch
#undef exch
static inline VOID FspFileSystemSortDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer)
{
PUINT8 Buffer = DirBuffer->Buffer;
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
FspFileSystemQSortDirectoryBuffer(Buffer, Index, 0, Count - 1);
}
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
BOOLEAN Reset, PNTSTATUS PResult)
{
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 == DirBuffer)
{
static SRWLOCK CreateLock = SRWLOCK_INIT;
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *NewDirBuffer;
NewDirBuffer = MemAlloc(sizeof *NewDirBuffer);
if (0 == NewDirBuffer)
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
memset(NewDirBuffer, 0, sizeof *NewDirBuffer);
InitializeSRWLock(&NewDirBuffer->Lock);
AcquireSRWLockExclusive(&NewDirBuffer->Lock);
AcquireSRWLockExclusive(&CreateLock);
DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 == DirBuffer)
*PDirBuffer = DirBuffer = NewDirBuffer;
ReleaseSRWLockExclusive(&CreateLock);
if (DirBuffer == NewDirBuffer)
RETURN(STATUS_SUCCESS, TRUE);
ReleaseSRWLockExclusive(&NewDirBuffer->Lock);
MemFree(NewDirBuffer);
}
if (Reset)
{
AcquireSRWLockExclusive(&DirBuffer->Lock);
DirBuffer->LoMark = 0;
DirBuffer->HiMark = DirBuffer->Capacity;
RETURN(STATUS_SUCCESS, TRUE);
}
RETURN(STATUS_SUCCESS, FALSE);
}
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult)
{
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
ULONG Capacity, LoMark, HiMark;
PUINT8 Buffer;
if (0 == DirInfo)
RETURN(STATUS_INVALID_PARAMETER, FALSE);
for (;;)
{
LoMark = DirBuffer->LoMark;
HiMark = DirBuffer->HiMark;
Buffer = DirBuffer->Buffer;
if (FspFileSystemAddDirInfo(DirInfo,
Buffer,
HiMark > sizeof(ULONG) ? HiMark - sizeof(ULONG)/*space for new index entry*/ : HiMark,
&LoMark))
{
HiMark -= sizeof(ULONG);
*(PULONG)(Buffer + HiMark) = DirBuffer->LoMark;
DirBuffer->LoMark = LoMark;
DirBuffer->HiMark = HiMark;
RETURN (STATUS_SUCCESS, TRUE);
}
if (0 == Buffer)
{
Buffer = MemAlloc(Capacity = 512);
if (0 == Buffer)
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
HiMark = Capacity;
}
else
{
Buffer = MemRealloc(Buffer, Capacity = DirBuffer->Capacity * 2);
if (0 == Buffer)
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
ULONG IndexSize = DirBuffer->Capacity - HiMark;
ULONG NewHiMark = Capacity - IndexSize;
memmove(Buffer + NewHiMark, Buffer + HiMark, IndexSize);
HiMark = NewHiMark;
}
DirBuffer->Capacity = Capacity;
DirBuffer->LoMark = LoMark;
DirBuffer->HiMark = HiMark;
DirBuffer->Buffer = Buffer;
}
}
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)
{
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
FspFileSystemSortDirectoryBuffer(DirBuffer);
ReleaseSRWLockExclusive(&DirBuffer->Lock);
}
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 != DirBuffer)
{
AcquireSRWLockShared(&DirBuffer->Lock);
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
ULONG IndexNum;
FSP_FSCTL_DIR_INFO *DirInfo;
if (0 == Marker)
IndexNum = 0;
else
{
FspFileSystemSearchDirectoryBuffer(DirBuffer,
Marker, lstrlenW(Marker),
&IndexNum);
IndexNum++;
}
for (; IndexNum < Count; IndexNum++)
{
DirInfo = (PVOID)(DirBuffer->Buffer + Index[IndexNum]);
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
{
ReleaseSRWLockShared(&DirBuffer->Lock);
return;
}
}
ReleaseSRWLockShared(&DirBuffer->Lock);
}
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
}
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer)
{
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
MemoryBarrier();
if (0 != DirBuffer)
{
MemFree(DirBuffer->Buffer);
MemFree(DirBuffer);
*PDirBuffer = 0;
}
}
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount)
{
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
*PBuffer = DirBuffer->Buffer;
*PIndex = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
*PCount = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
}

View File

@ -72,6 +72,48 @@ VOID FspFileSystemFinalize(BOOLEAN Dynamic)
TlsFree(FspFileSystemTlsKey);
}
FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
PWSTR MountPoint)
{
NTSTATUS Result;
WCHAR TargetPath[MAX_PATH];
HANDLE DirHandle;
Result = FspFsctlPreflight(DevicePath);
if (!NT_SUCCESS(Result))
return Result;
if (0 == MountPoint)
Result = STATUS_SUCCESS;
else
{
if (FspPathIsDrive(MountPoint))
Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ?
STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS;
else
{
DirHandle = CreateFileW(MountPoint,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
0);
if (INVALID_HANDLE_VALUE != DirHandle)
{
CloseHandle(DirHandle);
Result = STATUS_OBJECT_NAME_COLLISION;
}
else if (ERROR_FILE_NOT_FOUND != GetLastError())
Result = STATUS_OBJECT_NAME_INVALID;
else
Result = STATUS_SUCCESS;
}
}
return Result;
}
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
const FSP_FILE_SYSTEM_INTERFACE *Interface,

View File

@ -1133,11 +1133,12 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
BytesTransferred = 0;
Result = FileSystem->Interface->ReadDirectory(FileSystem,
(PVOID)ValOfFileContext(Request->Req.QueryDirectory),
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Offset,
Request->Req.QueryDirectory.Length,
0 != Request->Req.QueryDirectory.Pattern.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0,
0 != Request->Req.QueryDirectory.Marker.Size ?
(PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : 0,
(PVOID)Request->Req.QueryDirectory.Address,
Request->Req.QueryDirectory.Length,
&BytesTransferred);
if (!NT_SUCCESS(Result))
return Result;

View File

@ -230,36 +230,6 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
static void fsp_fuse_cleanup(struct fuse *f);
static NTSTATUS fsp_fuse_preflight(struct fuse *f)
{
NTSTATUS Result;
Result = FspFsctlPreflight(f->VolumeParams.Prefix[0] ?
L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME);
if (!NT_SUCCESS(Result))
return Result;
if (L'\0' != f->MountPoint)
{
if ((
(L'A' <= f->MountPoint[0] && f->MountPoint[0] <= L'Z') ||
(L'a' <= f->MountPoint[0] && f->MountPoint[0] <= L'z')
) &&
L':' == f->MountPoint[1] || L'\0' == f->MountPoint[2])
{
if (GetLogicalDrives() & (1 << ((f->MountPoint[0] & ~0x20) - 'a')))
return STATUS_OBJECT_NAME_COLLISION;
}
else
if (L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1])
;
else
return STATUS_OBJECT_NAME_INVALID;
}
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
struct fuse *f = Service->UserContext;
@ -380,7 +350,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
FspFileSystemSetOperationGuardStrategy(f->FileSystem, f->OpGuardStrategy);
FspFileSystemSetDebugLog(f->FileSystem, f->DebugLog);
if (L'\0' != f->MountPoint)
if (0 != f->MountPoint)
{
Result = FspFileSystemSetMountPoint(f->FileSystem,
L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1] ? 0 : f->MountPoint);
@ -515,6 +485,28 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
if (opt_data.help)
return 0;
if ((opt_data.set_uid && -1 == opt_data.uid) ||
(opt_data.set_gid && -1 == opt_data.gid))
{
HANDLE Token;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
{
fsp_fuse_get_token_uidgid(Token, TokenUser,
opt_data.set_uid && -1 == opt_data.uid ? &opt_data.uid : 0,
opt_data.set_gid && -1 == opt_data.gid ? &opt_data.gid : 0);
CloseHandle(Token);
}
if ((opt_data.set_uid && -1 == opt_data.uid) ||
(opt_data.set_gid && -1 == opt_data.gid))
{
ErrorMessage = L": unknown user/group.";
goto fail;
}
}
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
@ -548,7 +540,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
goto fail;
memcpy(f->MountPoint, ch->MountPoint, Size);
Result = fsp_fuse_preflight(f);
Result = FspFileSystemPreflight(
f->VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
'*' != f->MountPoint[0] || '\0' != f->MountPoint[1] ? f->MountPoint : 0);
if (!NT_SUCCESS(Result))
{
switch (Result)

View File

@ -116,19 +116,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName = 0, Suffix;
WCHAR Root[2] = L"\\";
HANDLE Token = 0;
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
union
{
TOKEN_PRIMARY_GROUP V;
UINT8 B[128];
} GroupInfoBuf;
PTOKEN_PRIMARY_GROUP GroupInfo = &GroupInfoBuf.V;
DWORD Size;
NTSTATUS Result;
if (FspFsctlTransactCreateKind == Request->Kind)
@ -157,55 +144,7 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
if (0 != Token)
{
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, sizeof GroupInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
GroupInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(UserInfo->User.Sid, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapSidToUid(GroupInfo->PrimaryGroup, &Gid);
Result = fsp_fuse_get_token_uidgid(Token, TokenUser, &Uid, &Gid);
if (!NT_SUCCESS(Result))
goto exit;
}
@ -230,12 +169,6 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
Result = STATUS_SUCCESS;
exit:
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
if (GroupInfo != &GroupInfoBuf.V)
MemFree(GroupInfo);
if (!NT_SUCCESS(Result) && 0 != PosixPath)
FspPosixDeletePath(PosixPath);
@ -882,7 +815,6 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
filedesc->OpenFlags = fi.flags;
filedesc->FileHandle = fi.fh;
filedesc->DirBuffer = 0;
filedesc->DirBufferSize = 0;
contexthdr->PosixPath = 0;
Result = STATUS_SUCCESS;
@ -1000,7 +932,6 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
filedesc->OpenFlags = fi.flags;
filedesc->FileHandle = fi.fh;
filedesc->DirBuffer = 0;
filedesc->DirBufferSize = 0;
contexthdr->PosixPath = 0;
Result = STATUS_SUCCESS;
@ -1113,7 +1044,7 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
f->ops.release(filedesc->PosixPath, &fi);
}
MemFree(filedesc->DirBuffer);
FspFileSystemDeleteDirectoryBuffer(&filedesc->DirBuffer);
MemFree(filedesc->PosixPath);
MemFree(filedesc);
}
@ -1459,7 +1390,13 @@ static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem,
memset(&dh, 0, sizeof dh);
if (0 != f->ops.readdir)
{
memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle;
err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_CanDeleteAddDirInfo, 0, &fi);
}
else if (0 != f->ops.getdir)
err = f->ops.getdir(filedesc->PosixPath, &dh, fsp_fuse_intf_CanDeleteAddDirInfoOld);
else
@ -1496,7 +1433,8 @@ static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem,
STATUS_OBJECT_PATH_NOT_FOUND != Result)
return Result;
if (NT_SUCCESS(Result))
if (NT_SUCCESS(Result) &&
(f->VolumeParams.CaseSensitiveSearch || 0 != invariant_wcsicmp(FileName, NewFileName)))
{
if (!ReplaceIfExists)
return STATUS_OBJECT_NAME_COLLISION;
@ -1603,101 +1541,157 @@ exit:
return Result;
}
int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
const struct fuse_stat *stbuf, fuse_off_t off)
{
struct fuse_dirhandle *dh = buf;
struct fsp_fuse_dirinfo *di;
ULONG len, xfersize;
len = lstrlenA(name);
if (len > 255)
len = 255;
di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred);
xfersize = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(struct fsp_fuse_dirinfo) + len + 1);
if ((PUINT8)di + xfersize > (PUINT8)dh->Buffer + dh->Length)
{
PVOID Buffer;
ULONG Length = dh->Length;
if (0 == Length)
Length = 16 * 1024;
else if (Length < 16 * 1024 * 1024)
Length *= 2;
else
return 1;
Buffer = MemAlloc(Length);
if (0 == Buffer)
return 1;
memcpy(Buffer, dh->Buffer, dh->BytesTransferred);
MemFree(dh->Buffer);
dh->Buffer = Buffer;
dh->Length = Length;
di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred);
}
dh->BytesTransferred += xfersize;
dh->NonZeroOffset = dh->NonZeroOffset || 0 != off;
di->Size = (UINT16)(sizeof(struct fsp_fuse_dirinfo) + len + 1);
di->FileInfoValid = FALSE;
di->NextOffset = 0 != off ? off : dh->BytesTransferred;
memcpy(di->PosixNameBuf, name, len);
di->PosixNameBuf[len] = '\0';
return 0;
}
int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
int type, fuse_ino_t ino)
{
return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0;
}
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_file_info fi;
struct fuse_dirhandle dh;
struct fsp_fuse_dirinfo *di;
PUINT8 diend;
struct fsp_fuse_file_desc *filedesc = dh->filedesc;
union
{
FSP_FSCTL_DIR_INFO V;
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)];
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V;
UINT32 Uid, Gid, Mode;
ULONG SizeA, SizeW;
if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1])
{
/* if this is the root directory do not add the dot entries */
if ('.' == name[0] && ('\0' == name[1] ||
('.' == name[1] && '\0' == name[2])))
return 0;
}
SizeA = lstrlenA(name);
if (SizeA > 255)
/* ignore bad filenames; should we return error code? */
return 0;
SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255);
if (0 == SizeW)
/* ignore bad filenames; should we return error code? */
return 0;
memset(DirInfo, 0, sizeof *DirInfo);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
return !FspFileSystemFillDirectoryBuffer(&filedesc->DirBuffer, DirInfo, &dh->Result);
}
static int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
int type, fuse_ino_t ino)
{
return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0;
}
static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
struct fsp_fuse_file_desc *filedesc)
{
char *PosixPath = 0, *PosixName, *PosixPathEnd, SavedPathChar;
PWSTR FileName = 0;
ULONG Size;
ULONG SizeA, SizeW;
PUINT8 Buffer;
PULONG Index, IndexEnd;
ULONG Count;
FSP_FSCTL_DIR_INFO *DirInfo;
UINT32 Uid, Gid, Mode;
NTSTATUS Result;
SizeA = lstrlenA(filedesc->PosixPath);
PosixPath = MemAlloc(SizeA + 1 + 255 + 1);
if (0 == PosixPath)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memcpy(PosixPath, filedesc->PosixPath, SizeA);
if (1 < SizeA)
/* if not root */
PosixPath[SizeA++] = '/';
PosixPath[SizeA] = '\0';
PosixName = PosixPath + SizeA;
FspFileSystemPeekInDirectoryBuffer(&filedesc->DirBuffer, &Buffer, &Index, &Count);
for (IndexEnd = Index + Count; IndexEnd > Index; Index++)
{
DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index);
SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR);
if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
PosixPathEnd--;
if (PosixPath == PosixPathEnd)
PosixPathEnd++;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
{
PosixPathEnd = 0;
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
if (0 == SizeA)
{
/* this should never happen because we just converted using MultiByteToWideChar */
Result = STATUS_OBJECT_NAME_INVALID;
goto exit;
}
PosixName[SizeA] = '\0';
}
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW);
}
Result = STATUS_SUCCESS;
exit:
MemFree(PosixPath);
return Result;
}
static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
struct fuse_dirhandle dh;
struct fuse_file_info fi;
int err;
NTSTATUS Result;
if (!filedesc->IsDirectory)
return STATUS_ACCESS_DENIED;
memset(&dh, 0, sizeof dh);
if (0 == filedesc->DirBuffer)
if (FspFileSystemAcquireDirectoryBuffer(&filedesc->DirBuffer, 0 == Marker, &Result))
{
memset(&dh, 0, sizeof dh);
dh.filedesc = filedesc;
dh.Result = STATUS_SUCCESS;
if (0 != f->ops.readdir)
{
memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle;
err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfo, Offset, &fi);
err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfo, 0, &fi);
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
}
else if (0 != f->ops.getdir)
@ -1708,142 +1702,23 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
else
Result = STATUS_INVALID_DEVICE_REQUEST;
if (!NT_SUCCESS(Result))
goto exit;
if (NT_SUCCESS(Result))
{
Result = dh.Result;
if (NT_SUCCESS(Result))
Result = fsp_fuse_intf_FixDirInfo(FileSystem, filedesc);
}
if (0 == dh.BytesTransferred)
{
/* EOF */
*PBytesTransferred = 0;
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
goto success;
}
else if (dh.NonZeroOffset)
{
di = (PVOID)((PUINT8)dh.Buffer + 0);
diend = (PUINT8)dh.Buffer + dh.BytesTransferred;
}
else
{
di = (PVOID)((PUINT8)dh.Buffer + Offset);
diend = (PUINT8)dh.Buffer + dh.BytesTransferred;
filedesc->DirBuffer = dh.Buffer;
filedesc->DirBufferSize = dh.BytesTransferred;
dh.Buffer = 0;
}
}
else
{
di = (PVOID)((PUINT8)filedesc->DirBuffer + Offset);
diend = (PUINT8)filedesc->DirBuffer + filedesc->DirBufferSize;
FspFileSystemReleaseDirectoryBuffer(&filedesc->DirBuffer);
}
for (;
(PUINT8)di + sizeof(di->Size) <= diend;
di = (PVOID)((PUINT8)di + FSP_FSCTL_DEFAULT_ALIGN_UP(di->Size)))
{
if (sizeof(struct fsp_fuse_dirinfo) > di->Size)
break;
if (!NT_SUCCESS(Result))
return Result;
if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1])
{
/* if this is the root directory do not add the dot entries */
FspFileSystemReadDirectoryBuffer(&filedesc->DirBuffer,
Marker, Buffer, Length, PBytesTransferred);
if ('.' == di->PosixNameBuf[0] && ('\0' == di->PosixNameBuf[1] ||
('.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2])))
continue;
}
if (!di->FileInfoValid)
{
if (0 == PosixPath)
{
Size = lstrlenA(filedesc->PosixPath);
PosixPath = MemAlloc(Size + 1 + 255 + 1);
if (0 == PosixPath)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memcpy(PosixPath, filedesc->PosixPath, Size);
if (1 < Size)
/* if not root */
PosixPath[Size++] = '/';
PosixPath[Size] = '\0';
PosixName = PosixPath + Size;
}
if ('.' == di->PosixNameBuf[0] && '\0' == di->PosixNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
if ('.' == di->PosixNameBuf[0] && '.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
PosixPathEnd--;
if (PosixPath == PosixPathEnd)
PosixPathEnd++;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
{
PosixPathEnd = 0;
Size = lstrlenA(di->PosixNameBuf);
if (Size > 255)
Size = 255;
memcpy(PosixName, di->PosixNameBuf, Size);
PosixName[Size] = '\0';
}
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &di->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
di->FileInfoValid = TRUE;
}
memcpy(&DirInfo->FileInfo, &di->FileInfo, sizeof di->FileInfo);
Result = FspPosixMapPosixToWindowsPath(di->PosixNameBuf, &FileName);
if (!NT_SUCCESS(Result))
goto exit;
Size = lstrlenW(FileName);
if (Size > 255)
Size = 255;
Size *= sizeof(WCHAR);
memcpy(DirInfo->FileNameBuf, FileName, Size);
FspPosixDeletePath(FileName);
memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size);
DirInfo->NextOffset = di->NextOffset;
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
break;
}
if ((PUINT8)di + sizeof(di->Size) > diend)
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
success:
Result = STATUS_SUCCESS;
exit:
MemFree(PosixPath);
MemFree(dh.Buffer);
return Result;
return STATUS_SUCCESS;
}
static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
@ -2120,3 +1995,140 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
fsp_fuse_intf_SetReparsePoint,
fsp_fuse_intf_DeleteReparsePoint,
};
/*
* Utility
*/
NTSTATUS fsp_fuse_get_token_uidgid(
HANDLE Token,
TOKEN_INFORMATION_CLASS UserOrOwnerClass, /* TokenUser|TokenOwner */
PUINT32 PUid, PUINT32 PGid)
{
UINT32 Uid, Gid;
union
{
TOKEN_USER V;
UINT8 B[128];
} UserInfoBuf;
PTOKEN_USER UserInfo = &UserInfoBuf.V;
union
{
TOKEN_OWNER V;
UINT8 B[128];
} OwnerInfoBuf;
PTOKEN_OWNER OwnerInfo = &OwnerInfoBuf.V;
union
{
TOKEN_PRIMARY_GROUP V;
UINT8 B[128];
} GroupInfoBuf;
PTOKEN_PRIMARY_GROUP GroupInfo = &GroupInfoBuf.V;
DWORD Size;
NTSTATUS Result;
if (0 != PUid && TokenUser == UserOrOwnerClass)
{
if (!GetTokenInformation(Token, TokenUser, UserInfo, sizeof UserInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
UserInfo = MemAlloc(Size);
if (0 == UserInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenUser, UserInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(UserInfo->User.Sid, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
}
else if (0 != PUid && TokenOwner == UserOrOwnerClass)
{
if (!GetTokenInformation(Token, TokenOwner, OwnerInfo, sizeof OwnerInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
OwnerInfo = MemAlloc(Size);
if (0 == OwnerInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenOwner, OwnerInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(OwnerInfo->Owner, &Uid);
if (!NT_SUCCESS(Result))
goto exit;
}
if (0 != PGid)
{
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, sizeof GroupInfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
GroupInfo = MemAlloc(Size);
if (0 == GroupInfo)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!GetTokenInformation(Token, TokenPrimaryGroup, GroupInfo, Size, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = FspPosixMapSidToUid(GroupInfo->PrimaryGroup, &Gid);
if (!NT_SUCCESS(Result))
goto exit;
}
if (0 != PUid)
*PUid = Uid;
if (0 != PGid)
*PGid = Gid;
Result = STATUS_SUCCESS;
exit:
if (UserInfo != &UserInfoBuf.V)
MemFree(UserInfo);
if (OwnerInfo != &OwnerInfoBuf.V)
MemFree(OwnerInfo);
if (GroupInfo != &GroupInfoBuf.V)
MemFree(GroupInfo);
return Result;
}

View File

@ -62,27 +62,15 @@ struct fsp_fuse_file_desc
int OpenFlags;
UINT64 FileHandle;
PVOID DirBuffer;
ULONG DirBufferSize;
};
struct fuse_dirhandle
{
PVOID Buffer;
ULONG Length;
ULONG BytesTransferred;
BOOLEAN NonZeroOffset;
struct fsp_fuse_file_desc *filedesc;
NTSTATUS Result;
BOOLEAN DotFiles, HasChild;
};
struct fsp_fuse_dirinfo
{
UINT16 Size;
FSP_FSCTL_FILE_INFO FileInfo;
BOOLEAN FileInfoValid;
UINT64 NextOffset;
char PosixNameBuf[]; /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */
};
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
@ -90,6 +78,11 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
extern FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf;
NTSTATUS fsp_fuse_get_token_uidgid(
HANDLE Token,
TOKEN_INFORMATION_CLASS UserOrOwnerClass, /* TokenUser|TokenOwner */
PUINT32 PUid, PUINT32 PGid);
/* NFS reparse points */
#define NFS_SPECFILE_FIFO 0x000000004F464946

View File

@ -51,6 +51,9 @@ NTSTATUS FspEventLogUnregister(VOID);
PWSTR FspDiagIdent(VOID);
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
@ -73,7 +76,7 @@ static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
(L'A' <= FileName[0] && FileName[0] <= L'Z') ||
(L'a' <= FileName[0] && FileName[0] <= L'z')
) &&
L':' == FileName[1] || L'\0' == FileName[2];
L':' == FileName[1] && L'\0' == FileName[2];
}
#endif

View File

@ -22,6 +22,7 @@
#define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
#define FSP_NP_ADDCONNECTION_TIMEOUT 15000
/*
* Define the following macro to use CredUIPromptForWindowsCredentials.
@ -583,6 +584,63 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
switch (NpResult)
{
case WN_SUCCESS:
/*
* The Launcher is reporting success. Wait until we can access the new volume
* root directory. If we see it report success, otherwise report error.
*/
{
WCHAR RemoteNameBuf[9 + sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
HANDLE Handle;
if (L'\0' != LocalNameBuf[0])
{
P = RemoteNameBuf;
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
*P++ = LocalNameBuf[0]; *P++ = L':'; *P++ = L'\\';
*P++ = L'\0';
}
else
{
P = RemoteNameBuf;
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
*P++ = L'U'; *P++ = L'N'; *P++ = L'C'; *P++ = L'\\';
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\\';
*P++ = L'\0';
}
NpResult = WN_NO_NETWORK; /* timeout error */
for (ULONG I = 0, N = 1 + FSP_NP_ADDCONNECTION_TIMEOUT / 500; N > I; I++)
{
if (0 != I)
Sleep(500);
Handle = CreateFileW(RemoteNameBuf,
FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE != Handle)
{
/* the file system is up and running */
CloseHandle(Handle);
NpResult = WN_SUCCESS;
break;
}
P = PipeBuf;
*P++ = LauncherSvcInstanceInfo;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
if (WN_SUCCESS != FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE))
{
/* looks like the file system is gone! */
NpResult = WN_NO_NETWORK;
break;
}
}
}
break;
case WN_ACCESS_DENIED:
break;
case ERROR_ALREADY_EXISTS:

View File

@ -923,3 +923,30 @@ FSP_API VOID FspPosixDeletePath(void *Path)
{
MemFree(Path);
}
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size)
{
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
{
WCHAR c = *p;
if (L'\\' == c)
*p = L'/';
/* encode characters in the Unicode private use area: U+F0XX -> XX */
else if (0xf000 <= c && c <= 0xf0ff)
*p &= ~0xf000;
}
}
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size)
{
for (PWSTR p = WindowsPath, endp = p + Size; endp > p; p++)
{
WCHAR c = *p;
if (L'/' == c)
*p = L'\\';
else if (128 > c && (FspPosixInvalidPathChars[c >> 5] & (0x80000000 >> (c & 0x1f))))
*p |= 0xf000;
}
}

View File

@ -126,6 +126,10 @@ static inline void *MemAlloc(size_t Size)
{
return HeapAlloc(GetProcessHeap(), 0, Size);
}
static inline void *MemRealloc(void *Pointer, size_t Size)
{
return HeapReAlloc(GetProcessHeap(), 0, Pointer, Size);
}
static inline void MemFree(void *Pointer)
{
if (0 != Pointer)

View File

@ -808,6 +808,16 @@ NTSTATUS FspFsvolCreateComplete(
}
/* populate the FileNode/FileDesc fields from the Response */
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
FILE_ATTRIBUTE_DIRECTORY);
FileNode->IsRootDirectory = FileNode->IsDirectory &&
sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0];
FileDesc->UserContext2 = Response->Rsp.Create.Opened.UserContext2;
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
/* handle normalized names */
if (!FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch)
{
/* is there a normalized file name as part of the response? */
@ -843,14 +853,6 @@ NTSTATUS FspFsvolCreateComplete(
RtlCopyMemory(FileNode->FileName.Buffer, NormalizedName.Buffer, NormalizedName.Length);
}
}
FileNode->UserContext = Response->Rsp.Create.Opened.UserContext;
FileNode->IndexNumber = Response->Rsp.Create.Opened.FileInfo.IndexNumber;
FileNode->IsDirectory = BooleanFlagOn(Response->Rsp.Create.Opened.FileInfo.FileAttributes,
FILE_ATTRIBUTE_DIRECTORY);
FileNode->IsRootDirectory = FileNode->IsDirectory &&
sizeof(WCHAR) == FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[0];
FileDesc->UserContext2 = Response->Rsp.Create.Opened.UserContext2;
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
/* open the FileNode */
Result = FspFileNodeOpen(FileNode, FileObject,
@ -876,8 +878,7 @@ NTSTATUS FspFsvolCreateComplete(
Result = FspFsvolCreateSharingViolationOplock(
FsvolDeviceObject, Irp, IrpSp, FALSE);
if (STATUS_PENDING == Result)
FSP_RETURN();
FSP_RETURN();
}
else
{
@ -1315,6 +1316,7 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
FSP_FSCTL_TRANSACT_RSP *Response;
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *ExtraFileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
ULONG SharingViolationReason = (ULONG)Irp->IoStatus.Information;
NTSTATUS Result;
@ -1351,6 +1353,12 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
return FspWqRepostIrpWorkItem(Irp,
FspFsvolCreateSharingViolationOplock, FspFsvolCreateRequestFini);
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
FspFsvolCreatePostClose(FileDesc);
Irp->IoStatus.Information = 0;
return STATUS_SHARING_VIOLATION;
}
@ -1369,7 +1377,6 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
* stream.
*/
FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc);
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
/* break Batch oplocks on the main file and this stream */
@ -1425,14 +1432,14 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock(
Response = FspIopIrpResponse(Irp);
if (STATUS_SUCCESS == Result)
{
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
}
else
FspFileNodeClose(ExtraFileNode, 0, TRUE);
FspFileNodeDereference(ExtraFileNode);
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
if (STATUS_SUCCESS != Result)
{
FspFsvolCreatePostClose(FileDesc);
Response->IoStatus.Status = (UINT32)Result;
Response->IoStatus.Information = (UINT32)Irp->IoStatus.Information;
}

View File

@ -28,7 +28,7 @@
static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
PVOID DestBuf, PULONG PDestLen);
@ -74,9 +74,6 @@ FSP_DRIVER_DISPATCH FspDirectoryControl;
#pragma alloc_text(PAGE, FspDirectoryControl)
#endif
#define FILE_INDEX_FROM_OFFSET(v) ((ULONG)(v))
#define OFFSET_FROM_FILE_INDEX(v) ((UINT64)(v))
enum
{
/* QueryDirectory */
@ -94,7 +91,7 @@ enum
static NTSTATUS FspFsvolQueryDirectoryCopy(
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
UINT64 DirectoryOffset, PUINT64 PDirectoryOffset,
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
PVOID DestBuf, PULONG PDestLen)
@ -104,7 +101,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
{\
TYPE InfoStruct = { 0 }, *Info = &InfoStruct;\
Info->NextEntryOffset = 0;\
Info->FileIndex = FILE_INDEX_FROM_OFFSET(DirInfo->NextOffset);\
Info->FileIndex = 0;\
Info->FileNameLength = FileName.Length;\
__VA_ARGS__\
Info = DestBuf;\
@ -128,7 +125,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
NTSTATUS Result = STATUS_SUCCESS;
BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match;
BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE;
BOOLEAN Loop = TRUE, DirectoryMarkerFound = FALSE;
FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo;
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
PUINT8 DestBufBgn = (PUINT8)DestBuf;
@ -178,16 +175,18 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
break;
}
if (0 != DirectoryOffset && !DirectoryOffsetFound)
{
DirectoryOffsetFound = DirInfo->NextOffset == DirectoryOffset;
continue;
}
FileName.Length =
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
FileName.Buffer = DirInfo->FileNameBuf;
if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer &&
!DirectoryMarkerFound)
{
DirectoryMarkerFound = 0 == FspFileNameCompare(
&FileName, DirectoryMarker, CaseInsensitive, 0);
continue;
}
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
CopyLength = FileName.Length;
@ -223,7 +222,6 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
*(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf);
PrevDestBuf = DestBuf;
*PDirectoryOffset = DirInfo->NextOffset;
*PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn);
switch (FileInformationClass)
@ -265,6 +263,9 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
break;
}
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length;
DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen);
DestBuf = (PVOID)((PUINT8)DestBuf +
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
@ -273,7 +274,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
Loop = FALSE;
}
else
*PDirectoryOffset = DirInfo->NextOffset;
*DirectoryMarkerOut = FileName;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
@ -315,7 +316,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
NTSTATUS Result;
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
PUINT8 DirInfoBgn = (PUINT8)DirInfo;
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
@ -323,17 +324,20 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
DirInfoSize = (ULONG)(DirInfoEnd - (PUINT8)DirInfo);
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
0 != FileDesc->DirInfoCacheHint ? 0 : DirectoryOffset, &DirectoryOffset,
0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker,
FileInformationClass, ReturnSingleEntry,
&DirInfo, DirInfoSize,
DestBuf, PDestLen);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
FileDesc->DirectoryOffset = DirectoryOffset;
FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn);
Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn);
}
}
else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile)
Result = STATUS_NO_SUCH_FILE;
@ -354,7 +358,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
NTSTATUS Result;
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
UINT64 DirectoryOffset = FileDesc->DirectoryOffset;
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
ASSERT(DirInfo == DestBuf);
FSP_FSCTL_STATIC_ASSERT(
@ -363,16 +367,19 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
"FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION");
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
0, &DirectoryOffset,
0, &DirectoryMarker,
FileInformationClass, ReturnSingleEntry,
&DirInfo, DirInfoSize,
DestBuf, PDestLen);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
FileDesc->DirectoryOffset = DirectoryOffset;
Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker);
if (NT_SUCCESS(Result))
{
if (0 != *PDestLen)
FileDesc->DirectoryHasSuchFile = TRUE;
}
}
else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile)
Result = STATUS_NO_SUCH_FILE;
@ -442,7 +449,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
* counter-productive to try to read more than we need.
*/
#define GetSystemBufferLengthMaybeCached()\
(0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryOffset) ||\
(0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryMarker.Buffer) ||\
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\
FspFsvolDeviceDirInfoCacheItemSizeMax : Length
#define GetSystemBufferLengthNonCached()\
@ -463,7 +470,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName;
ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
//ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
PVOID Buffer = 0 != Irp->AssociatedIrp.SystemBuffer ?
Irp->AssociatedIrp.SystemBuffer : Irp->UserBuffer;
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
@ -511,27 +518,14 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
Request = 0;
}
/* set the DirectoryPattern in the FileDesc */
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName,
RestartScan && 0 != FileName && 0 != FileName->Length);
/* reset the FileDesc */
Result = FspFileDescResetDirectory(FileDesc, FileName, RestartScan, IndexSpecified);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
/* determine where to (re)start */
if (IndexSpecified)
{
FileDesc->DirectoryHasSuchFile = FALSE;
FileDesc->DirectoryOffset = OFFSET_FROM_FILE_INDEX(FileIndex);
}
else if (RestartScan)
{
FileDesc->DirectoryHasSuchFile = FALSE;
FileDesc->DirectoryOffset = 0;
}
/* see if the required information is still in the cache and valid! */
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
{
@ -571,8 +565,10 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
/* create request */
Result = FspIopCreateRequestEx(Irp, 0,
(FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?
FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0,
FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0) +
(FsvolDeviceExtension->VolumeParams.MaxComponentLength + 1) * sizeof(WCHAR),
FspFsvolQueryDirectoryRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
@ -583,19 +579,38 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
Request->Kind = FspFsctlTransactQueryDirectoryKind;
Request->Req.QueryDirectory.UserContext = FileNode->UserContext;
Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2;
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
Request->Req.QueryDirectory.Length = SystemBufferLength;
Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive;
if (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
if (FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer)
{
Request->Req.QueryDirectory.Pattern.Offset = Request->FileName.Size;
Request->Req.QueryDirectory.Pattern.Offset =
Request->FileName.Size;
Request->Req.QueryDirectory.Pattern.Size =
FileDesc->DirectoryPattern.Length + sizeof(WCHAR);
RtlCopyMemory(Request->Buffer + Request->FileName.Size,
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset,
FileDesc->DirectoryPattern.Buffer, FileDesc->DirectoryPattern.Length);
*(PWSTR)(Request->Buffer + Request->FileName.Size + FileDesc->DirectoryPattern.Length) =
L'\0';
*(PWSTR)(Request->Buffer +
Request->Req.QueryDirectory.Pattern.Offset +
FileDesc->DirectoryPattern.Length) = L'\0';
}
if (0 != FileDesc->DirectoryMarker.Buffer)
{
ASSERT(
FsvolDeviceExtension->VolumeParams.MaxComponentLength >=
FileDesc->DirectoryMarker.Length);
Request->Req.QueryDirectory.Marker.Offset =
Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size;
Request->Req.QueryDirectory.Marker.Size =
FileDesc->DirectoryMarker.Length + sizeof(WCHAR);
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset,
FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length);
*(PWSTR)(Request->Buffer +
Request->Req.QueryDirectory.Marker.Offset +
FileDesc->DirectoryMarker.Length) = L'\0';
}
FspFileNodeSetOwner(FileNode, Full, Request);
@ -885,7 +900,6 @@ NTSTATUS FspFsvolDirectoryControlComplete(
BOOLEAN Success;
ASSERT(FileNode == FileDesc->FileNode);
ASSERT(Request->Req.QueryDirectory.Offset == FileDesc->DirectoryOffset);
if (0 == Response->IoStatus.Information)
{
@ -913,7 +927,8 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FSP_RETURN();
}
if (0 == FileDesc->DirectoryOffset &&
if (0 == Request->Req.QueryDirectory.Pattern.Size &&
0 == Request->Req.QueryDirectory.Marker.Size &&
FspFileNodeTrySetDirInfo(FileNode,
Irp->AssociatedIrp.SystemBuffer,
(ULONG)Response->IoStatus.Information,
@ -952,7 +967,24 @@ NTSTATUS FspFsvolDirectoryControlComplete(
FspIopResetRequest(Request, FspFsvolQueryDirectoryRequestFini);
Request->Req.QueryDirectory.Address = 0;
Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset;
Request->Req.QueryDirectory.Marker.Offset = 0;
Request->Req.QueryDirectory.Marker.Size = 0;
if (0 != FileDesc->DirectoryMarker.Buffer)
{
ASSERT(
FsvolDeviceExtension->VolumeParams.MaxComponentLength >=
FileDesc->DirectoryMarker.Length);
Request->Req.QueryDirectory.Marker.Offset =
Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size;
Request->Req.QueryDirectory.Marker.Size =
FileDesc->DirectoryMarker.Length + sizeof(WCHAR);
RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset,
FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length);
*(PWSTR)(Request->Buffer +
Request->Req.QueryDirectory.Marker.Offset +
FileDesc->DirectoryMarker.Length) = L'\0';
}
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;

View File

@ -1231,7 +1231,7 @@ typedef struct
DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1,
DirectoryHasSuchFile:1;
UNICODE_STRING DirectoryPattern;
UINT64 DirectoryOffset;
UNICODE_STRING DirectoryMarker;
UINT64 DirInfo;
ULONG DirInfoCacheHint;
/* stream support */
@ -1362,8 +1362,10 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified);
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,

View File

@ -84,8 +84,10 @@ NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified);
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName);
NTSTATUS FspMainFileOpen(
PDEVICE_OBJECT FsvolDeviceObject,
PDEVICE_OBJECT DeviceObjectHint,
@ -147,7 +149,8 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
#pragma alloc_text(PAGE, FspFileDescCreate)
#pragma alloc_text(PAGE, FspFileDescDelete)
#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern)
#pragma alloc_text(PAGE, FspFileDescResetDirectory)
#pragma alloc_text(PAGE, FspFileDescSetDirectoryMarker)
#pragma alloc_text(PAGE, FspMainFileOpen)
#pragma alloc_text(PAGE, FspMainFileClose)
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
@ -1984,15 +1987,19 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc)
RtlFreeUnicodeString(&FileDesc->DirectoryPattern);
}
if (0 != FileDesc->DirectoryMarker.Buffer)
FspFree(FileDesc->DirectoryMarker.Buffer);
FspFree(FileDesc);
}
NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset)
NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified)
{
PAGED_CODE();
if (Reset || 0 == FileDesc->DirectoryPattern.Buffer)
if (0 == FileDesc->DirectoryPattern.Buffer ||
(RestartScan && 0 != FileName && 0 != FileName->Length))
{
UNICODE_STRING DirectoryPattern;
@ -2029,7 +2036,63 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
}
FileDesc->DirectoryPattern = DirectoryPattern;
FileDesc->DirectoryHasSuchFile = FALSE;
if (0 != FileDesc->DirectoryMarker.Buffer)
{
FspFree(FileDesc->DirectoryMarker.Buffer);
FileDesc->DirectoryMarker.Buffer = 0;
}
}
else if (RestartScan)
{
ASSERT(0 == FileName || 0 == FileName->Length);
FileDesc->DirectoryHasSuchFile = FALSE;
if (0 != FileDesc->DirectoryMarker.Buffer)
{
FspFree(FileDesc->DirectoryMarker.Buffer);
FileDesc->DirectoryMarker.Buffer = 0;
}
}
else if (IndexSpecified && 0 != FileName && 0 != FileName->Length)
{
NTSTATUS Result;
Result = FspFileDescSetDirectoryMarker(FileDesc, FileName);
if (!NT_SUCCESS(Result))
return Result;
FileDesc->DirectoryHasSuchFile = FALSE;
}
return STATUS_SUCCESS;
}
NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName)
{
if (&FileDesc->DirectoryMarker == FileName)
return STATUS_SUCCESS;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject);
UNICODE_STRING DirectoryMarker;
if (FsvolDeviceExtension->VolumeParams.MaxComponentLength < FileName->Length)
return STATUS_OBJECT_NAME_INVALID;
DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length;
DirectoryMarker.Buffer = FspAlloc(FileName->Length);
if (0 == DirectoryMarker.Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(DirectoryMarker.Buffer, FileName->Buffer, FileName->Length);
if (0 != FileDesc->DirectoryMarker.Buffer)
FspFree(FileDesc->DirectoryMarker.Buffer);
FileDesc->DirectoryMarker = DirectoryMarker;
return STATUS_SUCCESS;
}

36
tools/build-sample.bat Normal file
View File

@ -0,0 +1,36 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
if not X%1==X set Config=%1
if not X%2==X set Arch=%2
if not X%3==X set Sample=%3
if not X%4==X set ProjDir=%~4
if X!ProjDir!==X (echo usage: build-sample Config Arch Sample ProjDir >&2 & goto fail)
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
set RegKey="HKLM\SOFTWARE\WinFsp"
set RegVal="InstallDir"
reg query !RegKey! /v !RegVal! /reg:32 >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "tokens=2,*" %%i in ('reg query !RegKey! /v !RegVal! /reg:32 ^| findstr !RegVal!') do (
set InstallDir=%%j
)
)
if not exist "!InstallDir!" (echo cannot find WinFsp installation >&2 & goto fail)
if not exist "!InstallDir!samples\!Sample!" (echo cannot find WinFsp sample !Sample! >&2 & goto fail)
if exist "!ProjDir!" rmdir /s/q "!ProjDir!"
mkdir "!ProjDir!"
xcopy /s/e/q/y "!InstallDir!samples\!Sample!" "!ProjDir!"
devenv "!ProjDir!\!Sample!.sln" /build "!Config!|!Arch!"
if !ERRORLEVEL! neq 0 goto :fail
exit /b 0
:fail
exit /b 1

41
tools/fsreg.bat Normal file
View File

@ -0,0 +1,41 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
set RegKey=HKLM\SYSTEM\CurrentControlSet\Services\WinFsp.Launcher\Services
if not X%1==X-u (
set unreg=0
if not X%1==X set fsname=%1
if not X%2==X set fsexec="%~f2"
if not X%3==X set fscmdl=%3
if not X%4==X set fssecu=%4
if X!fscmdl!==X goto usage
if not exist !fsexec! goto notfound
reg add !RegKey!\!fsname! /v Executable /t REG_SZ /d !fsexec! /f
reg add !RegKey!\!fsname! /v CommandLine /t REG_SZ /d !fscmdl! /f
if not X!fssecu!==X reg add !RegKey!\!fsname! /v Security /t REG_SZ /d !fssecu! /f
) else (
set unreg=1
if not X%2==X set fsname=%2
if X!fsname!==X goto usage
reg delete !RegKey!\!fsname! /f
)
exit /b 0
:notfound
echo executable !fsexec! not found >&2
exit /b 2
:usage
echo usage: fsreg NAME EXECUTABLE COMMANDLINE [SECURITY] >&2
echo usage: fsreg -u NAME >&2
exit /b 2

View File

@ -57,7 +57,11 @@ set dfl_tests=^
fscrash-x86
set opt_tests=^
ifstest-memfs-x64-disk ^
ifstest-memfs-x86-disk
ifstest-memfs-x86-disk ^
sample-passthrough-x64 ^
sample-passthrough-x86 ^
sample-passthrough-fuse-x64 ^
sample-passthrough-fuse-x86
set tests=
for %%f in (%dfl_tests%) do (
@ -139,7 +143,7 @@ if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x64-mountpoint-drive
winfsp-tests-x64 --mountpoint=X:
winfsp-tests-x64 --mountpoint=X: --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
@ -169,7 +173,7 @@ if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x86-mountpoint-drive
winfsp-tests-x86 --mountpoint=X:
winfsp-tests-x86 --mountpoint=X: --resilient
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
@ -477,6 +481,83 @@ for /F "delims=" %%l in ('call "%ProjRoot%\tools\ifstest.bat" %* /z /v ^| findst
if not X!IfsTestFound!==XYES set IfsTestExit=1
exit /b !IfsTestExit!
:sample-passthrough-x64
call :__sample-passthrough x64
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:sample-passthrough-x86
call :__sample-passthrough x86
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:__sample-passthrough
set SamplePassthroughExit=0
call %ProjRoot%\tools\build-sample %Configuration% %1 passthrough "%TMP%\passthrough-%1"
if !ERRORLEVEL! neq 0 goto fail
mkdir "%TMP%\passthrough-%1\test"
call "%ProjRoot%\tools\fsreg" passthrough "%TMP%\passthrough-%1\build\%Configuration%\passthrough-%1.exe" "-u %%%%1 -m %%%%2" "D:P(A;;RPWPLC;;;WD)"
echo net use L: "\\passthrough\%TMP::=$%\passthrough-%1\test"
net use L: "\\passthrough\%TMP::=$%\passthrough-%1\test"
if !ERRORLEVEL! neq 0 goto fail
echo net use ^| findstr L:
net use | findstr L:
pushd >nul
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough\%TMP::=$%\passthrough-%1\test" ^
-create_allocation_test -getfileinfo_name_test -rename_flipflop_test -rename_mmap_test -reparse* -stream*
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
popd
echo net use L: /delete
net use L: /delete
call "%ProjRoot%\tools\fsreg" -u passthrough
rmdir /s/q "%TMP%\passthrough-%1"
exit /b !SamplePassthroughExit!
:sample-passthrough-fuse-x64
call :__sample-passthrough-fuse x64
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:sample-passthrough-fuse-x86
call :__sample-passthrough-fuse x86
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:__sample-passthrough-fuse
set SamplePassthroughExit=0
call %ProjRoot%\tools\build-sample %Configuration% %1 passthrough-fuse "%TMP%\passthrough-fuse-%1"
if !ERRORLEVEL! neq 0 goto fail
mkdir "%TMP%\passthrough-fuse-%1\test"
call "%ProjRoot%\tools\fsreg" passthrough-fuse "%TMP%\passthrough-fuse-%1\build\%Configuration%\passthrough-fuse-%1.exe" ^
"-ouid=65792,gid=65792 -oCaseInsensitiveSearch --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)"
echo net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test"
net use L: "\\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test"
if !ERRORLEVEL! neq 0 goto fail
echo net use ^| findstr L:
net use | findstr L:
pushd >nul
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L:
"%ProjRoot%\build\VStudio\build\%Configuration%\winfsp-tests-%1.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\passthrough-fuse\%TMP::=$%\passthrough-fuse-%1\test" ^
-create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test ^
-reparse* -stream*
if !ERRORLEVEL! neq 0 set SamplePassthroughExit=1
popd
echo net use L: /delete
net use L: /delete
call "%ProjRoot%\tools\fsreg" -u passthrough-fuse
rmdir /s/q "%TMP%\passthrough-fuse-%1"
exit /b !SamplePassthroughExit!
:leak-test
for /F "tokens=1,2 delims=:" %%i in ('verifier /query ^| findstr ^
/c:"Current Pool Allocations:" ^

View File

@ -580,58 +580,6 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context)
free(Context->FileNodes);
}
typedef std::unordered_map<UINT64, std::wstring> MEMFS_DIR_DESC;
static inline
NTSTATUS MemfsDirDescCreate(MEMFS_DIR_DESC **PDirDesc)
{
*PDirDesc = 0;
try
{
*PDirDesc = new MEMFS_DIR_DESC;
return STATUS_SUCCESS;
}
catch (...)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
static inline
VOID MemfsDirDescDelete(MEMFS_DIR_DESC *DirDesc)
{
delete DirDesc;
}
static inline
VOID MemfsDirDescReset(MEMFS_DIR_DESC *DirDesc)
{
DirDesc->clear();
}
static inline
PWSTR MemfsDirDescGetFileName(MEMFS_DIR_DESC *DirDesc, UINT64 Offset)
{
MEMFS_DIR_DESC::iterator iter = DirDesc->find(Offset);
if (iter == DirDesc->end())
return 0;
return const_cast<PWSTR>(iter->second.c_str());
}
static inline
NTSTATUS MemfsDirDescInsertFileName(MEMFS_DIR_DESC *DirDesc, UINT64 Offset, PWSTR FileName)
{
try
{
DirDesc->insert(MEMFS_DIR_DESC::value_type(Offset, FileName));
return STATUS_SUCCESS;
}
catch (...)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
/*
* FSP_FILE_SYSTEM_INTERFACE
*/
@ -745,7 +693,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
#endif
MEMFS_FILE_NODE *FileNode;
MEMFS_FILE_NODE *ParentNode;
MEMFS_DIR_DESC *DirDesc = 0;
NTSTATUS Result;
BOOLEAN Inserted;
@ -794,20 +741,9 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
}
#endif
if (CreateOptions & FILE_DIRECTORY_FILE)
{
Result = MemfsDirDescCreate(&DirDesc);
if (!NT_SUCCESS(Result))
return Result;
}
Result = MemfsFileNodeCreate(FileName, &FileNode);
if (!NT_SUCCESS(Result))
{
if (0 != DirDesc)
MemfsDirDescDelete(DirDesc);
return Result;
}
#if defined(MEMFS_NAMED_STREAMS)
FileNode->MainFileNode = MemfsFileNodeMapGetMain(Memfs->FileNodeMap, FileName);
@ -823,8 +759,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
if (0 == FileNode->FileSecurity)
{
MemfsFileNodeDelete(FileNode);
if (0 != DirDesc)
MemfsDirDescDelete(DirDesc);
return STATUS_INSUFFICIENT_RESOURCES;
}
memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize);
@ -837,8 +771,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
if (0 == FileNode->FileData)
{
MemfsFileNodeDelete(FileNode);
if (0 != DirDesc)
MemfsDirDescDelete(DirDesc);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
@ -847,8 +779,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result) || !Inserted)
{
MemfsFileNodeDelete(FileNode);
if (0 != DirDesc)
MemfsDirDescDelete(DirDesc);
if (NT_SUCCESS(Result))
Result = STATUS_OBJECT_NAME_COLLISION; /* should not happen! */
return Result;
@ -869,9 +799,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
}
#endif
/* since we now use dir descriptors to quickly retrieve dir contents, place it in UserContext2 */
FspFileSystemGetOperationContext()->Response->Rsp.Create.Opened.UserContext2 = (UINT_PTR)DirDesc;
return STATUS_SUCCESS;
}
@ -881,7 +808,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode;
MEMFS_DIR_DESC *DirDesc = 0;
NTSTATUS Result;
if (MEMFS_MAX_PATH <= wcslen(FileName))
@ -895,13 +821,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
return Result;
}
if (0 != (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
Result = MemfsDirDescCreate(&DirDesc);
if (!NT_SUCCESS(Result))
return Result;
}
MemfsFileNodeReference(FileNode);
*PFileNode = FileNode;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
@ -917,9 +836,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
}
#endif
/* since we now use dir descriptors to quickly retrieve dir contents, place it in UserContext2 */
FspFileSystemGetOperationContext()->Response->Rsp.Create.Opened.UserContext2 = (UINT_PTR)DirDesc;
return STATUS_SUCCESS;
}
@ -1025,13 +941,8 @@ static VOID Close(FSP_FILE_SYSTEM *FileSystem,
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
MEMFS_DIR_DESC *DirDesc = (MEMFS_DIR_DESC *)(UINT_PTR)
FspFileSystemGetOperationContext()->Request->Req.Close.UserContext2;
MemfsFileNodeDereference(FileNode);
if (0 != DirDesc)
MemfsDirDescDelete(DirDesc);
}
static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
@ -1394,14 +1305,11 @@ static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem,
typedef struct _MEMFS_READ_DIRECTORY_CONTEXT
{
PVOID Buffer;
UINT64 Offset;
ULONG Length;
PULONG PBytesTransferred;
BOOLEAN OffsetFound;
MEMFS_DIR_DESC *DirDesc;
} MEMFS_READ_DIRECTORY_CONTEXT;
static BOOLEAN AddDirInfo(MEMFS_DIR_DESC *DirDesc, MEMFS_FILE_NODE *FileNode, PWSTR FileName,
static BOOLEAN AddDirInfo(MEMFS_FILE_NODE *FileNode, PWSTR FileName,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
UINT8 DirInfoBuf[sizeof(FSP_FSCTL_DIR_INFO) + sizeof FileNode->FileName];
@ -1414,14 +1322,11 @@ static BOOLEAN AddDirInfo(MEMFS_DIR_DESC *DirDesc, MEMFS_FILE_NODE *FileNode, PW
FspPathSuffix(FileNode->FileName, &Remain, &Suffix, Root);
FileName = Suffix;
FspPathCombine(FileNode->FileName, Suffix);
MemfsDirDescInsertFileName(DirDesc, FileNode->FileInfo.IndexNumber, FileName);
}
memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(FileName) * sizeof(WCHAR));
DirInfo->FileInfo = FileNode->FileInfo;
DirInfo->NextOffset = FileNode->FileInfo.IndexNumber;
memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO));
return FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred);
@ -1431,39 +1336,23 @@ static BOOLEAN ReadDirectoryEnumFn(MEMFS_FILE_NODE *FileNode, PVOID Context0)
{
MEMFS_READ_DIRECTORY_CONTEXT *Context = (MEMFS_READ_DIRECTORY_CONTEXT *)Context0;
if (0 != Context->Offset && !Context->OffsetFound)
{
Context->OffsetFound = FileNode->FileInfo.IndexNumber == Context->Offset;
return TRUE;
}
return AddDirInfo(Context->DirDesc, FileNode, 0,
return AddDirInfo(FileNode, 0,
Context->Buffer, Context->Length, Context->PBytesTransferred);
}
static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode0, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern,
PULONG PBytesTransferred)
PVOID FileNode0, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
MEMFS_DIR_DESC *DirDesc = (MEMFS_DIR_DESC *)(UINT_PTR)
FspFileSystemGetOperationContext()->Request->Req.QueryDirectory.UserContext2;
MEMFS_FILE_NODE *ParentNode;
MEMFS_READ_DIRECTORY_CONTEXT Context;
PWSTR PrevFileName = 0;
NTSTATUS Result;
Context.Buffer = Buffer;
Context.Offset = Offset;
Context.Length = Length;
Context.PBytesTransferred = PBytesTransferred;
Context.OffsetFound = FALSE;
Context.DirDesc = DirDesc;
if (0 == Offset)
MemfsDirDescReset(DirDesc);
if (L'\0' != FileNode->FileName[1])
{
@ -1473,25 +1362,20 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
if (0 == ParentNode)
return Result;
if (0 == Offset)
if (!AddDirInfo(DirDesc, FileNode, L".", Buffer, Length, PBytesTransferred))
return STATUS_SUCCESS;
if (0 == Offset || FileNode->FileInfo.IndexNumber == Offset)
if (0 == Marker)
{
Context.OffsetFound = FileNode->FileInfo.IndexNumber == Context.Offset;
if (!AddDirInfo(DirDesc, ParentNode, L"..", Buffer, Length, PBytesTransferred))
if (!AddDirInfo(FileNode, L".", Buffer, Length, PBytesTransferred))
return STATUS_SUCCESS;
}
if (0 == Marker || (L'.' == Marker[0] && L'\0' == Marker[1]))
{
if (!AddDirInfo(ParentNode, L"..", Buffer, Length, PBytesTransferred))
return STATUS_SUCCESS;
Marker = 0;
}
}
if (0 != Context.Offset && !Context.OffsetFound)
{
PrevFileName = MemfsDirDescGetFileName(DirDesc, Offset);
Context.OffsetFound = 0 != PrevFileName;
}
if (MemfsFileNodeMapEnumerateChildren(Memfs->FileNodeMap, FileNode, PrevFileName,
if (MemfsFileNodeMapEnumerateChildren(Memfs->FileNodeMap, FileNode, Marker,
ReadDirectoryEnumFn, &Context))
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);

7
tst/passthrough-fuse/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
build
*.ncb
*.suo
*.vcproj.*
*.vcxproj.user
*.exe
*.install

View File

@ -0,0 +1,18 @@
usage:
@echo "make cygfuse|winfsp-fuse" 1>&2
@echo "" 1>&2
@echo " cygfuse Link with CYGFUSE" 1>&2
@echo " winfsp-fuse Link with WinFsp-FUSE" 1>&2
@exit 2
cygfuse: passthrough-cygfuse
winfsp-fuse: passthrough-winfsp-fuse
passthrough-cygfuse: passthrough-fuse.c
gcc $^ -o $@ -g -Wall `pkg-config fuse --cflags --libs`
passthrough-winfsp-fuse: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib
passthrough-winfsp-fuse: passthrough-fuse.c
ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install
gcc $^ -o $@ -g -Wall `pkg-config fuse --cflags --libs`

View File

@ -0,0 +1,7 @@
`Passthrough-fuse` is a simple FUSE file system that passes all file system operations to an underlying file system.
It can be built with the following tools:
- Using Visual Studio (`winfsp.sln`).
- Using Cygwin GCC and linking directly with the WinFsp DLL (`make winfsp-fuse`).
- Using Cygwin GCC and linking to CYGFUSE (`make cygfuse`).

View File

@ -0,0 +1,327 @@
/**
* @file passthrough-fuse.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <fuse.h>
#if defined(_WIN64) || defined(_WIN32)
#include "winposix.h"
#else
#include <dirent.h>
#include <unistd.h>
#endif
#define FSNAME "passthrough"
#define PROGNAME "passthrough-fuse"
#define concat_path(ptfs, fn, fp) (sizeof fp > (unsigned)snprintf(fp, sizeof fp, "%s%s", ptfs->rootdir, fn))
#define fi_dirbit (0x8000000000000000ULL)
#define fi_fh(fi, MASK) ((fi)->fh & (MASK))
#define fi_setfh(fi, FH, MASK) ((fi)->fh = (intptr_t)(FH) | (MASK))
#define fi_fd(fi) (fi_fh(fi, fi_dirbit) ? \
dirfd((DIR *)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit))
#define fi_dirp(fi) ((DIR *)fi_fh(fi, ~fi_dirbit))
#define fi_setfd(fi, fd) (fi_setfh(fi, fd, 0))
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
#define ptfs_impl_fullpath(n) \
char full ## n[PATH_MAX]; \
if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
return -ENAMETOOLONG; \
n = full ## n
typedef struct
{
const char *rootdir;
} PTFS;
static int ptfs_getattr(const char *path, struct fuse_stat *stbuf)
{
ptfs_impl_fullpath(path);
return -1 != lstat(path, stbuf) ? 0 : -errno;
}
static int ptfs_mkdir(const char *path, fuse_mode_t mode)
{
ptfs_impl_fullpath(path);
return -1 != mkdir(path, mode) ? 0 : -errno;
}
static int ptfs_unlink(const char *path)
{
ptfs_impl_fullpath(path);
return -1 != unlink(path) ? 0 : -errno;
}
static int ptfs_rmdir(const char *path)
{
ptfs_impl_fullpath(path);
return -1 != rmdir(path) ? 0 : -errno;
}
static int ptfs_rename(const char *oldpath, const char *newpath)
{
ptfs_impl_fullpath(newpath);
ptfs_impl_fullpath(oldpath);
return -1 != rename(oldpath, newpath) ? 0 : -errno;
}
static int ptfs_chmod(const char *path, fuse_mode_t mode)
{
ptfs_impl_fullpath(path);
return -1 != chmod(path, mode) ? 0 : -errno;
}
static int ptfs_chown(const char *path, fuse_uid_t uid, fuse_gid_t gid)
{
ptfs_impl_fullpath(path);
return -1 != lchown(path, uid, gid) ? 0 : -errno;
}
static int ptfs_truncate(const char *path, fuse_off_t size)
{
ptfs_impl_fullpath(path);
return -1 != truncate(path, size) ? 0 : -errno;
}
static int ptfs_utime(const char *path, struct fuse_utimbuf *timbuf)
{
ptfs_impl_fullpath(path);
return -1 != utime(path, timbuf) ? 0 : -errno;
}
static int ptfs_open(const char *path, struct fuse_file_info *fi)
{
ptfs_impl_fullpath(path);
int fd;
return -1 != (fd = open(path, fi->flags)) ? (fi_setfd(fi, fd), 0) : -errno;
}
static int ptfs_read(const char *path, char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi)
{
int fd = fi_fd(fi);
int nb;
return -1 != (nb = pread(fd, buf, size, off)) ? nb : -errno;
}
static int ptfs_write(const char *path, const char *buf, size_t size, fuse_off_t off,
struct fuse_file_info *fi)
{
int fd = fi_fd(fi);
int nb;
return -1 != (nb = pwrite(fd, buf, size, off)) ? nb : -errno;
}
static int ptfs_statfs(const char *path, struct fuse_statvfs *stbuf)
{
ptfs_impl_fullpath(path);
return -1 != statvfs(path, stbuf) ? 0 : -errno;
}
static int ptfs_release(const char *path, struct fuse_file_info *fi)
{
int fd = fi_fd(fi);
close(fd);
return 0;
}
static int ptfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
{
int fd = fi_fd(fi);
return -1 != fsync(fd) ? 0 : -errno;
}
static int ptfs_opendir(const char *path, struct fuse_file_info *fi)
{
ptfs_impl_fullpath(path);
DIR *dirp;
return 0 != (dirp = opendir(path)) ? (fi_setdirp(fi, dirp), 0) : -errno;
}
static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
struct fuse_file_info *fi)
{
DIR *dirp = fi_dirp(fi);
struct dirent *de;
rewinddir(dirp);
for (;;)
{
errno = 0;
if (0 == (de = readdir(dirp)))
break;
if (0 != filler(buf, de->d_name, 0, 0))
return -ENOMEM;
}
return -errno;
}
static int ptfs_releasedir(const char *path, struct fuse_file_info *fi)
{
DIR *dirp = fi_dirp(fi);
return -1 != closedir(dirp) ? 0 : -errno;
}
static int ptfs_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi)
{
ptfs_impl_fullpath(path);
int fd;
return -1 != (fd = open(path, fi->flags, mode)) ? (fi_setfd(fi, fd), 0) : -errno;
}
static int ptfs_ftruncate(const char *path, fuse_off_t off, struct fuse_file_info *fi)
{
int fd = fi_fd(fi);
return -1 != ftruncate(fd, off) ? 0 : -errno;
}
static int ptfs_fgetattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi)
{
int fd = fi_fd(fi);
return -1 != fstat(fd, stbuf) ? 0 : -errno;
}
static struct fuse_operations ptfs_ops =
{
ptfs_getattr,
0, //getdir
0, //readlink
0, //mknod
ptfs_mkdir,
ptfs_unlink,
ptfs_rmdir,
0, //symlink
ptfs_rename,
0, //link
ptfs_chmod,
ptfs_chown,
ptfs_truncate,
ptfs_utime,
ptfs_open,
ptfs_read,
ptfs_write,
ptfs_statfs,
0, //flush
ptfs_release,
ptfs_fsync,
0, //setxattr
0, //getxattr
0, //listxattr
0, //removexattr
ptfs_opendir,
ptfs_readdir,
ptfs_releasedir,
0, //fsyncdir
0, //init
0, //destroy
0, //access
ptfs_create,
ptfs_ftruncate,
ptfs_fgetattr,
};
static void usage(void)
{
fprintf(stderr, "usage: " PROGNAME " [FUSE options] rootdir mountpoint\n");
exit(2);
}
int main(int argc, char *argv[])
{
PTFS ptfs = { 0 };
if (3 <= argc && '-' != argv[argc - 2][0] && '-' != argv[argc - 1][0])
{
ptfs.rootdir = realpath(argv[argc - 2], 0); /* memory freed at process end */
argv[argc - 2] = argv[argc - 1];
argc--;
}
#if defined(_WIN64) || defined(_WIN32)
/*
* When building for Windows (rather than Cygwin or POSIX OS)
* allow the path to be specified using the --VolumePrefix
* switch using the syntax \\passthrough-fuse\C$\Path. This
* allows us to run the file system under the WinFsp.Launcher
* and start it using commands like:
*
* net use z: \\passthrough-fuse\C$\Path
*/
if (0 == ptfs.rootdir)
for (int argi = 1; argc > argi; argi++)
{
int strncmp(const char *a, const char *b, size_t length);
char *strchr(const char *s, int c);
char *p = 0;
if (0 == strncmp("--UNC=", argv[argi], sizeof "--UNC=" - 1))
p = argv[argi] + sizeof "--UNC=" - 1;
else if (0 == strncmp("--VolumePrefix=", argv[argi], sizeof "--VolumePrefix=" - 1))
p = argv[argi] + sizeof "--VolumePrefix=" - 1;
if (0 != p && '\\' != p[1])
{
p = strchr(p + 1, '\\');
if (0 != p &&
(
('A' <= p[1] && p[1] <= 'Z') ||
('a' <= p[1] && p[1] <= 'z')
) &&
'$' == p[2])
{
p[2] = ':';
ptfs.rootdir = realpath(p + 1, 0); /* memory freed at process end */
p[2] = '$';
break;
}
}
}
#endif
if (0 == ptfs.rootdir)
usage();
return fuse_main(argc, argv, &ptfs_ops, &ptfs);
}

View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passthrough-fuse", "passthrough-fuse.vcxproj", "{C753851C-142F-4AAD-B2F7-CBF905C2A600}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Debug|x64.ActiveCfg = Debug|x64
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Debug|x64.Build.0 = Debug|x64
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Debug|x86.ActiveCfg = Debug|Win32
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Debug|x86.Build.0 = Debug|Win32
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Release|x64.ActiveCfg = Release|x64
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Release|x64.Build.0 = Release|x64
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Release|x86.ActiveCfg = Release|Win32
{C753851C-142F-4AAD-B2F7-CBF905C2A600}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C753851C-142F-4AAD-B2F7-CBF905C2A600}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>passthroughfuse</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="passthrough-fuse.c" />
<ClCompile Include="winposix.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="winposix.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="passthrough-fuse.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="winposix.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="winposix.h">
<Filter>Source</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,529 @@
/**
* @file passthrough-fuse.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
/*
* This is a very simple Windows POSIX layer. It handles all the POSIX
* file API's required to implement passthrough-fuse in POSIX, however
* the API handling is rather unsophisticated.
*
* Ways to improve it: use the FspPosix* API's to properly handle
* file names and security.
*/
#include <winfsp/winfsp.h>
#include <fcntl.h>
#include <fuse.h>
#include "winposix.h"
struct _DIR
{
HANDLE h, fh;
struct dirent de;
char path[];
};
static int maperror(int winerrno);
static inline void *error0(void)
{
errno = maperror(GetLastError());
return 0;
}
static inline int error(void)
{
errno = maperror(GetLastError());
return -1;
}
char *realpath(const char *path, char *resolved)
{
char *result;
if (0 == resolved)
{
result = malloc(PATH_MAX); /* sets errno */
if (0 == result)
return 0;
}
else
result = resolved;
int err = 0;
DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
if (0 == len)
err = GetLastError();
else if (PATH_MAX < len)
err = ERROR_INVALID_PARAMETER;
if (0 == err)
{
HANDLE h = CreateFileA(result,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE != h)
CloseHandle(h);
else
err = GetLastError();
}
if (0 != err)
{
if (result != resolved)
free(result);
errno = maperror(err);
result = 0;
}
return result;
}
int statvfs(const char *path, struct fuse_statvfs *stbuf)
{
char root[PATH_MAX];
DWORD
VolumeSerialNumber,
MaxComponentLength,
SectorsPerCluster,
BytesPerSector,
NumberOfFreeClusters,
TotalNumberOfClusters;
if (!GetVolumePathNameA(path, root, PATH_MAX) ||
!GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
!GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector,
&NumberOfFreeClusters, &TotalNumberOfClusters))
{
return error();
}
memset(stbuf, 0, sizeof *stbuf);
stbuf->f_bsize = SectorsPerCluster * BytesPerSector;
stbuf->f_frsize = BytesPerSector;
stbuf->f_blocks = TotalNumberOfClusters;
stbuf->f_bfree = NumberOfFreeClusters;
stbuf->f_bavail = TotalNumberOfClusters;
stbuf->f_fsid = VolumeSerialNumber;
stbuf->f_namemax = MaxComponentLength;
return 0;
}
int open(const char *path, int oflag, ...)
{
static DWORD da[] = { GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE, 0 };
static DWORD cd[] = { OPEN_EXISTING, OPEN_ALWAYS, TRUNCATE_EXISTING, CREATE_ALWAYS };
DWORD DesiredAccess = 0 == (oflag & _O_APPEND) ?
da[oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)] :
(da[oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)] & ~FILE_WRITE_DATA) | FILE_APPEND_DATA;
DWORD CreationDisposition = (_O_CREAT | _O_EXCL) == (oflag & (_O_CREAT | _O_EXCL)) ?
CREATE_NEW :
cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
HANDLE h = CreateFileA(path,
DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0/* default security */,
CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == h)
return error();
return (int)(intptr_t)h;
}
int fstat(int fd, struct fuse_stat *stbuf)
{
HANDLE h = (HANDLE)(intptr_t)fd;
BY_HANDLE_FILE_INFORMATION FileInfo;
UINT64 CreationTime, LastAccessTime, LastWriteTime;
if (!GetFileInformationByHandle(h, &FileInfo))
return error();
CreationTime = ((PLARGE_INTEGER)(&FileInfo.ftCreationTime))->QuadPart - 116444736000000000;
LastAccessTime = ((PLARGE_INTEGER)(&FileInfo.ftLastAccessTime))->QuadPart - 116444736000000000;
LastWriteTime = ((PLARGE_INTEGER)(&FileInfo.ftLastWriteTime))->QuadPart - 116444736000000000;
memset(stbuf, 0, sizeof *stbuf);
stbuf->st_mode = 0777 |
((FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
stbuf->st_nlink = 1;
stbuf->st_size = ((UINT64)FileInfo.nFileSizeHigh << 32) | ((UINT64)FileInfo.nFileSizeLow);
stbuf->st_atim.tv_sec = LastAccessTime / 10000000;
stbuf->st_atim.tv_nsec = LastAccessTime % 10000000 * 100;
stbuf->st_mtim.tv_sec = LastWriteTime / 10000000;
stbuf->st_mtim.tv_nsec = LastWriteTime % 10000000 * 100;
stbuf->st_ctim.tv_sec = LastWriteTime / 10000000;
stbuf->st_ctim.tv_nsec = LastWriteTime % 10000000 * 100;
stbuf->st_birthtim.tv_sec = CreationTime / 10000000;
stbuf->st_birthtim.tv_nsec = CreationTime % 10000000 * 100;
return 0;
}
int ftruncate(int fd, fuse_off_t size)
{
HANDLE h = (HANDLE)(intptr_t)fd;
FILE_END_OF_FILE_INFO EndOfFileInfo;
EndOfFileInfo.EndOfFile.QuadPart = size;
if (!SetFileInformationByHandle(h, FileEndOfFileInfo, &EndOfFileInfo, sizeof EndOfFileInfo))
return error();
return 0;
}
int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset)
{
HANDLE h = (HANDLE)(intptr_t)fd;
OVERLAPPED Overlapped = { 0 };
DWORD BytesTransferred;
Overlapped.Offset = (DWORD)offset;
Overlapped.OffsetHigh = (DWORD)(offset >> 32);
if (!ReadFile(h, buf, (DWORD)nbyte, &BytesTransferred, &Overlapped))
{
if (ERROR_HANDLE_EOF == GetLastError())
return 0;
return error();
}
return BytesTransferred;
}
int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset)
{
HANDLE h = (HANDLE)(intptr_t)fd;
OVERLAPPED Overlapped = { 0 };
DWORD BytesTransferred;
Overlapped.Offset = (DWORD)offset;
Overlapped.OffsetHigh = (DWORD)(offset >> 32);
if (!WriteFile(h, buf, (DWORD)nbyte, &BytesTransferred, &Overlapped))
return error();
return BytesTransferred;
}
int fsync(int fd)
{
HANDLE h = (HANDLE)(intptr_t)fd;
if (!FlushFileBuffers(h))
return error();
return 0;
}
int close(int fd)
{
HANDLE h = (HANDLE)(intptr_t)fd;
if (!CloseHandle(h))
return error();
return 0;
}
int lstat(const char *path, struct fuse_stat *stbuf)
{
HANDLE h = CreateFileA(path,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == h)
return error();
int res = fstat((int)(intptr_t)h, stbuf);
CloseHandle(h);
return res;
}
int chmod(const char *path, fuse_mode_t mode)
{
/* we do not support file security */
return 0;
}
int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid)
{
/* we do not support file security */
return 0;
}
int truncate(const char *path, fuse_off_t size)
{
HANDLE h = CreateFileA(path,
FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == h)
return error();
int res = ftruncate((int)(intptr_t)h, size);
CloseHandle(h);
return res;
}
int utime(const char *path, const struct fuse_utimbuf *timbuf)
{
HANDLE h = CreateFileA(path,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == h)
return error();
UINT64 LastAccessTime = timbuf->actime * 10000000 + 116444736000000000;
UINT64 LastWriteTime = timbuf->modtime * 10000000 + 116444736000000000;
int res = SetFileTime(h,
0, (PFILETIME)&LastAccessTime, (PFILETIME)&LastWriteTime) ? 0 : error();
CloseHandle(h);
return res;
}
int unlink(const char *path)
{
if (!DeleteFileA(path))
return error();
return 0;
}
int rename(const char *oldpath, const char *newpath)
{
if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
return error();
return 0;
}
int mkdir(const char *path, fuse_mode_t mode)
{
if (!CreateDirectoryA(path, 0/* default security */))
return error();
return 0;
}
int rmdir(const char *path)
{
if (!RemoveDirectoryA(path))
return error();
return 0;
}
DIR *opendir(const char *path)
{
HANDLE h = CreateFileA(path,
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == h)
return error0();
size_t pathlen = strlen(path);
if (0 < pathlen && '/' == path[pathlen - 1])
pathlen--;
DIR *dirp = malloc(sizeof *dirp + pathlen + 3); /* sets errno */
if (0 == dirp)
{
CloseHandle(h);
return 0;
}
memset(dirp, 0, sizeof *dirp);
dirp->h = h;
dirp->fh = INVALID_HANDLE_VALUE;
memcpy(dirp->path, path, pathlen);
dirp->path[pathlen + 0] = '/';
dirp->path[pathlen + 1] = '*';
dirp->path[pathlen + 2] = '\0';
return dirp;
}
int dirfd(DIR *dirp)
{
return (int)(intptr_t)dirp->h;
}
void rewinddir(DIR *dirp)
{
if (INVALID_HANDLE_VALUE != dirp->fh)
{
FindClose(dirp->fh);
dirp->fh = INVALID_HANDLE_VALUE;
}
}
struct dirent *readdir(DIR *dirp)
{
WIN32_FIND_DATAA FindData;
if (INVALID_HANDLE_VALUE == dirp->fh)
{
dirp->fh = FindFirstFileA(dirp->path, &FindData);
if (INVALID_HANDLE_VALUE == dirp->fh)
return error0();
}
else
{
if (!FindNextFileA(dirp->fh, &FindData))
{
if (ERROR_NO_MORE_FILES == GetLastError())
return 0;
return error0();
}
}
strcpy(dirp->de.d_name, FindData.cFileName);
return &dirp->de;
}
int closedir(DIR *dirp)
{
if (INVALID_HANDLE_VALUE != dirp->fh)
FindClose(dirp->fh);
CloseHandle(dirp->h);
free(dirp);
return 0;
}
static int maperror(int winerrno)
{
switch (winerrno)
{
case ERROR_INVALID_FUNCTION:
return EINVAL;
case ERROR_FILE_NOT_FOUND:
return ENOENT;
case ERROR_PATH_NOT_FOUND:
return ENOENT;
case ERROR_TOO_MANY_OPEN_FILES:
return EMFILE;
case ERROR_ACCESS_DENIED:
return EACCES;
case ERROR_INVALID_HANDLE:
return EBADF;
case ERROR_ARENA_TRASHED:
return ENOMEM;
case ERROR_NOT_ENOUGH_MEMORY:
return ENOMEM;
case ERROR_INVALID_BLOCK:
return ENOMEM;
case ERROR_BAD_ENVIRONMENT:
return E2BIG;
case ERROR_BAD_FORMAT:
return ENOEXEC;
case ERROR_INVALID_ACCESS:
return EINVAL;
case ERROR_INVALID_DATA:
return EINVAL;
case ERROR_INVALID_DRIVE:
return ENOENT;
case ERROR_CURRENT_DIRECTORY:
return EACCES;
case ERROR_NOT_SAME_DEVICE:
return EXDEV;
case ERROR_NO_MORE_FILES:
return ENOENT;
case ERROR_LOCK_VIOLATION:
return EACCES;
case ERROR_BAD_NETPATH:
return ENOENT;
case ERROR_NETWORK_ACCESS_DENIED:
return EACCES;
case ERROR_BAD_NET_NAME:
return ENOENT;
case ERROR_FILE_EXISTS:
return EEXIST;
case ERROR_CANNOT_MAKE:
return EACCES;
case ERROR_FAIL_I24:
return EACCES;
case ERROR_INVALID_PARAMETER:
return EINVAL;
case ERROR_NO_PROC_SLOTS:
return EAGAIN;
case ERROR_DRIVE_LOCKED:
return EACCES;
case ERROR_BROKEN_PIPE:
return EPIPE;
case ERROR_DISK_FULL:
return ENOSPC;
case ERROR_INVALID_TARGET_HANDLE:
return EBADF;
case ERROR_WAIT_NO_CHILDREN:
return ECHILD;
case ERROR_CHILD_NOT_COMPLETE:
return ECHILD;
case ERROR_DIRECT_ACCESS_HANDLE:
return EBADF;
case ERROR_NEGATIVE_SEEK:
return EINVAL;
case ERROR_SEEK_ON_DEVICE:
return EACCES;
case ERROR_DIR_NOT_EMPTY:
return ENOTEMPTY;
case ERROR_NOT_LOCKED:
return EACCES;
case ERROR_BAD_PATHNAME:
return ENOENT;
case ERROR_MAX_THRDS_REACHED:
return EAGAIN;
case ERROR_LOCK_FAILED:
return EACCES;
case ERROR_ALREADY_EXISTS:
return EEXIST;
case ERROR_FILENAME_EXCED_RANGE:
return ENOENT;
case ERROR_NESTING_NOT_ALLOWED:
return EAGAIN;
case ERROR_NOT_ENOUGH_QUOTA:
return ENOMEM;
default:
if (ERROR_WRITE_PROTECT <= winerrno && winerrno <= ERROR_SHARING_BUFFER_EXCEEDED)
return EACCES;
else if (ERROR_INVALID_STARTING_CODESEG <= winerrno && winerrno <= ERROR_INFLOOP_IN_RELOC_CHAIN)
return ENOEXEC;
else
return EINVAL;
}
}
long WinFspLoad(void)
{
return FspLoad(0);
}

View File

@ -0,0 +1,71 @@
/**
* @file winposix.h
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#ifndef WINPOSIX_H_INCLUDED
#define WINPOSIX_H_INCLUDED
#define O_RDONLY _O_RDONLY
#define O_WRONLY _O_WRONLY
#define O_RDWR _O_RDWR
#define O_APPEND _O_APPEND
#define O_CREAT _O_CREAT
#define O_EXCL _O_EXCL
#define O_TRUNC _O_TRUNC
#define PATH_MAX 1024
typedef struct _DIR DIR;
struct dirent
{
char d_name[255];
};
char *realpath(const char *path, char *resolved);
int statvfs(const char *path, struct fuse_statvfs *stbuf);
int open(const char *path, int oflag, ...);
int fstat(int fd, struct fuse_stat *stbuf);
int ftruncate(int fd, fuse_off_t size);
int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset);
int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset);
int fsync(int fd);
int close(int fd);
int lstat(const char *path, struct fuse_stat *stbuf);
int chmod(const char *path, fuse_mode_t mode);
int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid);
int truncate(const char *path, fuse_off_t size);
int utime(const char *path, const struct fuse_utimbuf *timbuf);
int unlink(const char *path);
int rename(const char *oldpath, const char *newpath);
int mkdir(const char *path, fuse_mode_t mode);
int rmdir(const char *path);
DIR *opendir(const char *path);
int dirfd(DIR *dirp);
void rewinddir(DIR *dirp);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
long WinFspLoad(void);
#undef fuse_main
#define fuse_main(argc, argv, ops, data)\
(WinFspLoad(), fuse_main_real(argc, argv, ops, sizeof *(ops), data))
#endif

5
tst/passthrough/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
build
*.ncb
*.suo
*.vcproj.*
*.vcxproj.user

View File

@ -0,0 +1,930 @@
/**
* @file passthrough.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <winfsp/winfsp.h>
#include <strsafe.h>
#define PROGNAME "passthrough"
#define ALLOCATION_UNIT 4096
#define FULLPATH_SIZE (MAX_PATH + FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR))
#define info(format, ...) FspServiceLog(EVENTLOG_INFORMATION_TYPE, format, __VA_ARGS__)
#define warn(format, ...) FspServiceLog(EVENTLOG_WARNING_TYPE, format, __VA_ARGS__)
#define fail(format, ...) FspServiceLog(EVENTLOG_ERROR_TYPE, format, __VA_ARGS__)
#define ConcatPath(Ptfs, FN, FP) (0 == StringCbPrintfW(FP, sizeof FP, L"%s%s", Ptfs->Path, FN))
#define HandleFromContext(FC) (((PTFS_FILE_CONTEXT *)(FC))->Handle)
typedef struct
{
FSP_FILE_SYSTEM *FileSystem;
PWSTR Path;
} PTFS;
typedef struct
{
HANDLE Handle;
PVOID DirBuffer;
} PTFS_FILE_CONTEXT;
static NTSTATUS GetFileInfoInternal(HANDLE Handle, FSP_FSCTL_FILE_INFO *FileInfo)
{
BY_HANDLE_FILE_INFORMATION ByHandleFileInfo;
if (!GetFileInformationByHandle(Handle, &ByHandleFileInfo))
return FspNtStatusFromWin32(GetLastError());
FileInfo->FileAttributes = ByHandleFileInfo.dwFileAttributes;
FileInfo->ReparseTag = 0;
FileInfo->FileSize =
((UINT64)ByHandleFileInfo.nFileSizeHigh << 32) | (UINT64)ByHandleFileInfo.nFileSizeLow;
FileInfo->AllocationSize = (FileInfo->FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
FileInfo->CreationTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftCreationTime)->QuadPart;
FileInfo->LastAccessTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastAccessTime)->QuadPart;
FileInfo->LastWriteTime = ((PLARGE_INTEGER)&ByHandleFileInfo.ftLastWriteTime)->QuadPart;
FileInfo->ChangeTime = FileInfo->LastWriteTime;
FileInfo->IndexNumber = 0;
FileInfo->HardLinks = 0;
return STATUS_SUCCESS;
}
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
WCHAR Root[MAX_PATH];
ULARGE_INTEGER TotalSize, FreeSize;
if (!GetVolumePathName(Ptfs->Path, Root, MAX_PATH))
return FspNtStatusFromWin32(GetLastError());
if (!GetDiskFreeSpaceEx(Root, 0, &TotalSize, &FreeSize))
return FspNtStatusFromWin32(GetLastError());
VolumeInfo->TotalSize = TotalSize.QuadPart;
VolumeInfo->FreeSize = FreeSize.QuadPart;
return STATUS_SUCCESS;
}
static NTSTATUS SetVolumeLabel_(FSP_FILE_SYSTEM *FileSystem,
PWSTR VolumeLabel,
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{
/* we do not support changing the volume label */
return STATUS_INVALID_DEVICE_REQUEST;
}
static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, PUINT32 PFileAttributes,
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize)
{
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
WCHAR FullPath[FULLPATH_SIZE];
HANDLE Handle;
FILE_ATTRIBUTE_TAG_INFO AttributeTagInfo;
DWORD SecurityDescriptorSizeNeeded;
NTSTATUS Result;
if (!ConcatPath(Ptfs, FileName, FullPath))
return STATUS_OBJECT_NAME_INVALID;
Handle = CreateFileW(FullPath,
FILE_READ_ATTRIBUTES | READ_CONTROL, 0, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == Handle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (0 != PFileAttributes)
{
if (!GetFileInformationByHandleEx(Handle,
FileAttributeTagInfo, &AttributeTagInfo, sizeof AttributeTagInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
*PFileAttributes = AttributeTagInfo.FileAttributes;
}
if (0 != PSecurityDescriptorSize)
{
if (!GetKernelObjectSecurity(Handle,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
SecurityDescriptor, (DWORD)*PSecurityDescriptorSize, &SecurityDescriptorSizeNeeded))
{
*PSecurityDescriptorSize = SecurityDescriptorSizeNeeded;
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
*PSecurityDescriptorSize = SecurityDescriptorSizeNeeded;
}
Result = STATUS_SUCCESS;
exit:
if (INVALID_HANDLE_VALUE != Handle)
CloseHandle(Handle);
return Result;
}
static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo)
{
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
WCHAR FullPath[FULLPATH_SIZE];
SECURITY_ATTRIBUTES SecurityAttributes;
ULONG CreateFlags;
PTFS_FILE_CONTEXT *FileContext;
if (!ConcatPath(Ptfs, FileName, FullPath))
return STATUS_OBJECT_NAME_INVALID;
FileContext = malloc(sizeof *FileContext);
if (0 == FileContext)
return STATUS_INSUFFICIENT_RESOURCES;
memset(FileContext, 0, sizeof *FileContext);
SecurityAttributes.nLength = sizeof SecurityAttributes;
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
SecurityAttributes.bInheritHandle = FALSE;
CreateFlags = FILE_FLAG_BACKUP_SEMANTICS;
if (CreateOptions & FILE_DELETE_ON_CLOSE)
CreateFlags |= FILE_FLAG_DELETE_ON_CLOSE;
if (CreateOptions & FILE_DIRECTORY_FILE)
{
/*
* It is not widely known but CreateFileW can be used to create directories!
* It requires the specification of both FILE_FLAG_BACKUP_SEMANTICS and
* FILE_FLAG_POSIX_SEMANTICS. It also requires that FileAttributes has
* FILE_ATTRIBUTE_DIRECTORY set.
*/
CreateFlags |= FILE_FLAG_POSIX_SEMANTICS;
FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
}
else
FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
if (0 == FileAttributes)
FileAttributes = FILE_ATTRIBUTE_NORMAL;
FileContext->Handle = CreateFileW(FullPath,
GrantedAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SecurityAttributes,
CREATE_NEW, CreateFlags | FileAttributes, 0);
if (INVALID_HANDLE_VALUE == FileContext->Handle)
{
free(FileContext);
return FspNtStatusFromWin32(GetLastError());
}
*PFileContext = FileContext;
return GetFileInfoInternal(FileContext->Handle, FileInfo);
}
static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo)
{
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
WCHAR FullPath[FULLPATH_SIZE];
ULONG CreateFlags;
PTFS_FILE_CONTEXT *FileContext;
if (!ConcatPath(Ptfs, FileName, FullPath))
return STATUS_OBJECT_NAME_INVALID;
FileContext = malloc(sizeof *FileContext);
if (0 == FileContext)
return STATUS_INSUFFICIENT_RESOURCES;
memset(FileContext, 0, sizeof *FileContext);
CreateFlags = FILE_FLAG_BACKUP_SEMANTICS;
if (CreateOptions & FILE_DELETE_ON_CLOSE)
CreateFlags |= FILE_FLAG_DELETE_ON_CLOSE;
FileContext->Handle = CreateFileW(FullPath,
GrantedAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
OPEN_EXISTING, CreateFlags, 0);
if (INVALID_HANDLE_VALUE == FileContext->Handle)
{
free(FileContext);
return FspNtStatusFromWin32(GetLastError());
}
*PFileContext = FileContext;
return GetFileInfoInternal(FileContext->Handle, FileInfo);
}
static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
HANDLE Handle = HandleFromContext(FileContext);
FILE_BASIC_INFO BasicInfo = { 0 };
FILE_ALLOCATION_INFO AllocationInfo = { 0 };
FILE_ATTRIBUTE_TAG_INFO AttributeTagInfo;
if (ReplaceFileAttributes)
{
if (0 == FileAttributes)
FileAttributes = FILE_ATTRIBUTE_NORMAL;
BasicInfo.FileAttributes = FileAttributes;
if (!SetFileInformationByHandle(Handle,
FileBasicInfo, &BasicInfo, sizeof BasicInfo))
return FspNtStatusFromWin32(GetLastError());
}
else if (0 != FileAttributes)
{
if (!GetFileInformationByHandleEx(Handle,
FileAttributeTagInfo, &AttributeTagInfo, sizeof AttributeTagInfo))
return FspNtStatusFromWin32(GetLastError());
BasicInfo.FileAttributes = FileAttributes | AttributeTagInfo.FileAttributes;
if (BasicInfo.FileAttributes ^ FileAttributes)
{
if (!SetFileInformationByHandle(Handle,
FileBasicInfo, &BasicInfo, sizeof BasicInfo))
return FspNtStatusFromWin32(GetLastError());
}
}
if (!SetFileInformationByHandle(Handle,
FileAllocationInfo, &AllocationInfo, sizeof AllocationInfo))
return FspNtStatusFromWin32(GetLastError());
return GetFileInfoInternal(Handle, FileInfo);
}
static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName, ULONG Flags)
{
HANDLE Handle = HandleFromContext(FileContext);
if (Flags & FspCleanupDelete)
{
CloseHandle(Handle);
/* this will make all future uses of Handle to fail with STATUS_INVALID_HANDLE */
HandleFromContext(FileContext) = INVALID_HANDLE_VALUE;
}
}
static VOID Close(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext0)
{
PTFS_FILE_CONTEXT *FileContext = FileContext0;
HANDLE Handle = HandleFromContext(FileContext);
CloseHandle(Handle);
FspFileSystemDeleteDirectoryBuffer(&FileContext->DirBuffer);
free(FileContext);
}
static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
PULONG PBytesTransferred)
{
HANDLE Handle = HandleFromContext(FileContext);
OVERLAPPED Overlapped = { 0 };
Overlapped.Offset = (DWORD)Offset;
Overlapped.OffsetHigh = (DWORD)(Offset >> 32);
if (!ReadFile(Handle, Buffer, Length, PBytesTransferred, &Overlapped))
return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS;
}
static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length,
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo)
{
HANDLE Handle = HandleFromContext(FileContext);
LARGE_INTEGER FileSize;
OVERLAPPED Overlapped = { 0 };
if (ConstrainedIo)
{
if (!GetFileSizeEx(Handle, &FileSize))
return FspNtStatusFromWin32(GetLastError());
if (Offset >= (UINT64)FileSize.QuadPart)
return STATUS_SUCCESS;
if (Offset + Length > (UINT64)FileSize.QuadPart)
Length = (ULONG)((UINT64)FileSize.QuadPart - Offset);
}
Overlapped.Offset = (DWORD)Offset;
Overlapped.OffsetHigh = (DWORD)(Offset >> 32);
if (!WriteFile(Handle, Buffer, Length, PBytesTransferred, &Overlapped))
return FspNtStatusFromWin32(GetLastError());
return GetFileInfoInternal(Handle, FileInfo);
}
NTSTATUS Flush(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
FSP_FSCTL_FILE_INFO *FileInfo)
{
HANDLE Handle = HandleFromContext(FileContext);
/* we do not flush the whole volume, so just return SUCCESS */
if (0 == Handle)
return STATUS_SUCCESS;
if (!FlushFileBuffers(Handle))
return FspNtStatusFromWin32(GetLastError());
return GetFileInfoInternal(Handle, FileInfo);
}
static NTSTATUS GetFileInfo(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
FSP_FSCTL_FILE_INFO *FileInfo)
{
HANDLE Handle = HandleFromContext(FileContext);
return GetFileInfoInternal(Handle, FileInfo);
}
static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT32 FileAttributes,
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo)
{
HANDLE Handle = HandleFromContext(FileContext);
FILE_BASIC_INFO BasicInfo = { 0 };
if (INVALID_FILE_ATTRIBUTES == FileAttributes)
FileAttributes = 0;
else if (0 == FileAttributes)
FileAttributes = FILE_ATTRIBUTE_NORMAL;
BasicInfo.FileAttributes = FileAttributes;
BasicInfo.CreationTime.QuadPart = CreationTime;
BasicInfo.LastAccessTime.QuadPart = LastAccessTime;
BasicInfo.LastWriteTime.QuadPart = LastWriteTime;
//BasicInfo.ChangeTime = ChangeTime;
if (!SetFileInformationByHandle(Handle,
FileBasicInfo, &BasicInfo, sizeof BasicInfo))
return FspNtStatusFromWin32(GetLastError());
return GetFileInfoInternal(Handle, FileInfo);
}
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
HANDLE Handle = HandleFromContext(FileContext);
FILE_ALLOCATION_INFO AllocationInfo;
FILE_END_OF_FILE_INFO EndOfFileInfo;
if (SetAllocationSize)
{
/*
* This file system does not maintain AllocationSize, although NTFS clearly can.
* However it must always be FileSize <= AllocationSize and NTFS will make sure
* to truncate the FileSize if it sees an AllocationSize < FileSize.
*
* If OTOH a very large AllocationSize is passed, the call below will increase
* the AllocationSize of the underlying file, although our file system does not
* expose this fact. This AllocationSize is only temporary as NTFS will reset
* the AllocationSize of the underlying file when it is closed.
*/
AllocationInfo.AllocationSize.QuadPart = NewSize;
if (!SetFileInformationByHandle(Handle,
FileAllocationInfo, &AllocationInfo, sizeof AllocationInfo))
return FspNtStatusFromWin32(GetLastError());
}
else
{
EndOfFileInfo.EndOfFile.QuadPart = NewSize;
if (!SetFileInformationByHandle(Handle,
FileEndOfFileInfo, &EndOfFileInfo, sizeof EndOfFileInfo))
return FspNtStatusFromWin32(GetLastError());
}
return GetFileInfoInternal(Handle, FileInfo);
}
static NTSTATUS CanDelete(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName)
{
HANDLE Handle = HandleFromContext(FileContext);
FILE_DISPOSITION_INFO DispositionInfo;
DispositionInfo.DeleteFile = TRUE;
if (!SetFileInformationByHandle(Handle,
FileDispositionInfo, &DispositionInfo, sizeof DispositionInfo))
return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS;
}
static NTSTATUS Rename(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists)
{
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
WCHAR FullPath[FULLPATH_SIZE], NewFullPath[FULLPATH_SIZE];
if (!ConcatPath(Ptfs, FileName, FullPath))
return STATUS_OBJECT_NAME_INVALID;
if (!ConcatPath(Ptfs, NewFileName, NewFullPath))
return STATUS_OBJECT_NAME_INVALID;
if (!MoveFileExW(FullPath, NewFullPath, ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0))
return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS;
}
static NTSTATUS GetSecurity(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize)
{
HANDLE Handle = HandleFromContext(FileContext);
DWORD SecurityDescriptorSizeNeeded;
if (!GetKernelObjectSecurity(Handle,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
SecurityDescriptor, (DWORD)*PSecurityDescriptorSize, &SecurityDescriptorSizeNeeded))
{
*PSecurityDescriptorSize = SecurityDescriptorSizeNeeded;
return FspNtStatusFromWin32(GetLastError());
}
*PSecurityDescriptorSize = SecurityDescriptorSizeNeeded;
return STATUS_SUCCESS;
}
static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext,
SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor)
{
HANDLE Handle = HandleFromContext(FileContext);
if (!SetKernelObjectSecurity(Handle, SecurityInformation, ModificationDescriptor))
return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS;
}
static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext0, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG BufferLength, PULONG PBytesTransferred)
{
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
PTFS_FILE_CONTEXT *FileContext = FileContext0;
HANDLE Handle = HandleFromContext(FileContext);
WCHAR FullPath[FULLPATH_SIZE];
ULONG Length, PatternLength;
HANDLE FindHandle;
WIN32_FIND_DATAW FindData;
union
{
UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + MAX_PATH * sizeof(WCHAR)];
FSP_FSCTL_DIR_INFO D;
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D;
NTSTATUS DirBufferResult;
DirBufferResult = STATUS_SUCCESS;
if (FspFileSystemAcquireDirectoryBuffer(&FileContext->DirBuffer, 0 == Marker, &DirBufferResult))
{
if (0 == Pattern)
Pattern = L"*";
PatternLength = (ULONG)wcslen(Pattern);
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
if (0 == Length)
return FspNtStatusFromWin32(GetLastError());
if (Length + 1 + PatternLength >= FULLPATH_SIZE)
return STATUS_OBJECT_NAME_INVALID;
if (L'\\' != FullPath[Length - 1])
FullPath[Length++] = L'\\';
memcpy(FullPath + Length, Pattern, PatternLength * sizeof(WCHAR));
FullPath[Length + PatternLength] = L'\0';
FindHandle = FindFirstFileW(FullPath, &FindData);
if (INVALID_HANDLE_VALUE != FindHandle)
{
do
{
memset(DirInfo, 0, sizeof *DirInfo);
Length = (ULONG)wcslen(FindData.cFileName);
DirInfo->Size = (UINT16)(FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + Length * sizeof(WCHAR));
DirInfo->FileInfo.FileAttributes = FindData.dwFileAttributes;
DirInfo->FileInfo.ReparseTag = 0;
DirInfo->FileInfo.FileSize =
((UINT64)FindData.nFileSizeHigh << 32) | (UINT64)FindData.nFileSizeLow;
DirInfo->FileInfo.AllocationSize = (DirInfo->FileInfo.FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
DirInfo->FileInfo.CreationTime = ((PLARGE_INTEGER)&FindData.ftCreationTime)->QuadPart;
DirInfo->FileInfo.LastAccessTime = ((PLARGE_INTEGER)&FindData.ftLastAccessTime)->QuadPart;
DirInfo->FileInfo.LastWriteTime = ((PLARGE_INTEGER)&FindData.ftLastWriteTime)->QuadPart;
DirInfo->FileInfo.ChangeTime = DirInfo->FileInfo.LastWriteTime;
DirInfo->FileInfo.IndexNumber = 0;
DirInfo->FileInfo.HardLinks = 0;
memcpy(DirInfo->FileNameBuf, FindData.cFileName, Length * sizeof(WCHAR));
if (!FspFileSystemFillDirectoryBuffer(&FileContext->DirBuffer, DirInfo, &DirBufferResult))
break;
} while (FindNextFileW(FindHandle, &FindData));
FindClose(FindHandle);
}
FspFileSystemReleaseDirectoryBuffer(&FileContext->DirBuffer);
}
if (!NT_SUCCESS(DirBufferResult))
return DirBufferResult;
FspFileSystemReadDirectoryBuffer(&FileContext->DirBuffer,
Marker, Buffer, BufferLength, PBytesTransferred);
return STATUS_SUCCESS;
}
static FSP_FILE_SYSTEM_INTERFACE PtfsInterface =
{
GetVolumeInfo,
SetVolumeLabel_,
GetSecurityByName,
Create,
Open,
Overwrite,
Cleanup,
Close,
Read,
Write,
Flush,
GetFileInfo,
SetBasicInfo,
SetFileSize,
CanDelete,
Rename,
GetSecurity,
SetSecurity,
ReadDirectory,
};
static VOID PtfsDelete(PTFS *Ptfs);
static NTSTATUS PtfsCreate(PWSTR Path, PWSTR VolumePrefix, PWSTR MountPoint, UINT32 DebugFlags,
PTFS **PPtfs)
{
WCHAR FullPath[MAX_PATH];
ULONG Length;
HANDLE Handle;
FILETIME CreationTime;
DWORD LastError;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
PTFS *Ptfs = 0;
NTSTATUS Result;
*PPtfs = 0;
Handle = CreateFileW(
Path, FILE_READ_ATTRIBUTES, 0, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE == Handle)
return FspNtStatusFromWin32(GetLastError());
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
if (0 == Length)
{
LastError = GetLastError();
CloseHandle(Handle);
return FspNtStatusFromWin32(LastError);
}
if (L'\\' == FullPath[Length - 1])
FullPath[--Length] = L'\0';
if (!GetFileTime(Handle, &CreationTime, 0, 0))
{
LastError = GetLastError();
CloseHandle(Handle);
return FspNtStatusFromWin32(LastError);
}
CloseHandle(Handle);
/* from now on we must goto exit on failure */
Ptfs = malloc(sizeof *Ptfs);
if (0 == Ptfs)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memset(Ptfs, 0, sizeof *Ptfs);
Length = (Length + 1) * sizeof(WCHAR);
Ptfs->Path = malloc(Length);
if (0 == Ptfs->Path)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memcpy(Ptfs->Path, FullPath, Length);
memset(&VolumeParams, 0, sizeof VolumeParams);
VolumeParams.SectorSize = ALLOCATION_UNIT;
VolumeParams.SectorsPerAllocationUnit = 1;
VolumeParams.VolumeCreationTime = ((PLARGE_INTEGER)&CreationTime)->QuadPart;
VolumeParams.VolumeSerialNumber = 0;
VolumeParams.FileInfoTimeout = 1000;
VolumeParams.CaseSensitiveSearch = 0;
VolumeParams.CasePreservedNames = 1;
VolumeParams.UnicodeOnDisk = 1;
VolumeParams.PersistentAcls = 1;
VolumeParams.PostCleanupWhenModifiedOnly = 1;
VolumeParams.PassQueryDirectoryPattern = 1;
VolumeParams.UmFileContextIsUserContext2 = 1;
if (0 != VolumePrefix)
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),
L"" PROGNAME);
Result = FspFileSystemCreate(
VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
&VolumeParams,
&PtfsInterface,
&Ptfs->FileSystem);
if (!NT_SUCCESS(Result))
goto exit;
Ptfs->FileSystem->UserContext = Ptfs;
Result = FspFileSystemSetMountPoint(Ptfs->FileSystem, MountPoint);
if (!NT_SUCCESS(Result))
goto exit;
FspFileSystemSetDebugLog(Ptfs->FileSystem, DebugFlags);
Result = STATUS_SUCCESS;
exit:
if (NT_SUCCESS(Result))
*PPtfs = Ptfs;
else if (0 != Ptfs)
PtfsDelete(Ptfs);
return Result;
}
static VOID PtfsDelete(PTFS *Ptfs)
{
if (0 != Ptfs->FileSystem)
FspFileSystemDelete(Ptfs->FileSystem);
if (0 != Ptfs->Path)
free(Ptfs->Path);
free(Ptfs);
}
static NTSTATUS EnableBackupRestorePrivileges(VOID)
{
union
{
TOKEN_PRIVILEGES P;
UINT8 B[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
} Privileges;
HANDLE Token;
Privileges.P.PrivilegeCount = 2;
Privileges.P.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
Privileges.P.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValueW(0, SE_BACKUP_NAME, &Privileges.P.Privileges[0].Luid) ||
!LookupPrivilegeValueW(0, SE_RESTORE_NAME, &Privileges.P.Privileges[1].Luid))
return FspNtStatusFromWin32(GetLastError());
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token))
return FspNtStatusFromWin32(GetLastError());
if (!AdjustTokenPrivileges(Token, FALSE, &Privileges.P, 0, 0, 0))
{
CloseHandle(Token);
return FspNtStatusFromWin32(GetLastError());
}
CloseHandle(Token);
return STATUS_SUCCESS;
}
static ULONG wcstol_deflt(wchar_t *w, ULONG deflt)
{
wchar_t *endp;
ULONG ul = wcstol(w, &endp, 0);
return L'\0' != w[0] && L'\0' == *endp ? ul : deflt;
}
static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
{
#define argtos(v) if (arge > ++argp) v = *argp; else goto usage
#define argtol(v) if (arge > ++argp) v = wcstol_deflt(*argp, v); else goto usage
wchar_t **argp, **arge;
PWSTR DebugLogFile = 0;
ULONG DebugFlags = 0;
PWSTR VolumePrefix = 0;
PWSTR PassThrough = 0;
PWSTR MountPoint = 0;
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
WCHAR PassThroughBuf[MAX_PATH];
PTFS *Ptfs = 0;
NTSTATUS Result;
for (argp = argv + 1, arge = argv + argc; arge > argp; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
goto usage;
case L'd':
argtol(DebugFlags);
break;
case L'D':
argtos(DebugLogFile);
break;
case L'm':
argtos(MountPoint);
break;
case L'p':
argtos(PassThrough);
break;
case L'u':
argtos(VolumePrefix);
break;
default:
goto usage;
}
}
if (arge > argp)
goto usage;
if (0 == PassThrough && 0 != VolumePrefix)
{
PWSTR P;
P = wcschr(VolumePrefix, L'\\');
if (0 != P && L'\\' != P[1])
{
P = wcschr(P + 1, L'\\');
if (0 != P &&
(
(L'A' <= P[1] && P[1] <= L'Z') ||
(L'a' <= P[1] && P[1] <= L'z')
) &&
L'$' == P[2])
{
StringCbPrintf(PassThroughBuf, sizeof PassThroughBuf, L"%c:%s", P[1], P + 3);
PassThrough = PassThroughBuf;
}
}
}
if (0 == PassThrough || 0 == MountPoint)
goto usage;
EnableBackupRestorePrivileges();
if (0 != DebugLogFile)
{
if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_OUTPUT_HANDLE);
else
DebugLogHandle = CreateFileW(
DebugLogFile,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == DebugLogHandle)
{
fail(L"cannot open debug log file");
goto usage;
}
FspDebugLogSetHandle(DebugLogHandle);
}
Result = PtfsCreate(PassThrough, VolumePrefix, MountPoint, DebugFlags, &Ptfs);
if (!NT_SUCCESS(Result))
{
fail(L"cannot create file system");
goto exit;
}
Result = FspFileSystemStartDispatcher(Ptfs->FileSystem, 0);
if (!NT_SUCCESS(Result))
{
fail(L"cannot start file system");
goto exit;
}
MountPoint = FspFileSystemMountPoint(Ptfs->FileSystem);
info(L"%s%s%s -p %s -m %s",
L"" PROGNAME,
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"",
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"",
PassThrough,
MountPoint);
Service->UserContext = Ptfs;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && 0 != Ptfs)
PtfsDelete(Ptfs);
return Result;
usage:
static wchar_t usage[] = L""
"usage: %s OPTIONS\n"
"\n"
"options:\n"
" -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stdout]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -p Directory [directory to expose as pass through file system]\n"
" -m MountPoint [X:|*|directory]\n";
fail(usage, L"" PROGNAME);
return STATUS_UNSUCCESSFUL;
#undef argtos
#undef argtol
}
static NTSTATUS SvcStop(FSP_SERVICE *Service)
{
PTFS *Ptfs = Service->UserContext;
FspFileSystemStopDispatcher(Ptfs->FileSystem);
PtfsDelete(Ptfs);
return STATUS_SUCCESS;
}
int wmain(int argc, wchar_t **argv)
{
if (!NT_SUCCESS(FspLoad(0)))
return ERROR_DELAY_LOAD_FAILED;
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
}

View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passthrough", "passthrough.vcxproj", "{9E0E5997-7316-4818-A130-00B3AF1AD354}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Debug|x64.ActiveCfg = Debug|x64
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Debug|x64.Build.0 = Debug|x64
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Debug|x86.ActiveCfg = Debug|Win32
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Debug|x86.Build.0 = Debug|Win32
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Release|x64.ActiveCfg = Release|x64
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Release|x64.Build.0 = Release|x64
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Release|x86.ActiveCfg = Release|Win32
{9E0E5997-7316-4818-A130-00B3AF1AD354}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="passthrough.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9E0E5997-7316-4818-A130-00B3AF1AD354}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>passthrough</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="passthrough.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,322 @@
/**
* @file dirbuf-test.c
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <winfsp/winfsp.h>
#include <tlib/testsuite.h>
#include <time.h>
#include "winfsp-tests.h"
static void dirbuf_empty_test(void)
{
PVOID DirBuffer = 0;
NTSTATUS Result;
BOOLEAN Success;
UINT8 Buffer[64];
ULONG BytesTransferred;
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
ASSERT(sizeof(UINT16) == BytesTransferred);
Result = STATUS_UNSUCCESSFUL;
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
ASSERT(sizeof(UINT16) == BytesTransferred);
Result = STATUS_UNSUCCESSFUL;
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
ASSERT(!Success);
ASSERT(STATUS_SUCCESS == Result);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
ASSERT(sizeof(UINT16) == BytesTransferred);
Result = STATUS_UNSUCCESSFUL;
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, TRUE, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
ASSERT(sizeof(UINT16) == BytesTransferred);
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
}
static void dirbuf_dots_test(void)
{
PVOID DirBuffer = 0;
NTSTATUS Result;
BOOLEAN Success;
union
{
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + MAX_PATH * sizeof(WCHAR)];
FSP_FSCTL_DIR_INFO D;
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D, *DirInfoEnd;
UINT8 Buffer[1024];
ULONG Length, BytesTransferred;
WCHAR CurrFileName[MAX_PATH];
ULONG N;
Length = sizeof Buffer;
Result = STATUS_UNSUCCESSFUL;
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + 1 * sizeof(WCHAR));
DirInfo->FileNameBuf[0] = L'.';
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + 1 * sizeof(WCHAR));
DirInfo->FileNameBuf[0] = L' ';
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + 2 * sizeof(WCHAR));
DirInfo->FileNameBuf[0] = L'.';
DirInfo->FileNameBuf[1] = L'.';
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, Length, &BytesTransferred);
N = 0;
for (
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
{
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
if (0 == N)
ASSERT(0 == wcscmp(CurrFileName, L"."));
else if (1 == N)
ASSERT(0 == wcscmp(CurrFileName, L".."));
else if (2 == N)
ASSERT(0 == wcscmp(CurrFileName, L" "));
}
ASSERT(DirInfoEnd > DirInfo);
ASSERT(0 == DirInfo->Size);
ASSERT(N == 3);
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
}
static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
{
PVOID DirBuffer = 0;
NTSTATUS Result;
BOOLEAN Success;
union
{
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + MAX_PATH * sizeof(WCHAR)];
FSP_FSCTL_DIR_INFO D;
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D, *DirInfoEnd;
PUINT8 Buffer;
ULONG Length, BytesTransferred;
WCHAR CurrFileName[MAX_PATH], PrevFileName[MAX_PATH];
ULONG DotIndex = Count / 3, DotDotIndex = Count / 3 * 2;
WCHAR Marker[MAX_PATH];
ULONG N, MarkerIndex, MarkerLength;
srand(seed);
Length = Count * FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof DirInfoBuf) + sizeof(UINT16);
Buffer = malloc(Length);
ASSERT(0 != Buffer);
Result = STATUS_UNSUCCESSFUL;
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
for (ULONG I = 0; Count > I; I++)
{
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
if (I == DotIndex)
{
N = 1;
DirInfo->FileNameBuf[0] = L'.';
}
else if (I == DotDotIndex)
{
N = 2;
DirInfo->FileNameBuf[0] = L'.';
DirInfo->FileNameBuf[1] = L'.';
}
else
{
N = 24 + rand() % (32 - 24);
for (ULONG J = 0; N > J; J++)
DirInfo->FileNameBuf[J] = 'A' + rand() % 26;
}
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + N * sizeof(WCHAR));
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
}
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
MarkerIndex = rand() % Count;
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, Length, &BytesTransferred);
N = 0;
PrevFileName[0] = L'\0';
for (
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
{
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
if (0 == N)
ASSERT(0 == wcscmp(CurrFileName, L"."));
else if (1 == N)
ASSERT(0 == wcscmp(CurrFileName, L".."));
else
ASSERT(0 != wcscmp(CurrFileName, L".") && 0 != wcscmp(CurrFileName, L".."));
//ASSERT(wcscmp(PrevFileName, CurrFileName) <= 0);
/* filenames are random enought that should not happen in practice */
ASSERT(wcscmp(PrevFileName, CurrFileName) < 0);
memcpy(PrevFileName, CurrFileName, sizeof CurrFileName);
if (N == MarkerIndex)
{
memcpy(Marker, CurrFileName, sizeof CurrFileName);
MarkerLength = (ULONG)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size) - Buffer);
}
}
ASSERT(DirInfoEnd > DirInfo);
ASSERT(0 == DirInfo->Size);
ASSERT(N == Count);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, Marker, Buffer, Length, &BytesTransferred);
N = 0;
PrevFileName[0] = L'\0';
for (
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
{
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
ASSERT(0 != wcscmp(CurrFileName, Marker));
//ASSERT(wcscmp(PrevFileName, CurrFileName) <= 0);
/* filenames are random enought that should not happen in practice */
ASSERT(wcscmp(PrevFileName, CurrFileName) < 0);
memcpy(PrevFileName, CurrFileName, sizeof CurrFileName);
}
ASSERT(DirInfoEnd > DirInfo);
ASSERT(0 == DirInfo->Size);
ASSERT(N == Count - MarkerIndex - 1);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, MarkerLength, &BytesTransferred);
N = 0;
PrevFileName[0] = L'\0';
for (
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
{
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
if (N == MarkerIndex)
ASSERT(0 == wcscmp(CurrFileName, Marker));
else
ASSERT(0 != wcscmp(CurrFileName, Marker));
//ASSERT(wcscmp(PrevFileName, CurrFileName) <= 0);
/* filenames are random enought that should not happen in practice */
ASSERT(wcscmp(PrevFileName, CurrFileName) < 0);
memcpy(PrevFileName, CurrFileName, sizeof CurrFileName);
}
ASSERT(DirInfoEnd <= DirInfo);
ASSERT(N == MarkerIndex + 1);
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
free(Buffer);
}
static void dirbuf_fill_test(void)
{
unsigned seed = (unsigned)time(0);
dirbuf_fill_dotest(1485473509, 10);
for (ULONG I = 0; 10000 > I; I++)
dirbuf_fill_dotest(seed + I, 10);
for (ULONG I = 0; 1000 > I; I++)
dirbuf_fill_dotest(seed + I, 100);
for (ULONG I = 0; 100 > I; I++)
dirbuf_fill_dotest(seed + I, 1000);
for (ULONG I = 0; 10 > I; I++)
dirbuf_fill_dotest(seed + I, 10000);
}
void dirbuf_tests(void)
{
TEST(dirbuf_empty_test);
TEST(dirbuf_dots_test);
TEST(dirbuf_fill_test);
}

View File

@ -272,6 +272,68 @@ void mount_volume_transact_test(void)
mount_volume_transact_dotest(L"WinFsp.Net", L"\\\\winfsp-tests\\share");
}
void mount_preflight_dotest(PWSTR DeviceName)
{
NTSTATUS Result;
WCHAR MountPoint[MAX_PATH];
WCHAR DirBuf[MAX_PATH];
DWORD Drives;
WCHAR Drive;
BOOL Success;
MountPoint[0] = L'C';
MountPoint[1] = L':';
MountPoint[2] = L'\0';
GetTestDirectory(DirBuf);
Drives = GetLogicalDrives();
ASSERT(0 != Drives);
Result = FspFileSystemPreflight(DeviceName, 0);
ASSERT(STATUS_SUCCESS == Result);
for (Drive = 'Z'; 'A' <= Drive; Drive--)
if (0 == (Drives & (1 << (Drive - 'A'))))
break;
ASSERT('A' <= Drive);
MountPoint[0] = Drive;
Result = FspFileSystemPreflight(DeviceName, MountPoint);
ASSERT(STATUS_SUCCESS == Result);
for (Drive = 'Z'; 'A' <= Drive; Drive--)
if (0 != (Drives & (1 << (Drive - 'A'))))
break;
ASSERT('A' <= Drive);
MountPoint[0] = Drive;
Result = FspFileSystemPreflight(DeviceName, MountPoint);
ASSERT(STATUS_OBJECT_NAME_COLLISION == Result);
StringCbPrintfW(MountPoint, sizeof MountPoint, L"%s\\dir1", DirBuf);
Result = FspFileSystemPreflight(DeviceName, MountPoint);
ASSERT(STATUS_SUCCESS == Result);
Success = CreateDirectoryW(MountPoint, 0);
ASSERT(Success);
Result = FspFileSystemPreflight(DeviceName, MountPoint);
ASSERT(STATUS_OBJECT_NAME_COLLISION == Result);
Success = RemoveDirectoryW(MountPoint);
ASSERT(Success);
}
void mount_preflight_test(void)
{
if (WinFspDiskTests)
mount_preflight_dotest(L"WinFsp.Disk");
if (WinFspNetTests)
mount_preflight_dotest(L"WinFsp.Net");
}
void mount_tests(void)
{
if (NtfsTests || OptOplock)
@ -282,4 +344,5 @@ void mount_tests(void)
TEST_OPT(mount_create_volume_test);
TEST_OPT(mount_volume_cancel_test);
TEST_OPT(mount_volume_transact_test);
TEST_OPT(mount_preflight_test);
}

View File

@ -29,6 +29,7 @@ int WinFspDiskTests = 1;
int WinFspNetTests = 1;
BOOLEAN OptResilient = FALSE;
BOOLEAN OptCaseInsensitiveCmp = FALSE;
BOOLEAN OptCaseInsensitive = FALSE;
BOOLEAN OptCaseRandomize = FALSE;
WCHAR OptOplock = 0;
@ -53,7 +54,7 @@ int mywcscmp(PWSTR a, int alen, PWSTR b, int blen)
len = alen < blen ? alen : blen;
/* we should still be in the C locale */
if (OptCaseRandomize)
if (OptCaseInsensitiveCmp)
res = _wcsnicmp(a, b, len);
else
res = wcsncmp(a, b, len);
@ -182,6 +183,7 @@ int main(int argc, char *argv[])
TESTSUITE(posix_tests);
TESTSUITE(eventlog_tests);
TESTSUITE(path_tests);
TESTSUITE(dirbuf_tests);
TESTSUITE(mount_tests);
TESTSUITE(timeout_tests);
TESTSUITE(memfs_tests);
@ -217,6 +219,11 @@ int main(int argc, char *argv[])
OptResilient = TRUE;
rmarg(argv, argc, argi);
}
else if (0 == strcmp("--case-insensitive-cmp", a))
{
OptCaseInsensitiveCmp = TRUE;
rmarg(argv, argc, argi);
}
else if (0 == strcmp("--case-insensitive", a))
{
OptCaseInsensitive = TRUE;
@ -226,6 +233,7 @@ int main(int argc, char *argv[])
{
OptCaseRandomize = TRUE;
OptCaseInsensitive = TRUE;
OptCaseInsensitiveCmp = TRUE;
rmarg(argv, argc, argi);
}
else if (0 == strcmp("--oplock=batch", a))
@ -287,6 +295,20 @@ int main(int argc, char *argv[])
WinFspNetTests = 0;
}
}
else if (0 == strncmp("--share-prefix=", a, sizeof "--share-prefix=" - 1))
{
/* hack to allow name queries on network file systems with mapped drives */
WCHAR SharePrefixBuf[MAX_PATH];
if (0 != MultiByteToWideChar(CP_UTF8, 0,
a + sizeof "--share-prefix=" - 1, -1, SharePrefixBuf, MAX_PATH))
{
rmarg(argv, argc, argi);
OptSharePrefixLength = (ULONG)(wcslen(SharePrefixBuf) * sizeof(WCHAR));
}
}
else if (0 == strcmp("--no-traverse", a))
{
if (LookupPrivilegeValueW(0, SE_CHANGE_NOTIFY_NAME, &OptNoTraverseLuid) &&

View File

@ -138,6 +138,7 @@ extern int WinFspDiskTests;
extern int WinFspNetTests;
extern BOOLEAN OptResilient;
extern BOOLEAN OptCaseInsensitiveCmp;
extern BOOLEAN OptCaseInsensitive;
extern BOOLEAN OptCaseRandomize;
extern WCHAR OptOplock;