mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
53 Commits
Author | SHA1 | Date | |
---|---|---|---|
2a3eabfab2 | |||
35255526d3 | |||
b2e474658d | |||
a2ec40008f | |||
f3819ba839 | |||
ead599e337 | |||
eb88f25f40 | |||
c2b066a054 | |||
266e0f4bab | |||
d02030897d | |||
c87ff75b8f | |||
2ca33665ef | |||
391dcf8a21 | |||
69d68eb22f | |||
d58f4b84a5 | |||
61935e4671 | |||
41838627c0 | |||
0b67329fc2 | |||
5c962c8fc5 | |||
a9080208d9 | |||
3cc9697248 | |||
9f45d513ca | |||
77349c1330 | |||
7c11a45e6e | |||
48ad297df1 | |||
3d2de57e9d | |||
658d873efb | |||
efc93cacd3 | |||
41b54ef57a | |||
fd662ee848 | |||
895bf67691 | |||
e06fe4153d | |||
9f2fe92db7 | |||
d3f829b2df | |||
fa4651b3ce | |||
5a44e5c04a | |||
68122b5c68 | |||
b672312c79 | |||
0ab35fde1a | |||
9be2b7a2b9 | |||
39dd7662bd | |||
244afc8a3c | |||
111955db84 | |||
76ff8232bc | |||
9a3ac3c7a1 | |||
4adc0d4700 | |||
91c714dd53 | |||
11cb57a0bf | |||
045a1fa19c | |||
c9b2c0460b | |||
1468df78a2 | |||
0fb6299f17 | |||
0da43fe2d4 |
@ -1,6 +1,45 @@
|
||||
= Changelog
|
||||
|
||||
|
||||
v1.2POST1 (2017.2; issue #127)::
|
||||
|
||||
Changes since v1.1:
|
||||
|
||||
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
|
||||
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
|
||||
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
|
||||
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
|
||||
- New command line tool `fsptool` allows command line access to some WinFsp features.
|
||||
- The WinFsp launcher now passes the name of the user who launched the file system as a special parameter %U. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win. [Please note that in earlier betas the user name was passed as parameter %3; the previous method was insecure and is no longer supported.]
|
||||
- Important GitHub issues fixed: #96, #97, #103, #107, #127
|
||||
|
||||
|
||||
v1.2 (2017.2)::
|
||||
|
||||
Changes since v1.1:
|
||||
|
||||
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
|
||||
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
|
||||
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
|
||||
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
|
||||
- New command line tool `fsptool` allows command line access to some WinFsp features.
|
||||
- The WinFsp launcher now passes the name of the user who launched the file system as a special parameter %U. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win. [Please note that in earlier betas the user name was passed as parameter %3; the previous method was insecure and is no longer supported.]
|
||||
- Important GitHub issues fixed: #96, #97, #103, #107
|
||||
|
||||
|
||||
v1.2B3 (2017.2 B3)::
|
||||
|
||||
Changes since v1.1:
|
||||
|
||||
- WinFsp-FUSE now supports BSD flags (Windows file attributes) during `getattr` and `fgetattr`. It also adds the `chflags` operation. BSD flags support requires use of the `FSP_FUSE_CAP_STAT_EX` capability and the new `struct fuse_stat_ex` which includes an `st_flags` field. If the preprocessor macro `FSP_FUSE_USE_STAT_EX` is defined before inclusion of `<fuse.h>` then `struct fuse_stat` will also be defined to include the `st_flags` field.
|
||||
- WinFsp-FUSE also adds the following OSXFUSE operations: `setcrtime`, `setchgtime`. These can be used to set the creation (birth) time and change (ctime) time of a file.
|
||||
- New `GetDirInfoByName` file system operation adds fast queries of directory info by file name rather than pattern [e.g. `FindFirstFileW(L"foobar", FindData)`]. Tests with fsbench showed that such queries are sped up by an order of magnitude when using `GetDirInfoByName` in MEMFS. Case-sensitive FUSE file systems get this optimization for free. The .NET layer also adds `GetDirInfoByName`.
|
||||
- New `FspFileSystemOperationProcessId` API adds support for getting the originating process ID (PID) during `Create`, `Open` and `Rename` calls. FUSE file systems can now access `fuse_context::pid`. The .NET layer also adds `GetOperationProcessId`.
|
||||
- New command line tool `fsptool` allows command line access to some WinFsp features.
|
||||
- The WinFsp launcher now passes the username of the user who launched the file system as parameter %3. This is useful to file systems that use the launcher infrastructure, such as SSHFS-Win.
|
||||
- Important GitHub issues fixed: #96, #97, #103, #107
|
||||
|
||||
|
||||
v1.2B2 (2017.2 B2)::
|
||||
|
||||
Changes since v1.1:
|
||||
|
@ -55,6 +55,7 @@ CONTRIBUTOR LIST
|
||||
----------------
|
||||
|===
|
||||
|Bill Zissimopoulos |billziss at navimatics.com
|
||||
|John Oberschelp |john at oberschelp.net
|
||||
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|
||||
|Tobias Urlaub |saibotu at outlook.de
|
||||
|===
|
||||
|
32
README.md
32
README.md
@ -30,21 +30,23 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
|
||||
|
||||
The project source code is organized as follows:
|
||||
|
||||
* build/VStudio: WinFsp solution and project files.
|
||||
* doc: The WinFsp design documents and additional documentation can be found here.
|
||||
* ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||
* ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||
* inc/winfsp: Public headers for the WinFsp API.
|
||||
* inc/fuse: Public headers for the FUSE compatibility layer.
|
||||
* src/dll: Source code to the WinFsp DLL.
|
||||
* src/dll/fuse: Source code to the FUSE compatibility layer.
|
||||
* src/dotnet: Source code to the .NET layer.
|
||||
* src/launcher: Source code to the launcher service and the launchctl utility.
|
||||
* src/sys: Source code to the WinFsp FSD.
|
||||
* opt/cygfuse: Source code for the Cygwin FUSE package.
|
||||
* tst/memfs*: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet).
|
||||
* tst/passthrough*: Source code to additional example file systems.
|
||||
* tst/winfsp-tests: WinFsp test suite.
|
||||
* `build/VStudio`: WinFsp solution and project files.
|
||||
* `doc`: The WinFsp design documents and additional documentation can be found here.
|
||||
* `ext/tlib`: A small test library originally from the secfs (Secure Cloud File System) project.
|
||||
* `ext/test`: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
|
||||
* `inc/fuse`: Public headers for the FUSE compatibility layer.
|
||||
* `inc/winfsp`: Public headers for the WinFsp API.
|
||||
* `src/dll`: Source code to the WinFsp DLL.
|
||||
* `src/dll/fuse`: Source code to the FUSE compatibility layer.
|
||||
* `src/dotnet`: Source code to the .NET layer.
|
||||
* `src/fsptool`: Source code to fsptool command line utility.
|
||||
* `src/launcher`: Source code to the launcher service and the launchctl utility.
|
||||
* `src/sys`: Source code to the WinFsp FSD.
|
||||
* `opt/cygfuse`: Source code for the Cygwin FUSE package.
|
||||
* `tst/memfs*`: Source code to an example file system written in C/C++ (memfs) or C# (memfs-dotnet).
|
||||
* `tst/passthrough*`: Source code to additional example file systems.
|
||||
* `tst/winfsp-tests`: WinFsp test suite.
|
||||
* `tools`: Various tools for building and testing WinFsp.
|
||||
|
||||
## Building and Running
|
||||
|
||||
|
@ -6,10 +6,10 @@ environment:
|
||||
TESTING: Func
|
||||
- CONFIGURATION: Release
|
||||
TESTING: Func
|
||||
- CONFIGURATION: Release
|
||||
TESTING: Avast
|
||||
- CONFIGURATION: Release
|
||||
TESTING: Perf
|
||||
#- CONFIGURATION: Release
|
||||
# TESTING: Avast
|
||||
#- CONFIGURATION: Release
|
||||
# TESTING: Perf
|
||||
|
||||
install:
|
||||
- git submodule update --init --recursive
|
||||
@ -32,6 +32,7 @@ test_script:
|
||||
- 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%==Func tools\run-tests.bat %CONFIGURATION% compat
|
||||
- if %TESTING%==Avast choco install avastfreeantivirus && fltmc instances -v "C:"
|
||||
- if %TESTING%==Avast tools\run-tests.bat %CONFIGURATION% avast-tests
|
||||
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
|
||||
|
@ -310,12 +310,12 @@
|
||||
<Directory Id="OPTDIR.cygfuse" Name="cygfuse" FileSource="..\..\..\opt\cygfuse\dist">
|
||||
<Directory Id="OPTDIR.cygfuse.x64" Name="x64">
|
||||
<Component Id="C.fuse.tar.xz.x64">
|
||||
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-6.tar.xz" KeyPath="yes" />
|
||||
<File Id="FILE.fuse.tar.xz.x64" Name="fuse-2.8-7.tar.xz" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="OPTDIR.cygfuse.x86" Name="x86">
|
||||
<Component Id="C.fuse.tar.xz.x86">
|
||||
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-6.tar.xz" KeyPath="yes" />
|
||||
<File Id="FILE.fuse.tar.xz.x86" Name="fuse-2.8-7.tar.xz" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Component Id="C.fuse.install.sh">
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
<MyCanonicalVersion>1.2</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2017.2 B2</MyProductVersion>
|
||||
<MyProductStage>Beta</MyProductStage>
|
||||
<MyProductVersion>2017.2</MyProductVersion>
|
||||
<MyProductStage>Gold</MyProductStage>
|
||||
|
||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||
|
@ -28,7 +28,7 @@ if ($key.Count -eq 1) {
|
||||
-File "$file"
|
||||
}
|
||||
} elseif ($key.Count -eq 0) {
|
||||
Write-Warning "$packageName has already been uninstalled by other means."
|
||||
# Write-Warning "$packageName is not installed"
|
||||
} elseif ($key.Count -gt 1) {
|
||||
Write-Warning "Too many matching packages found! Package may not be uninstalled."
|
||||
Write-Warning "Please alert package maintainer the following packages were matched:"
|
@ -1,16 +1,14 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
$fileLocation = @(Get-ChildItem $toolsDir -filter winfsp-*.msi)[0].FullName
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
. "$toolsdir\chocolateyHelper.ps1"
|
||||
|
||||
$packageArgs = @{
|
||||
packageName = 'winfsp'
|
||||
fileType = 'msi'
|
||||
file = $fileLocation
|
||||
file = @(Get-ChildItem $toolsDir -filter winfsp-*.msi)[0].FullName
|
||||
silentArgs = "/qn /norestart INSTALLLEVEL=1000"
|
||||
validExitCodes = @(0, 3010, 1641)
|
||||
}
|
||||
|
||||
Install-ChocolateyInstallPackage @packageArgs
|
||||
|
||||
Remove-Item -Force $packageArgs.file
|
||||
|
4
build/choco/chocolateyUninstall.ps1
Normal file
4
build/choco/chocolateyUninstall.ps1
Normal file
@ -0,0 +1,4 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
. "$toolsdir\chocolateyHelper.ps1"
|
@ -50,7 +50,8 @@ To verify installation:
|
||||
<file src="LICENSE.txt" target="tools" />
|
||||
<file src="VERIFICATION.txt" target="tools" />
|
||||
<file src="chocolateyInstall.ps1" target="tools" />
|
||||
<file src="chocolateyBeforeModify.ps1" target="tools" />
|
||||
<file src="chocolateyUninstall.ps1" target="tools" />
|
||||
<file src="chocolateyHelper.ps1" target="tools" />
|
||||
<file src="winfsp-$version$.msi" target="tools" />
|
||||
</files>
|
||||
</package>
|
||||
|
@ -4,6 +4,8 @@ This document contains a list of known file systems and file system libraries th
|
||||
|
||||
== File Systems
|
||||
|
||||
- https://github.com/ihaveamac/fuse-3ds[fuse-3ds] - FUSE Filesystem Python scripts for Nintendo 3DS files
|
||||
- https://github.com/FrKaram/KS2.Drive[KS2.Drive] - Mount a webDAV/AOS server as a local drive
|
||||
- https://github.com/billziss-gh/nfs-win[nfs-win] - NFS for Windows
|
||||
- https://github.com/ncw/rclone[rclone] - rsync for cloud storage
|
||||
- https://github.com/hasse69/rar2fs[rar2fs] - FUSE file system for reading RAR archives
|
||||
|
@ -95,7 +95,7 @@ if (!Success)
|
||||
|
||||
In Release builds the +DEBUGTEST(90)+ macro will evaluate to +TRUE+ and the Cache Manager will be asked directly via +CcCanIWrite+ whether a WRITE should be deferred. In Debug builds the +DEBUGTEST(90)+ macro will evaluate to +FALSE+ sometimes (10% of the time) and the WRITE will be deferred, thus allowing us to test the retry code path.
|
||||
|
||||
== Compatibility Testing
|
||||
== NTFS Compatibility Testing
|
||||
|
||||
WinFsp allows the creation of user mode file systems that exhibit behavior similar to NTFS. This means that Windows applications that use such a file system should not be able to tell the difference between NTFS and the WinFsp-based file system. OTOH specialized applications (such as Defrag) will not work properly on WinFsp file systems.
|
||||
|
||||
@ -123,6 +123,12 @@ The goal of performance testing is to evaluate and understand how software behav
|
||||
|
||||
WinFsp uses a tool called fsbench for this purpose. Fsbench is able to test specific scenarios, for example: "how long does it take to delete 1000 files?" Fsbench has been very useful for WinFsp and has helped improve its performance: in one situation it helped identify quadratic behavior with the MEMFS ReadDirectory operation, in another situation it helped fine tune the performance of the WinFsp I/O Queue.
|
||||
|
||||
== Backwards Compatibility testing
|
||||
|
||||
As the WinFsp API's mature it is important to verify that they remain backwards compatible with existing file system binaries. For this purpose binaries that have been compiled against earlier versions of WinFsp are used to verify that they run correctly against the latest version.
|
||||
|
||||
For example, in version v1.2B3 of WinFsp an +FSP_FUSE_CAP_STAT_EX+ FUSE extension was introduced. This can change the layout of +struct fuse_stat+ and is therefore a potentially dangerous change. To test against inadvertent breakage a FUSE file system binary that was compiled against v1.2B2 is regularly used to verify backwards compatibility.
|
||||
|
||||
== Code Analysis
|
||||
|
||||
WinFsp is regularly run under the Visual Studio's Code Analyzer. Any issues found are examined and if necessary acted upon.
|
||||
|
112
inc/fuse/fuse.h
112
inc/fuse/fuse.h
@ -39,54 +39,82 @@ typedef int (*fuse_dirfil_t)(fuse_dirh_t h, const char *name,
|
||||
|
||||
struct fuse_operations
|
||||
{
|
||||
int (*getattr)(const char *path, struct fuse_stat *stbuf);
|
||||
int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
|
||||
int (*readlink)(const char *path, char *buf, size_t size);
|
||||
int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
|
||||
int (*mkdir)(const char *path, fuse_mode_t mode);
|
||||
int (*unlink)(const char *path);
|
||||
int (*rmdir)(const char *path);
|
||||
int (*symlink)(const char *dstpath, const char *srcpath);
|
||||
int (*rename)(const char *oldpath, const char *newpath);
|
||||
int (*link)(const char *srcpath, const char *dstpath);
|
||||
int (*chmod)(const char *path, fuse_mode_t mode);
|
||||
int (*chown)(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, struct fuse_utimbuf *timbuf);
|
||||
int (*open)(const char *path, struct fuse_file_info *fi);
|
||||
int (*read)(const char *path, char *buf, size_t size, fuse_off_t off,
|
||||
/* S - supported by WinFsp */
|
||||
/* S */ int (*getattr)(const char *path, struct fuse_stat *stbuf);
|
||||
/* S */ int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
|
||||
/* S */ int (*readlink)(const char *path, char *buf, size_t size);
|
||||
/* S */ int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
|
||||
/* S */ int (*mkdir)(const char *path, fuse_mode_t mode);
|
||||
/* S */ int (*unlink)(const char *path);
|
||||
/* S */ int (*rmdir)(const char *path);
|
||||
/* S */ int (*symlink)(const char *dstpath, const char *srcpath);
|
||||
/* S */ int (*rename)(const char *oldpath, const char *newpath);
|
||||
/* _ */ int (*link)(const char *srcpath, const char *dstpath);
|
||||
/* S */ int (*chmod)(const char *path, fuse_mode_t mode);
|
||||
/* S */ int (*chown)(const char *path, fuse_uid_t uid, fuse_gid_t gid);
|
||||
/* S */ int (*truncate)(const char *path, fuse_off_t size);
|
||||
/* S */ int (*utime)(const char *path, struct fuse_utimbuf *timbuf);
|
||||
/* S */ int (*open)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*read)(const char *path, char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off,
|
||||
/* S */ int (*write)(const char *path, const char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
|
||||
int (*flush)(const char *path, struct fuse_file_info *fi);
|
||||
int (*release)(const char *path, struct fuse_file_info *fi);
|
||||
int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
/* S */ int (*statfs)(const char *path, struct fuse_statvfs *stbuf);
|
||||
/* S */ int (*flush)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*release)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
/* _ */ int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
int flags);
|
||||
int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
int (*removexattr)(const char *path, const char *name);
|
||||
int (*opendir)(const char *path, struct fuse_file_info *fi);
|
||||
int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
/* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
/* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
/* _ */ int (*removexattr)(const char *path, const char *name);
|
||||
/* S */ int (*opendir)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int (*releasedir)(const char *path, struct fuse_file_info *fi);
|
||||
int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
void *(*init)(struct fuse_conn_info *conn);
|
||||
void (*destroy)(void *data);
|
||||
int (*access)(const char *path, int mask);
|
||||
int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi);
|
||||
int (*ftruncate)(const char *path, fuse_off_t off, struct fuse_file_info *fi);
|
||||
int (*fgetattr)(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi);
|
||||
int (*lock)(const char *path, struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
|
||||
int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
|
||||
int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
|
||||
unsigned int flag_nullpath_ok:1;
|
||||
unsigned int flag_reserved:31;
|
||||
int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
/* S */ int (*releasedir)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*fsyncdir)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
/* S */ void *(*init)(struct fuse_conn_info *conn);
|
||||
/* S */ void (*destroy)(void *data);
|
||||
/* _ */ int (*access)(const char *path, int mask);
|
||||
/* S */ int (*create)(const char *path, fuse_mode_t mode, struct fuse_file_info *fi);
|
||||
/* S */ int (*ftruncate)(const char *path, fuse_off_t off, struct fuse_file_info *fi);
|
||||
/* S */ int (*fgetattr)(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi);
|
||||
/* _ */ int (*lock)(const char *path,
|
||||
struct fuse_file_info *fi, int cmd, struct fuse_flock *lock);
|
||||
/* S */ int (*utimens)(const char *path, const struct fuse_timespec tv[2]);
|
||||
/* _ */ int (*bmap)(const char *path, size_t blocksize, uint64_t *idx);
|
||||
/* _ */ unsigned int flag_nullpath_ok:1;
|
||||
/* _ */ unsigned int flag_nopath:1;
|
||||
/* _ */ unsigned int flag_utime_omit_ok:1;
|
||||
/* _ */ unsigned int flag_reserved:29;
|
||||
/* _ */ int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
unsigned int flags, void *data);
|
||||
int (*poll)(const char *path, struct fuse_file_info *fi,
|
||||
/* _ */ int (*poll)(const char *path, struct fuse_file_info *fi,
|
||||
struct fuse_pollhandle *ph, unsigned *reventsp);
|
||||
/* FUSE 2.9 */
|
||||
/* _ */ int (*write_buf)(const char *path,
|
||||
struct fuse_bufvec *buf, fuse_off_t off, struct fuse_file_info *fi);
|
||||
/* _ */ int (*read_buf)(const char *path,
|
||||
struct fuse_bufvec **bufp, size_t size, fuse_off_t off, struct fuse_file_info *fi);
|
||||
/* _ */ int (*flock)(const char *path, struct fuse_file_info *, int op);
|
||||
/* _ */ int (*fallocate)(const char *path, int mode, fuse_off_t off, fuse_off_t len,
|
||||
struct fuse_file_info *fi);
|
||||
/* OSXFUSE */
|
||||
/* _ */ int (*reserved00)();
|
||||
/* _ */ int (*reserved01)();
|
||||
/* _ */ int (*reserved02)();
|
||||
/* _ */ int (*statfs_x)(const char *path, struct fuse_statfs *stbuf);
|
||||
/* _ */ int (*setvolname)(const char *volname);
|
||||
/* _ */ int (*exchange)(const char *oldpath, const char *newpath, unsigned long flags);
|
||||
/* _ */ int (*getxtimes)(const char *path,
|
||||
struct fuse_timespec *bkuptime, struct fuse_timespec *crtime);
|
||||
/* _ */ int (*setbkuptime)(const char *path, const struct fuse_timespec *tv);
|
||||
/* S */ int (*setchgtime)(const char *path, const struct fuse_timespec *tv);
|
||||
/* S */ int (*setcrtime)(const char *path, const struct fuse_timespec *tv);
|
||||
/* S */ int (*chflags)(const char *path, uint32_t flags);
|
||||
/* _ */ int (*setattr_x)(const char *path, struct fuse_setattr_x *attr);
|
||||
/* _ */ int (*fsetattr_x)(const char *path, struct fuse_setattr_x *attr,
|
||||
struct fuse_file_info *fi);
|
||||
};
|
||||
|
||||
struct fuse_context
|
||||
|
@ -49,6 +49,7 @@ extern "C" {
|
||||
|
||||
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */
|
||||
#define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */
|
||||
#define FSP_FUSE_CAP_STAT_EX (1 << 23) /* file system supports fuse_stat_ex */
|
||||
#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
|
||||
|
||||
#define FUSE_IOCTL_COMPAT (1 << 0)
|
||||
@ -56,6 +57,24 @@ extern "C" {
|
||||
#define FUSE_IOCTL_RETRY (1 << 2)
|
||||
#define FUSE_IOCTL_MAX_IOV 256
|
||||
|
||||
/* from FreeBSD */
|
||||
#define FSP_FUSE_UF_HIDDEN 0x00008000
|
||||
#define FSP_FUSE_UF_READONLY 0x00001000
|
||||
#define FSP_FUSE_UF_SYSTEM 0x00000080
|
||||
#define FSP_FUSE_UF_ARCHIVE 0x00000800
|
||||
#if !defined(UF_HIDDEN)
|
||||
#define UF_HIDDEN FSP_FUSE_UF_HIDDEN
|
||||
#endif
|
||||
#if !defined(UF_READONLY)
|
||||
#define UF_READONLY FSP_FUSE_UF_READONLY
|
||||
#endif
|
||||
#if !defined(UF_SYSTEM)
|
||||
#define UF_SYSTEM FSP_FUSE_UF_SYSTEM
|
||||
#endif
|
||||
#if !defined(UF_ARCHIVE)
|
||||
#define UF_ARCHIVE FSP_FUSE_UF_ARCHIVE
|
||||
#endif
|
||||
|
||||
struct fuse_file_info
|
||||
{
|
||||
int flags;
|
||||
@ -85,6 +104,9 @@ struct fuse_conn_info
|
||||
struct fuse_session;
|
||||
struct fuse_chan;
|
||||
struct fuse_pollhandle;
|
||||
struct fuse_bufvec;
|
||||
struct fuse_statfs;
|
||||
struct fuse_setattr_x;
|
||||
|
||||
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_version)(struct fsp_fuse_env *env);
|
||||
FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,
|
||||
|
@ -65,6 +65,27 @@ extern "C" {
|
||||
* to be usable from Cygwin.
|
||||
*/
|
||||
|
||||
#define FSP_FUSE_STAT_FIELD_DEFN \
|
||||
fuse_dev_t st_dev; \
|
||||
fuse_ino_t st_ino; \
|
||||
fuse_mode_t st_mode; \
|
||||
fuse_nlink_t st_nlink; \
|
||||
fuse_uid_t st_uid; \
|
||||
fuse_gid_t st_gid; \
|
||||
fuse_dev_t st_rdev; \
|
||||
fuse_off_t st_size; \
|
||||
struct fuse_timespec st_atim; \
|
||||
struct fuse_timespec st_mtim; \
|
||||
struct fuse_timespec st_ctim; \
|
||||
fuse_blksize_t st_blksize; \
|
||||
fuse_blkcnt_t st_blocks; \
|
||||
struct fuse_timespec st_birthtim;
|
||||
#define FSP_FUSE_STAT_EX_FIELD_DEFN \
|
||||
FSP_FUSE_STAT_FIELD_DEFN \
|
||||
uint32_t st_flags; \
|
||||
uint32_t st_reserved32[3]; \
|
||||
uint64_t st_reserved64[2];
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
|
||||
typedef uint32_t fuse_uid_t;
|
||||
@ -111,23 +132,17 @@ struct fuse_timespec
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(FSP_FUSE_USE_STAT_EX)
|
||||
struct fuse_stat
|
||||
{
|
||||
fuse_dev_t st_dev;
|
||||
fuse_ino_t st_ino;
|
||||
fuse_mode_t st_mode;
|
||||
fuse_nlink_t st_nlink;
|
||||
fuse_uid_t st_uid;
|
||||
fuse_gid_t st_gid;
|
||||
fuse_dev_t st_rdev;
|
||||
fuse_off_t st_size;
|
||||
struct fuse_timespec st_atim;
|
||||
struct fuse_timespec st_mtim;
|
||||
struct fuse_timespec st_ctim;
|
||||
fuse_blksize_t st_blksize;
|
||||
fuse_blkcnt_t st_blocks;
|
||||
struct fuse_timespec st_birthtim;
|
||||
FSP_FUSE_STAT_FIELD_DEFN
|
||||
};
|
||||
#else
|
||||
struct fuse_stat
|
||||
{
|
||||
FSP_FUSE_STAT_EX_FIELD_DEFN
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
struct fuse_statvfs
|
||||
@ -222,7 +237,14 @@ struct fuse_flock
|
||||
#define fuse_utimbuf utimbuf
|
||||
#define fuse_timespec timespec
|
||||
|
||||
#if !defined(FSP_FUSE_USE_STAT_EX)
|
||||
#define fuse_stat stat
|
||||
#else
|
||||
struct fuse_stat
|
||||
{
|
||||
FSP_FUSE_STAT_EX_FIELD_DEFN
|
||||
};
|
||||
#endif
|
||||
#define fuse_statvfs statvfs
|
||||
#define fuse_flock flock
|
||||
|
||||
@ -246,6 +268,11 @@ struct fuse_flock
|
||||
#error unsupported environment
|
||||
#endif
|
||||
|
||||
struct fuse_stat_ex
|
||||
{
|
||||
FSP_FUSE_STAT_EX_FIELD_DEFN
|
||||
};
|
||||
|
||||
struct fsp_fuse_env
|
||||
{
|
||||
unsigned environment;
|
||||
|
@ -1472,6 +1472,21 @@ NTSTATUS FspPosixMapPosixToWindowsPath(const char *PosixPath, PWSTR *PWindowsPat
|
||||
FSP_API VOID FspPosixDeletePath(void *Path);
|
||||
FSP_API VOID FspPosixEncodeWindowsPath(PWSTR WindowsPath, ULONG Size);
|
||||
FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
|
||||
static inline
|
||||
VOID FspPosixFileTimeToUnixTime(UINT64 FileTime0, __int3264 UnixTime[2])
|
||||
{
|
||||
INT64 FileTime = (INT64)FileTime0 - 116444736000000000LL;
|
||||
UnixTime[0] = (__int3264)(FileTime / 10000000);
|
||||
UnixTime[1] = (__int3264)(FileTime % 10000000 * 100);
|
||||
/* may produce negative nsec for times before UNIX epoch; strictly speaking this is incorrect */
|
||||
}
|
||||
static inline
|
||||
VOID FspPosixUnixTimeToFileTime(const __int3264 UnixTime[2], PUINT64 PFileTime)
|
||||
{
|
||||
INT64 FileTime = (INT64)UnixTime[0] * 10000000 + (INT64)UnixTime[1] / 100 +
|
||||
116444736000000000LL;
|
||||
*PFileTime = FileTime;
|
||||
}
|
||||
|
||||
/*
|
||||
* Path Handling
|
||||
|
@ -22,7 +22,9 @@ cygport:
|
||||
dist: cygport
|
||||
case $(shell uname -m) in \
|
||||
x86_64)\
|
||||
mkdir -p dist/x64 && \
|
||||
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x64 ;;\
|
||||
*)\
|
||||
mkdir -p dist/x86 && \
|
||||
cp fuse-*/dist/fuse/fuse-*[0-9].tar.xz dist/x86 ;;\
|
||||
esac
|
||||
|
BIN
opt/cygfuse/dist/x64/fuse-2.8-6.tar.xz
vendored
BIN
opt/cygfuse/dist/x64/fuse-2.8-6.tar.xz
vendored
Binary file not shown.
BIN
opt/cygfuse/dist/x64/fuse-2.8-7.tar.xz
vendored
Normal file
BIN
opt/cygfuse/dist/x64/fuse-2.8-7.tar.xz
vendored
Normal file
Binary file not shown.
BIN
opt/cygfuse/dist/x86/fuse-2.8-6.tar.xz
vendored
BIN
opt/cygfuse/dist/x86/fuse-2.8-6.tar.xz
vendored
Binary file not shown.
BIN
opt/cygfuse/dist/x86/fuse-2.8-7.tar.xz
vendored
Normal file
BIN
opt/cygfuse/dist/x86/fuse-2.8-7.tar.xz
vendored
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
NAME="fuse"
|
||||
VERSION=2.8
|
||||
RELEASE=6
|
||||
RELEASE=7
|
||||
CATEGORY="Utils"
|
||||
SUMMARY="WinFsp-FUSE compatibility layer"
|
||||
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
|
||||
|
@ -299,6 +299,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
FUSE_CAP_DONT_MASK |
|
||||
FSP_FUSE_CAP_READDIR_PLUS |
|
||||
FSP_FUSE_CAP_READ_ONLY |
|
||||
FSP_FUSE_CAP_STAT_EX |
|
||||
FSP_FUSE_CAP_CASE_INSENSITIVE;
|
||||
if (0 != f->ops.init)
|
||||
{
|
||||
@ -340,7 +341,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
}
|
||||
if (0 != f->ops.getattr)
|
||||
{
|
||||
struct fuse_stat stbuf;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err;
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
@ -354,14 +355,12 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
if (0 == f->VolumeParams.VolumeCreationTime)
|
||||
{
|
||||
if (0 != stbuf.st_birthtim.tv_sec)
|
||||
f->VolumeParams.VolumeCreationTime =
|
||||
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_birthtim.tv_nsec / 100;
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim,
|
||||
&f->VolumeParams.VolumeCreationTime);
|
||||
else
|
||||
if (0 != stbuf.st_ctim.tv_sec)
|
||||
f->VolumeParams.VolumeCreationTime =
|
||||
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_ctim.tv_nsec / 100;
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim,
|
||||
&f->VolumeParams.VolumeCreationTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ static NTSTATUS fsp_fuse_intf_NewHiddenName(FSP_FILE_SYSTEM *FileSystem,
|
||||
struct { UINT32 V[4]; } Values;
|
||||
UUID Uuid;
|
||||
} UuidBuf;
|
||||
struct fuse_stat stbuf;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err, maxtries = 3;
|
||||
|
||||
*PPosixHiddenPath = 0;
|
||||
@ -291,7 +291,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
char *PosixDotPath = 0;
|
||||
size_t Length;
|
||||
struct fuse_stat stbuf;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err;
|
||||
BOOLEAN Result = FALSE;
|
||||
|
||||
@ -304,6 +304,7 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
PosixDotPath[Length + 1] = '.';
|
||||
PosixDotPath[Length + 2] = '\0';
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
if (0 != f->ops.getattr)
|
||||
err = f->ops.getattr(PosixDotPath, (void *)&stbuf);
|
||||
else
|
||||
@ -317,25 +318,57 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline uint32_t fsp_fuse_intf_MapFileAttributesToFlags(UINT32 FileAttributes)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
flags |= FSP_FUSE_UF_READONLY;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
||||
flags |= FSP_FUSE_UF_HIDDEN;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_SYSTEM)
|
||||
flags |= FSP_FUSE_UF_SYSTEM;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE)
|
||||
flags |= FSP_FUSE_UF_ARCHIVE;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline UINT32 fsp_fuse_intf_MapFlagsToFileAttributes(uint32_t flags)
|
||||
{
|
||||
UINT32 FileAttributes = 0;
|
||||
|
||||
if (flags & FSP_FUSE_UF_READONLY)
|
||||
FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
if (flags & FSP_FUSE_UF_HIDDEN)
|
||||
FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
if (flags & FSP_FUSE_UF_SYSTEM)
|
||||
FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
|
||||
if (flags & FSP_FUSE_UF_ARCHIVE)
|
||||
FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
return FileAttributes;
|
||||
}
|
||||
|
||||
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
|
||||
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
|
||||
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
|
||||
const char *PosixPath, struct fuse_file_info *fi, const struct fuse_stat *stbufp,
|
||||
const char *PosixPath, struct fuse_file_info *fi, const void *stbufp,
|
||||
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
UINT64 AllocationUnit;
|
||||
struct fuse_stat stbuf;
|
||||
struct fuse_stat_ex stbuf;
|
||||
BOOLEAN StatEx = 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX);
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
if (0 != stbufp)
|
||||
memcpy(&stbuf, stbufp, sizeof stbuf);
|
||||
memcpy(&stbuf, stbufp, StatEx ? sizeof(struct fuse_stat_ex) : sizeof(struct fuse_stat));
|
||||
else
|
||||
{
|
||||
int err;
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
|
||||
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
|
||||
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
|
||||
else if (0 != f->ops.getattr)
|
||||
@ -390,21 +423,15 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
|
||||
FileInfo->ReparseTag = 0;
|
||||
break;
|
||||
}
|
||||
if (StatEx)
|
||||
FileInfo->FileAttributes |= fsp_fuse_intf_MapFlagsToFileAttributes(stbuf.st_flags);
|
||||
FileInfo->FileSize = stbuf.st_size;
|
||||
FileInfo->AllocationSize =
|
||||
(FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||
FileInfo->CreationTime =
|
||||
Int32x32To64(stbuf.st_birthtim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_birthtim.tv_nsec / 100;
|
||||
FileInfo->LastAccessTime =
|
||||
Int32x32To64(stbuf.st_atim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_atim.tv_nsec / 100;
|
||||
FileInfo->LastWriteTime =
|
||||
Int32x32To64(stbuf.st_mtim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_mtim.tv_nsec / 100;
|
||||
FileInfo->ChangeTime =
|
||||
Int32x32To64(stbuf.st_ctim.tv_sec, 10000000) + 116444736000000000 +
|
||||
stbuf.st_ctim.tv_nsec / 100;
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_birthtim, &FileInfo->CreationTime);
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_atim, &FileInfo->LastAccessTime);
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_mtim, &FileInfo->LastWriteTime);
|
||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim, &FileInfo->ChangeTime);
|
||||
FileInfo->IndexNumber = stbuf.st_ino;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
@ -738,9 +765,9 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
memset(&fi, 0, sizeof fi);
|
||||
if ('C' == f->env->environment) /* Cygwin */
|
||||
fi.flags = 0x0200 | 2 /*O_CREAT|O_RDWR*/;
|
||||
fi.flags = 0x0200 | 0x0800 | 2 /*O_CREAT|O_EXCL|O_RDWR*/;
|
||||
else
|
||||
fi.flags = 0x0100 | 2 /*O_CREAT|O_RDWR*/;
|
||||
fi.flags = 0x0100 | 0x0400 | 2 /*O_CREAT|O_EXCL|O_RDWR*/;
|
||||
|
||||
if (CreateOptions & FILE_DIRECTORY_FILE)
|
||||
{
|
||||
@ -794,16 +821,25 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
Opened = TRUE;
|
||||
|
||||
if (Uid != context->uid || Gid != context->gid)
|
||||
if (0 != f->ops.chown)
|
||||
{
|
||||
err = f->ops.chown(contexthdr->PosixPath, Uid, Gid);
|
||||
if (0 != err)
|
||||
{
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
if (0 != FileAttributes &&
|
||||
0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
|
||||
{
|
||||
err = f->ops.chflags(contexthdr->PosixPath,
|
||||
fsp_fuse_intf_MapFileAttributesToFlags(CreateOptions & FILE_DIRECTORY_FILE ?
|
||||
FileAttributes : FileAttributes | FILE_ATTRIBUTE_ARCHIVE));
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((Uid != context->uid || Gid != context->gid) &&
|
||||
0 != f->ops.chown)
|
||||
{
|
||||
err = f->ops.chown(contexthdr->PosixPath, Uid, Gid);
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
|
||||
@ -988,6 +1024,22 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (0 != FileAttributes &&
|
||||
0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
|
||||
{
|
||||
/*
|
||||
* The code below is not strictly correct. File attributes should be
|
||||
* replaced when ReplaceFileAttributes is TRUE and merged (or'ed) when
|
||||
* ReplaceFileAttributes is FALSE. I am punting on this detail for now.
|
||||
*/
|
||||
|
||||
err = f->ops.chflags(filedesc->PosixPath,
|
||||
fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes | FILE_ATTRIBUTE_ARCHIVE));
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result)
|
||||
return Result;
|
||||
}
|
||||
|
||||
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
|
||||
&Uid, &Gid, &Mode, FileInfo);
|
||||
}
|
||||
@ -1241,67 +1293,74 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
int err;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (0 == f->ops.utimens && 0 == f->ops.utime)
|
||||
return STATUS_SUCCESS; /* liar! */
|
||||
|
||||
/* no way to set FileAttributes, CreationTime! */
|
||||
if (0 == LastAccessTime && 0 == LastWriteTime)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
memset(&fi, 0, sizeof fi);
|
||||
fi.flags = filedesc->OpenFlags;
|
||||
fi.fh = filedesc->FileHandle;
|
||||
|
||||
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
|
||||
&Uid, &Gid, &Mode, &FileInfoBuf);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (0 != LastAccessTime)
|
||||
FileInfoBuf.LastAccessTime = LastAccessTime;
|
||||
if (0 != LastWriteTime)
|
||||
FileInfoBuf.LastWriteTime = LastWriteTime;
|
||||
|
||||
/* UNIX epoch in 100-ns intervals */
|
||||
LastAccessTime = FileInfoBuf.LastAccessTime - 116444736000000000;
|
||||
LastWriteTime = FileInfoBuf.LastWriteTime - 116444736000000000;
|
||||
|
||||
if (0 != f->ops.utimens)
|
||||
if (INVALID_FILE_ATTRIBUTES != FileAttributes &&
|
||||
0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
tv[0].tv_sec = (int64_t)(LastAccessTime / 10000000);
|
||||
tv[0].tv_nsec = (int64_t)(LastAccessTime % 10000000) * 100;
|
||||
tv[1].tv_sec = (int64_t)(LastWriteTime / 10000000);
|
||||
tv[1].tv_nsec = (int64_t)(LastWriteTime % 10000000) * 100;
|
||||
#else
|
||||
tv[0].tv_sec = (int32_t)(LastAccessTime / 10000000);
|
||||
tv[0].tv_nsec = (int32_t)(LastAccessTime % 10000000) * 100;
|
||||
tv[1].tv_sec = (int32_t)(LastWriteTime / 10000000);
|
||||
tv[1].tv_nsec = (int32_t)(LastWriteTime % 10000000) * 100;
|
||||
#endif
|
||||
|
||||
err = f->ops.utimens(filedesc->PosixPath, tv);
|
||||
err = f->ops.chflags(filedesc->PosixPath,
|
||||
fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes));
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
else
|
||||
|
||||
if ((0 != LastAccessTime || 0 != LastWriteTime) &&
|
||||
(0 != f->ops.utimens || 0 != f->ops.utime))
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
timbuf.actime = (int64_t)(LastAccessTime / 10000000);
|
||||
timbuf.modtime = (int64_t)(LastWriteTime / 10000000);
|
||||
#else
|
||||
timbuf.actime = (int32_t)(LastAccessTime / 10000000);
|
||||
timbuf.modtime = (int32_t)(LastWriteTime / 10000000);
|
||||
#endif
|
||||
if (0 == LastAccessTime || 0 == LastWriteTime)
|
||||
{
|
||||
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
|
||||
&Uid, &Gid, &Mode, &FileInfoBuf);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
err = f->ops.utime(filedesc->PosixPath, &timbuf);
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (0 == LastAccessTime)
|
||||
LastAccessTime = FileInfoBuf.LastAccessTime;
|
||||
if (0 == LastWriteTime)
|
||||
LastWriteTime = FileInfoBuf.LastWriteTime;
|
||||
}
|
||||
|
||||
FspPosixFileTimeToUnixTime(LastAccessTime, (void *)&tv[0]);
|
||||
FspPosixFileTimeToUnixTime(LastWriteTime, (void *)&tv[1]);
|
||||
if (0 != f->ops.utimens)
|
||||
{
|
||||
err = f->ops.utimens(filedesc->PosixPath, tv);
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
else
|
||||
{
|
||||
timbuf.actime = tv[0].tv_sec;
|
||||
timbuf.modtime = tv[1].tv_sec;
|
||||
err = f->ops.utime(filedesc->PosixPath, &timbuf);
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
memcpy(FileInfo, &FileInfoBuf, sizeof FileInfoBuf);
|
||||
if (0 != CreationTime && 0 != f->ops.setcrtime)
|
||||
{
|
||||
FspPosixFileTimeToUnixTime(CreationTime, (void *)&tv[0]);
|
||||
err = f->ops.setcrtime(filedesc->PosixPath, &tv[0]);
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
if (0 != ChangeTime && 0 != f->ops.setchgtime)
|
||||
{
|
||||
FspPosixFileTimeToUnixTime(ChangeTime, (void *)&tv[0]);
|
||||
err = f->ops.setchgtime(filedesc->PosixPath, &tv[0]);
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
|
||||
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
|
||||
&Uid, &Gid, &Mode, FileInfo);
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
@ -147,7 +147,7 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
|
||||
static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
|
||||
PWSTR UserName, ULONG UserNameSize/* in chars */)
|
||||
{
|
||||
PWSTR ClassName, InstanceName, P;
|
||||
@ -721,7 +721,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
||||
lstrcpyW(UserName, L"UNSPECIFIED");
|
||||
Password[0] = L'\0';
|
||||
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
|
||||
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
||||
FspNpParseRemoteUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
||||
do
|
||||
{
|
||||
NpResult = FspNpGetCredentials(
|
||||
|
@ -21,12 +21,16 @@
|
||||
#define PROGNAME "WinFsp.Launcher"
|
||||
|
||||
BOOL CreateOverlappedPipe(
|
||||
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size,
|
||||
PHANDLE PReadPipe, PHANDLE PWritePipe,
|
||||
DWORD Size,
|
||||
BOOL ReadInherit, BOOL WriteInherit,
|
||||
DWORD ReadMode, DWORD WriteMode)
|
||||
{
|
||||
RPC_STATUS RpcStatus;
|
||||
UUID Uuid;
|
||||
WCHAR PipeNameBuf[MAX_PATH];
|
||||
SECURITY_ATTRIBUTES ReadSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, ReadInherit };
|
||||
SECURITY_ATTRIBUTES WriteSecurityAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, WriteInherit };
|
||||
HANDLE ReadPipe, WritePipe;
|
||||
DWORD LastError;
|
||||
|
||||
@ -46,13 +50,13 @@ BOOL CreateOverlappedPipe(
|
||||
ReadPipe = CreateNamedPipeW(PipeNameBuf,
|
||||
PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
|
||||
1, Size, Size, 120 * 1000, SecurityAttributes);
|
||||
1, Size, Size, 120 * 1000, &ReadSecurityAttributes);
|
||||
if (INVALID_HANDLE_VALUE == ReadPipe)
|
||||
return FALSE;
|
||||
|
||||
WritePipe = CreateFileW(PipeNameBuf,
|
||||
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
SecurityAttributes, OPEN_EXISTING, WriteMode, 0);
|
||||
&WriteSecurityAttributes, OPEN_EXISTING, WriteMode, 0);
|
||||
if (INVALID_HANDLE_VALUE == WritePipe)
|
||||
{
|
||||
LastError = GetLastError();
|
||||
@ -67,6 +71,76 @@ BOOL CreateOverlappedPipe(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NTSTATUS GetTokenUserName(HANDLE Token, PWSTR *PUserName)
|
||||
{
|
||||
TOKEN_USER *User = 0;
|
||||
WCHAR Name[256], Domn[256];
|
||||
DWORD UserSize, NameSize, DomnSize;
|
||||
SID_NAME_USE Use;
|
||||
PWSTR P;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PUserName = 0;
|
||||
|
||||
if (GetTokenInformation(Token, TokenUser, 0, 0, &UserSize))
|
||||
{
|
||||
Result = STATUS_INVALID_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
User = MemAlloc(UserSize);
|
||||
if (0 == User)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!GetTokenInformation(Token, TokenUser, User, UserSize, &UserSize))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NameSize = sizeof Name / sizeof Name[0];
|
||||
DomnSize = sizeof Domn / sizeof Domn[0];
|
||||
if (!LookupAccountSidW(0, User->User.Sid, Name, &NameSize, Domn, &DomnSize, &Use))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NameSize = lstrlenW(Name);
|
||||
DomnSize = lstrlenW(Domn);
|
||||
|
||||
P = *PUserName = MemAlloc((DomnSize + 1 + NameSize + 1) * sizeof(WCHAR));
|
||||
if (0 == P)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (0 < DomnSize)
|
||||
{
|
||||
memcpy(P, Domn, DomnSize * sizeof(WCHAR));
|
||||
P[DomnSize] = L'\\';
|
||||
P += DomnSize + 1;
|
||||
}
|
||||
memcpy(P, Name, NameSize * sizeof(WCHAR));
|
||||
P[NameSize] = L'\0';
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
MemFree(User);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE Process;
|
||||
@ -142,6 +216,17 @@ typedef struct
|
||||
static CRITICAL_SECTION SvcInstanceLock;
|
||||
static HANDLE SvcInstanceEvent;
|
||||
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
|
||||
static DWORD SvcInstanceTlsKey = TLS_OUT_OF_INDEXES;
|
||||
|
||||
static inline PWSTR SvcInstanceUserName(VOID)
|
||||
{
|
||||
return TlsGetValue(SvcInstanceTlsKey);
|
||||
}
|
||||
|
||||
static inline VOID SvcInstanceSetUserName(PWSTR UserName)
|
||||
{
|
||||
TlsSetValue(SvcInstanceTlsKey, UserName);
|
||||
}
|
||||
|
||||
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout);
|
||||
|
||||
@ -210,6 +295,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
||||
else
|
||||
Length += SvcInstanceArgumentLength(EmptyArg);
|
||||
}
|
||||
else
|
||||
if (L'U' == *P)
|
||||
{
|
||||
if (0 != SvcInstanceUserName())
|
||||
Length += SvcInstanceArgumentLength(SvcInstanceUserName());
|
||||
else
|
||||
Length += SvcInstanceArgumentLength(EmptyArg);
|
||||
}
|
||||
else
|
||||
Length++;
|
||||
break;
|
||||
@ -236,6 +329,14 @@ static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Arg
|
||||
else
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
|
||||
}
|
||||
else
|
||||
if (L'U' == *P)
|
||||
{
|
||||
if (0 != SvcInstanceUserName())
|
||||
Q = SvcInstanceArgumentCopy(Q, SvcInstanceUserName());
|
||||
else
|
||||
Q = SvcInstanceArgumentCopy(Q, EmptyArg);
|
||||
}
|
||||
else
|
||||
*Q++ = *P;
|
||||
break;
|
||||
@ -286,7 +387,6 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
|
||||
STARTUPINFOEXW StartupInfoEx;
|
||||
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
|
||||
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
|
||||
SECURITY_ATTRIBUTES PipeAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
|
||||
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
|
||||
SIZE_T Size;
|
||||
NTSTATUS Result;
|
||||
@ -304,16 +404,16 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
|
||||
*/
|
||||
|
||||
/* create stdin read/write ends; make them inheritable */
|
||||
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0], &PipeAttributes, 0,
|
||||
0, 0))
|
||||
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0],
|
||||
0, TRUE, FALSE, 0, 0))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* create stdout read/write ends; make them inheritable */
|
||||
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1], &PipeAttributes, 0,
|
||||
FILE_FLAG_OVERLAPPED, 0))
|
||||
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1],
|
||||
0, FALSE, TRUE, FILE_FLAG_OVERLAPPED, 0))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
@ -361,8 +461,28 @@ NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
|
||||
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, 0, 0,
|
||||
&StartupInfoEx.StartupInfo, ProcessInfo))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
if (ERROR_NO_SYSTEM_RESOURCES != GetLastError())
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* On Win7 CreateProcessW with EXTENDED_STARTUPINFO_PRESENT
|
||||
* may fail with ERROR_NO_SYSTEM_RESOURCES.
|
||||
*
|
||||
* In that case go ahead and retry with a CreateProcessW with
|
||||
* bInheritHandles==TRUE, but without EXTENDED_STARTUPINFO_PRESENT.
|
||||
* Not ideal, but...
|
||||
*/
|
||||
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
|
||||
if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE,
|
||||
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0,
|
||||
&StartupInfoEx.StartupInfo, ProcessInfo))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -752,6 +872,10 @@ exit:
|
||||
|
||||
SvcInstanceRelease(SvcInstance);
|
||||
|
||||
if (STATUS_TIMEOUT == Result)
|
||||
/* convert to an error! */
|
||||
Result = 0x80070000 | ERROR_TIMEOUT;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@ -918,6 +1042,10 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
if (0 == SvcInstanceEvent)
|
||||
goto fail;
|
||||
|
||||
SvcInstanceTlsKey = TlsAlloc();
|
||||
if (TLS_OUT_OF_INDEXES == SvcInstanceTlsKey)
|
||||
goto fail;
|
||||
|
||||
SvcJob = CreateJobObjectW(0, 0);
|
||||
if (0 != SvcJob)
|
||||
{
|
||||
@ -980,6 +1108,9 @@ fail:
|
||||
if (0 != SvcJob)
|
||||
CloseHandle(SvcJob);
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
|
||||
TlsFree(SvcInstanceTlsKey);
|
||||
|
||||
if (0 != SvcInstanceEvent)
|
||||
CloseHandle(SvcInstanceEvent);
|
||||
|
||||
@ -1023,6 +1154,9 @@ static NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||
if (0 != SvcJob)
|
||||
CloseHandle(SvcJob);
|
||||
|
||||
if (TLS_OUT_OF_INDEXES != SvcInstanceTlsKey)
|
||||
TlsFree(SvcInstanceTlsKey);
|
||||
|
||||
if (0 != SvcInstanceEvent)
|
||||
CloseHandle(SvcInstanceEvent);
|
||||
|
||||
@ -1194,13 +1328,16 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
return;
|
||||
|
||||
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
|
||||
PWSTR ClassName, InstanceName;
|
||||
PWSTR ClassName, InstanceName, UserName;
|
||||
ULONG Argc; PWSTR Argv[9];
|
||||
BOOLEAN HasSecret = FALSE;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PSize = 0;
|
||||
|
||||
GetTokenUserName(ClientToken, &UserName);
|
||||
SvcInstanceSetUserName(UserName);
|
||||
|
||||
switch (*P++)
|
||||
{
|
||||
case LauncherSvcInstanceStartWithSecret:
|
||||
@ -1264,6 +1401,9 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
|
||||
SvcPipeTransactResult(STATUS_INVALID_PARAMETER, PipeBuf, PSize);
|
||||
break;
|
||||
}
|
||||
|
||||
SvcInstanceSetUserName(0);
|
||||
MemFree(UserName);
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
|
@ -611,7 +611,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
ASSERT(
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength >=
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) >=
|
||||
FileDesc->DirectoryMarker.Length);
|
||||
|
||||
Request->Req.QueryDirectory.Marker.Offset =
|
||||
@ -921,7 +921,7 @@ NTSTATUS FspFsvolDirectoryControlComplete(
|
||||
if (0 != FileDesc->DirectoryMarker.Buffer)
|
||||
{
|
||||
ASSERT(
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength >=
|
||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) >=
|
||||
FileDesc->DirectoryMarker.Length);
|
||||
|
||||
Request->Req.QueryDirectory.Marker.Offset =
|
||||
|
@ -2166,7 +2166,7 @@ NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc,
|
||||
FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject);
|
||||
UNICODE_STRING DirectoryMarker;
|
||||
|
||||
if (FsvolDeviceExtension->VolumeParams.MaxComponentLength < FileName->Length)
|
||||
if (FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR) < FileName->Length)
|
||||
return STATUS_OBJECT_NAME_INVALID;
|
||||
|
||||
DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length;
|
||||
|
@ -39,6 +39,7 @@ set dfl_tests=^
|
||||
winfsp-tests-x64-external-share ^
|
||||
fsx-memfs-x64-disk ^
|
||||
fsx-memfs-x64-net ^
|
||||
fsx-memfs-x64-slowio ^
|
||||
standby-memfs-x64-disk ^
|
||||
standby-memfs-x64-net ^
|
||||
net-use-memfs-x64 ^
|
||||
@ -55,6 +56,7 @@ set dfl_tests=^
|
||||
winfsp-tests-x86-external-share ^
|
||||
fsx-memfs-x86-disk ^
|
||||
fsx-memfs-x86-net ^
|
||||
fsx-memfs-x86-slowio ^
|
||||
standby-memfs-x86-disk ^
|
||||
standby-memfs-x86-net ^
|
||||
net-use-memfs-x86 ^
|
||||
@ -78,6 +80,8 @@ set opt_tests=^
|
||||
sample-passthrough-fuse-x86 ^
|
||||
sample-fsx-passthrough-fuse-x86 ^
|
||||
sample-passthrough-dotnet ^
|
||||
compat-v1.1-passthrough-fuse-x64 ^
|
||||
compat-v1.1-passthrough-fuse-x86 ^
|
||||
avast-tests-x64 ^
|
||||
avast-tests-x86 ^
|
||||
avast-tests-dotnet
|
||||
@ -452,6 +456,35 @@ if !ERRORLEVEL! neq 0 goto fail
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
exit /b 0
|
||||
|
||||
:fsx-memfs-x64-slowio
|
||||
call :__run_fsx_memfs_slowio_test memfs64-slowio memfs-x64
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
exit /b 0
|
||||
|
||||
:fsx-memfs-x86-slowio
|
||||
call :__run_fsx_memfs_slowio_test memfs32-slowio memfs-x86
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
exit /b 0
|
||||
|
||||
:__run_fsx_memfs_slowio_test
|
||||
set RunSampleTestExit=0
|
||||
call "%ProjRoot%\tools\fsreg" %1 "%ProjRoot%\build\VStudio\build\%Configuration%\%2.exe" "-u %%%%1 -m %%%%2 -M 50 -P 10 -R 5" "D:P(A;;RPWPLC;;;WD)"
|
||||
echo net use L: "\\%1\share"
|
||||
net use L: "\\%1\share"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
echo net use ^| findstr L:
|
||||
net use | findstr L:
|
||||
pushd >nul
|
||||
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
|
||||
L:
|
||||
"%ProjRoot%\ext\test\fstools\src\fsx\fsx.exe" -N 5000 test xxxxxx
|
||||
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
|
||||
popd
|
||||
echo net use L: /delete
|
||||
net use L: /delete
|
||||
call "%ProjRoot%\tools\fsreg" -u %1
|
||||
exit /b !RunSampleTestExit!
|
||||
|
||||
:winfstest-memfs-dotnet-disk
|
||||
Q:
|
||||
call "%ProjRoot%\ext\test\winfstest\run-winfstest.bat"
|
||||
@ -624,7 +657,7 @@ exit /b 0
|
||||
|
||||
:sample-passthrough-dotnet
|
||||
call :__run_sample_test passthrough-dotnet anycpu passthrough-dotnet winfsp-tests-x64 ^
|
||||
"-create_backup_test -create_restore_test -create_namelen_test -delete_access_test"
|
||||
"-create_backup_test -create_restore_test -create_namelen_test -delete_access_test -querydir_namelen_test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
exit /b 0
|
||||
|
||||
@ -692,7 +725,7 @@ L:
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^
|
||||
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%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 -exec_rename_dir_test ^
|
||||
-getfileinfo_name_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^
|
||||
-reparse* -stream*
|
||||
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
|
||||
popd
|
||||
@ -726,6 +759,42 @@ call "%ProjRoot%\tools\fsreg" -u %1
|
||||
rmdir /s/q "%TMP%\%1"
|
||||
exit /b !RunSampleTestExit!
|
||||
|
||||
:compat-v1.1-passthrough-fuse-x64
|
||||
call :__run_compat_fuse_test passthrough-fuse v1.1\passthrough-fuse\passthrough-fuse-x64 winfsp-tests-x64
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
exit /b 0
|
||||
|
||||
:compat-v1.1-passthrough-fuse-x86
|
||||
call :__run_compat_fuse_test passthrough-fuse v1.1\passthrough-fuse\passthrough-fuse-x86 winfsp-tests-x86
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
exit /b 0
|
||||
|
||||
:__run_compat_fuse_test
|
||||
set RunSampleTestExit=0
|
||||
mkdir "%TMP%\%1\test"
|
||||
call "%ProjRoot%\tools\fsreg" %1 "%ProjRoot%\tst\compat\%2.exe" ^
|
||||
"-ouid=11,gid=65792 --VolumePrefix=%%%%1 %%%%2" "D:P(A;;RPWPLC;;;WD)"
|
||||
echo net use L: "\\%1\%TMP::=$%\%1\test"
|
||||
net use L: "\\%1\%TMP::=$%\%1\test"
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
echo net use ^| findstr L:
|
||||
net use | findstr L:
|
||||
pushd >nul
|
||||
cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
|
||||
L:
|
||||
"%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^
|
||||
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
|
||||
-create_fileattr_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 -querydir_namelen_test -exec_rename_dir_test ^
|
||||
-reparse* -stream*
|
||||
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
|
||||
popd
|
||||
echo net use L: /delete
|
||||
net use L: /delete
|
||||
call "%ProjRoot%\tools\fsreg" -u %1
|
||||
rmdir /s/q "%TMP%\%1"
|
||||
exit /b !RunSampleTestExit!
|
||||
|
||||
:avast-tests-x64
|
||||
call :winfsp-tests-x64-external
|
||||
if !ERRORLEVEL! neq 0 goto fail
|
||||
|
3
tst/compat/v1.1/passthrough-fuse/README.md
Normal file
3
tst/compat/v1.1/passthrough-fuse/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
This directory contains binaries of `passthrough-fuse` from release `v1.2B2`. Both `x64` and `x86` binaries are provided.
|
||||
|
||||
The WinFsp-FUSE layer added support for `struct fuse_stat_ex` in `v1.2B3` which was a potentially breaking change for backwards compatibility. These binaries are used to verify that WinFsp-FUSE remains backwards compatible.
|
BIN
tst/compat/v1.1/passthrough-fuse/passthrough-fuse-x64.exe
Normal file
BIN
tst/compat/v1.1/passthrough-fuse/passthrough-fuse-x64.exe
Normal file
Binary file not shown.
BIN
tst/compat/v1.1/passthrough-fuse/passthrough-fuse-x86.exe
Normal file
BIN
tst/compat/v1.1/passthrough-fuse/passthrough-fuse-x86.exe
Normal file
Binary file not shown.
@ -44,6 +44,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
ULONG FileInfoTimeout = INFINITE;
|
||||
ULONG MaxFileNodes = 1024;
|
||||
ULONG MaxFileSize = 16 * 1024 * 1024;
|
||||
ULONG SlowioMaxDelay = 0; /* -M: maximum slow IO delay in millis */
|
||||
ULONG SlowioPercentDelay = 0; /* -P: percent of slow IO to make pending */
|
||||
ULONG SlowioRarefyDelay = 0; /* -R: adjust the rarity of pending slow IO */
|
||||
PWSTR FileSystemName = 0;
|
||||
PWSTR MountPoint = 0;
|
||||
PWSTR VolumePrefix = 0;
|
||||
@ -75,9 +78,18 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
case L'm':
|
||||
argtos(MountPoint);
|
||||
break;
|
||||
case L'M':
|
||||
argtol(SlowioMaxDelay);
|
||||
break;
|
||||
case L'n':
|
||||
argtol(MaxFileNodes);
|
||||
break;
|
||||
case L'P':
|
||||
argtol(SlowioPercentDelay);
|
||||
break;
|
||||
case L'R':
|
||||
argtol(SlowioRarefyDelay);
|
||||
break;
|
||||
case L'S':
|
||||
argtos(RootSddl);
|
||||
break;
|
||||
@ -130,6 +142,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
FileInfoTimeout,
|
||||
MaxFileNodes,
|
||||
MaxFileSize,
|
||||
SlowioMaxDelay,
|
||||
SlowioPercentDelay,
|
||||
SlowioRarefyDelay,
|
||||
FileSystemName,
|
||||
VolumePrefix,
|
||||
RootSddl,
|
||||
@ -189,6 +204,9 @@ usage:
|
||||
" -t FileInfoTimeout [millis]\n"
|
||||
" -n MaxFileNodes\n"
|
||||
" -s MaxFileSize [bytes]\n"
|
||||
" -M MaxDelay [maximum slow IO delay in millis]\n"
|
||||
" -P PercentDelay [percent of slow IO to make pending]\n"
|
||||
" -R RarefyDelay [adjust the rarity of pending slow IO]\n"
|
||||
" -F FileSystemName\n"
|
||||
" -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n"
|
||||
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
/* SLOWIO */
|
||||
#include <thread>
|
||||
|
||||
#define MEMFS_MAX_PATH 512
|
||||
FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
|
||||
"MEMFS_MAX_PATH must be greater than MAX_PATH.");
|
||||
@ -47,6 +50,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
|
||||
*/
|
||||
#define MEMFS_DIRINFO_BY_NAME
|
||||
|
||||
/*
|
||||
* Define the MEMFS_SLOWIO macro to include delayed I/O response support.
|
||||
*/
|
||||
#define MEMFS_SLOWIO
|
||||
|
||||
/*
|
||||
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
||||
* a check for the Write buffer to ensure that it is read-only.
|
||||
@ -281,6 +289,12 @@ typedef struct _MEMFS
|
||||
MEMFS_FILE_NODE_MAP *FileNodeMap;
|
||||
ULONG MaxFileNodes;
|
||||
ULONG MaxFileSize;
|
||||
#ifdef MEMFS_SLOWIO
|
||||
ULONG SlowioMaxDelay;
|
||||
ULONG SlowioPercentDelay;
|
||||
ULONG SlowioRarefyDelay;
|
||||
volatile LONG SlowioThreadsRunning;
|
||||
#endif
|
||||
UINT16 VolumeLabelLength;
|
||||
WCHAR VolumeLabel[32];
|
||||
} MEMFS;
|
||||
@ -646,6 +660,126 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context)
|
||||
free(Context->FileNodes);
|
||||
}
|
||||
|
||||
#ifdef MEMFS_SLOWIO
|
||||
/*
|
||||
* SLOWIO
|
||||
*
|
||||
* This is included for two uses:
|
||||
*
|
||||
* 1) For testing winfsp, by allowing memfs to act more like a non-ram file system,
|
||||
* with some IO taking many milliseconds, and some IO completion delayed.
|
||||
*
|
||||
* 2) As sample code for how to use winfsp's STATUS_PENDING capabilities.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline UINT64 Hash(UINT64 x)
|
||||
{
|
||||
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ull;
|
||||
x = (x ^ (x >> 27)) * 0x94d049bb133111ebull;
|
||||
x = x ^ (x >> 31);
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline ULONG PseudoRandom(ULONG to)
|
||||
{
|
||||
/* John Oberschelp's PRNG */
|
||||
static UINT64 spin = 0;
|
||||
InterlockedIncrement(&spin);
|
||||
return Hash(spin) % to;
|
||||
}
|
||||
|
||||
static inline BOOLEAN SlowioReturnPending(FSP_FILE_SYSTEM *FileSystem)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
if (0 == Memfs->SlowioMaxDelay)
|
||||
return FALSE;
|
||||
return PseudoRandom(100) < Memfs->SlowioPercentDelay;
|
||||
}
|
||||
|
||||
static inline VOID SlowioSnooze(FSP_FILE_SYSTEM *FileSystem)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
if (0 == Memfs->SlowioMaxDelay)
|
||||
return;
|
||||
ULONG millis = PseudoRandom(Memfs->SlowioMaxDelay + 1) >> PseudoRandom(Memfs->SlowioRarefyDelay + 1);
|
||||
Sleep(millis);
|
||||
}
|
||||
|
||||
void SlowioReadThread(
|
||||
FSP_FILE_SYSTEM *FileSystem,
|
||||
MEMFS_FILE_NODE *FileNode,
|
||||
PVOID Buffer,
|
||||
UINT64 Offset,
|
||||
UINT64 EndOffset,
|
||||
UINT64 RequestHint)
|
||||
{
|
||||
SlowioSnooze(FileSystem);
|
||||
|
||||
memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset));
|
||||
UINT32 BytesTransferred = (ULONG)(EndOffset - Offset);
|
||||
|
||||
FSP_FSCTL_TRANSACT_RSP ResponseBuf;
|
||||
memset(&ResponseBuf, 0, sizeof ResponseBuf);
|
||||
ResponseBuf.Size = sizeof ResponseBuf;
|
||||
ResponseBuf.Kind = FspFsctlTransactReadKind;
|
||||
ResponseBuf.Hint = RequestHint; // IRP that is being completed
|
||||
ResponseBuf.IoStatus.Status = STATUS_SUCCESS;
|
||||
ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read
|
||||
FspFileSystemSendResponse(FileSystem, &ResponseBuf);
|
||||
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
|
||||
}
|
||||
|
||||
void SlowioWriteThread(
|
||||
FSP_FILE_SYSTEM *FileSystem,
|
||||
MEMFS_FILE_NODE *FileNode,
|
||||
PVOID Buffer,
|
||||
UINT64 Offset,
|
||||
UINT64 EndOffset,
|
||||
UINT64 RequestHint)
|
||||
{
|
||||
SlowioSnooze(FileSystem);
|
||||
|
||||
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
|
||||
UINT32 BytesTransferred = (ULONG)(EndOffset - Offset);
|
||||
|
||||
FSP_FSCTL_TRANSACT_RSP ResponseBuf;
|
||||
memset(&ResponseBuf, 0, sizeof ResponseBuf);
|
||||
ResponseBuf.Size = sizeof ResponseBuf;
|
||||
ResponseBuf.Kind = FspFsctlTransactWriteKind;
|
||||
ResponseBuf.Hint = RequestHint; // IRP that is being completed
|
||||
ResponseBuf.IoStatus.Status = STATUS_SUCCESS;
|
||||
ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written
|
||||
MemfsFileNodeGetFileInfo(FileNode, &ResponseBuf.Rsp.Write.FileInfo);
|
||||
FspFileSystemSendResponse(FileSystem, &ResponseBuf);
|
||||
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
|
||||
}
|
||||
|
||||
void SlowioReadDirectoryThread(
|
||||
FSP_FILE_SYSTEM *FileSystem,
|
||||
ULONG BytesTransferred,
|
||||
UINT64 RequestHint)
|
||||
{
|
||||
SlowioSnooze(FileSystem);
|
||||
|
||||
FSP_FSCTL_TRANSACT_RSP ResponseBuf;
|
||||
memset(&ResponseBuf, 0, sizeof ResponseBuf);
|
||||
ResponseBuf.Size = sizeof ResponseBuf;
|
||||
ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind;
|
||||
ResponseBuf.Hint = RequestHint; // IRP that is being completed
|
||||
ResponseBuf.IoStatus.Status = STATUS_SUCCESS;
|
||||
ResponseBuf.IoStatus.Information = BytesTransferred; // bytes of directory info read
|
||||
FspFileSystemSendResponse(FileSystem, &ResponseBuf);
|
||||
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FSP_FILE_SYSTEM_INTERFACE
|
||||
*/
|
||||
@ -1029,6 +1163,27 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (EndOffset > FileNode->FileInfo.FileSize)
|
||||
EndOffset = FileNode->FileInfo.FileSize;
|
||||
|
||||
#ifdef MEMFS_SLOWIO
|
||||
if (SlowioReturnPending(FileSystem))
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
try
|
||||
{
|
||||
InterlockedIncrement(&Memfs->SlowioThreadsRunning);
|
||||
std::thread(SlowioReadThread,
|
||||
FileSystem, FileNode, Buffer, Offset, EndOffset,
|
||||
FspFileSystemGetOperationContext()->Request->Hint).
|
||||
detach();
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
|
||||
}
|
||||
}
|
||||
SlowioSnooze(FileSystem);
|
||||
#endif
|
||||
|
||||
memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset));
|
||||
|
||||
*PBytesTransferred = (ULONG)(EndOffset - Offset);
|
||||
@ -1082,6 +1237,27 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MEMFS_SLOWIO
|
||||
if (SlowioReturnPending(FileSystem))
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
try
|
||||
{
|
||||
InterlockedIncrement(&Memfs->SlowioThreadsRunning);
|
||||
std::thread(SlowioWriteThread,
|
||||
FileSystem, FileNode, Buffer, Offset, EndOffset,
|
||||
FspFileSystemGetOperationContext()->Request->Hint).
|
||||
detach();
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
|
||||
}
|
||||
}
|
||||
SlowioSnooze(FileSystem);
|
||||
#endif
|
||||
|
||||
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
|
||||
|
||||
*PBytesTransferred = (ULONG)(EndOffset - Offset);
|
||||
@ -1451,6 +1627,26 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
ReadDirectoryEnumFn, &Context))
|
||||
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||
|
||||
#ifdef MEMFS_SLOWIO
|
||||
if (SlowioReturnPending(FileSystem))
|
||||
{
|
||||
try
|
||||
{
|
||||
InterlockedIncrement(&Memfs->SlowioThreadsRunning);
|
||||
std::thread(SlowioReadDirectoryThread,
|
||||
FileSystem, *PBytesTransferred,
|
||||
FspFileSystemGetOperationContext()->Request->Hint).
|
||||
detach();
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
|
||||
}
|
||||
}
|
||||
SlowioSnooze(FileSystem);
|
||||
#endif
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1752,6 +1948,9 @@ NTSTATUS MemfsCreateFunnel(
|
||||
ULONG FileInfoTimeout,
|
||||
ULONG MaxFileNodes,
|
||||
ULONG MaxFileSize,
|
||||
ULONG SlowioMaxDelay,
|
||||
ULONG SlowioPercentDelay,
|
||||
ULONG SlowioRarefyDelay,
|
||||
PWSTR FileSystemName,
|
||||
PWSTR VolumePrefix,
|
||||
PWSTR RootSddl,
|
||||
@ -1793,6 +1992,12 @@ NTSTATUS MemfsCreateFunnel(
|
||||
AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
|
||||
Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit);
|
||||
|
||||
#ifdef MEMFS_SLOWIO
|
||||
Memfs->SlowioMaxDelay = SlowioMaxDelay;
|
||||
Memfs->SlowioPercentDelay = SlowioPercentDelay;
|
||||
Memfs->SlowioRarefyDelay = SlowioRarefyDelay;
|
||||
#endif
|
||||
|
||||
Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
@ -1895,12 +2100,21 @@ VOID MemfsDelete(MEMFS *Memfs)
|
||||
|
||||
NTSTATUS MemfsStart(MEMFS *Memfs)
|
||||
{
|
||||
#ifdef MEMFS_SLOWIO
|
||||
Memfs->SlowioThreadsRunning = 0;
|
||||
#endif
|
||||
|
||||
return FspFileSystemStartDispatcher(Memfs->FileSystem, 0);
|
||||
}
|
||||
|
||||
VOID MemfsStop(MEMFS *Memfs)
|
||||
{
|
||||
FspFileSystemStopDispatcher(Memfs->FileSystem);
|
||||
|
||||
#ifdef MEMFS_SLOWIO
|
||||
while (Memfs->SlowioThreadsRunning)
|
||||
Sleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs)
|
||||
|
@ -33,13 +33,27 @@ enum
|
||||
MemfsCaseInsensitive = 0x80,
|
||||
};
|
||||
|
||||
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
|
||||
MemfsCreateFunnel(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, 0, VolumePrefix, RootSddl, PMemfs)
|
||||
#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\
|
||||
MemfsCreateFunnel(\
|
||||
Flags,\
|
||||
FileInfoTimeout,\
|
||||
MaxFileNodes,\
|
||||
MaxFileSize,\
|
||||
0/*SlowioMaxDelay*/,\
|
||||
0/*SlowioPercentDelay*/,\
|
||||
0/*SlowioRarefyDelay*/,\
|
||||
0/*FileSystemName*/,\
|
||||
VolumePrefix,\
|
||||
RootSddl,\
|
||||
PMemfs)
|
||||
NTSTATUS MemfsCreateFunnel(
|
||||
ULONG Flags,
|
||||
ULONG FileInfoTimeout,
|
||||
ULONG MaxFileNodes,
|
||||
ULONG MaxFileSize,
|
||||
ULONG SlowioMaxDelay,
|
||||
ULONG SlowioPercentDelay,
|
||||
ULONG SlowioRarefyDelay,
|
||||
PWSTR FileSystemName,
|
||||
PWSTR VolumePrefix,
|
||||
PWSTR RootSddl,
|
||||
|
@ -375,6 +375,7 @@ namespace passthrough
|
||||
4096,
|
||||
0,
|
||||
Security));
|
||||
FileDesc.SetFileAttributes(FileAttributes | (UInt32)System.IO.FileAttributes.Archive);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -388,8 +389,8 @@ namespace passthrough
|
||||
}
|
||||
FileDesc = new FileDesc(
|
||||
Directory.CreateDirectory(FileName, Security));
|
||||
FileDesc.SetFileAttributes(FileAttributes);
|
||||
}
|
||||
FileDesc.SetFileAttributes(FileAttributes);
|
||||
FileNode = default(Object);
|
||||
FileDesc0 = FileDesc;
|
||||
NormalizedName = default(String);
|
||||
@ -453,9 +454,11 @@ namespace passthrough
|
||||
{
|
||||
FileDesc FileDesc = (FileDesc)FileDesc0;
|
||||
if (ReplaceFileAttributes)
|
||||
FileDesc.SetFileAttributes(FileAttributes);
|
||||
FileDesc.SetFileAttributes(FileAttributes |
|
||||
(UInt32)System.IO.FileAttributes.Archive);
|
||||
else if (0 != FileAttributes)
|
||||
FileDesc.SetFileAttributes(FileDesc.GetFileAttributes() | FileAttributes);
|
||||
FileDesc.SetFileAttributes(FileDesc.GetFileAttributes() | FileAttributes |
|
||||
(UInt32)System.IO.FileAttributes.Archive);
|
||||
FileDesc.Stream.SetLength(0);
|
||||
return FileDesc.GetFileInfo(out FileInfo);
|
||||
}
|
||||
@ -637,11 +640,17 @@ namespace passthrough
|
||||
FileDesc FileDesc = (FileDesc)FileDesc0;
|
||||
if (null == FileDesc.FileSystemInfos)
|
||||
{
|
||||
IEnumerable Enum = FileDesc.DirInfo.EnumerateFileSystemInfos(
|
||||
null != Pattern ? Pattern : "*");
|
||||
if (null != Pattern)
|
||||
Pattern = Pattern.Replace('<', '*').Replace('>', '?').Replace('"', '.');
|
||||
else
|
||||
Pattern = "*";
|
||||
IEnumerable Enum = FileDesc.DirInfo.EnumerateFileSystemInfos(Pattern);
|
||||
SortedList List = new SortedList();
|
||||
List.Add(".", FileDesc.DirInfo);
|
||||
List.Add("..", FileDesc.DirInfo.Parent);
|
||||
if (null != FileDesc.DirInfo && null != FileDesc.DirInfo.Parent)
|
||||
{
|
||||
List.Add(".", FileDesc.DirInfo);
|
||||
List.Add("..", FileDesc.DirInfo.Parent);
|
||||
}
|
||||
foreach (FileSystemInfo Info in Enum)
|
||||
List.Add(Info.Name, Info);
|
||||
FileDesc.FileSystemInfos = new DictionaryEntry[List.Count];
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define PTFS_UTIMENS
|
||||
|
||||
#define FSNAME "passthrough"
|
||||
#define PROGNAME "passthrough-fuse"
|
||||
|
||||
@ -39,8 +41,8 @@
|
||||
#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))
|
||||
dirfd((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit))
|
||||
#define fi_dirp(fi) ((DIR *)(intptr_t)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))
|
||||
|
||||
@ -112,12 +114,14 @@ static int ptfs_truncate(const char *path, fuse_off_t size)
|
||||
return -1 != truncate(path, size) ? 0 : -errno;
|
||||
}
|
||||
|
||||
#if !defined(PTFS_UTIMENS)
|
||||
static int ptfs_utime(const char *path, struct fuse_utimbuf *timbuf)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != utime(path, timbuf) ? 0 : -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ptfs_open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
@ -212,6 +216,10 @@ static void *ptfs_init(struct fuse_conn_info *conn)
|
||||
conn->want |= (conn->capable & FSP_FUSE_CAP_READDIR_PLUS);
|
||||
#endif
|
||||
|
||||
#if defined(FSP_FUSE_USE_STAT_EX) && defined(FSP_FUSE_CAP_STAT_EX)
|
||||
conn->want |= (conn->capable & FSP_FUSE_CAP_STAT_EX);
|
||||
#endif
|
||||
|
||||
#if defined(FSP_FUSE_CAP_CASE_INSENSITIVE)
|
||||
conn->want |= (conn->capable & FSP_FUSE_CAP_CASE_INSENSITIVE);
|
||||
#endif
|
||||
@ -242,43 +250,68 @@ static int ptfs_fgetattr(const char *path, struct fuse_stat *stbuf, struct fuse_
|
||||
return -1 != fstat(fd, stbuf) ? 0 : -errno;
|
||||
}
|
||||
|
||||
#if defined(PTFS_UTIMENS)
|
||||
static int ptfs_utimens(const char *path, const struct fuse_timespec tv[2])
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != utimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW) ? 0 : -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
static int ptfs_setcrtime(const char *path, const struct fuse_timespec *tv)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != setcrtime(path, tv) ? 0 : -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
static int ptfs_chflags(const char *path, uint32_t flags)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != lchflags(path, flags) ? 0 : -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
ptfs_init,
|
||||
0, //destroy
|
||||
0, //access
|
||||
ptfs_create,
|
||||
ptfs_ftruncate,
|
||||
ptfs_fgetattr,
|
||||
.getattr = ptfs_getattr,
|
||||
.mkdir = ptfs_mkdir,
|
||||
.unlink = ptfs_unlink,
|
||||
.rmdir = ptfs_rmdir,
|
||||
.rename = ptfs_rename,
|
||||
.chmod = ptfs_chmod,
|
||||
.chown = ptfs_chown,
|
||||
.truncate = ptfs_truncate,
|
||||
#if !defined(PTFS_UTIMENS)
|
||||
.utime = ptfs_utime,
|
||||
#endif
|
||||
.open = ptfs_open,
|
||||
.read = ptfs_read,
|
||||
.write = ptfs_write,
|
||||
.statfs = ptfs_statfs,
|
||||
.release = ptfs_release,
|
||||
.fsync = ptfs_fsync,
|
||||
.opendir = ptfs_opendir,
|
||||
.readdir = ptfs_readdir,
|
||||
.releasedir = ptfs_releasedir,
|
||||
.init = ptfs_init,
|
||||
.create = ptfs_create,
|
||||
.ftruncate = ptfs_ftruncate,
|
||||
.fgetattr = ptfs_fgetattr,
|
||||
#if defined(PTFS_UTIMENS)
|
||||
.utimens = ptfs_utimens,
|
||||
#endif
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
.setcrtime = ptfs_setcrtime,
|
||||
#endif
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
.chflags = ptfs_chflags,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
|
@ -99,7 +99,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -118,7 +118,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -139,7 +139,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -162,7 +162,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>FSP_FUSE_USE_STAT_EX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file passthrough-fuse.c
|
||||
* @file winposix.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
@ -36,6 +36,40 @@ struct _DIR
|
||||
char path[];
|
||||
};
|
||||
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
static inline uint32_t MapFileAttributesToFlags(UINT32 FileAttributes)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
flags |= FSP_FUSE_UF_READONLY;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
||||
flags |= FSP_FUSE_UF_HIDDEN;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_SYSTEM)
|
||||
flags |= FSP_FUSE_UF_SYSTEM;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE)
|
||||
flags |= FSP_FUSE_UF_ARCHIVE;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline UINT32 MapFlagsToFileAttributes(uint32_t flags)
|
||||
{
|
||||
UINT32 FileAttributes = 0;
|
||||
|
||||
if (flags & FSP_FUSE_UF_READONLY)
|
||||
FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
if (flags & FSP_FUSE_UF_HIDDEN)
|
||||
FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
if (flags & FSP_FUSE_UF_SYSTEM)
|
||||
FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
|
||||
if (flags & FSP_FUSE_UF_ARCHIVE)
|
||||
FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
return FileAttributes;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int maperror(int winerrno);
|
||||
|
||||
static inline void *error0(void)
|
||||
@ -151,28 +185,22 @@ 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;
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftCreationTime, (void *)&stbuf->st_birthtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastAccessTime, (void *)&stbuf->st_atim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_mtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_ctim);
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
stbuf->st_flags = MapFileAttributesToFlags(FileInfo.dwFileAttributes);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -272,6 +300,21 @@ int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lchflags(const char *path, uint32_t flags)
|
||||
{
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
UINT32 FileAttributes = MapFlagsToFileAttributes(flags);
|
||||
|
||||
if (0 == FileAttributes)
|
||||
FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
if (!SetFileAttributesA(path, FileAttributes))
|
||||
return error();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int truncate(const char *path, fuse_off_t size)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
@ -290,6 +333,24 @@ int truncate(const char *path, fuse_off_t size)
|
||||
|
||||
int utime(const char *path, const struct fuse_utimbuf *timbuf)
|
||||
{
|
||||
if (0 == timbuf)
|
||||
return utimensat(AT_FDCWD, path, 0, AT_SYMLINK_NOFOLLOW);
|
||||
else
|
||||
{
|
||||
struct fuse_timespec times[2];
|
||||
times[0].tv_sec = timbuf->actime;
|
||||
times[0].tv_nsec = 0;
|
||||
times[1].tv_sec = timbuf->modtime;
|
||||
times[1].tv_nsec = 0;
|
||||
return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
}
|
||||
|
||||
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag)
|
||||
{
|
||||
/* ignore dirfd and assume that it is always AT_FDCWD */
|
||||
/* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
|
||||
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
@ -297,8 +358,18 @@ int utime(const char *path, const struct fuse_utimbuf *timbuf)
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
UINT64 LastAccessTime = timbuf->actime * 10000000 + 116444736000000000;
|
||||
UINT64 LastWriteTime = timbuf->modtime * 10000000 + 116444736000000000;
|
||||
UINT64 LastAccessTime, LastWriteTime;
|
||||
if (0 == times)
|
||||
{
|
||||
FILETIME FileTime;
|
||||
GetSystemTimeAsFileTime(&FileTime);
|
||||
LastAccessTime = LastWriteTime = *(PUINT64)&FileTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
FspPosixUnixTimeToFileTime((void *)×[0], &LastAccessTime);
|
||||
FspPosixUnixTimeToFileTime((void *)×[1], &LastWriteTime);
|
||||
}
|
||||
|
||||
int res = SetFileTime(h,
|
||||
0, (PFILETIME)&LastAccessTime, (PFILETIME)&LastWriteTime) ? 0 : error();
|
||||
@ -308,6 +379,26 @@ int utime(const char *path, const struct fuse_utimbuf *timbuf)
|
||||
return res;
|
||||
}
|
||||
|
||||
int setcrtime(const char *path, const struct fuse_timespec *tv)
|
||||
{
|
||||
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 CreationTime;
|
||||
FspPosixUnixTimeToFileTime((void *)tv, &CreationTime);
|
||||
|
||||
int res = SetFileTime(h,
|
||||
(PFILETIME)&CreationTime, 0, 0) ? 0 : error();
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unlink(const char *path)
|
||||
{
|
||||
if (!DeleteFileA(path))
|
||||
@ -388,7 +479,6 @@ void rewinddir(DIR *dirp)
|
||||
struct dirent *readdir(DIR *dirp)
|
||||
{
|
||||
WIN32_FIND_DATAA FindData;
|
||||
UINT64 CreationTime, LastAccessTime, LastWriteTime;
|
||||
struct fuse_stat *stbuf = &dirp->de.d_stat;
|
||||
|
||||
if (INVALID_HANDLE_VALUE == dirp->fh)
|
||||
@ -407,23 +497,18 @@ struct dirent *readdir(DIR *dirp)
|
||||
}
|
||||
}
|
||||
|
||||
CreationTime = ((PLARGE_INTEGER)(&FindData.ftCreationTime))->QuadPart - 116444736000000000;
|
||||
LastAccessTime = ((PLARGE_INTEGER)(&FindData.ftLastAccessTime))->QuadPart - 116444736000000000;
|
||||
LastWriteTime = ((PLARGE_INTEGER)(&FindData.ftLastWriteTime))->QuadPart - 116444736000000000;
|
||||
|
||||
memset(stbuf, 0, sizeof *stbuf);
|
||||
stbuf->st_mode = 0777 |
|
||||
((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = ((UINT64)FindData.nFileSizeHigh << 32) | ((UINT64)FindData.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;
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftCreationTime, (void *)&stbuf->st_birthtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastAccessTime, (void *)&stbuf->st_atim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_mtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_ctim);
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
|
||||
#endif
|
||||
|
||||
strcpy(dirp->de.d_name, FindData.cFileName);
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
#define O_TRUNC _O_TRUNC
|
||||
|
||||
#define PATH_MAX 1024
|
||||
#define AT_FDCWD -2
|
||||
#define AT_SYMLINK_NOFOLLOW 2
|
||||
|
||||
typedef struct _DIR DIR;
|
||||
struct dirent
|
||||
@ -50,8 +52,11 @@ 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 lchflags(const char *path, uint32_t flags);
|
||||
int truncate(const char *path, fuse_off_t size);
|
||||
int utime(const char *path, const struct fuse_utimbuf *timbuf);
|
||||
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag);
|
||||
int setcrtime(const char *path, const struct fuse_timespec *tv);
|
||||
int unlink(const char *path);
|
||||
int rename(const char *oldpath, const char *newpath);
|
||||
|
||||
|
@ -39,6 +39,11 @@ void create_dotest(ULONG Flags, PWSTR Prefix)
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||
ASSERT(ERROR_FILE_EXISTS == GetLastError());
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
@ -227,6 +232,122 @@ void create_test(void)
|
||||
create_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||
}
|
||||
|
||||
static void create_fileattr_dotest(ULONG Flags, PWSTR Prefix)
|
||||
{
|
||||
void *memfs = memfs_start(Flags);
|
||||
|
||||
HANDLE Handle;
|
||||
BOOLEAN Success;
|
||||
DWORD FileAttributes;
|
||||
WCHAR FilePath[MAX_PATH];
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT(FILE_ATTRIBUTE_ARCHIVE == FileAttributes);
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_READONLY, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY) == FileAttributes);
|
||||
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
|
||||
ASSERT(Success);
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM) == FileAttributes);
|
||||
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
|
||||
ASSERT(Success);
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN) == FileAttributes);
|
||||
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
|
||||
ASSERT(Success);
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT(FILE_ATTRIBUTE_ARCHIVE == FileAttributes);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY) == FileAttributes);
|
||||
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
|
||||
ASSERT(Success);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM) == FileAttributes);
|
||||
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
|
||||
ASSERT(Success);
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
FileAttributes = GetFileAttributesW(FilePath);
|
||||
ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN) == FileAttributes);
|
||||
Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL);
|
||||
ASSERT(Success);
|
||||
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
memfs_stop(memfs);
|
||||
}
|
||||
|
||||
static void create_fileattr_test(void)
|
||||
{
|
||||
if (NtfsTests)
|
||||
{
|
||||
WCHAR DirBuf[MAX_PATH];
|
||||
GetTestDirectory(DirBuf);
|
||||
create_fileattr_dotest(-1, DirBuf);
|
||||
}
|
||||
if (WinFspDiskTests)
|
||||
create_fileattr_dotest(MemfsDisk, 0);
|
||||
if (WinFspNetTests)
|
||||
create_fileattr_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||
}
|
||||
|
||||
void create_related_dotest(ULONG Flags, PWSTR Prefix)
|
||||
{
|
||||
void *memfs = memfs_start(Flags);
|
||||
@ -1136,6 +1257,7 @@ void create_pid_test(void)
|
||||
void create_tests(void)
|
||||
{
|
||||
TEST(create_test);
|
||||
TEST(create_fileattr_test);
|
||||
TEST(create_related_test);
|
||||
TEST(create_allocation_test);
|
||||
TEST(create_sd_test);
|
||||
|
@ -416,6 +416,98 @@ void querydir_buffer_overflow_test(void)
|
||||
}
|
||||
}
|
||||
|
||||
static VOID querydir_namelen_exists(PWSTR FilePath)
|
||||
{
|
||||
HANDLE Handle;
|
||||
WIN32_FIND_DATAW FindData;
|
||||
|
||||
Handle = FindFirstFileW(FilePath, &FindData);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
FindClose(Handle);
|
||||
}
|
||||
|
||||
static void querydir_namelen_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
|
||||
{
|
||||
/* based on create_namelen_dotest */
|
||||
|
||||
void *memfs = memfs_start(Flags);
|
||||
|
||||
WCHAR FilePath[1024];
|
||||
PWSTR FilePathBgn, P, EndP;
|
||||
DWORD MaxComponentLength;
|
||||
HANDLE Handle;
|
||||
BOOL Success;
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Drive ? Drive : memfs_volumename(memfs));
|
||||
|
||||
Success = GetVolumeInformationW(FilePath,
|
||||
0, 0,
|
||||
0, &MaxComponentLength, 0,
|
||||
0, 0);
|
||||
ASSERT(Success);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
FilePathBgn = FilePath + wcslen(FilePath);
|
||||
|
||||
for (P = FilePathBgn, EndP = P + MaxComponentLength - 1; EndP > P; P++)
|
||||
*P = (P - FilePathBgn) % 10 + '0';
|
||||
*P = L'\0';
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
querydir_namelen_exists(FilePath);
|
||||
Success = CloseHandle(Handle);
|
||||
ASSERT(Success);
|
||||
|
||||
for (P = FilePathBgn, EndP = P + MaxComponentLength; EndP > P; P++)
|
||||
*P = (P - FilePathBgn) % 10 + '0';
|
||||
*P = L'\0';
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
querydir_namelen_exists(FilePath);
|
||||
Success = CloseHandle(Handle);
|
||||
ASSERT(Success);
|
||||
|
||||
for (P = FilePathBgn, EndP = P + MaxComponentLength + 1; EndP > P; P++)
|
||||
*P = (P - FilePathBgn) % 10 + '0';
|
||||
*P = L'\0';
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE == Handle);
|
||||
ASSERT(ERROR_INVALID_NAME == GetLastError());
|
||||
|
||||
memfs_stop(memfs);
|
||||
}
|
||||
|
||||
static void querydir_namelen_test(void)
|
||||
{
|
||||
if (OptShareName || OptMountPoint)
|
||||
return;
|
||||
|
||||
if (NtfsTests)
|
||||
{
|
||||
WCHAR DirBuf[MAX_PATH], DriveBuf[3];
|
||||
GetTestDirectoryAndDrive(DirBuf, DriveBuf);
|
||||
querydir_namelen_dotest(-1, DirBuf, DriveBuf);
|
||||
}
|
||||
if (WinFspDiskTests)
|
||||
querydir_namelen_dotest(MemfsDisk, 0, 0);
|
||||
#if 0
|
||||
/* This test does not work when going through the MUP! */
|
||||
if (WinFspNetTests)
|
||||
querydir_namelen_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share");
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned __stdcall dirnotify_dotest_thread(void *FilePath)
|
||||
{
|
||||
FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
|
||||
@ -552,5 +644,7 @@ void dirctl_tests(void)
|
||||
TEST(querydir_expire_cache_test);
|
||||
if (!OptShareName)
|
||||
TEST(querydir_buffer_overflow_test);
|
||||
if (!OptShareName && !OptMountPoint)
|
||||
TEST(querydir_namelen_test);
|
||||
TEST(dirnotify_test);
|
||||
}
|
||||
|
@ -291,22 +291,22 @@ void setfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
|
||||
ASSERT(Success);
|
||||
ASSERT(FILE_ATTRIBUTE_HIDDEN == FileInfo.dwFileAttributes);
|
||||
|
||||
*(PUINT64)&FileTime = 0x4200000042ULL;
|
||||
*(PUINT64)&FileTime = 116444736000000000ULL + 0x4200000042ULL;
|
||||
Success = SetFileTime(Handle, 0, &FileTime, &FileTime);
|
||||
ASSERT(Success);
|
||||
|
||||
Success = GetFileInformationByHandle(Handle, &FileInfo);
|
||||
ASSERT(Success);
|
||||
ASSERT(*(PUINT64)&FileInfo0.ftCreationTime == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
|
||||
|
||||
Success = SetFileTime(Handle, &FileTime, 0, 0);
|
||||
ASSERT(Success);
|
||||
|
||||
Success = GetFileInformationByHandle(Handle, &FileInfo);
|
||||
ASSERT(Success);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
|
||||
Offset = SetFilePointer(Handle, 42, 0, 0);
|
||||
ASSERT(42 == Offset);
|
||||
|
@ -35,11 +35,15 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
|
||||
MEMFS *Memfs;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = MemfsCreate(
|
||||
Result = MemfsCreateFunnel(
|
||||
(OptCaseInsensitive ? MemfsCaseInsensitive : 0) | Flags,
|
||||
FileInfoTimeout,
|
||||
1024,
|
||||
1024 * 1024,
|
||||
50, /*SlowioMaxDelay*/
|
||||
10, /*SlowioPercentDelay*/
|
||||
5, /*SlowioRarefyDelay*/
|
||||
0,
|
||||
MemfsNet == Flags ? L"\\memfs\\share" : 0,
|
||||
0,
|
||||
&Memfs);
|
||||
|
@ -1194,22 +1194,22 @@ static void stream_setfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoT
|
||||
ASSERT(Success);
|
||||
ASSERT(FILE_ATTRIBUTE_HIDDEN == FileInfo.dwFileAttributes);
|
||||
|
||||
*(PUINT64)&FileTime = 0x4200000042ULL;
|
||||
*(PUINT64)&FileTime = 116444736000000000ULL + 0x4200000042ULL;
|
||||
Success = SetFileTime(StreamHandle, 0, &FileTime, &FileTime);
|
||||
ASSERT(Success);
|
||||
|
||||
Success = GetFileInformationByHandle(StreamHandle, &FileInfo);
|
||||
ASSERT(Success);
|
||||
ASSERT(*(PUINT64)&FileInfo0.ftCreationTime == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
|
||||
|
||||
Success = SetFileTime(StreamHandle, &FileTime, 0, 0);
|
||||
ASSERT(Success);
|
||||
|
||||
Success = GetFileInformationByHandle(StreamHandle, &FileInfo);
|
||||
ASSERT(Success);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
|
||||
Offset = SetFilePointer(StreamHandle, 42, 0, 0);
|
||||
ASSERT(42 == Offset);
|
||||
@ -1238,9 +1238,9 @@ static void stream_setfileinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoT
|
||||
Success = GetFileInformationByHandle(Handle, &FileInfo);
|
||||
ASSERT(Success);
|
||||
ASSERT(0 != (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN));
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
|
||||
ASSERT(0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastAccessTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftLastWriteTime);
|
||||
ASSERT(116444736000000000ULL + 0x4200000042ULL == *(PUINT64)&FileInfo.ftCreationTime);
|
||||
ASSERT(0 == FileInfo.nFileSizeLow);
|
||||
ASSERT(0 == FileInfo.nFileSizeHigh);
|
||||
|
||||
|
Reference in New Issue
Block a user