Compare commits
90 Commits
v1.0RC1
...
GPLv3-FLOS
Author | SHA1 | Date | |
---|---|---|---|
9c4b73dac1 | |||
9ecfc64178 | |||
fbe46d8c81 | |||
2a12ed490d | |||
c6d9e68c3f | |||
bfc41127d0 | |||
6e70500afc | |||
dca3cb93f3 | |||
2f0061b4ba | |||
3fcef3b0fa | |||
6a0574e309 | |||
0c945b67f3 | |||
25b3e111fa | |||
09101129a3 | |||
3700b375a7 | |||
22fccdb575 | |||
c4932f7c7e | |||
303cadb55d | |||
5617d09edc | |||
eefaad241d | |||
11dce32baa | |||
3b8396dc27 | |||
da7082030a | |||
7425eba8af | |||
acf6ce1008 | |||
06f6c192ed | |||
b7a06c7046 | |||
edb675d2d4 | |||
9533815931 | |||
fe74fc4013 | |||
5bd6c1a122 | |||
7b15d32c33 | |||
c186289672 | |||
ff649e05c5 | |||
9a9d3cd4e8 | |||
d1bb65a998 | |||
178200fd63 | |||
396d9d97d2 | |||
1d35069aab | |||
4421c82ce0 | |||
36f0978971 | |||
dae4bad732 | |||
75744571ff | |||
0494726f52 | |||
a964ab1b73 | |||
796010c9fe | |||
dc343ecbe5 | |||
706fa2cc07 | |||
c0aaebd0a5 | |||
9c2b4e5631 | |||
206b85c278 | |||
075d1821a2 | |||
c252382204 | |||
a91e5b01ab | |||
473914d45f | |||
e12e3630bb | |||
960c627924 | |||
f97ef5704f | |||
41605a3d5a | |||
e4f0406c4f | |||
b5bf84b618 | |||
3c340345c0 | |||
63c23f382b | |||
de5ef0c81d | |||
7288605f65 | |||
55a7864173 | |||
4fe72ab332 | |||
76a2926116 | |||
7843c73d34 | |||
ebad86387c | |||
5475c414b3 | |||
e3e111ab27 | |||
9cd6710438 | |||
a5f8736b1e | |||
2ced698256 | |||
53a4bdc478 | |||
eea92e89ef | |||
d519145f61 | |||
2809f56217 | |||
8cb76783ad | |||
117ab9c3e4 | |||
61a001baf1 | |||
d0c700eb0f | |||
b774aea4f4 | |||
f8e4c1bbc4 | |||
3bbff30f14 | |||
2fe4e18d9c | |||
b65322c2ac | |||
7764663386 | |||
c6ae62f301 |
@ -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:
|
||||
|
31
License.txt
@ -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
|
||||
|
@ -2,6 +2,11 @@
|
||||
|
||||

|
||||
|
||||
|
||||
<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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
<MyCanonicalVersion>1.0</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2017 RC1</MyProductVersion>
|
||||
<MyProductVersion>2017 RC2</MyProductVersion>
|
||||
<MyProductStage>RC</MyProductStage>
|
||||
|
||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||
|
@ -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) >$(OutDir)fuse-$(PlatformTarget).pc
|
||||
copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(PlatformTarget).pc >nul</Command>
|
||||
|
@ -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>
|
||||
|
@ -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
BIN
doc/WinFsp-Tutorial/EntryExit.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
doc/WinFsp-Tutorial/Explorer.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
doc/WinFsp-Tutorial/FirstRun.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
doc/WinFsp-Tutorial/Installer.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
doc/WinFsp-Tutorial/MissingDll.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
doc/WinFsp-Tutorial/NetUse.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/WinFsp-Tutorial/NewProject.png
Normal file
After Width: | Height: | Size: 20 KiB |
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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);
|
||||
}
|
42
src/dll/fs.c
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
58
src/dll/np.c
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
138
src/sys/dirctl.c
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
@ -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
@ -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
|
@ -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:" ^
|
||||
|
@ -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
@ -0,0 +1,7 @@
|
||||
build
|
||||
*.ncb
|
||||
*.suo
|
||||
*.vcproj.*
|
||||
*.vcxproj.user
|
||||
*.exe
|
||||
*.install
|
18
tst/passthrough-fuse/Makefile
Normal 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`
|
7
tst/passthrough-fuse/README.md
Normal 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`).
|
327
tst/passthrough-fuse/passthrough-fuse.c
Normal 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);
|
||||
}
|
28
tst/passthrough-fuse/passthrough-fuse.sln
Normal 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
|
190
tst/passthrough-fuse/passthrough-fuse.vcxproj
Normal 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>
|
22
tst/passthrough-fuse/passthrough-fuse.vcxproj.filters
Normal 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>
|
529
tst/passthrough-fuse/winposix.c
Normal 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);
|
||||
}
|
71
tst/passthrough-fuse/winposix.h
Normal 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
@ -0,0 +1,5 @@
|
||||
build
|
||||
*.ncb
|
||||
*.suo
|
||||
*.vcproj.*
|
||||
*.vcxproj.user
|
930
tst/passthrough/passthrough.c
Normal 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);
|
||||
}
|
28
tst/passthrough/passthrough.sln
Normal 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
|
182
tst/passthrough/passthrough.vcxproj
Normal 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>
|
14
tst/passthrough/passthrough.vcxproj.filters
Normal 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>
|
322
tst/winfsp-tests/dirbuf-test.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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) &&
|
||||
|
@ -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;
|
||||
|